<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 logcfg

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/spf13/cast"

	"mynewt.apache.org/newt/newt/newtutil"
	"mynewt.apache.org/newt/newt/pkg"
	"mynewt.apache.org/newt/newt/syscfg"
	"mynewt.apache.org/newt/util"
)

const HEADER_PATH = "logcfg/logcfg.h"

type LogSetting struct {
	// The exact text specified as the YAML map key.
	Text string

	// If this setting refers to a syscfg setting via the `MYNEWT_VAL(...)`
	// notation, this contains the name of the setting.  Otherwise, "".
	RefName string

	// The setting value, after setting references are resolved.
	Value string
}

type Log struct {
	// Log name; equal to the name of the YAML map that defines the log.
	Name string

	// The package that defines the log.
	Source *pkg.LocalPackage

	// The log's numeric module ID.
	Module LogSetting

	// The level assigned to this log.
	Level LogSetting
}

// Map of: [log-name] => log
type LogMap map[string]Log

// The log configuration of the target.
type LCfg struct {
	// [log-name] => log
	Logs LogMap

	// Strings describing errors encountered while parsing the log config.
	InvalidSettings []string

	// Contains sets of logs with conflicting module IDs.
	//     [module-ID] => <slice-of-logs-with-module-id>
	ModuleConflicts map[int][]Log
}

// Maps numeric log levels to their string representations.  Used when
// generating the C log macros.
var logLevelNames = []string{
	0: "DEBUG",
	1: "INFO",
	2: "WARN",
	3: "ERROR",
	4: "CRITICAL",
}

func LogLevelString(level int) string {
	if level < 0 || level >= len(logLevelNames) {
		return "???"
	}

	return logLevelNames[level]
}

func NewLCfg() LCfg {
	return LCfg{
		Logs:            map[string]Log{},
		ModuleConflicts: map[int][]Log{},
	}
}

// IntVal Extracts a log setting's integer value.
func (ls *LogSetting) IntVal() (int, error) {
	iv, err := util.AtoiNoOct(ls.Value)
	if err != nil {
		return 0, util.ChildNewtError(err)
	}

	return iv, nil
}

// Constructs a log setting from a YAML string.
func resolveLogVal(s string, cfg *syscfg.Cfg) (LogSetting, error) {
	refName, val, err := cfg.ExpandRef(s)
	if err != nil {
		return LogSetting{},
			util.FmtNewtError("value \"%s\" references undefined setting", s)
	}

	return LogSetting{
		Text:    s,
		RefName: refName,
		Value:   val,
	}, nil
}

// Parses a single log definition from a YAML map.  The `logMapItf` parameter
// should be a map with the following elements:
//     "module": <module-string>
//     "level": <level-string>
func parseOneLog(name string, lpkg *pkg.LocalPackage, logMapItf interface{},
	cfg *syscfg.Cfg) (Log, error) {

	cl := Log{
		Name:   name,
		Source: lpkg,
	}

	logMap := cast.ToStringMapString(logMapItf)
	if logMap == nil {
		return cl, util.FmtNewtError(
			"\"%s\" missing required field \"module\"", name)
	}

	modStr := logMap["module"]
	if modStr == "" {
		return cl, util.FmtNewtError(
			"\"%s\" missing required field \"module\"", name)
	}
	mod, err := resolveLogVal(modStr, cfg)
	if err != nil {
		return cl, util.FmtNewtError(
			"\"%s\" contains invalid \"module\": %s",
			name, err.Error())
	}
	if _, err := mod.IntVal(); err != nil {
		return cl, util.FmtNewtError(
			"\"%s\" contains invalid \"module\": %s", name, err.Error())
	}

	levelStr := logMap["level"]
	if levelStr == "" {
		return cl, util.FmtNewtError(
			"\"%s\" missing required field \"level\"", name)
	}
	level, err := resolveLogVal(levelStr, cfg)
	if err != nil {
		return cl, util.FmtNewtError(
			"\"%s\" contains invalid \"level\": %s",
			name, err.Error())
	}
	if _, err := level.IntVal(); err != nil {
		return cl, util.FmtNewtError(
			"\"%s\" contains invalid \"level\": %s", name, err.Error())
	}

	cl.Module = mod
	cl.Level = level

	return cl, nil
}

// Reads all the logs defined by the specified package.  The log definitions
// are read from the `syscfg.logs` map in the package's `syscfg.yml` file.
func (lcfg *LCfg) readOnePkg(lpkg *pkg.LocalPackage, cfg *syscfg.Cfg) {
	lsettings := cfg.AllSettingsForLpkg(lpkg)
	logMaps := lpkg.SyscfgY.GetValStringMap("syscfg.logs", lsettings)
	for name, logMapItf := range logMaps {
		cl, err := parseOneLog(name, lpkg, logMapItf, cfg)
		if err != nil {
			lcfg.InvalidSettings =
				append(lcfg.InvalidSettings, strings.TrimSpace(err.Error()))
		} else {
			lcfg.Logs[cl.Name] = cl
		}
	}
}

// Searches the log configuration for logs with identical module IDs.  The log
// configuration object is populated with the results.
func (lcfg *LCfg) detectModuleConflicts() {
	m := map[int][]Log{}

	for _, l := range lcfg.Logs {
		intMod, _ := l.Module.IntVal()
		m[intMod] = append(m[intMod], l)
	}

	for mod, logs := range m {
		if len(logs) > 1 {
			for _, l := range logs {
				lcfg.ModuleConflicts[mod] =
					append(lcfg.ModuleConflicts[mod], l)
			}
		}
	}
}

// Reads all log definitions for each of the specified packages.  The
// returned LCfg object is populated with the result of this operation.
func Read(lpkgs []*pkg.LocalPackage, cfg *syscfg.Cfg) LCfg {
	lcfg := NewLCfg()

	for _, lpkg := range lpkgs {
		lcfg.readOnePkg(lpkg, cfg)
	}

	lcfg.detectModuleConflicts()

	return lcfg
}

// If any errors were encountered while parsing log definitions, this function
// returns a string indicating the errors.  If no errors were encountered, ""
// is returned.
func (lcfg *LCfg) ErrorText() string {
	str := ""

	if len(lcfg.InvalidSettings) > 0 {
		str += "Invalid log definitions detected:"
		for _, e := range lcfg.InvalidSettings {
			str += "\n    " + e
		}
	}

	if len(lcfg.ModuleConflicts) > 0 {
		str += "Log module conflicts detected:\n"
		for mod, logs := range lcfg.ModuleConflicts {
			for _, l := range logs {
				str += fmt.Sprintf("    Module=%d Log=%s Package=%s\n",
					mod, l.Name, l.Source.FullName())
			}
		}

		str +=
			"\nResolve the problem by assigning unique module IDs to each log."
	}

	return str
}

// Retrieves a sorted slice of logs from the receiving log configuration.
func (lcfg *LCfg) sortedLogs() []Log {
	names := make([]string, 0, len(lcfg.Logs))

	for n, _ := range lcfg.Logs {
		names = append(names, n)
	}
	sort.Strings(names)

	logs := make([]Log, 0, len(names))
	for _, n := range names {
		logs = append(logs, lcfg.Logs[n])
	}

	return logs
}

// Writes a no-op stub log C macro definition.
func writeLogStub(logName string, levelStr string, w io.Writer) {
	fmt.Fprintf(w, "#define %s_%s(...) IGNORE(__VA_ARGS__)\n",
		logName, levelStr)
}

// Writes a log C macro definition.
func writeLogMacro(logName string, module int, levelStr string, w io.Writer) {
	fmt.Fprintf(w,
		"#define %s_%s(...) MODLOG_%s(%d, __VA_ARGS__)\n",
		logName, levelStr, levelStr, module)
}

// Write log C macro definitions for each log in the log configuration.
func (lcfg *LCfg) writeLogMacros(w io.Writer) {
	logs := lcfg.sortedLogs()
	for _, l := range logs {
		fmt.Fprintf(w, "\n")

		levelInt, _ := util.AtoiNoOct(l.Level.Value)
		for i, levelStr := range logLevelNames {
			if i < levelInt {
				writeLogStub(l.Name, levelStr, w)
			} else {
				modInt, _ := l.Module.IntVal()
				writeLogMacro(l.Name, modInt, levelStr, w)
			}
		}
	}
}

// Writes a logcfg header file to the specified writer.
func (lcfg *LCfg) write(w io.Writer) {
	fmt.Fprintf(w, newtutil.GeneratedPreamble())

	fmt.Fprintf(w, "#ifndef H_MYNEWT_LOGCFG_\n")
	fmt.Fprintf(w, "#define H_MYNEWT_LOGCFG_\n\n")

	if len(lcfg.Logs) > 0 {
		fmt.Fprintf(w, "#include \"modlog/modlog.h\"\n")
		fmt.Fprintf(w, "#include \"log_common/log_common.h\"\n")

		lcfg.writeLogMacros(w)
		fmt.Fprintf(w, "\n")
	}

	fmt.Fprintf(w, "#endif\n")
}

// Ensures an up-to-date logcfg header is written for the target.
func (lcfg *LCfg) EnsureWritten(includeDir string) error {
	buf := bytes.Buffer{}
	lcfg.write(&buf)

	path := includeDir + "/" + HEADER_PATH

	writeReqd, err := util.FileContentsChanged(path, buf.Bytes())
	if err != nil {
		return err
	}
	if !writeReqd {
		log.Debugf("logcfg unchanged; not writing header file (%s).", path)
		return nil
	}

	log.Debugf("logcfg changed; writing header file (%s).", path)

	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
		return util.NewNewtError(err.Error())
	}

	if err := ioutil.WriteFile(path, buf.Bytes(), 0644); err != nil {
		return util.NewNewtError(err.Error())
	}

	return nil
}
<commit_msg>logcfg: use ValSetting (generic setting value)<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 logcfg

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/spf13/cast"

	"mynewt.apache.org/newt/newt/newtutil"
	"mynewt.apache.org/newt/newt/pkg"
	"mynewt.apache.org/newt/newt/syscfg"
	"mynewt.apache.org/newt/newt/val"
	"mynewt.apache.org/newt/util"
)

const HEADER_PATH = "logcfg/logcfg.h"

type Log struct {
	// Log name; equal to the name of the YAML map that defines the log.
	Name string

	// The package that defines the log.
	Source *pkg.LocalPackage

	// The log's numeric module ID.
	Module val.ValSetting

	// The level assigned to this log.
	Level val.ValSetting
}

// Map of: [log-name] => log
type LogMap map[string]Log

// The log configuration of the target.
type LCfg struct {
	// [log-name] => log
	Logs LogMap

	// Strings describing errors encountered while parsing the log config.
	InvalidSettings []string

	// Contains sets of logs with conflicting module IDs.
	//     [module-ID] => <slice-of-logs-with-module-id>
	ModuleConflicts map[int][]Log
}

// Maps numeric log levels to their string representations.  Used when
// generating the C log macros.
var logLevelNames = []string{
	0: "DEBUG",
	1: "INFO",
	2: "WARN",
	3: "ERROR",
	4: "CRITICAL",
}

func LogLevelString(level int) string {
	if level < 0 || level >= len(logLevelNames) {
		return "???"
	}

	return logLevelNames[level]
}

func NewLCfg() LCfg {
	return LCfg{
		Logs:            map[string]Log{},
		ModuleConflicts: map[int][]Log{},
	}
}

// Parses a single log definition from a YAML map.  The `logMapItf` parameter
// should be a map with the following elements:
//     "module": <module-string>
//     "level": <level-string>
func parseOneLog(name string, lpkg *pkg.LocalPackage, logMapItf interface{},
	cfg *syscfg.Cfg) (Log, error) {

	cl := Log{
		Name:   name,
		Source: lpkg,
	}

	logMap := cast.ToStringMapString(logMapItf)
	if logMap == nil {
		return cl, util.FmtNewtError(
			"\"%s\" missing required field \"module\"", name)
	}

	modStr := logMap["module"]
	if modStr == "" {
		return cl, util.FmtNewtError(
			"\"%s\" missing required field \"module\"", name)
	}
	mod, err := val.ResolveValSetting(modStr, cfg)
	if err != nil {
		return cl, util.FmtNewtError(
			"\"%s\" contains invalid \"module\": %s",
			name, err.Error())
	}
	if _, err := mod.IntVal(); err != nil {
		return cl, util.FmtNewtError(
			"\"%s\" contains invalid \"module\": %s", name, err.Error())
	}

	levelStr := logMap["level"]
	if levelStr == "" {
		return cl, util.FmtNewtError(
			"\"%s\" missing required field \"level\"", name)
	}
	level, err := val.ResolveValSetting(levelStr, cfg)
	if err != nil {
		return cl, util.FmtNewtError(
			"\"%s\" contains invalid \"level\": %s",
			name, err.Error())
	}
	if _, err := level.IntVal(); err != nil {
		return cl, util.FmtNewtError(
			"\"%s\" contains invalid \"level\": %s", name, err.Error())
	}

	cl.Module = mod
	cl.Level = level

	return cl, nil
}

// Reads all the logs defined by the specified package.  The log definitions
// are read from the `syscfg.logs` map in the package's `syscfg.yml` file.
func (lcfg *LCfg) readOnePkg(lpkg *pkg.LocalPackage, cfg *syscfg.Cfg) {
	lsettings := cfg.AllSettingsForLpkg(lpkg)
	logMaps := lpkg.SyscfgY.GetValStringMap("syscfg.logs", lsettings)
	for name, logMapItf := range logMaps {
		cl, err := parseOneLog(name, lpkg, logMapItf, cfg)
		if err != nil {
			lcfg.InvalidSettings =
				append(lcfg.InvalidSettings, strings.TrimSpace(err.Error()))
		} else {
			lcfg.Logs[cl.Name] = cl
		}
	}
}

// Searches the log configuration for logs with identical module IDs.  The log
// configuration object is populated with the results.
func (lcfg *LCfg) detectModuleConflicts() {
	m := map[int][]Log{}

	for _, l := range lcfg.Logs {
		intMod, _ := l.Module.IntVal()
		m[intMod] = append(m[intMod], l)
	}

	for mod, logs := range m {
		if len(logs) > 1 {
			for _, l := range logs {
				lcfg.ModuleConflicts[mod] =
					append(lcfg.ModuleConflicts[mod], l)
			}
		}
	}
}

// Reads all log definitions for each of the specified packages.  The
// returned LCfg object is populated with the result of this operation.
func Read(lpkgs []*pkg.LocalPackage, cfg *syscfg.Cfg) LCfg {
	lcfg := NewLCfg()

	for _, lpkg := range lpkgs {
		lcfg.readOnePkg(lpkg, cfg)
	}

	lcfg.detectModuleConflicts()

	return lcfg
}

// If any errors were encountered while parsing log definitions, this function
// returns a string indicating the errors.  If no errors were encountered, ""
// is returned.
func (lcfg *LCfg) ErrorText() string {
	str := ""

	if len(lcfg.InvalidSettings) > 0 {
		str += "Invalid log definitions detected:"
		for _, e := range lcfg.InvalidSettings {
			str += "\n    " + e
		}
	}

	if len(lcfg.ModuleConflicts) > 0 {
		str += "Log module conflicts detected:\n"
		for mod, logs := range lcfg.ModuleConflicts {
			for _, l := range logs {
				str += fmt.Sprintf("    Module=%d Log=%s Package=%s\n",
					mod, l.Name, l.Source.FullName())
			}
		}

		str +=
			"\nResolve the problem by assigning unique module IDs to each log."
	}

	return str
}

// Retrieves a sorted slice of logs from the receiving log configuration.
func (lcfg *LCfg) sortedLogs() []Log {
	names := make([]string, 0, len(lcfg.Logs))

	for n, _ := range lcfg.Logs {
		names = append(names, n)
	}
	sort.Strings(names)

	logs := make([]Log, 0, len(names))
	for _, n := range names {
		logs = append(logs, lcfg.Logs[n])
	}

	return logs
}

// Writes a no-op stub log C macro definition.
func writeLogStub(logName string, levelStr string, w io.Writer) {
	fmt.Fprintf(w, "#define %s_%s(...) IGNORE(__VA_ARGS__)\n",
		logName, levelStr)
}

// Writes a log C macro definition.
func writeLogMacro(logName string, module int, levelStr string, w io.Writer) {
	fmt.Fprintf(w,
		"#define %s_%s(...) MODLOG_%s(%d, __VA_ARGS__)\n",
		logName, levelStr, levelStr, module)
}

// Write log C macro definitions for each log in the log configuration.
func (lcfg *LCfg) writeLogMacros(w io.Writer) {
	logs := lcfg.sortedLogs()
	for _, l := range logs {
		fmt.Fprintf(w, "\n")

		levelInt, _ := util.AtoiNoOct(l.Level.Value)
		for i, levelStr := range logLevelNames {
			if i < levelInt {
				writeLogStub(l.Name, levelStr, w)
			} else {
				modInt, _ := l.Module.IntVal()
				writeLogMacro(l.Name, modInt, levelStr, w)
			}
		}
	}
}

// Writes a logcfg header file to the specified writer.
func (lcfg *LCfg) write(w io.Writer) {
	fmt.Fprintf(w, newtutil.GeneratedPreamble())

	fmt.Fprintf(w, "#ifndef H_MYNEWT_LOGCFG_\n")
	fmt.Fprintf(w, "#define H_MYNEWT_LOGCFG_\n\n")

	if len(lcfg.Logs) > 0 {
		fmt.Fprintf(w, "#include \"modlog/modlog.h\"\n")
		fmt.Fprintf(w, "#include \"log_common/log_common.h\"\n")

		lcfg.writeLogMacros(w)
		fmt.Fprintf(w, "\n")
	}

	fmt.Fprintf(w, "#endif\n")
}

// Ensures an up-to-date logcfg header is written for the target.
func (lcfg *LCfg) EnsureWritten(includeDir string) error {
	buf := bytes.Buffer{}
	lcfg.write(&buf)

	path := includeDir + "/" + HEADER_PATH

	writeReqd, err := util.FileContentsChanged(path, buf.Bytes())
	if err != nil {
		return err
	}
	if !writeReqd {
		log.Debugf("logcfg unchanged; not writing header file (%s).", path)
		return nil
	}

	log.Debugf("logcfg changed; writing header file (%s).", path)

	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
		return util.NewNewtError(err.Error())
	}

	if err := ioutil.WriteFile(path, buf.Bytes(), 0644); err != nil {
		return util.NewNewtError(err.Error())
	}

	return nil
}
<|endoftext|>


<commit_before>package dex

// Very nearly all testing for dex is integration testing, sadly; this is inevitable since we're relying on exec to use git.

import (
	"path/filepath"
	"io/ioutil"
	"bytes"
	"os"
	"archive/tar"
	"testing"
	"strings"
	"github.com/coocood/assrt"
)

func TestLoadGraphAbsentIsNil(t *testing.T) {
	do(func() {
		assert := assrt.NewAssert(t)

		assert.Nil(LoadGraph("."))

		assert.Nil(LoadGraph("notadir"))
	})
}

func assertLegitGraph(assert *assrt.Assert, g *Graph) {
	assert.NotNil(g)

	gstat, _ := os.Stat(filepath.Join(g.dir))
	assert.True(gstat.IsDir())

	assert.True(g.HasBranch("docket/init"))

	assert.Equal(
		"",
		g.cmd("ls-tree")("HEAD").Output(),
	)
}

func TestNewGraphInit(t *testing.T) {
	do(func() {
		assertLegitGraph(
			assrt.NewAssert(t),
			NewGraph("."),
		)
	})
}

func TestLoadGraphEmpty(t *testing.T) {
	do(func() {
		assert := assrt.NewAssert(t)

		NewGraph(".")

		assertLegitGraph(assert, LoadGraph("."))
	})
}

func TestNewGraphInitNewDir(t *testing.T) {
	do(func() {
		assertLegitGraph(
			assrt.NewAssert(t),
			NewGraph("deep"),
		)
	})
}

func TestNewGraphInitRejectedOnDeeper(t *testing.T) {
	do(func() {
		defer func() {
			err := recover()
			if err == nil { t.Fail(); }
		}()
		NewGraph("deep/deeper")
	})
}

func fwriteSetA(pth string) {
	// file 'a' is just ascii text with normal permissions
	if err := ioutil.WriteFile(
		filepath.Join(pth, "a"),
		[]byte{ 'a', 'b' },
		0644,
	); err != nil { panic(err); }

	// file 'b' is binary with unusual permissions
	if err := ioutil.WriteFile(
		filepath.Join(pth, "b"),
		[]byte{ 0x1, 0x2, 0x3 },
		0640,
	); err != nil { panic(err); }

	// file 'd/d/d' is so dddeep
	//TODO
}

func fwriteSetB(pth string) {
	// file 'a' is unchanged
	if err := ioutil.WriteFile(
		filepath.Join(pth, "a"),
		[]byte{ 'a', 'b' },
		0644,
	); err != nil { panic(err); }

	// file 'b' is removed
	// (you're just expected to have nuked the working tree before calling this)

	// add an executable file
	//TODO

	// all of this is horseshit, and what you're really going to do is make a tar stream programatically, because that's the input guitar understands.

	// file 'd/d/d' is renamed to 'd/e' and 'd/d' dropped
	//TODO
}

func fsSetA() *tar.Reader {
	var buf bytes.Buffer
	fs := tar.NewWriter(&buf)

	// file 'a' is just ascii text with normal permissions
	fs.WriteHeader(&tar.Header{
		Name:     "a",
		Mode:     0644,
		Size:     2,
		Typeflag: tar.TypeReg,
	})
	fs.Write([]byte{ 'a', 'b' })

	// file 'b' is binary with unusual permissions
	fs.WriteHeader(&tar.Header{
		Name:     "b",
		Mode:     0640,
		Size:     3,
		Typeflag: tar.TypeReg,
	})
	fs.Write([]byte{ 0x1, 0x2, 0x3 })

	fs.Close()
	return tar.NewReader(&buf)
}

func fsSetB() *tar.Reader {
	var buf bytes.Buffer
	fs := tar.NewWriter(&buf)

	// file 'a' is unchanged from SetA
	fs.WriteHeader(&tar.Header{
		Name:     "a",
		Mode:     0644,
		Size:     2,
		Typeflag: tar.TypeReg,
	})
	fs.Write([]byte{ 'a', 'b' })

	// file 'b' is removed

	// file 'e' is executable
	fs.WriteHeader(&tar.Header{
		Name:     "e",
		Mode:     0755,
		Size:     3,
		Typeflag: tar.TypeReg,
	})
	fs.Write([]byte{ 'e', 'x', 'e' })

	// file 'd/d/z' is deeper
	fs.WriteHeader(&tar.Header{
		Name:     "d/d/z",
		Mode:     0644,
		Size:     2,
		Typeflag: tar.TypeReg,
	})
	fs.Write([]byte{ 'z', '\n' })

	fs.Close()
	return tar.NewReader(&buf)
}

func TestNewOrphanLineage(t *testing.T) {
	do(func() {
		assert := assrt.NewAssert(t)

		g := NewGraph(".")
		lineage := "line"
		ancestor := ""

		g.Publish(
			lineage,
			ancestor,
			&GraphStoreRequest_Tar{
				Tarstream: fsSetA(),
			},
		)

		assert.Equal(
			3,
			strings.Count(
				g.cmd("ls-tree", "refs/heads/"+lineage).Output(),
				"\n",
			),
		)
	})
}

func TestLinearExtensionToLineage(t *testing.T) {
	do(func() {
		assert := assrt.NewAssert(t)

		g := NewGraph(".")
		lineage := "line"
		ancestor := "line"

		g.Publish(
			lineage,
			"",
			&GraphStoreRequest_Tar{
				Tarstream: fsSetA(),
			},
		)

		g.Publish(
			lineage,
			ancestor,
			&GraphStoreRequest_Tar{
				Tarstream: fsSetB(),
			},
		)

		assert.Equal(
			4,
			strings.Count(
				g.cmd("ls-tree", "refs/heads/"+lineage).Output(),
				"\n",
			),
		)
	})
}

// func TestNewDerivedLineage(t *testing.T) {
// 	do(func() {
// 		assert := assrt.NewAssert(t)

// 		//TODO
// 	})
// }

// func TestDerivativeExtensionToLineage(t *testing.T) {
// 	do(func() {
// 		assert := assrt.NewAssert(t)

// 		//TODO
// 	})
// }
<commit_msg>also test that the deeper parts of the tree made it into git<commit_after>package dex

// Very nearly all testing for dex is integration testing, sadly; this is inevitable since we're relying on exec to use git.

import (
	"path/filepath"
	"io/ioutil"
	"bytes"
	"os"
	"archive/tar"
	"testing"
	"strings"
	"github.com/coocood/assrt"
)

func TestLoadGraphAbsentIsNil(t *testing.T) {
	do(func() {
		assert := assrt.NewAssert(t)

		assert.Nil(LoadGraph("."))

		assert.Nil(LoadGraph("notadir"))
	})
}

func assertLegitGraph(assert *assrt.Assert, g *Graph) {
	assert.NotNil(g)

	gstat, _ := os.Stat(filepath.Join(g.dir))
	assert.True(gstat.IsDir())

	assert.True(g.HasBranch("docket/init"))

	assert.Equal(
		"",
		g.cmd("ls-tree")("HEAD").Output(),
	)
}

func TestNewGraphInit(t *testing.T) {
	do(func() {
		assertLegitGraph(
			assrt.NewAssert(t),
			NewGraph("."),
		)
	})
}

func TestLoadGraphEmpty(t *testing.T) {
	do(func() {
		assert := assrt.NewAssert(t)

		NewGraph(".")

		assertLegitGraph(assert, LoadGraph("."))
	})
}

func TestNewGraphInitNewDir(t *testing.T) {
	do(func() {
		assertLegitGraph(
			assrt.NewAssert(t),
			NewGraph("deep"),
		)
	})
}

func TestNewGraphInitRejectedOnDeeper(t *testing.T) {
	do(func() {
		defer func() {
			err := recover()
			if err == nil { t.Fail(); }
		}()
		NewGraph("deep/deeper")
	})
}

func fwriteSetA(pth string) {
	// file 'a' is just ascii text with normal permissions
	if err := ioutil.WriteFile(
		filepath.Join(pth, "a"),
		[]byte{ 'a', 'b' },
		0644,
	); err != nil { panic(err); }

	// file 'b' is binary with unusual permissions
	if err := ioutil.WriteFile(
		filepath.Join(pth, "b"),
		[]byte{ 0x1, 0x2, 0x3 },
		0640,
	); err != nil { panic(err); }

	// file 'd/d/d' is so dddeep
	//TODO
}

func fwriteSetB(pth string) {
	// file 'a' is unchanged
	if err := ioutil.WriteFile(
		filepath.Join(pth, "a"),
		[]byte{ 'a', 'b' },
		0644,
	); err != nil { panic(err); }

	// file 'b' is removed
	// (you're just expected to have nuked the working tree before calling this)

	// add an executable file
	//TODO

	// all of this is horseshit, and what you're really going to do is make a tar stream programatically, because that's the input guitar understands.

	// file 'd/d/d' is renamed to 'd/e' and 'd/d' dropped
	//TODO
}

func fsSetA() *tar.Reader {
	var buf bytes.Buffer
	fs := tar.NewWriter(&buf)

	// file 'a' is just ascii text with normal permissions
	fs.WriteHeader(&tar.Header{
		Name:     "a",
		Mode:     0644,
		Size:     2,
		Typeflag: tar.TypeReg,
	})
	fs.Write([]byte{ 'a', 'b' })

	// file 'b' is binary with unusual permissions
	fs.WriteHeader(&tar.Header{
		Name:     "b",
		Mode:     0640,
		Size:     3,
		Typeflag: tar.TypeReg,
	})
	fs.Write([]byte{ 0x1, 0x2, 0x3 })

	fs.Close()
	return tar.NewReader(&buf)
}

func fsSetB() *tar.Reader {
	var buf bytes.Buffer
	fs := tar.NewWriter(&buf)

	// file 'a' is unchanged from SetA
	fs.WriteHeader(&tar.Header{
		Name:     "a",
		Mode:     0644,
		Size:     2,
		Typeflag: tar.TypeReg,
	})
	fs.Write([]byte{ 'a', 'b' })

	// file 'b' is removed

	// file 'e' is executable
	fs.WriteHeader(&tar.Header{
		Name:     "e",
		Mode:     0755,
		Size:     3,
		Typeflag: tar.TypeReg,
	})
	fs.Write([]byte{ 'e', 'x', 'e' })

	// file 'd/d/z' is deeper
	fs.WriteHeader(&tar.Header{
		Name:     "d/d/z",
		Mode:     0644,
		Size:     2,
		Typeflag: tar.TypeReg,
	})
	fs.Write([]byte{ 'z', '\n' })

	fs.Close()
	return tar.NewReader(&buf)
}

func TestNewOrphanLineage(t *testing.T) {
	do(func() {
		assert := assrt.NewAssert(t)

		g := NewGraph(".")
		lineage := "line"
		ancestor := ""

		g.Publish(
			lineage,
			ancestor,
			&GraphStoreRequest_Tar{
				Tarstream: fsSetA(),
			},
		)

		assert.Equal(
			3,
			strings.Count(
				g.cmd("ls-tree", "refs/heads/"+lineage).Output(),
				"\n",
			),
		)
	})
}

func TestLinearExtensionToLineage(t *testing.T) {
	do(func() {
		assert := assrt.NewAssert(t)

		g := NewGraph(".")
		lineage := "line"
		ancestor := "line"

		g.Publish(
			lineage,
			"",
			&GraphStoreRequest_Tar{
				Tarstream: fsSetA(),
			},
		)

		g.Publish(
			lineage,
			ancestor,
			&GraphStoreRequest_Tar{
				Tarstream: fsSetB(),
			},
		)

		assert.Equal(
			4,
			strings.Count(
				g.cmd("ls-tree", "refs/heads/"+lineage).Output(),
				"\n",
			),
		)

		assert.Equal(
			1,	// shows a tree
			strings.Count(
				g.cmd("ls-tree", "refs/heads/"+lineage, "d/d").Output(),
				"\n",
			),
		)

		assert.Equal(
			1,	// shows the file
			strings.Count(
				g.cmd("ls-tree", "refs/heads/"+lineage, "d/d/z").Output(),
				"\n",
			),
		)
	})
}

// func TestNewDerivedLineage(t *testing.T) {
// 	do(func() {
// 		assert := assrt.NewAssert(t)

// 		//TODO
// 	})
// }

// func TestDerivativeExtensionToLineage(t *testing.T) {
// 	do(func() {
// 		assert := assrt.NewAssert(t)

// 		//TODO
// 	})
// }
<|endoftext|>


<commit_before>package jeebie

import "github.com/valep27/go-jeebie/jeebie/util"

const titleLenght = 11

const (
	entryPointAddress       = 0x100
	logoAddress             = 0x104
	titleAddress            = 0x134
	manufacturerCodeAddress = 0x13F
	cgbFlagAddress          = 0x143
	newLicenseCodeAddress   = 0x144
	sgbFlagAddress          = 0x146
	cartridgeTypeAddress    = 0x147
	romSizeAddress          = 0x148
	ramSizeAddress          = 0x149
	destinationCodeAddress  = 0x14A
	oldLicenseCodeAddress   = 0x14B
	versionNumberAddress    = 0x14C
	headerChecksumAddress   = 0x14D
	globalChecksumAddress   = 0x14E
)

type Cartridge struct {
	data           []byte
	title          string
	headerChecksum uint16
	globalChecksum uint16
	version        uint8
	cartType       uint8
	romSize        uint8
	ramSize        uint8
}

// NewCartridgeWithData initializes a new Cartridge from a slice of bytes.
func NewCartridgeWithData(bytes []byte) *Cartridge {
	// TODO: process metadata into actual types instead of just reading it (cart type, rom/ram size, etc.)

	titleBytes := bytes[titleAddress:titleAddress+titleLenght]

	cart := &Cartridge{
		data:           make([]byte, len(bytes)),
		title:          string(titleBytes),
		headerChecksum: util.CombineBytes(bytes[headerChecksumAddress+1], bytes[headerChecksumAddress]),
		globalChecksum: util.CombineBytes(bytes[globalChecksumAddress+1], bytes[globalChecksumAddress]),
		version:        bytes[versionNumberAddress],
		cartType:       bytes[cartridgeTypeAddress],
		romSize:        bytes[romSizeAddress],
		ramSize:        bytes[ramSizeAddress],
	}

	copy(cart.data, bytes)

	return cart
}

// ReadByte reads a byte at the specified address. Does not check bounds, so the caller must make sure the
// address is valid for the cartridge.
func (c Cartridge) ReadByte(addr uint16) uint8 {
	return c.data[addr]
}

// WriteByte attempts a write to the specified address. Writing to a cartridge has sense if the cartridge
// has extra RAM or for some special operations, like switching ROM banks.
func (c Cartridge) WriteByte(addr uint16, value uint8) uint8 {
	return c.data[addr]
}<commit_msg>fix constant typo<commit_after>package jeebie

import "github.com/valep27/go-jeebie/jeebie/util"

const titleLength = 11

const (
	entryPointAddress       = 0x100
	logoAddress             = 0x104
	titleAddress            = 0x134
	manufacturerCodeAddress = 0x13F
	cgbFlagAddress          = 0x143
	newLicenseCodeAddress   = 0x144
	sgbFlagAddress          = 0x146
	cartridgeTypeAddress    = 0x147
	romSizeAddress          = 0x148
	ramSizeAddress          = 0x149
	destinationCodeAddress  = 0x14A
	oldLicenseCodeAddress   = 0x14B
	versionNumberAddress    = 0x14C
	headerChecksumAddress   = 0x14D
	globalChecksumAddress   = 0x14E
)

type Cartridge struct {
	data           []byte
	title          string
	headerChecksum uint16
	globalChecksum uint16
	version        uint8
	cartType       uint8
	romSize        uint8
	ramSize        uint8
}

// NewCartridgeWithData initializes a new Cartridge from a slice of bytes.
func NewCartridgeWithData(bytes []byte) *Cartridge {
	// TODO: process metadata into actual types instead of just reading it (cart type, rom/ram size, etc.)

	titleBytes := bytes[titleAddress:titleAddress+titleLength]

	cart := &Cartridge{
		data:           make([]byte, len(bytes)),
		title:          string(titleBytes),
		headerChecksum: util.CombineBytes(bytes[headerChecksumAddress+1], bytes[headerChecksumAddress]),
		globalChecksum: util.CombineBytes(bytes[globalChecksumAddress+1], bytes[globalChecksumAddress]),
		version:        bytes[versionNumberAddress],
		cartType:       bytes[cartridgeTypeAddress],
		romSize:        bytes[romSizeAddress],
		ramSize:        bytes[ramSizeAddress],
	}

	copy(cart.data, bytes)

	return cart
}

// ReadByte reads a byte at the specified address. Does not check bounds, so the caller must make sure the
// address is valid for the cartridge.
func (c Cartridge) ReadByte(addr uint16) uint8 {
	return c.data[addr]
}

// WriteByte attempts a write to the specified address. Writing to a cartridge has sense if the cartridge
// has extra RAM or for some special operations, like switching ROM banks.
func (c Cartridge) WriteByte(addr uint16, value uint8) uint8 {
	return c.data[addr]
}<|endoftext|>


<commit_before>package vkapi

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

const (
	LPFlagMessageUnread = 1 << iota
	LPFlagMessageOutBox
	LPFlagMessageReplied
	LPFlagMessageImportant
	LPFlagMessageChat
	LPFlagMessageFriends
	LPFlagMessageSpam
	LPFlagMessageDeleted
	LPFlagMessageFixed
	LPFlagMessageMedia
	LPFlagMessageHidden = 65536
)

const (
	LPModeAttachments   = 2
	LPModeExtendedEvent = 8
	LPModePts           = 32
	LPModeExtra         = 64
	LPModeRandomID      = 128
)

const (
	LPCodeNewMessage    = 4
	LPCodeFriendOnline  = 8
	LPCodeFriendOffline = 9
)

const (
	LPPlatformUndefined = iota
	LPPlatformMobile
	LPPlatformIPhone
	LPPlatformIPad
	LPPlatformAndroid
	LPPlatformWPhone
	LPPlatformWindows
	LPPlatformWeb
)

// LongPoll allow you to interact with long poll server.
type LongPoll struct {
	Host      string `json:"server"`
	Path      string `json:"path"`
	Key       string `json:"key"`
	Timestamp int64  `json:"ts"`
	LPVersion int    `json:"-"`
	NeedPts   int    `json:"-"`
}

// LPUpdate stores response from a long poll server.
type LPUpdate struct {
	Code               int64
	Update             []interface{}
	Message            *LPMessage
	FriendNotification *LPFriendNotification
}

// Event returns event as a string.
func (update *LPUpdate) Event() (event string) {
	switch update.Code {
	case LPCodeNewMessage:
		event = "New message"
	case LPCodeFriendOnline:
		event = "Friend online"
	case LPCodeFriendOffline:
		event = "Friend offline"
	}

	return
}

// UnmarshalUpdate unmarshal a LPUpdate.
func (update *LPUpdate) UnmarshalUpdate(mode int) error {
	update.Code = int64(update.Update[0].(float64))
	switch update.Code {
	case LPCodeNewMessage:
		message := new(LPMessage)

		message.ID = int64(update.Update[1].(float64))
		message.Flags = int64(update.Update[2].(float64))
		message.FromID = int64(update.Update[3].(float64))
		message.Timestamp = int64(update.Update[4].(float64))
		message.Text = update.Update[5].(string)

		if mode&LPModeAttachments == LPModeAttachments {
			message.Attachments = make(map[string]string)
			for key, value := range update.Update[6].(map[string]interface{}) {
				message.Attachments[key] = value.(string)
			}
		}

		if mode&LPModeRandomID&LPModeRandomID == (LPModeAttachments | LPModeRandomID) {
			message.RandomId = int64(update.Update[7].(float64))
		} else {
			if mode&LPModeRandomID == LPModeRandomID {
				message.RandomId = int64(update.Update[6].(float64))
			}
		}

		update.Message = message
	case LPCodeFriendOnline, LPCodeFriendOffline:
		if len(update.Update) < 3 {
			return errors.New("(" + string(update.Code) + ") invalid update size.")
		}

		friend := new(LPFriendNotification)
		friend.ID = -int64(update.Update[1].(float64))
		friend.Arg = int(update.Update[2].(float64)) & 0xFF
		friend.Timestamp = int64(update.Update[3].(float64))

		update.FriendNotification = friend
	}

	return nil
}

// LPMessage is new messages
// that come from long poll server.
type LPMessage struct {
	ID          int64
	Flags       int64
	FromID      int64
	Timestamp   int64
	Text        string
	Attachments map[string]string
	RandomId    int64
}

// LPFriendNotification is a notification
// that a friend has become online or offline.
type LPFriendNotification struct {
	ID int64

	// If friend is online,
	// then Arg is equal to platform.
	//
	// If the friend offline, then
	// 0 - friend logout,
	// 1 - offline by timeout.
	Arg       int
	Timestamp int64
}

// LPAnswer is response from long poll server.
type LPAnswer struct {
	Failed    int64           `json:"failed"`
	Timestamp int64           `json:"ts"`
	Updates   [][]interface{} `json:"updates"`
}

// LPChan allows to receive new LPUpdate.
type LPChan <-chan LPUpdate

// InitLongPoll establishes a new connection
// to long poll server.
func (client *Client) InitLongPoll(needPts int, lpVersion int) *Error {
	var req Request
	req.Method = "messages.getLongPollServer"

	v := url.Values{}
	v.Add("need_pts", strconv.FormatInt(int64(needPts), 10))
	v.Add("lp_version", strconv.FormatInt(int64(lpVersion), 10))
	req.Values = v

	res, err := client.Do(req)
	if err != nil {
		return err
	}

	client.LongPoll = new(LongPoll)
	if err := res.To(&client.LongPoll); err != nil {
		return NewError(ErrBadCode, err.Error())
	}

	u, error := url.Parse(client.LongPoll.Host)
	if error != nil {
		return NewError(ErrBadCode, error.Error())
	}

	client.LongPoll.Host = u.Host
	client.LongPoll.Path = u.Path
	client.LongPoll.LPVersion = lpVersion
	client.LongPoll.NeedPts = needPts

	return nil
}

// LPConfig stores data to connect to long poll server.
type LPConfig struct {
	Wait int
	Mode int
}

// GetLPAnswer makes a query with parameters
// from LPConfig to long poll server
// and returns a LPAnswer in case of success.
func (client *Client) GetLPAnswer(config LPConfig) (LPAnswer, error) {
	if client.apiClient == nil {
		return LPAnswer{}, errors.New("A api client was not initialized")
	}

	if client.LongPoll == nil {
		return LPAnswer{}, errors.New("A long poll was not initialized")
	}

	values := url.Values{}
	values.Add("act", "a_check")
	values.Add("key", client.LongPoll.Key)
	values.Add("ts", strconv.FormatInt(client.LongPoll.Timestamp, 10))
	values.Add("wait", strconv.FormatInt(int64(config.Wait), 10))
	values.Add("mode", strconv.FormatInt(int64(config.Mode), 10))
	values.Add("version", strconv.FormatInt(int64(client.LongPoll.LPVersion), 10))

	if client.apiClient.Log {
		client.apiClient.logPrintf("Request: %s", NewRequest("getLongPoll", "", values).JS())
	}

	u := url.URL{}
	u.Host = client.LongPoll.Host
	u.Path = client.LongPoll.Path
	u.Scheme = "https"
	u.RawQuery = values.Encode()

	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return LPAnswer{}, err
	}

	res, err := client.apiClient.httpClient.Do(req)
	if err != nil {
		client.apiClient.logPrintf("Response error: %s", err.Error())
		return LPAnswer{}, err
	}

	var reader io.Reader
	reader = res.Body

	if client.apiClient.Log {
		b, err := ioutil.ReadAll(res.Body)
		if err != nil {
			panic(err)
		}

		client.apiClient.logPrintf("Response: %s", string(b))
		reader = bytes.NewReader(b)
	}

	if res.StatusCode != http.StatusOK {
		client.apiClient.logPrintf("Response error: %s", res.Status)
		return LPAnswer{}, errors.New(res.Status)
	}

	var answer LPAnswer
	if err = json.NewDecoder(reader).Decode(&answer); err != nil {
		return LPAnswer{}, err
	}

	return answer, nil
}

// GetLPUpdates makes a query with parameters
// from LPConfig to long poll server
// and returns array LPUpdate in case of success.
func (client *Client) GetLPUpdates(config LPConfig) ([]LPUpdate, error) {
	answer, err := client.GetLPAnswer(config)
	if err != nil {
		return []LPUpdate{}, err
	}

	var LPUpdates []LPUpdate

	switch answer.Failed {
	case 0:
		for i := len(answer.Updates) - 1; i >= 0; i-- {
			var LPUpdate LPUpdate
			LPUpdate.Update = answer.Updates[i]
			if err := LPUpdate.UnmarshalUpdate(config.Mode); err != nil {
				if client.apiClient.Log {
					client.apiClient.Logger.Println(err)
				}
			}

			LPUpdates = append(LPUpdates, LPUpdate)
		}

		client.LongPoll.Timestamp = answer.Timestamp
		return LPUpdates, nil
	case 1:
		client.LongPoll.Timestamp = answer.Timestamp
		if client.apiClient.Log {
			client.apiClient.Logger.Println("Timestamp updated")
		}

	case 2, 3:
		if err := client.InitLongPoll(client.LongPoll.NeedPts, client.LongPoll.LPVersion); err != nil {
			if client.apiClient.Log {
				client.apiClient.Logger.Println("Long poll update error:", err)
			}
			return []LPUpdate{}, err
		}

		if client.apiClient.Log {
			client.apiClient.Logger.Println("Long poll config updated")
		}
	}

	return []LPUpdate{}, nil
}

// GetLPUpdatesChan makes a query with parameters
// from LPConfig to long poll server
// and returns LPChan in case of success.
func (client *Client) GetLPUpdatesChan(bufSize int, config LPConfig) (LPChan, *bool, error) {
	ch := make(chan LPUpdate, bufSize)
	run := true

	go func() {
		for run {
			updates, err := client.GetLPUpdates(config)
			if err != nil {
				log.Println("Failed to get updates, retrying in 3 seconds...")
				time.Sleep(time.Second * 3)

				continue
			}

			for _, u := range updates {
				ch <- u
			}
		}

		close(ch)
	}()

	return ch, &run, nil
}
<commit_msg>Update longpoll<commit_after>package vkapi

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

const (
	LPFlagMessageUnread = 1 << iota
	LPFlagMessageOutBox
	LPFlagMessageReplied
	LPFlagMessageImportant
	LPFlagMessageChat
	LPFlagMessageFriends
	LPFlagMessageSpam
	LPFlagMessageDeleted
	LPFlagMessageFixed
	LPFlagMessageMedia
	LPFlagMessageHidden = 65536
)

const (
	LPModeAttachments   = 2
	LPModeExtendedEvent = 8
	LPModePts           = 32
	LPModeExtra         = 64
	LPModeRandomID      = 128
)

const (
	LPCodeNewMessage    = 4
	LPCodeFriendOnline  = 8
	LPCodeFriendOffline = 9
)

const (
	LPPlatformUndefined = iota
	LPPlatformMobile
	LPPlatformIPhone
	LPPlatformIPad
	LPPlatformAndroid
	LPPlatformWPhone
	LPPlatformWindows
	LPPlatformWeb
)

// Timestamp is the wrapper of int64.
type Timestamp int64

func (ts Timestamp) String() string {
	return time.Unix(int64(ts), 0).Format("15:04:05 02/01/2006")
}

// LongPoll allow you to interact with long poll server.
type LongPoll struct {
	Host      string    `json:"server"`
	Path      string    `json:"path"`
	Key       string    `json:"key"`
	Timestamp Timestamp `json:"ts"`
	LPVersion int       `json:"-"`
	NeedPts   int       `json:"-"`
}

// LPUpdate stores response from a long poll server.
type LPUpdate struct {
	Code               int64
	Update             []interface{}
	Message            *LPMessage
	FriendNotification *LPFriendNotification
}

// Event returns event as a string.
func (update *LPUpdate) Event() (event string) {
	switch update.Code {
	case LPCodeNewMessage:
		event = "New message"
	case LPCodeFriendOnline:
		event = "Friend online"
	case LPCodeFriendOffline:
		event = "Friend offline"
	default:
		event = "Undefined event"
	}

	return
}

// UnmarshalUpdate unmarshal a LPUpdate.
func (update *LPUpdate) UnmarshalUpdate(mode int) error {
	update.Code = int64(update.Update[0].(float64))
	switch update.Code {
	case LPCodeNewMessage:
		message := new(LPMessage)

		message.ID = int64(update.Update[1].(float64))
		message.Flags = int64(update.Update[2].(float64))
		message.FromID = int64(update.Update[3].(float64))
		message.Timestamp = Timestamp(update.Update[4].(float64))
		message.Text = update.Update[5].(string)

		if mode&LPModeAttachments == LPModeAttachments {
			message.Attachments = make(map[string]string)
			for key, value := range update.Update[6].(map[string]interface{}) {
				message.Attachments[key] = value.(string)
			}
		}

		if mode&LPModeRandomID&LPModeRandomID == (LPModeAttachments | LPModeRandomID) {
			message.RandomId = int64(update.Update[7].(float64))
		} else {
			if mode&LPModeRandomID == LPModeRandomID {
				message.RandomId = int64(update.Update[6].(float64))
			}
		}

		update.Message = message
	case LPCodeFriendOnline, LPCodeFriendOffline:
		if len(update.Update) < 3 {
			return errors.New("(" + string(update.Code) + ") invalid update size.")
		}

		friend := new(LPFriendNotification)
		friend.Code = update.Code
		friend.ID = -int64(update.Update[1].(float64))
		friend.Arg = int(update.Update[2].(float64)) & 0xFF
		friend.Timestamp = Timestamp(update.Update[3].(float64))

		update.FriendNotification = friend
	}

	return nil
}

// LPMessage is new messages
// that come from long poll server.
type LPMessage struct {
	ID          int64
	Flags       int64
	FromID      int64
	Timestamp   Timestamp
	Text        string
	Attachments map[string]string
	RandomId    int64
}

func (message *LPMessage) String() string {
	return fmt.Sprintf("Message (%d):`%s` from (%d) at %s", message.ID, message.Text, message.FromID, message.Timestamp)
}

// LPFriendNotification is a notification
// that a friend has become online or offline.
type LPFriendNotification struct {
	ID int64

	// If friend is online,
	// then Arg is equal to platform.
	//
	// If the friend offline, then
	// 0 - friend logout,
	// 1 - offline by timeout.
	Arg       int
	Timestamp Timestamp
	Code      int64
}

// Status returns event as a string.
func (friend *LPFriendNotification) Status() (status string) {
	switch friend.Code {
	case LPCodeFriendOnline:
		status = "Online"
	case LPCodeFriendOffline:
		status = "Offline"
	default:
		status = "Undefined event"
	}

	return
}

func (friend *LPFriendNotification) String() string {
	return fmt.Sprintf("Friend (%d) was %s at %s", friend.ID, friend.Status(), friend.Timestamp)
}

// LPAnswer is response from long poll server.
type LPAnswer struct {
	Failed    int64           `json:"failed"`
	Timestamp Timestamp       `json:"ts"`
	Updates   [][]interface{} `json:"updates"`
}

// LPChan allows to receive new LPUpdate.
type LPChan <-chan LPUpdate

// InitLongPoll establishes a new connection
// to long poll server.
func (client *Client) InitLongPoll(needPts int, lpVersion int) *Error {
	var req Request
	req.Method = "messages.getLongPollServer"

	v := url.Values{}
	v.Add("need_pts", strconv.FormatInt(int64(needPts), 10))
	v.Add("lp_version", strconv.FormatInt(int64(lpVersion), 10))
	req.Values = v

	res, err := client.Do(req)
	if err != nil {
		return err
	}

	client.LongPoll = new(LongPoll)
	if err := res.To(&client.LongPoll); err != nil {
		return NewError(ErrBadCode, err.Error())
	}

	u, error := url.Parse(client.LongPoll.Host)
	if error != nil {
		return NewError(ErrBadCode, error.Error())
	}

	client.LongPoll.Host = u.Host
	client.LongPoll.Path = u.Path
	client.LongPoll.LPVersion = lpVersion
	client.LongPoll.NeedPts = needPts

	return nil
}

// LPConfig stores data to connect to long poll server.
type LPConfig struct {
	Wait int
	Mode int
}

// GetLPAnswer makes a query with parameters
// from LPConfig to long poll server
// and returns a LPAnswer in case of success.
func (client *Client) GetLPAnswer(config LPConfig) (LPAnswer, error) {
	if client.apiClient == nil {
		return LPAnswer{}, errors.New(ErrApiClientNotFound)
	}

	if client.LongPoll == nil {
		return LPAnswer{}, errors.New("A long poll was not initialized")
	}

	values := url.Values{}
	values.Add("act", "a_check")
	values.Add("key", client.LongPoll.Key)
	values.Add("ts", strconv.FormatInt(int64(client.LongPoll.Timestamp), 10))
	values.Add("wait", strconv.FormatInt(int64(config.Wait), 10))
	values.Add("mode", strconv.FormatInt(int64(config.Mode), 10))
	values.Add("version", strconv.FormatInt(int64(client.LongPoll.LPVersion), 10))

	if client.apiClient.Log {
		client.apiClient.logPrintf("Request: %s", NewRequest("getLongPoll", "", values).JS())
	}

	u := url.URL{}
	u.Host = client.LongPoll.Host
	u.Path = client.LongPoll.Path
	u.Scheme = "https"
	u.RawQuery = values.Encode()

	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return LPAnswer{}, err
	}

	res, err := client.apiClient.httpClient.Do(req)
	if err != nil {
		client.apiClient.logPrintf("Response error: %s", err.Error())
		return LPAnswer{}, err
	}

	var reader io.Reader
	reader = res.Body

	if client.apiClient.Log {
		b, err := ioutil.ReadAll(res.Body)
		if err != nil {
			panic(err)
		}

		client.apiClient.logPrintf("Response: %s", string(b))
		reader = bytes.NewReader(b)
	}

	if res.StatusCode != http.StatusOK {
		client.apiClient.logPrintf("Response error: %s", res.Status)
		return LPAnswer{}, errors.New(res.Status)
	}

	var answer LPAnswer
	if err = json.NewDecoder(reader).Decode(&answer); err != nil {
		return LPAnswer{}, err
	}

	return answer, nil
}

// GetLPUpdates makes a query with parameters
// from LPConfig to long poll server
// and returns array LPUpdate in case of success.
func (client *Client) GetLPUpdates(config LPConfig) ([]LPUpdate, error) {
	answer, err := client.GetLPAnswer(config)
	if err != nil {
		return []LPUpdate{}, err
	}

	var LPUpdates []LPUpdate

	switch answer.Failed {
	case 0:
		for i := len(answer.Updates) - 1; i >= 0; i-- {
			var LPUpdate LPUpdate
			LPUpdate.Update = answer.Updates[i]
			if err := LPUpdate.UnmarshalUpdate(config.Mode); err != nil {
				if client.apiClient.Log {
					client.apiClient.Logger.Println(err)
				}
			}

			LPUpdates = append(LPUpdates, LPUpdate)
		}

		client.LongPoll.Timestamp = answer.Timestamp
		return LPUpdates, nil
	case 1:
		client.LongPoll.Timestamp = answer.Timestamp
		if client.apiClient.Log {
			client.apiClient.Logger.Println("Timestamp updated")
		}

	case 2, 3:
		if err := client.InitLongPoll(client.LongPoll.NeedPts, client.LongPoll.LPVersion); err != nil {
			if client.apiClient.Log {
				client.apiClient.Logger.Println("Long poll update error:", err)
			}
			return []LPUpdate{}, err
		}

		if client.apiClient.Log {
			client.apiClient.Logger.Println("Long poll config updated")
		}
	}

	return []LPUpdate{}, nil
}

// GetLPUpdatesChan makes a query with parameters
// from LPConfig to long poll server
// and returns LPChan in case of success.
func (client *Client) GetLPUpdatesChan(bufSize int, config LPConfig) (LPChan, *bool, error) {
	ch := make(chan LPUpdate, bufSize)
	run := true

	go func() {
		for run {
			updates, err := client.GetLPUpdates(config)
			if err != nil {
				log.Println("Failed to get updates, retrying in 3 seconds...")
				time.Sleep(time.Second * 3)

				continue
			}

			for _, u := range updates {
				ch <- u
			}
		}

		close(ch)
	}()

	return ch, &run, nil
}
<|endoftext|>


<commit_before>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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 obcpbft

import (
	"fmt"
	"time"

	"github.com/openblockchain/obc-peer/openchain/consensus"
	pb "github.com/openblockchain/obc-peer/protos"

	"github.com/golang/protobuf/proto"
	"github.com/spf13/viper"
)

type obcBatch struct {
	cpi              consensus.CPI
	pbft             *pbftCore
	batchSize        int
	batchStore       map[string]*Request
	batchTimer       *time.Timer
	batchTimerActive bool
	batchTimeout     time.Duration
}

func newObcBatch(id uint64, config *viper.Viper, cpi consensus.CPI) *obcBatch {
	var err error
	op := &obcBatch{cpi: cpi}
	op.pbft = newPbftCore(id, config, op)
	op.batchSize = config.GetInt("general.batchSize")
	op.batchStore = make(map[string]*Request)
	op.batchTimeout, err = time.ParseDuration(config.GetString("general.timeout.batch"))
	if err != nil {
		panic(fmt.Errorf("Cannot parse batch timeout: %s", err))
	}
	// create non-running timer XXX ugly
	op.batchTimer = time.NewTimer(100 * time.Hour)
	op.batchTimer.Stop()
	go op.batchTimerHander()
	return op
}

// RecvMsg receives both CHAIN_TRANSACTION and CONSENSUS messages from
// the stack. New transaction requests are broadcast to all replicas,
// so that the current primary will receive the request.
func (op *obcBatch) RecvMsg(ocMsg *pb.OpenchainMessage) error {
	if ocMsg.Type == pb.OpenchainMessage_CHAIN_TRANSACTION {
		logger.Info("New consensus request received")
		// TODO verify transaction
		// if _, err := op.cpi.TransactionPreValidation(...); err != nil {
		//   logger.Warning("Invalid request");
		//   return err
		// }

		req := &Request{Payload: ocMsg.Payload, ReplicaId: op.pbft.id}

		if (op.pbft.primary(op.pbft.view) == op.pbft.id) && op.pbft.activeView { // primary
			err := op.leaderProcReq(req)
			if err != nil {
				return err
			}
		} else { // backup
			msg := &Message{&Message_Request{req}}
			msgRaw, _ := proto.Marshal(msg)
			op.broadcast(msgRaw)
		}
		return nil
	}

	if ocMsg.Type != pb.OpenchainMessage_CONSENSUS {
		return fmt.Errorf("Unexpected message type: %s", ocMsg.Type)
	}

	pbftMsg := &Message{}
	err := proto.Unmarshal(ocMsg.Payload, pbftMsg)
	if err != nil {
		return err
	}

	if req := pbftMsg.GetRequest(); req != nil {
		// TODO verify first, we need to be sure about the sender
		switch req.ReplicaId {
		case op.pbft.primary(op.pbft.view):
			// a request sent by the primary; primary should ignore this
			if op.pbft.primary(op.pbft.view) != op.pbft.id {
				op.pbft.request(req.Payload)
			}
		default:
			// a request sent by a backup; backups should ignore this
			if (op.pbft.primary(op.pbft.view) == op.pbft.id) && op.pbft.activeView {
				err := op.leaderProcReq(req)
				if err != nil {
					return err
				}
			}
		}
	} else {
		op.pbft.receive(ocMsg.Payload)
	}

	return nil
}

// Close tells us to release resources we are holding
func (op *obcBatch) Close() {
	op.pbft.close()
}

// =============================================================================
// innerCPI interface (functions called by pbft-core)
// =============================================================================

// multicast a message to all replicas
func (op *obcBatch) broadcast(msgPayload []byte) {
	ocMsg := &pb.OpenchainMessage{
		Type:    pb.OpenchainMessage_CONSENSUS,
		Payload: msgPayload,
	}
	op.cpi.Broadcast(ocMsg)
}

// execute an opaque request which corresponds to an OBC Transaction
func (op *obcBatch) execute(tbRaw []byte) {
	tb := &pb.TransactionBlock{}
	err := proto.Unmarshal(tbRaw, tb)
	if err != nil {
		return
	}
	// TODO verify transaction
	// if tx, err = op.cpi.TransactionPreExecution(...); err != nil {
	//   logger.Error("Invalid request");
	// } else {
	// ...
	// }

	txs := tb.Transactions
	_, _ = op.cpi.ExecTXs(txs)

	/* if ledger, err := ledger.GetLedger(); err != nil {
		panic(fmt.Errorf("Fail to get the ledger: %v", err))
	}

	txBatchID := base64.StdEncoding.EncodeToString(util.ComputeCryptoHash(tbRaw))

	if err = ledger.BeginTxBatch(txBatchID); err != nil {
		panic(fmt.Errorf("Fail to begin transactions with the ledger: %v", err))
	}

	hash, errs := op.cpi.ExecTXs(txs)
	// There are n+1 elements of errors in this array. On complete success
	// they'll all be nil. In particular, the last err will be error in
	// producing the hash, if any. That's the only error we do want to check

	if errs[len(txs)] != nil {
		panic(fmt.Errorf("Fail to execute transactions: %v", errs))
	}

	if err = ledger.CommitTxBatch(txBatchID, txs, nil); err != nil {
		ledger.RollbackTxBatch(txBatchID)
		panic(fmt.Errorf("Fail to commit transactions to the ledger: %v", err))
	} */
}

// signal when a view-change happened
func (op *obcBatch) viewChange(curView uint64) {
	if op.batchTimerActive {
		op.stopBatchTimer()
	}
}

// =============================================================================
// functions specific to batch mode
// =============================================================================

// tear down resources opened by newObcBatch
func (op *obcBatch) close() {
	op.batchTimer.Reset(0)
}

func (op *obcBatch) leaderProcReq(req *Request) error {
	digest := hashReq(req)
	op.batchStore[digest] = req

	if !op.batchTimerActive {
		op.startBatchTimer()
	}

	if len(op.batchStore) >= op.batchSize {
		op.sendBatch()
	}

	return nil
}

func (op *obcBatch) sendBatch() error {
	op.stopBatchTimer()
	// assemble new Request message
	txs := make([]*pb.Transaction, len(op.batchStore))
	var i int
	for d, req := range op.batchStore {
		txs[i] = &pb.Transaction{}
		err := proto.Unmarshal(req.Payload, txs[i])
		if err != nil {
			err = fmt.Errorf("Unable to unpack payload of request %d", i)
			logger.Error("%s", err)
			return err
		}
		i++
		delete(op.batchStore, d) // clean up
	}
	tb := &pb.TransactionBlock{Transactions: txs}
	tbPacked, err := proto.Marshal(tb)
	if err != nil {
		err = fmt.Errorf("Unable to pack transaction block for new batch request")
		logger.Error("%s", err)
		return err
	}
	// process internally
	op.pbft.request(tbPacked)
	// broadcast
	batchReq := &Request{Payload: tbPacked}
	msg := &Message{&Message_Request{batchReq}}
	msgRaw, _ := proto.Marshal(msg)
	op.broadcast(msgRaw)

	return nil
}

// allow the primary to send a batch when the timer expires
func (op *obcBatch) batchTimerHander() {
	for {
		select {
		case <-op.batchTimer.C:
			op.pbft.lock.Lock()
			if op.pbft.closed {
				op.pbft.lock.Unlock()
				return
			}
			logger.Info("Replica %d batch timeout expired", op.pbft.id)
			if op.pbft.activeView && (len(op.batchStore) > 0) {
				op.sendBatch()
			}
			op.pbft.lock.Unlock()
		}
	}
}

func (op *obcBatch) startBatchTimer() {
	op.batchTimer.Reset(op.batchTimeout)
	logger.Debug("Replica %d started the batch timer", op.pbft.id)
	op.batchTimerActive = true
}

func (op *obcBatch) stopBatchTimer() {
	op.batchTimer.Stop()
	logger.Debug("Replica %d stopped the batch timer", op.pbft.id)
	op.batchTimerActive = false
	if op.pbft.closed {
		return
	}
loopBatch:
	for {
		select {
		case <-op.batchTimer.C:
		default:
			break loopBatch
		}
	}
}
<commit_msg>Update obc-batch close function<commit_after>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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 obcpbft

import (
	"fmt"
	"time"

	"github.com/openblockchain/obc-peer/openchain/consensus"
	pb "github.com/openblockchain/obc-peer/protos"

	"github.com/golang/protobuf/proto"
	"github.com/spf13/viper"
)

type obcBatch struct {
	cpi  consensus.CPI
	pbft *pbftCore

	id               uint64
	batchSize        int
	batchStore       map[string]*Request
	batchTimer       *time.Timer
	batchTimerActive bool
	batchTimeout     time.Duration
}

func newObcBatch(id uint64, config *viper.Viper, cpi consensus.CPI) *obcBatch {
	var err error
	op := &obcBatch{cpi: cpi, id: id}
	op.pbft = newPbftCore(id, config, op)
	op.batchSize = config.GetInt("general.batchSize")
	op.batchStore = make(map[string]*Request)
	op.batchTimeout, err = time.ParseDuration(config.GetString("general.timeout.batch"))
	if err != nil {
		panic(fmt.Errorf("Cannot parse batch timeout: %s", err))
	}
	// create non-running timer XXX ugly
	op.batchTimer = time.NewTimer(100 * time.Hour)
	op.batchTimer.Stop()
	go op.batchTimerHander()
	return op
}

// RecvMsg receives both CHAIN_TRANSACTION and CONSENSUS messages from
// the stack. New transaction requests are broadcast to all replicas,
// so that the current primary will receive the request.
func (op *obcBatch) RecvMsg(ocMsg *pb.OpenchainMessage) error {
	if ocMsg.Type == pb.OpenchainMessage_CHAIN_TRANSACTION {
		logger.Info("New consensus request received")
		// TODO verify transaction
		// if _, err := op.cpi.TransactionPreValidation(...); err != nil {
		//   logger.Warning("Invalid request");
		//   return err
		// }

		req := &Request{Payload: ocMsg.Payload, ReplicaId: op.pbft.id}

		if (op.pbft.primary(op.pbft.view) == op.pbft.id) && op.pbft.activeView { // primary
			err := op.leaderProcReq(req)
			if err != nil {
				return err
			}
		} else { // backup
			msg := &Message{&Message_Request{req}}
			msgRaw, _ := proto.Marshal(msg)
			op.broadcast(msgRaw)
		}
		return nil
	}

	if ocMsg.Type != pb.OpenchainMessage_CONSENSUS {
		return fmt.Errorf("Unexpected message type: %s", ocMsg.Type)
	}

	pbftMsg := &Message{}
	err := proto.Unmarshal(ocMsg.Payload, pbftMsg)
	if err != nil {
		return err
	}

	if req := pbftMsg.GetRequest(); req != nil {
		// TODO verify first, we need to be sure about the sender
		switch req.ReplicaId {
		case op.pbft.primary(op.pbft.view):
			// a request sent by the primary; primary should ignore this
			if op.pbft.primary(op.pbft.view) != op.pbft.id {
				op.pbft.request(req.Payload)
			}
		default:
			// a request sent by a backup; backups should ignore this
			if (op.pbft.primary(op.pbft.view) == op.pbft.id) && op.pbft.activeView {
				err := op.leaderProcReq(req)
				if err != nil {
					return err
				}
			}
		}
	} else {
		op.pbft.receive(ocMsg.Payload)
	}

	return nil
}

// Close tells us to release resources we are holding
func (op *obcBatch) close() {
	op.pbft.close()
	op.batchTimer.Reset(0)
}

// =============================================================================
// innerCPI interface (functions called by pbft-core)
// =============================================================================

// multicast a message to all replicas
func (op *obcBatch) broadcast(msgPayload []byte) {
	ocMsg := &pb.OpenchainMessage{
		Type:    pb.OpenchainMessage_CONSENSUS,
		Payload: msgPayload,
	}
	op.cpi.Broadcast(ocMsg)
}

// execute an opaque request which corresponds to an OBC Transaction
func (op *obcBatch) execute(tbRaw []byte) {
	tb := &pb.TransactionBlock{}
	err := proto.Unmarshal(tbRaw, tb)
	if err != nil {
		return
	}
	// TODO verify transaction
	// if tx, err = op.cpi.TransactionPreExecution(...); err != nil {
	//   logger.Error("Invalid request");
	// } else {
	// ...
	// }

	txs := tb.Transactions
	_, _ = op.cpi.ExecTXs(txs)

	/* if ledger, err := ledger.GetLedger(); err != nil {
		panic(fmt.Errorf("Fail to get the ledger: %v", err))
	}

	txBatchID := base64.StdEncoding.EncodeToString(util.ComputeCryptoHash(tbRaw))

	if err = ledger.BeginTxBatch(txBatchID); err != nil {
		panic(fmt.Errorf("Fail to begin transactions with the ledger: %v", err))
	}

	hash, errs := op.cpi.ExecTXs(txs)
	// There are n+1 elements of errors in this array. On complete success
	// they'll all be nil. In particular, the last err will be error in
	// producing the hash, if any. That's the only error we do want to check

	if errs[len(txs)] != nil {
		panic(fmt.Errorf("Fail to execute transactions: %v", errs))
	}

	if err = ledger.CommitTxBatch(txBatchID, txs, nil); err != nil {
		ledger.RollbackTxBatch(txBatchID)
		panic(fmt.Errorf("Fail to commit transactions to the ledger: %v", err))
	} */
}

// signal when a view-change happened
func (op *obcBatch) viewChange(curView uint64) {
	if op.batchTimerActive {
		op.stopBatchTimer()
	}
}

// =============================================================================
// functions specific to batch mode
// =============================================================================

func (op *obcBatch) leaderProcReq(req *Request) error {
	digest := hashReq(req)
	op.batchStore[digest] = req

	if !op.batchTimerActive {
		op.startBatchTimer()
	}

	if len(op.batchStore) >= op.batchSize {
		op.sendBatch()
	}

	return nil
}

func (op *obcBatch) sendBatch() error {
	op.stopBatchTimer()
	// assemble new Request message
	txs := make([]*pb.Transaction, len(op.batchStore))
	var i int
	for d, req := range op.batchStore {
		txs[i] = &pb.Transaction{}
		err := proto.Unmarshal(req.Payload, txs[i])
		if err != nil {
			err = fmt.Errorf("Unable to unpack payload of request %d", i)
			logger.Error("%s", err)
			return err
		}
		i++
		delete(op.batchStore, d) // clean up
	}
	tb := &pb.TransactionBlock{Transactions: txs}
	tbPacked, err := proto.Marshal(tb)
	if err != nil {
		err = fmt.Errorf("Unable to pack transaction block for new batch request")
		logger.Error("%s", err)
		return err
	}
	// process internally
	op.pbft.request(tbPacked)
	// broadcast
	batchReq := &Request{Payload: tbPacked}
	msg := &Message{&Message_Request{batchReq}}
	msgRaw, _ := proto.Marshal(msg)
	op.broadcast(msgRaw)

	return nil
}

// allow the primary to send a batch when the timer expires
func (op *obcBatch) batchTimerHander() {
	for {
		select {
		case <-op.batchTimer.C:
			op.pbft.lock.Lock()
			if op.pbft.closed {
				op.pbft.lock.Unlock()
				return
			}
			logger.Info("Replica %d batch timeout expired", op.pbft.id)
			if op.pbft.activeView && (len(op.batchStore) > 0) {
				op.sendBatch()
			}
			op.pbft.lock.Unlock()
		}
	}
}

func (op *obcBatch) startBatchTimer() {
	op.batchTimer.Reset(op.batchTimeout)
	logger.Debug("Replica %d started the batch timer", op.pbft.id)
	op.batchTimerActive = true
}

func (op *obcBatch) stopBatchTimer() {
	op.batchTimer.Stop()
	logger.Debug("Replica %d stopped the batch timer", op.pbft.id)
	op.batchTimerActive = false
	if op.pbft.closed {
		return
	}
loopBatch:
	for {
		select {
		case <-op.batchTimer.C:
		default:
			break loopBatch
		}
	}
}
<|endoftext|>


<commit_before>package libgobuster

import (
	"strings"
	"testing"
)

func TestNewStringSet(t *testing.T) {
	if newStringSet().Set == nil {
		t.Fatal("newStringSet returned nil Set")
	}
}

func TestNewIntSet(t *testing.T) {
	if newIntSet().Set == nil {
		t.Fatal("newIntSet returned nil Set")
	}
}

func TestStringSetAdd(t *testing.T) {
	x := newStringSet()
	x.Add("test")
	if len(x.Set) != 1 {
		t.Fatalf("Unexptected size. Should have 1 Got %v", len(x.Set))
	}
}

func TestStringSetAddDouble(t *testing.T) {
	x := newStringSet()
	x.Add("test")
	x.Add("test")
	if len(x.Set) != 1 {
		t.Fatalf("Unexptected size. Should have 1 Got %d", len(x.Set))
	}
}

func TestStringSetAddRange(t *testing.T) {
	x := newStringSet()
	x.AddRange([]string{"asdf", "ghjk"})
	if len(x.Set) != 2 {
		t.Fatalf("Unexptected size. Should have 2 Got %d", len(x.Set))
	}
}

func TestStringSetAddRangeDouble(t *testing.T) {
	x := newStringSet()
	x.AddRange([]string{"asdf", "ghjk", "asdf", "ghjk"})
	if len(x.Set) != 2 {
		t.Fatalf("Unexptected size. Should have 2 Got %d", len(x.Set))
	}
}

func TestStringSetContains(t *testing.T) {
	x := newStringSet()
	v := []string{"asdf", "ghjk", "1234", "5678"}
	x.AddRange(v)
	for _, y := range v {
		if !x.Contains(y) {
			t.Fatalf("Did not find value %s in array. %v", y, x.Set)
		}
	}
}

func TestStringSetContainsAny(t *testing.T) {
	x := newStringSet()
	v := []string{"asdf", "ghjk", "1234", "5678"}
	x.AddRange(v)
	if !x.ContainsAny(v) {
		t.Fatalf("Did not find any")
	}

	// test not found
	if x.ContainsAny([]string{"mmmm", "nnnnn"}) {
		t.Fatal("Found unexpected values")
	}
}

func TestStringSetStringify(t *testing.T) {
	x := newStringSet()
	v := []string{"asdf", "ghjk", "1234", "5678"}
	x.AddRange(v)
	z := x.Stringify()
	// order is random
	for _, y := range v {
		if !strings.Contains(z, y) {
			t.Fatalf("Did not find value %q in %q", y, z)
		}
	}
}

func TestIntSetAdd(t *testing.T) {
	x := newIntSet()
	x.Add(1)
	if len(x.Set) != 1 {
		t.Fatalf("Unexptected size. Should have 1 Got %d", len(x.Set))
	}
}

func TestIntSetAddDouble(t *testing.T) {
	x := newIntSet()
	x.Add(1)
	x.Add(1)
	if len(x.Set) != 1 {
		t.Fatalf("Unexptected size. Should have 1 Got %d", len(x.Set))
	}
}

func TestIntSetContains(t *testing.T) {
	x := newIntSet()
	v := []int{1, 2, 3, 4}
	for _, y := range v {
		x.Add(y)
	}
	for _, y := range v {
		if !x.Contains(y) {
			t.Fatalf("Did not find value %d in array. %v", y, x.Set)
		}
	}
}

func TestIntSetStringify(t *testing.T) {
	x := newIntSet()
	v := []int{1, 3, 2, 4}
	expected := "1,2,3,4"
	for _, y := range v {
		x.Add(y)
	}
	z := x.Stringify()
	// should be sorted
	if expected != z {
		t.Fatalf("Expected %q got %q", expected, z)
	}
}
<commit_msg>more tests<commit_after>package libgobuster

import (
	"strings"
	"testing"
	"testing/iotest"
)

func TestNewStringSet(t *testing.T) {
	if newStringSet().Set == nil {
		t.Fatal("newStringSet returned nil Set")
	}
}

func TestNewIntSet(t *testing.T) {
	if newIntSet().Set == nil {
		t.Fatal("newIntSet returned nil Set")
	}
}

func TestStringSetAdd(t *testing.T) {
	x := newStringSet()
	x.Add("test")
	if len(x.Set) != 1 {
		t.Fatalf("Unexptected size. Should have 1 Got %v", len(x.Set))
	}
}

func TestStringSetAddDouble(t *testing.T) {
	x := newStringSet()
	x.Add("test")
	x.Add("test")
	if len(x.Set) != 1 {
		t.Fatalf("Unexptected size. Should have 1 Got %d", len(x.Set))
	}
}

func TestStringSetAddRange(t *testing.T) {
	x := newStringSet()
	x.AddRange([]string{"asdf", "ghjk"})
	if len(x.Set) != 2 {
		t.Fatalf("Unexptected size. Should have 2 Got %d", len(x.Set))
	}
}

func TestStringSetAddRangeDouble(t *testing.T) {
	x := newStringSet()
	x.AddRange([]string{"asdf", "ghjk", "asdf", "ghjk"})
	if len(x.Set) != 2 {
		t.Fatalf("Unexptected size. Should have 2 Got %d", len(x.Set))
	}
}

func TestStringSetContains(t *testing.T) {
	x := newStringSet()
	v := []string{"asdf", "ghjk", "1234", "5678"}
	x.AddRange(v)
	for _, y := range v {
		if !x.Contains(y) {
			t.Fatalf("Did not find value %s in array. %v", y, x.Set)
		}
	}
}

func TestStringSetContainsAny(t *testing.T) {
	x := newStringSet()
	v := []string{"asdf", "ghjk", "1234", "5678"}
	x.AddRange(v)
	if !x.ContainsAny(v) {
		t.Fatalf("Did not find any")
	}

	// test not found
	if x.ContainsAny([]string{"mmmm", "nnnnn"}) {
		t.Fatal("Found unexpected values")
	}
}

func TestStringSetStringify(t *testing.T) {
	x := newStringSet()
	v := []string{"asdf", "ghjk", "1234", "5678"}
	x.AddRange(v)
	z := x.Stringify()
	// order is random
	for _, y := range v {
		if !strings.Contains(z, y) {
			t.Fatalf("Did not find value %q in %q", y, z)
		}
	}
}

func TestIntSetAdd(t *testing.T) {
	x := newIntSet()
	x.Add(1)
	if len(x.Set) != 1 {
		t.Fatalf("Unexptected size. Should have 1 Got %d", len(x.Set))
	}
}

func TestIntSetAddDouble(t *testing.T) {
	x := newIntSet()
	x.Add(1)
	x.Add(1)
	if len(x.Set) != 1 {
		t.Fatalf("Unexptected size. Should have 1 Got %d", len(x.Set))
	}
}

func TestIntSetContains(t *testing.T) {
	x := newIntSet()
	v := []int{1, 2, 3, 4}
	for _, y := range v {
		x.Add(y)
	}
	for _, y := range v {
		if !x.Contains(y) {
			t.Fatalf("Did not find value %d in array. %v", y, x.Set)
		}
	}
}

func TestIntSetStringify(t *testing.T) {
	x := newIntSet()
	v := []int{1, 3, 2, 4}
	expected := "1,2,3,4"
	for _, y := range v {
		x.Add(y)
	}
	z := x.Stringify()
	// should be sorted
	if expected != z {
		t.Fatalf("Expected %q got %q", expected, z)
	}
}

func TestLineCounter(t *testing.T) {
	var tt = []struct {
		testName string
		s        string
		expected int
	}{
		{"One Line", "test", 1},
		{"3 Lines", "TestString\nTest\n1234", 3},
		{"Trailing newline", "TestString\nTest\n1234\n", 4},
		{"3 Lines cr lf", "TestString\r\nTest\r\n1234", 3},
		{"Empty", "", 1},
	}
	for _, x := range tt {
		t.Run(x.testName, func(t *testing.T) {
			r := strings.NewReader(x.s)
			l, err := lineCounter(r)
			if err != nil {
				t.Fatalf("Got error: %v", err)
			}
			if l != x.expected {
				t.Fatalf("wrong line count! Got %d expected %d", l, x.expected)
			}
		})
	}
}

func TestLineCounterError(t *testing.T) {
	r := iotest.TimeoutReader(strings.NewReader("test"))
	_, err := lineCounter(r)
	if err != iotest.ErrTimeout {
		t.Fatalf("Got wrong error! %v", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"

	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/maputnik/desktop/filewatch"
	"github.com/urfave/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "maputnik"
	app.Usage = "Server for integrating Maputnik locally"
	app.Version = "Editor: 1.6.1; Desktop: 1.0.4"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "file, f",
			Usage: "Allow access to JSON style from web client",
		},
		cli.BoolFlag{
			Name:  "watch",
			Usage: "Notify web client about JSON style file changes",
		},
		cli.IntFlag{
			Name: "port",
			Value: 8000,
			Usage: "TCP port to listen on",
		},
	}

	app.Action = func(c *cli.Context) error {
		gui := http.FileServer(assetFS())

		router := mux.NewRouter().StrictSlash(true)

		filename := c.String("file")
		if filename != "" {
			fmt.Printf("%s is accessible via Maputnik\n", filename)
			// Allow access to reading and writing file on the local system
			path, _ := filepath.Abs(filename)
			accessor := StyleFileAccessor(path)
			router.Path("/styles").Methods("GET").HandlerFunc(accessor.ListFiles)
			router.Path("/styles/{styleId}").Methods("GET").HandlerFunc(accessor.ReadFile)
			router.Path("/styles/{styleId}").Methods("PUT").HandlerFunc(accessor.SaveFile)

			// Register websocket to notify we clients about file changes
			if c.Bool("watch") {
				router.Path("/ws").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
					filewatch.ServeWebsocketFileWatcher(filename, w, r)
				})
			}
		}

		router.PathPrefix("/").Handler(http.StripPrefix("/", gui))
		loggedRouter := handlers.LoggingHandler(os.Stdout, router)
		corsRouter := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}), handlers.AllowedMethods([]string{"GET", "PUT"}), handlers.AllowedOrigins([]string{"*"}), handlers.AllowCredentials())(loggedRouter)

		fmt.Printf("Exposing Maputnik on http://localhost:%d\n", c.Int("port"))
		return http.ListenAndServe(fmt.Sprintf(":%d", c.Int("port")), corsRouter)
	}

	app.Run(os.Args)
}
<commit_msg>fixed the error `cannot use cli.StringFlag literal ...`<commit_after>package main

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"

	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/maputnik/desktop/filewatch"
	"github.com/urfave/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "maputnik"
	app.Usage = "Server for integrating Maputnik locally"
	app.Version = "Editor: 1.6.1; Desktop: 1.0.4"

	app.Flags = []cli.Flag{
		&cli.StringFlag{
			Name:  "file, f",
			Usage: "Allow access to JSON style from web client",
		},
		&cli.BoolFlag{
			Name:  "watch",
			Usage: "Notify web client about JSON style file changes",
		},
		&cli.IntFlag{
			Name: "port",
			Value: 8000,
			Usage: "TCP port to listen on",
		},
	}

	app.Action = func(c *cli.Context) error {
		gui := http.FileServer(assetFS())

		router := mux.NewRouter().StrictSlash(true)

		filename := c.String("file")
		if filename != "" {
			fmt.Printf("%s is accessible via Maputnik\n", filename)
			// Allow access to reading and writing file on the local system
			path, _ := filepath.Abs(filename)
			accessor := StyleFileAccessor(path)
			router.Path("/styles").Methods("GET").HandlerFunc(accessor.ListFiles)
			router.Path("/styles/{styleId}").Methods("GET").HandlerFunc(accessor.ReadFile)
			router.Path("/styles/{styleId}").Methods("PUT").HandlerFunc(accessor.SaveFile)

			// Register websocket to notify we clients about file changes
			if c.Bool("watch") {
				router.Path("/ws").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
					filewatch.ServeWebsocketFileWatcher(filename, w, r)
				})
			}
		}

		router.PathPrefix("/").Handler(http.StripPrefix("/", gui))
		loggedRouter := handlers.LoggingHandler(os.Stdout, router)
		corsRouter := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}), handlers.AllowedMethods([]string{"GET", "PUT"}), handlers.AllowedOrigins([]string{"*"}), handlers.AllowCredentials())(loggedRouter)

		fmt.Printf("Exposing Maputnik on http://localhost:%d\n", c.Int("port"))
		return http.ListenAndServe(fmt.Sprintf(":%d", c.Int("port")), corsRouter)
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"github.com/lxc/lxd"
)

type execCmd struct{}

const execUsage = `
exec specified command in a container.

lxc exec container [command]
`

func (c *execCmd) usage() string {
	return execUsage
}

func (c *execCmd) flags() {}

func (c *execCmd) run(config *lxd.Config, args []string) error {
	if len(args) < 2 {
		return errArgs
	}

	d, name, err := lxd.NewClient(config, args[0])
	if err != nil {
		return err
	}

	return d.Exec(name, args[1:], os.Stdin, os.Stdout, os.Stderr)
}
<commit_msg>Emulate a terminal slightly more accurately<commit_after>package main

import (
	"os"
	"syscall"

	"github.com/lxc/lxd"
	"golang.org/x/crypto/ssh/terminal"
)

type execCmd struct{}

const execUsage = `
exec specified command in a container.

lxc exec container [command]
`

func (c *execCmd) usage() string {
	return execUsage
}

func (c *execCmd) flags() {}

func (c *execCmd) run(config *lxd.Config, args []string) error {
	if len(args) < 2 {
		return errArgs
	}

	d, name, err := lxd.NewClient(config, args[0])
	if err != nil {
		return err
	}

	cfd := syscall.Stdout
	if terminal.IsTerminal(cfd) {
		oldttystate, err := terminal.MakeRaw(cfd)
		if err != nil {
			return err
		}
		defer terminal.Restore(cfd, oldttystate)
	}

	return d.Exec(name, args[1:], os.Stdin, os.Stdout, os.Stderr)
}
<|endoftext|>


<commit_before>package opentracing

import "math"

const (
	stringType fieldType = iota
	boolType
	intType
	int64Type
	float64Type
	errorType
	objectType
	deferredObjectType
)

// LogField instances are constructed via LogBool, LogString, and so on.
// Tracing implementations may then handle them via the LogField.Process
// method.
type LogField struct {
	key          string
	valType      valType
	numericVal   int64
	stringVal    string
	interfaceVal interface{}
}

func LogString(key, val string) LogField {
	return LogField{
		key:       key,
		valType:   stringType,
		stringVal: val,
	}
}

func LogBool(key string, val bool) LogField {
	var numericVal int64
	if val {
		numericVal = 1
	}
	return LogField{
		key:        key,
		valType:    boolType,
		numericVal: numericVal,
	}
}

func LogInt(key string, val int) LogField {
	var numericVal int64 = int64(val)
	return LogField{
		key:        key,
		valType:    intType,
		numericVal: numericVal,
	}
}

func LogInt64(key string, val int64) LogField {
	return LogField{
		key:        key,
		valType:    int64Type,
		numericVal: val,
	}
}

func LogFloat64(key string, val float64) LogField {
	return LogField{
		key:        key,
		valType:    float64Type,
		numericVal: int64(math.Float64bits(val)),
	}
}

// REVIEWERS: etc etc for other numeric types if we like this direction

func LogError(err error) LogField {
	return LogField{
		key:          "error",
		valType:      errorType,
		interfaceVal: err,
	}
}

func LogObject(key string, obj interface{}) LogField {
	return LogField{
		key:          key,
		valType:      objectType,
		interfaceVal: obj,
	}
}

type DeferredObjectGenerator func() interface{}

func LogDeferredObject(key string, generator DeferredObjectGenerator) LogField {
	return LogField{
		key:          key,
		valType:      deferredObjectType,
		interfaceVal: generator,
	}
}

// LogFieldProcessor allows access to the contents of a LogField (via a call to
// LogField.Process).
//
// Tracer implementations typically provide an implementation of
// LogFieldProcessor; OpenTracing callers should not need to concern themselves
// with it.
type LogFieldProcessor interface {
	AddString(key, value string)
	AddBool(key string, value bool)
	AddInt(key string, value int)
	AddInt64(key string, value int64)
	AddFloat64(key string, value float64)
	AddObject(key string, value interface{})
}

// Process passes a LogField instance through to the appropriate type-specific
// method of a LogFieldProcessor.
func (lf LogField) Process(processor LogFieldProcessor) {
	switch lf.valType {
	case stringType:
		processor.AddString(lf.key, lf.stringVal)
	case boolType:
		processor.AddBool(lf.key, lf.numericVal != 0)
	case intType:
		processor.AddInt(lf.key, int(lf.numericVal))
	case int64Type:
		processor.AddInt64(lf.key, lf.numericVal)
	case float64Type:
		processor.AddFloat64(lf.key, math.Float64frombits(uint64(lf.numericVal)))
	case errorType:
		processor.AddString(lf.key, lf.obj.(error).Error())
	case objectType:
		processor.AddObject(lf.key, lf.interfaceVal)
	case deferredObjectType:
		processor.AddObject(lf.key, lf.interfaceVal.(DeferredObjectGenerator)())
	}
}
<commit_msg>Give credit where credit is due<commit_after>package opentracing

import "math"

const (
	stringType fieldType = iota
	boolType
	intType
	int64Type
	float64Type
	errorType
	objectType
	deferredObjectType
)

// LogField instances are constructed via LogBool, LogString, and so on.
// Tracing implementations may then handle them via the LogField.Process
// method.
//
// "heavily influenced by" (i.e., partially stolen from)
// https://github.com/uber-go/zap
type LogField struct {
	key          string
	valType      valType
	numericVal   int64
	stringVal    string
	interfaceVal interface{}
}

func LogString(key, val string) LogField {
	return LogField{
		key:       key,
		valType:   stringType,
		stringVal: val,
	}
}

func LogBool(key string, val bool) LogField {
	var numericVal int64
	if val {
		numericVal = 1
	}
	return LogField{
		key:        key,
		valType:    boolType,
		numericVal: numericVal,
	}
}

func LogInt(key string, val int) LogField {
	var numericVal int64 = int64(val)
	return LogField{
		key:        key,
		valType:    intType,
		numericVal: numericVal,
	}
}

func LogInt64(key string, val int64) LogField {
	return LogField{
		key:        key,
		valType:    int64Type,
		numericVal: val,
	}
}

func LogFloat64(key string, val float64) LogField {
	return LogField{
		key:        key,
		valType:    float64Type,
		numericVal: int64(math.Float64bits(val)),
	}
}

// REVIEWERS: etc etc for other numeric types if we like this direction

func LogError(err error) LogField {
	return LogField{
		key:          "error",
		valType:      errorType,
		interfaceVal: err,
	}
}

func LogObject(key string, obj interface{}) LogField {
	return LogField{
		key:          key,
		valType:      objectType,
		interfaceVal: obj,
	}
}

type DeferredObjectGenerator func() interface{}

func LogDeferredObject(key string, generator DeferredObjectGenerator) LogField {
	return LogField{
		key:          key,
		valType:      deferredObjectType,
		interfaceVal: generator,
	}
}

// LogFieldProcessor allows access to the contents of a LogField (via a call to
// LogField.Process).
//
// Tracer implementations typically provide an implementation of
// LogFieldProcessor; OpenTracing callers should not need to concern themselves
// with it.
type LogFieldProcessor interface {
	AddString(key, value string)
	AddBool(key string, value bool)
	AddInt(key string, value int)
	AddInt64(key string, value int64)
	AddFloat64(key string, value float64)
	AddObject(key string, value interface{})
}

// Process passes a LogField instance through to the appropriate type-specific
// method of a LogFieldProcessor.
func (lf LogField) Process(processor LogFieldProcessor) {
	switch lf.valType {
	case stringType:
		processor.AddString(lf.key, lf.stringVal)
	case boolType:
		processor.AddBool(lf.key, lf.numericVal != 0)
	case intType:
		processor.AddInt(lf.key, int(lf.numericVal))
	case int64Type:
		processor.AddInt64(lf.key, lf.numericVal)
	case float64Type:
		processor.AddFloat64(lf.key, math.Float64frombits(uint64(lf.numericVal)))
	case errorType:
		processor.AddString(lf.key, lf.obj.(error).Error())
	case objectType:
		processor.AddObject(lf.key, lf.interfaceVal)
	case deferredObjectType:
		processor.AddObject(lf.key, lf.interfaceVal.(DeferredObjectGenerator)())
	}
}
<|endoftext|>