<commit_before>// Copyright 2019 The gVisor 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
//
//     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 gomarshal

import (
	"fmt"
	"go/ast"
	"go/token"
	"strings"
)

// interfaceGenerator generates marshalling interfaces for a single type.
//
// getState is not thread-safe.
type interfaceGenerator struct {
	sourceBuffer

	// The type we're serializing.
	t *ast.TypeSpec

	// Receiver argument for generated methods.
	r string

	// FileSet containing the tokens for the type we're processing.
	f *token.FileSet

	// is records external packages referenced by the generated implementation.
	is map[string]struct{}

	// ms records Marshallable types referenced by the generated implementation
	// of t's interfaces.
	ms map[string]struct{}

	// as records fields in t that are potentially not packed. The key is the
	// accessor for the field.
	as map[string]struct{}
}

// typeName returns the name of the type this g represents.
func (g *interfaceGenerator) typeName() string {
	return g.t.Name.Name
}

// newinterfaceGenerator creates a new interface generator.
func newInterfaceGenerator(t *ast.TypeSpec, r string, fset *token.FileSet) *interfaceGenerator {
	g := &interfaceGenerator{
		t:  t,
		r:  r,
		f:  fset,
		is: make(map[string]struct{}),
		ms: make(map[string]struct{}),
		as: make(map[string]struct{}),
	}
	g.recordUsedMarshallable(g.typeName())
	return g
}

func (g *interfaceGenerator) recordUsedMarshallable(m string) {
	g.ms[m] = struct{}{}

}

func (g *interfaceGenerator) recordUsedImport(i string) {
	g.is[i] = struct{}{}
}

func (g *interfaceGenerator) recordPotentiallyNonPackedField(fieldName string) {
	g.as[fieldName] = struct{}{}
}

// abortAt aborts the go_marshal tool with the given error message, with a
// reference position to the input source. Same as abortAt, but uses g to
// resolve p to position.
func (g *interfaceGenerator) abortAt(p token.Pos, msg string) {
	abortAt(g.f.Position(p), msg)
}

// scalarSize returns the size of type identified by t. If t isn't a primitive
// type, the size isn't known at code generation time, and must be resolved via
// the marshal.Marshallable interface.
func (g *interfaceGenerator) scalarSize(t *ast.Ident) (size int, unknownSize bool) {
	switch t.Name {
	case "int8", "uint8", "byte":
		return 1, false
	case "int16", "uint16":
		return 2, false
	case "int32", "uint32":
		return 4, false
	case "int64", "uint64":
		return 8, false
	default:
		return 0, true
	}
}

func (g *interfaceGenerator) shift(bufVar string, n int) {
	g.emit("%s = %s[%d:]\n", bufVar, bufVar, n)
}

func (g *interfaceGenerator) shiftDynamic(bufVar, name string) {
	g.emit("%s = %s[%s.SizeBytes():]\n", bufVar, bufVar, name)
}

// marshalScalar writes a single scalar to a byte slice.
func (g *interfaceGenerator) marshalScalar(accessor, typ, bufVar string) {
	switch typ {
	case "int8", "uint8", "byte":
		g.emit("%s[0] = byte(%s)\n", bufVar, accessor)
		g.shift(bufVar, 1)
	case "int16", "uint16":
		g.recordUsedImport("hostarch")
		g.emit("hostarch.ByteOrder.PutUint16(%s[:2], uint16(%s))\n", bufVar, accessor)
		g.shift(bufVar, 2)
	case "int32", "uint32":
		g.recordUsedImport("hostarch")
		g.emit("hostarch.ByteOrder.PutUint32(%s[:4], uint32(%s))\n", bufVar, accessor)
		g.shift(bufVar, 4)
	case "int64", "uint64":
		g.recordUsedImport("hostarch")
		g.emit("hostarch.ByteOrder.PutUint64(%s[:8], uint64(%s))\n", bufVar, accessor)
		g.shift(bufVar, 8)
	default:
		g.emit("%s = %s.MarshalBytes(%s)\n", bufVar, accessor, bufVar)
	}
}

// unmarshalScalar reads a single scalar from a byte slice.
func (g *interfaceGenerator) unmarshalScalar(accessor, typ, bufVar string) {
	switch typ {
	case "byte":
		g.emit("%s = %s[0]\n", accessor, bufVar)
		g.shift(bufVar, 1)
	case "int8", "uint8":
		g.emit("%s = %s(%s[0])\n", accessor, typ, bufVar)
		g.shift(bufVar, 1)
	case "int16", "uint16":
		g.recordUsedImport("hostarch")
		g.emit("%s = %s(hostarch.ByteOrder.Uint16(%s[:2]))\n", accessor, typ, bufVar)
		g.shift(bufVar, 2)
	case "int32", "uint32":
		g.recordUsedImport("hostarch")
		g.emit("%s = %s(hostarch.ByteOrder.Uint32(%s[:4]))\n", accessor, typ, bufVar)
		g.shift(bufVar, 4)
	case "int64", "uint64":
		g.recordUsedImport("hostarch")
		g.emit("%s = %s(hostarch.ByteOrder.Uint64(%s[:8]))\n", accessor, typ, bufVar)
		g.shift(bufVar, 8)
	default:
		g.emit("%s = %s.UnmarshalBytes(%s)\n", bufVar, accessor, bufVar)
		g.recordPotentiallyNonPackedField(accessor)
	}
}

// emitCastToByteSlice unsafely casts an arbitrary type's underlying memory to a
// byte slice, bypassing escape analysis. The caller is responsible for ensuring
// srcPtr lives until they're done with dstVar, the runtime does not consider
// dstVar dependent on srcPtr due to the escape analysis bypass.
//
// srcPtr must be a pointer.
//
// This function uses internally uses the identifier "hdr", and cannot be used
// in a context where it is already bound.
func (g *interfaceGenerator) emitCastToByteSlice(srcPtr, dstVar, lenExpr string) {
	g.recordUsedImport("gohacks")
	g.emit("// Construct a slice backed by dst's underlying memory.\n")
	g.emit("var %s []byte\n", dstVar)
	g.emit("hdr := (*reflect.SliceHeader)(unsafe.Pointer(&%s))\n", dstVar)
	g.emit("hdr.Data = uintptr(gohacks.Noescape(unsafe.Pointer(%s)))\n", srcPtr)
	g.emit("hdr.Len = %s\n", lenExpr)
	g.emit("hdr.Cap = %s\n\n", lenExpr)
}

// emitCastToByteSlice unsafely casts a slice with elements of an abitrary type
// to a byte slice. As part of the cast, the byte slice is made to look
// independent of the src slice by bypassing escape analysis. This means the
// byte slice can be used without causing the source to escape. The caller is
// responsible for ensuring srcPtr lives until they're done with dstVar, as the
// runtime no longer considers dstVar dependent on srcPtr and is free to GC it.
//
// srcPtr must be a pointer.
//
// This function uses internally uses the identifiers "ptr", "val" and "hdr",
// and cannot be used in a context where these identifiers are already bound.
func (g *interfaceGenerator) emitCastSliceToByteSlice(srcPtr, dstVar, lenExpr string) {
	g.emitNoEscapeSliceDataPointer(srcPtr, "val")

	g.emit("// Construct a slice backed by dst's underlying memory.\n")
	g.emit("var %s []byte\n", dstVar)
	g.emit("hdr := (*reflect.SliceHeader)(unsafe.Pointer(&%s))\n", dstVar)
	g.emit("hdr.Data = uintptr(val)\n")
	g.emit("hdr.Len = %s\n", lenExpr)
	g.emit("hdr.Cap = %s\n\n", lenExpr)
}

// emitNoEscapeSliceDataPointer unsafely casts a slice's data pointer to an
// unsafe.Pointer, bypassing escape analysis. The caller is responsible for
// ensuring srcPtr lives until they're done with dstVar, as the runtime no
// longer considers dstVar dependent on srcPtr and is free to GC it.
//
// srcPtr must be a pointer.
//
// This function uses internally uses the identifier "ptr" cannot be used in a
// context where this identifier is already bound.
func (g *interfaceGenerator) emitNoEscapeSliceDataPointer(srcPtr, dstVar string) {
	g.recordUsedImport("gohacks")
	g.emit("ptr := unsafe.Pointer(%s)\n", srcPtr)
	g.emit("%s := gohacks.Noescape(unsafe.Pointer((*reflect.SliceHeader)(ptr).Data))\n\n", dstVar)
}

func (g *interfaceGenerator) emitKeepAlive(ptrVar string) {
	g.emit("// Since we bypassed the compiler's escape analysis, indicate that %s\n", ptrVar)
	g.emit("// must live until the use above.\n")
	g.emit("runtime.KeepAlive(%s) // escapes: replaced by intrinsic.\n", ptrVar)
}

func (g *interfaceGenerator) expandBinaryExpr(b *strings.Builder, e *ast.BinaryExpr) {
	switch x := e.X.(type) {
	case *ast.BinaryExpr:
		// Recursively expand sub-expression.
		g.expandBinaryExpr(b, x)
	case *ast.Ident:
		fmt.Fprintf(b, "%s", x.Name)
	case *ast.BasicLit:
		fmt.Fprintf(b, "%s", x.Value)
	default:
		g.abortAt(e.Pos(), "Cannot convert binary expression to output code. Go-marshal currently only handles simple expressions of literals, constants and basic identifiers")
	}

	fmt.Fprintf(b, "%s", e.Op)

	switch y := e.Y.(type) {
	case *ast.BinaryExpr:
		// Recursively expand sub-expression.
		g.expandBinaryExpr(b, y)
	case *ast.Ident:
		fmt.Fprintf(b, "%s", y.Name)
	case *ast.BasicLit:
		fmt.Fprintf(b, "%s", y.Value)
	default:
		g.abortAt(e.Pos(), "Cannot convert binary expression to output code. Go-marshal currently only handles simple expressions of literals, constants and basic identifiers")
	}
}

// arrayLenExpr returns a string containing a valid golang expression
// representing the length of array a. The returned expression should be treated
// as a single value, and will be already parenthesized as required.
func (g *interfaceGenerator) arrayLenExpr(a *ast.ArrayType) string {
	var b strings.Builder

	switch l := a.Len.(type) {
	case *ast.Ident:
		fmt.Fprintf(&b, "%s", l.Name)
	case *ast.BasicLit:
		fmt.Fprintf(&b, "%s", l.Value)
	case *ast.BinaryExpr:
		g.expandBinaryExpr(&b, l)
		return fmt.Sprintf("(%s)", b.String())
	default:
		g.abortAt(l.Pos(), "Cannot convert this array len expression to output code. Go-marshal currently only handles simple expressions of literals, constants and basic identifiers")
	}
	return b.String()
}
<commit_msg>Use faster marshalling method for non primitive struct fields.<commit_after>// Copyright 2019 The gVisor 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
//
//     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 gomarshal

import (
	"fmt"
	"go/ast"
	"go/token"
	"strings"
)

// interfaceGenerator generates marshalling interfaces for a single type.
//
// getState is not thread-safe.
type interfaceGenerator struct {
	sourceBuffer

	// The type we're serializing.
	t *ast.TypeSpec

	// Receiver argument for generated methods.
	r string

	// FileSet containing the tokens for the type we're processing.
	f *token.FileSet

	// is records external packages referenced by the generated implementation.
	is map[string]struct{}

	// ms records Marshallable types referenced by the generated implementation
	// of t's interfaces.
	ms map[string]struct{}

	// as records fields in t that are potentially not packed. The key is the
	// accessor for the field.
	as map[string]struct{}
}

// typeName returns the name of the type this g represents.
func (g *interfaceGenerator) typeName() string {
	return g.t.Name.Name
}

// newinterfaceGenerator creates a new interface generator.
func newInterfaceGenerator(t *ast.TypeSpec, r string, fset *token.FileSet) *interfaceGenerator {
	g := &interfaceGenerator{
		t:  t,
		r:  r,
		f:  fset,
		is: make(map[string]struct{}),
		ms: make(map[string]struct{}),
		as: make(map[string]struct{}),
	}
	g.recordUsedMarshallable(g.typeName())
	return g
}

func (g *interfaceGenerator) recordUsedMarshallable(m string) {
	g.ms[m] = struct{}{}

}

func (g *interfaceGenerator) recordUsedImport(i string) {
	g.is[i] = struct{}{}
}

func (g *interfaceGenerator) recordPotentiallyNonPackedField(fieldName string) {
	g.as[fieldName] = struct{}{}
}

// abortAt aborts the go_marshal tool with the given error message, with a
// reference position to the input source. Same as abortAt, but uses g to
// resolve p to position.
func (g *interfaceGenerator) abortAt(p token.Pos, msg string) {
	abortAt(g.f.Position(p), msg)
}

// scalarSize returns the size of type identified by t. If t isn't a primitive
// type, the size isn't known at code generation time, and must be resolved via
// the marshal.Marshallable interface.
func (g *interfaceGenerator) scalarSize(t *ast.Ident) (size int, unknownSize bool) {
	switch t.Name {
	case "int8", "uint8", "byte":
		return 1, false
	case "int16", "uint16":
		return 2, false
	case "int32", "uint32":
		return 4, false
	case "int64", "uint64":
		return 8, false
	default:
		return 0, true
	}
}

func (g *interfaceGenerator) shift(bufVar string, n int) {
	g.emit("%s = %s[%d:]\n", bufVar, bufVar, n)
}

func (g *interfaceGenerator) shiftDynamic(bufVar, name string) {
	g.emit("%s = %s[%s.SizeBytes():]\n", bufVar, bufVar, name)
}

// marshalScalar writes a single scalar to a byte slice.
func (g *interfaceGenerator) marshalScalar(accessor, typ, bufVar string) {
	switch typ {
	case "int8", "uint8", "byte":
		g.emit("%s[0] = byte(%s)\n", bufVar, accessor)
		g.shift(bufVar, 1)
	case "int16", "uint16":
		g.recordUsedImport("hostarch")
		g.emit("hostarch.ByteOrder.PutUint16(%s[:2], uint16(%s))\n", bufVar, accessor)
		g.shift(bufVar, 2)
	case "int32", "uint32":
		g.recordUsedImport("hostarch")
		g.emit("hostarch.ByteOrder.PutUint32(%s[:4], uint32(%s))\n", bufVar, accessor)
		g.shift(bufVar, 4)
	case "int64", "uint64":
		g.recordUsedImport("hostarch")
		g.emit("hostarch.ByteOrder.PutUint64(%s[:8], uint64(%s))\n", bufVar, accessor)
		g.shift(bufVar, 8)
	default:
		g.emit("%s = %s.MarshalUnsafe(%s)\n", bufVar, accessor, bufVar)
	}
}

// unmarshalScalar reads a single scalar from a byte slice.
func (g *interfaceGenerator) unmarshalScalar(accessor, typ, bufVar string) {
	switch typ {
	case "byte":
		g.emit("%s = %s[0]\n", accessor, bufVar)
		g.shift(bufVar, 1)
	case "int8", "uint8":
		g.emit("%s = %s(%s[0])\n", accessor, typ, bufVar)
		g.shift(bufVar, 1)
	case "int16", "uint16":
		g.recordUsedImport("hostarch")
		g.emit("%s = %s(hostarch.ByteOrder.Uint16(%s[:2]))\n", accessor, typ, bufVar)
		g.shift(bufVar, 2)
	case "int32", "uint32":
		g.recordUsedImport("hostarch")
		g.emit("%s = %s(hostarch.ByteOrder.Uint32(%s[:4]))\n", accessor, typ, bufVar)
		g.shift(bufVar, 4)
	case "int64", "uint64":
		g.recordUsedImport("hostarch")
		g.emit("%s = %s(hostarch.ByteOrder.Uint64(%s[:8]))\n", accessor, typ, bufVar)
		g.shift(bufVar, 8)
	default:
		g.emit("%s = %s.UnmarshalUnsafe(%s)\n", bufVar, accessor, bufVar)
		g.recordPotentiallyNonPackedField(accessor)
	}
}

// emitCastToByteSlice unsafely casts an arbitrary type's underlying memory to a
// byte slice, bypassing escape analysis. The caller is responsible for ensuring
// srcPtr lives until they're done with dstVar, the runtime does not consider
// dstVar dependent on srcPtr due to the escape analysis bypass.
//
// srcPtr must be a pointer.
//
// This function uses internally uses the identifier "hdr", and cannot be used
// in a context where it is already bound.
func (g *interfaceGenerator) emitCastToByteSlice(srcPtr, dstVar, lenExpr string) {
	g.recordUsedImport("gohacks")
	g.emit("// Construct a slice backed by dst's underlying memory.\n")
	g.emit("var %s []byte\n", dstVar)
	g.emit("hdr := (*reflect.SliceHeader)(unsafe.Pointer(&%s))\n", dstVar)
	g.emit("hdr.Data = uintptr(gohacks.Noescape(unsafe.Pointer(%s)))\n", srcPtr)
	g.emit("hdr.Len = %s\n", lenExpr)
	g.emit("hdr.Cap = %s\n\n", lenExpr)
}

// emitCastToByteSlice unsafely casts a slice with elements of an abitrary type
// to a byte slice. As part of the cast, the byte slice is made to look
// independent of the src slice by bypassing escape analysis. This means the
// byte slice can be used without causing the source to escape. The caller is
// responsible for ensuring srcPtr lives until they're done with dstVar, as the
// runtime no longer considers dstVar dependent on srcPtr and is free to GC it.
//
// srcPtr must be a pointer.
//
// This function uses internally uses the identifiers "ptr", "val" and "hdr",
// and cannot be used in a context where these identifiers are already bound.
func (g *interfaceGenerator) emitCastSliceToByteSlice(srcPtr, dstVar, lenExpr string) {
	g.emitNoEscapeSliceDataPointer(srcPtr, "val")

	g.emit("// Construct a slice backed by dst's underlying memory.\n")
	g.emit("var %s []byte\n", dstVar)
	g.emit("hdr := (*reflect.SliceHeader)(unsafe.Pointer(&%s))\n", dstVar)
	g.emit("hdr.Data = uintptr(val)\n")
	g.emit("hdr.Len = %s\n", lenExpr)
	g.emit("hdr.Cap = %s\n\n", lenExpr)
}

// emitNoEscapeSliceDataPointer unsafely casts a slice's data pointer to an
// unsafe.Pointer, bypassing escape analysis. The caller is responsible for
// ensuring srcPtr lives until they're done with dstVar, as the runtime no
// longer considers dstVar dependent on srcPtr and is free to GC it.
//
// srcPtr must be a pointer.
//
// This function uses internally uses the identifier "ptr" cannot be used in a
// context where this identifier is already bound.
func (g *interfaceGenerator) emitNoEscapeSliceDataPointer(srcPtr, dstVar string) {
	g.recordUsedImport("gohacks")
	g.emit("ptr := unsafe.Pointer(%s)\n", srcPtr)
	g.emit("%s := gohacks.Noescape(unsafe.Pointer((*reflect.SliceHeader)(ptr).Data))\n\n", dstVar)
}

func (g *interfaceGenerator) emitKeepAlive(ptrVar string) {
	g.emit("// Since we bypassed the compiler's escape analysis, indicate that %s\n", ptrVar)
	g.emit("// must live until the use above.\n")
	g.emit("runtime.KeepAlive(%s) // escapes: replaced by intrinsic.\n", ptrVar)
}

func (g *interfaceGenerator) expandBinaryExpr(b *strings.Builder, e *ast.BinaryExpr) {
	switch x := e.X.(type) {
	case *ast.BinaryExpr:
		// Recursively expand sub-expression.
		g.expandBinaryExpr(b, x)
	case *ast.Ident:
		fmt.Fprintf(b, "%s", x.Name)
	case *ast.BasicLit:
		fmt.Fprintf(b, "%s", x.Value)
	default:
		g.abortAt(e.Pos(), "Cannot convert binary expression to output code. Go-marshal currently only handles simple expressions of literals, constants and basic identifiers")
	}

	fmt.Fprintf(b, "%s", e.Op)

	switch y := e.Y.(type) {
	case *ast.BinaryExpr:
		// Recursively expand sub-expression.
		g.expandBinaryExpr(b, y)
	case *ast.Ident:
		fmt.Fprintf(b, "%s", y.Name)
	case *ast.BasicLit:
		fmt.Fprintf(b, "%s", y.Value)
	default:
		g.abortAt(e.Pos(), "Cannot convert binary expression to output code. Go-marshal currently only handles simple expressions of literals, constants and basic identifiers")
	}
}

// arrayLenExpr returns a string containing a valid golang expression
// representing the length of array a. The returned expression should be treated
// as a single value, and will be already parenthesized as required.
func (g *interfaceGenerator) arrayLenExpr(a *ast.ArrayType) string {
	var b strings.Builder

	switch l := a.Len.(type) {
	case *ast.Ident:
		fmt.Fprintf(&b, "%s", l.Name)
	case *ast.BasicLit:
		fmt.Fprintf(&b, "%s", l.Value)
	case *ast.BinaryExpr:
		g.expandBinaryExpr(&b, l)
		return fmt.Sprintf("(%s)", b.String())
	default:
		g.abortAt(l.Pos(), "Cannot convert this array len expression to output code. Go-marshal currently only handles simple expressions of literals, constants and basic identifiers")
	}
	return b.String()
}
<|endoftext|>


<commit_before>//  Copyright (c) 2017 Couchbase, Inc.
//
// 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 zap

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"math"
	"reflect"
	"sort"

	"github.com/blevesearch/bleve/index"
	"github.com/blevesearch/bleve/index/scorch/segment"
	"github.com/blevesearch/bleve/size"
	"github.com/golang/snappy"
)

var reflectStaticSizedocValueReader int

func init() {
	var dvi docValueReader
	reflectStaticSizedocValueReader = int(reflect.TypeOf(dvi).Size())
}

type docNumTermsVisitor func(docNum uint64, terms []byte) error

type docVisitState struct {
	dvrs    map[uint16]*docValueReader
	segment *Segment
}

type docValueReader struct {
	field          string
	curChunkNum    uint64
	chunkOffsets   []uint64
	dvDataLoc      uint64
	curChunkHeader []MetaData
	curChunkData   []byte // compressed data cache
	uncompressed   []byte // temp buf for snappy decompression
}

func (di *docValueReader) size() int {
	return reflectStaticSizedocValueReader + size.SizeOfPtr +
		len(di.field) +
		len(di.chunkOffsets)*size.SizeOfUint64 +
		len(di.curChunkHeader)*reflectStaticSizeMetaData +
		len(di.curChunkData)
}

func (di *docValueReader) cloneInto(rv *docValueReader) *docValueReader {
	if rv == nil {
		rv = &docValueReader{}
	}

	rv.field = di.field
	rv.curChunkNum = math.MaxUint64
	rv.chunkOffsets = di.chunkOffsets // immutable, so it's sharable
	rv.dvDataLoc = di.dvDataLoc
	rv.curChunkHeader = rv.curChunkHeader[:0]
	rv.curChunkData = nil
	rv.uncompressed = rv.uncompressed[:0]

	return rv
}

func (di *docValueReader) fieldName() string {
	return di.field
}

func (di *docValueReader) curChunkNumber() uint64 {
	return di.curChunkNum
}

func (s *SegmentBase) loadFieldDocValueReader(field string,
	fieldDvLocStart, fieldDvLocEnd uint64) (*docValueReader, error) {
	// get the docValue offset for the given fields
	if fieldDvLocStart == fieldNotUninverted {
		// no docValues found, nothing to do
		return nil, nil
	}

	// read the number of chunks, and chunk offsets position
	var numChunks, chunkOffsetsPosition uint64

	if fieldDvLocEnd-fieldDvLocStart > 16 {
		numChunks = binary.BigEndian.Uint64(s.mem[fieldDvLocEnd-8 : fieldDvLocEnd])
		// read the length of chunk offsets
		chunkOffsetsLen := binary.BigEndian.Uint64(s.mem[fieldDvLocEnd-16 : fieldDvLocEnd-8])
		// acquire position of chunk offsets
		chunkOffsetsPosition = (fieldDvLocEnd - 16) - chunkOffsetsLen
	} else {
		return nil, fmt.Errorf("loadFieldDocValueReader: fieldDvLoc too small: %d-%d", fieldDvLocEnd, fieldDvLocStart)
	}

	fdvIter := &docValueReader{
		curChunkNum:  math.MaxUint64,
		field:        field,
		chunkOffsets: make([]uint64, int(numChunks)),
	}

	// read the chunk offsets
	var offset uint64
	for i := 0; i < int(numChunks); i++ {
		loc, read := binary.Uvarint(s.mem[chunkOffsetsPosition+offset : chunkOffsetsPosition+offset+binary.MaxVarintLen64])
		if read <= 0 {
			return nil, fmt.Errorf("corrupted chunk offset during segment load")
		}
		fdvIter.chunkOffsets[i] = loc
		offset += uint64(read)
	}

	// set the data offset
	fdvIter.dvDataLoc = fieldDvLocStart

	return fdvIter, nil
}

func (di *docValueReader) loadDvChunk(chunkNumber uint64, s *SegmentBase) error {
	// advance to the chunk where the docValues
	// reside for the given docNum
	destChunkDataLoc, curChunkEnd := di.dvDataLoc, di.dvDataLoc
	start, end := readChunkBoundary(int(chunkNumber), di.chunkOffsets)
	if start >= end {
		di.curChunkHeader = di.curChunkHeader[:0]
		di.curChunkData = nil
		di.curChunkNum = chunkNumber
		di.uncompressed = di.uncompressed[:0]
		return nil
	}

	destChunkDataLoc += start
	curChunkEnd += end

	// read the number of docs reside in the chunk
	numDocs, read := binary.Uvarint(s.mem[destChunkDataLoc : destChunkDataLoc+binary.MaxVarintLen64])
	if read <= 0 {
		return fmt.Errorf("failed to read the chunk")
	}
	chunkMetaLoc := destChunkDataLoc + uint64(read)

	offset := uint64(0)
	if cap(di.curChunkHeader) < int(numDocs) {
		di.curChunkHeader = make([]MetaData, int(numDocs))
	} else {
		di.curChunkHeader = di.curChunkHeader[:int(numDocs)]
	}
	for i := 0; i < int(numDocs); i++ {
		di.curChunkHeader[i].DocNum, read = binary.Uvarint(s.mem[chunkMetaLoc+offset : chunkMetaLoc+offset+binary.MaxVarintLen64])
		offset += uint64(read)
		di.curChunkHeader[i].DocDvOffset, read = binary.Uvarint(s.mem[chunkMetaLoc+offset : chunkMetaLoc+offset+binary.MaxVarintLen64])
		offset += uint64(read)
	}

	compressedDataLoc := chunkMetaLoc + offset
	dataLength := curChunkEnd - compressedDataLoc
	di.curChunkData = s.mem[compressedDataLoc : compressedDataLoc+dataLength]
	di.curChunkNum = chunkNumber
	di.uncompressed = di.uncompressed[:0]
	return nil
}

func (di *docValueReader) iterateAllDocValues(s *SegmentBase, visitor docNumTermsVisitor) error {
	for i := 0; i < len(di.chunkOffsets); i++ {
		err := di.loadDvChunk(uint64(i), s)
		if err != nil {
			return err
		}
		if di.curChunkData == nil || len(di.curChunkHeader) == 0 {
			continue
		}

		// uncompress the already loaded data
		uncompressed, err := snappy.Decode(di.uncompressed[:cap(di.uncompressed)], di.curChunkData)
		if err != nil {
			return err
		}
		di.uncompressed = uncompressed

		start := uint64(0)
		for _, entry := range di.curChunkHeader {
			err = visitor(entry.DocNum, uncompressed[start:entry.DocDvOffset])
			if err != nil {
				return err
			}

			start = entry.DocDvOffset
		}
	}

	return nil
}

func (di *docValueReader) visitDocValues(docNum uint64,
	visitor index.DocumentFieldTermVisitor) error {
	// binary search the term locations for the docNum
	start, end := di.getDocValueLocs(docNum)
	if start == math.MaxUint64 || end == math.MaxUint64 || start == end {
		return nil
	}

	var uncompressed []byte
	var err error
	// use the uncompressed copy if available
	if len(di.uncompressed) > 0 {
		uncompressed = di.uncompressed
	} else {
		// uncompress the already loaded data
		uncompressed, err = snappy.Decode(di.uncompressed[:cap(di.uncompressed)], di.curChunkData)
		if err != nil {
			return err
		}
		di.uncompressed = uncompressed
	}

	// pick the terms for the given docNum
	uncompressed = uncompressed[start:end]
	for {
		i := bytes.Index(uncompressed, termSeparatorSplitSlice)
		if i < 0 {
			break
		}

		visitor(di.field, uncompressed[0:i])
		uncompressed = uncompressed[i+1:]
	}

	return nil
}

func (di *docValueReader) getDocValueLocs(docNum uint64) (uint64, uint64) {
	i := sort.Search(len(di.curChunkHeader), func(i int) bool {
		return di.curChunkHeader[i].DocNum >= docNum
	})
	if i < len(di.curChunkHeader) && di.curChunkHeader[i].DocNum == docNum {
		return ReadDocValueBoundary(i, di.curChunkHeader)
	}
	return math.MaxUint64, math.MaxUint64
}

// VisitDocumentFieldTerms is an implementation of the
// DocumentFieldTermVisitable interface
func (s *Segment) VisitDocumentFieldTerms(localDocNum uint64, fields []string,
	visitor index.DocumentFieldTermVisitor, dvsIn segment.DocVisitState) (
	segment.DocVisitState, error) {
	dvs, ok := dvsIn.(*docVisitState)
	if !ok || dvs == nil {
		dvs = &docVisitState{}
	} else {
		if dvs.segment != s {
			dvs.segment = s
			dvs.dvrs = nil
		}
	}

	var fieldIDPlus1 uint16
	if dvs.dvrs == nil {
		dvs.dvrs = make(map[uint16]*docValueReader, len(fields))
		for _, field := range fields {
			if fieldIDPlus1, ok = s.fieldsMap[field]; !ok {
				continue
			}
			fieldID := fieldIDPlus1 - 1
			if dvIter, exists := s.fieldDvReaders[fieldID]; exists &&
				dvIter != nil {
				dvs.dvrs[fieldID] = dvIter.cloneInto(dvs.dvrs[fieldID])
			}
		}
	}

	// find the chunkNumber where the docValues are stored
	docInChunk := localDocNum / uint64(s.chunkFactor)
	var dvr *docValueReader
	for _, field := range fields {
		if fieldIDPlus1, ok = s.fieldsMap[field]; !ok {
			continue
		}
		fieldID := fieldIDPlus1 - 1
		if dvr, ok = dvs.dvrs[fieldID]; ok && dvr != nil {
			// check if the chunk is already loaded
			if docInChunk != dvr.curChunkNumber() {
				err := dvr.loadDvChunk(docInChunk, &s.SegmentBase)
				if err != nil {
					return dvs, err
				}
			}

			_ = dvr.visitDocValues(localDocNum, visitor)
		}
	}
	return dvs, nil
}

// VisitableDocValueFields returns the list of fields with
// persisted doc value terms ready to be visitable using the
// VisitDocumentFieldTerms method.
func (s *Segment) VisitableDocValueFields() ([]string, error) {
	return s.fieldDvNames, nil
}
<commit_msg>move the impl of DocumentFieldTermVisitable (#1208)<commit_after>//  Copyright (c) 2017 Couchbase, Inc.
//
// 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 zap

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"math"
	"reflect"
	"sort"

	"github.com/blevesearch/bleve/index"
	"github.com/blevesearch/bleve/index/scorch/segment"
	"github.com/blevesearch/bleve/size"
	"github.com/golang/snappy"
)

var reflectStaticSizedocValueReader int

func init() {
	var dvi docValueReader
	reflectStaticSizedocValueReader = int(reflect.TypeOf(dvi).Size())
}

type docNumTermsVisitor func(docNum uint64, terms []byte) error

type docVisitState struct {
	dvrs    map[uint16]*docValueReader
	segment *SegmentBase
}

type docValueReader struct {
	field          string
	curChunkNum    uint64
	chunkOffsets   []uint64
	dvDataLoc      uint64
	curChunkHeader []MetaData
	curChunkData   []byte // compressed data cache
	uncompressed   []byte // temp buf for snappy decompression
}

func (di *docValueReader) size() int {
	return reflectStaticSizedocValueReader + size.SizeOfPtr +
		len(di.field) +
		len(di.chunkOffsets)*size.SizeOfUint64 +
		len(di.curChunkHeader)*reflectStaticSizeMetaData +
		len(di.curChunkData)
}

func (di *docValueReader) cloneInto(rv *docValueReader) *docValueReader {
	if rv == nil {
		rv = &docValueReader{}
	}

	rv.field = di.field
	rv.curChunkNum = math.MaxUint64
	rv.chunkOffsets = di.chunkOffsets // immutable, so it's sharable
	rv.dvDataLoc = di.dvDataLoc
	rv.curChunkHeader = rv.curChunkHeader[:0]
	rv.curChunkData = nil
	rv.uncompressed = rv.uncompressed[:0]

	return rv
}

func (di *docValueReader) fieldName() string {
	return di.field
}

func (di *docValueReader) curChunkNumber() uint64 {
	return di.curChunkNum
}

func (s *SegmentBase) loadFieldDocValueReader(field string,
	fieldDvLocStart, fieldDvLocEnd uint64) (*docValueReader, error) {
	// get the docValue offset for the given fields
	if fieldDvLocStart == fieldNotUninverted {
		// no docValues found, nothing to do
		return nil, nil
	}

	// read the number of chunks, and chunk offsets position
	var numChunks, chunkOffsetsPosition uint64

	if fieldDvLocEnd-fieldDvLocStart > 16 {
		numChunks = binary.BigEndian.Uint64(s.mem[fieldDvLocEnd-8 : fieldDvLocEnd])
		// read the length of chunk offsets
		chunkOffsetsLen := binary.BigEndian.Uint64(s.mem[fieldDvLocEnd-16 : fieldDvLocEnd-8])
		// acquire position of chunk offsets
		chunkOffsetsPosition = (fieldDvLocEnd - 16) - chunkOffsetsLen
	} else {
		return nil, fmt.Errorf("loadFieldDocValueReader: fieldDvLoc too small: %d-%d", fieldDvLocEnd, fieldDvLocStart)
	}

	fdvIter := &docValueReader{
		curChunkNum:  math.MaxUint64,
		field:        field,
		chunkOffsets: make([]uint64, int(numChunks)),
	}

	// read the chunk offsets
	var offset uint64
	for i := 0; i < int(numChunks); i++ {
		loc, read := binary.Uvarint(s.mem[chunkOffsetsPosition+offset : chunkOffsetsPosition+offset+binary.MaxVarintLen64])
		if read <= 0 {
			return nil, fmt.Errorf("corrupted chunk offset during segment load")
		}
		fdvIter.chunkOffsets[i] = loc
		offset += uint64(read)
	}

	// set the data offset
	fdvIter.dvDataLoc = fieldDvLocStart

	return fdvIter, nil
}

func (di *docValueReader) loadDvChunk(chunkNumber uint64, s *SegmentBase) error {
	// advance to the chunk where the docValues
	// reside for the given docNum
	destChunkDataLoc, curChunkEnd := di.dvDataLoc, di.dvDataLoc
	start, end := readChunkBoundary(int(chunkNumber), di.chunkOffsets)
	if start >= end {
		di.curChunkHeader = di.curChunkHeader[:0]
		di.curChunkData = nil
		di.curChunkNum = chunkNumber
		di.uncompressed = di.uncompressed[:0]
		return nil
	}

	destChunkDataLoc += start
	curChunkEnd += end

	// read the number of docs reside in the chunk
	numDocs, read := binary.Uvarint(s.mem[destChunkDataLoc : destChunkDataLoc+binary.MaxVarintLen64])
	if read <= 0 {
		return fmt.Errorf("failed to read the chunk")
	}
	chunkMetaLoc := destChunkDataLoc + uint64(read)

	offset := uint64(0)
	if cap(di.curChunkHeader) < int(numDocs) {
		di.curChunkHeader = make([]MetaData, int(numDocs))
	} else {
		di.curChunkHeader = di.curChunkHeader[:int(numDocs)]
	}
	for i := 0; i < int(numDocs); i++ {
		di.curChunkHeader[i].DocNum, read = binary.Uvarint(s.mem[chunkMetaLoc+offset : chunkMetaLoc+offset+binary.MaxVarintLen64])
		offset += uint64(read)
		di.curChunkHeader[i].DocDvOffset, read = binary.Uvarint(s.mem[chunkMetaLoc+offset : chunkMetaLoc+offset+binary.MaxVarintLen64])
		offset += uint64(read)
	}

	compressedDataLoc := chunkMetaLoc + offset
	dataLength := curChunkEnd - compressedDataLoc
	di.curChunkData = s.mem[compressedDataLoc : compressedDataLoc+dataLength]
	di.curChunkNum = chunkNumber
	di.uncompressed = di.uncompressed[:0]
	return nil
}

func (di *docValueReader) iterateAllDocValues(s *SegmentBase, visitor docNumTermsVisitor) error {
	for i := 0; i < len(di.chunkOffsets); i++ {
		err := di.loadDvChunk(uint64(i), s)
		if err != nil {
			return err
		}
		if di.curChunkData == nil || len(di.curChunkHeader) == 0 {
			continue
		}

		// uncompress the already loaded data
		uncompressed, err := snappy.Decode(di.uncompressed[:cap(di.uncompressed)], di.curChunkData)
		if err != nil {
			return err
		}
		di.uncompressed = uncompressed

		start := uint64(0)
		for _, entry := range di.curChunkHeader {
			err = visitor(entry.DocNum, uncompressed[start:entry.DocDvOffset])
			if err != nil {
				return err
			}

			start = entry.DocDvOffset
		}
	}

	return nil
}

func (di *docValueReader) visitDocValues(docNum uint64,
	visitor index.DocumentFieldTermVisitor) error {
	// binary search the term locations for the docNum
	start, end := di.getDocValueLocs(docNum)
	if start == math.MaxUint64 || end == math.MaxUint64 || start == end {
		return nil
	}

	var uncompressed []byte
	var err error
	// use the uncompressed copy if available
	if len(di.uncompressed) > 0 {
		uncompressed = di.uncompressed
	} else {
		// uncompress the already loaded data
		uncompressed, err = snappy.Decode(di.uncompressed[:cap(di.uncompressed)], di.curChunkData)
		if err != nil {
			return err
		}
		di.uncompressed = uncompressed
	}

	// pick the terms for the given docNum
	uncompressed = uncompressed[start:end]
	for {
		i := bytes.Index(uncompressed, termSeparatorSplitSlice)
		if i < 0 {
			break
		}

		visitor(di.field, uncompressed[0:i])
		uncompressed = uncompressed[i+1:]
	}

	return nil
}

func (di *docValueReader) getDocValueLocs(docNum uint64) (uint64, uint64) {
	i := sort.Search(len(di.curChunkHeader), func(i int) bool {
		return di.curChunkHeader[i].DocNum >= docNum
	})
	if i < len(di.curChunkHeader) && di.curChunkHeader[i].DocNum == docNum {
		return ReadDocValueBoundary(i, di.curChunkHeader)
	}
	return math.MaxUint64, math.MaxUint64
}

// VisitDocumentFieldTerms is an implementation of the
// DocumentFieldTermVisitable interface
func (s *SegmentBase) VisitDocumentFieldTerms(localDocNum uint64, fields []string,
	visitor index.DocumentFieldTermVisitor, dvsIn segment.DocVisitState) (
	segment.DocVisitState, error) {
	dvs, ok := dvsIn.(*docVisitState)
	if !ok || dvs == nil {
		dvs = &docVisitState{}
	} else {
		if dvs.segment != s {
			dvs.segment = s
			dvs.dvrs = nil
		}
	}

	var fieldIDPlus1 uint16
	if dvs.dvrs == nil {
		dvs.dvrs = make(map[uint16]*docValueReader, len(fields))
		for _, field := range fields {
			if fieldIDPlus1, ok = s.fieldsMap[field]; !ok {
				continue
			}
			fieldID := fieldIDPlus1 - 1
			if dvIter, exists := s.fieldDvReaders[fieldID]; exists &&
				dvIter != nil {
				dvs.dvrs[fieldID] = dvIter.cloneInto(dvs.dvrs[fieldID])
			}
		}
	}

	// find the chunkNumber where the docValues are stored
	docInChunk := localDocNum / uint64(s.chunkFactor)
	var dvr *docValueReader
	for _, field := range fields {
		if fieldIDPlus1, ok = s.fieldsMap[field]; !ok {
			continue
		}
		fieldID := fieldIDPlus1 - 1
		if dvr, ok = dvs.dvrs[fieldID]; ok && dvr != nil {
			// check if the chunk is already loaded
			if docInChunk != dvr.curChunkNumber() {
				err := dvr.loadDvChunk(docInChunk, s)
				if err != nil {
					return dvs, err
				}
			}

			_ = dvr.visitDocValues(localDocNum, visitor)
		}
	}
	return dvs, nil
}

// VisitableDocValueFields returns the list of fields with
// persisted doc value terms ready to be visitable using the
// VisitDocumentFieldTerms method.
func (s *SegmentBase) VisitableDocValueFields() ([]string, error) {
	return s.fieldDvNames, nil
}
<|endoftext|>


<commit_before>package rollinghash_test

import (
	"hash"
	"math/rand"
	"testing"

	"github.com/chmduquesne/rollinghash"
	_adler32 "github.com/chmduquesne/rollinghash/adler32"
	"github.com/chmduquesne/rollinghash/bozo32"
	"github.com/chmduquesne/rollinghash/buzhash32"
	"github.com/chmduquesne/rollinghash/buzhash64"
	"github.com/chmduquesne/rollinghash/rabinkarp64"
)

var allHashes = []struct {
	name    string
	classic hash.Hash
	rolling rollinghash.Hash
}{
	{"adler32", _adler32.New(), _adler32.New()},
	{"buzhash32", buzhash32.New(), buzhash32.New()},
	{"buzhash64", buzhash64.New(), buzhash64.New()},
	{"bozo32", bozo32.New(), bozo32.New()},
	{"rabinkarp64", rabinkarp64.New(), rabinkarp64.New()},
}

// Gets the hash sum as a uint64
func sum64(h hash.Hash) (res uint64) {
	buf := make([]byte, 0, 8)
	s := h.Sum(buf)
	for _, b := range s {
		res <<= 8
		res |= uint64(b)
	}
	return
}

// Compute the hash by creating a byte slice with an additionnal '\0' at
// the beginning, writing the slice without the last byte, and then
// rolling the last byte.
func SumByWriteAndRoll(h rollinghash.Hash, b []byte) uint64 {
	q := []byte("\x00")
	q = append(q, b...)

	h.Reset()
	h.Write(q[:len(q)-1])
	h.Roll(q[len(q)-1])
	return sum64(h)
}

// Compute the hash the classic way
func SumByWriteOnly(h hash.Hash, b []byte) uint64 {
	h.Reset()
	h.Write(b)
	return sum64(h)
}

// Create some random slice (length betwen 0 and 8KB, random content)
func RandomBytes() (res []byte) {
	n := rand.Intn(8192)
	res = make([]byte, n)
	rand.Read(res)
	return res
}

// Verify that, on random inputs, the classic hash and the rollinghash
// return the same values
func blackBox(t *testing.T, hashname string, classic hash.Hash, rolling rollinghash.Hash) {
	for i := 0; i < 1000; i++ {
		in := RandomBytes()
		if len(in) > 0 {
			sum := SumByWriteAndRoll(rolling, in)
			ref := SumByWriteOnly(classic, in)

			if ref != sum {
				t.Errorf("[%s] Expected 0x%x, got 0x%x", hashname, ref, sum)
			}
		}
	}
}

// Roll a window of 16 bytes with a classic hash and a rolling hash and
// compare the results
func foxDog(t *testing.T, hashname string, classic hash.Hash, rolling rollinghash.Hash) {
	s := []byte("The quick brown fox jumps over the lazy dog")

	// Window len
	n := 16

	// Load the window into the rolling hash
	rolling.Write(s[:n])

	// Roll it and compare the result with full re-calculus every time
	for i := n; i < len(s); i++ {

		// Reset and write the window in classic
		classic.Reset()
		classic.Write(s[i-n+1 : i+1])

		// Roll the incoming byte in rolling
		rolling.Roll(s[i])

		// Compare the hashes
		sumc := sum64(classic)
		sumr := sum64(rolling)
		if sumc != sumr {
			t.Errorf("[%s] %v: expected %x, got %x",
				hashname, s[i-n+1:i+1], sumc, sumr)
		}
	}
}

func rollEmptyWindow(t *testing.T, hashname string, classic hash.Hash, rolling rollinghash.Hash) {
	defer func() {
		if r := recover(); r == nil {
			t.Errorf("[%s] Rolling an empty window should cause a panic", hashname)
		}
	}()
	// This should panic
	rolling.Roll(byte('x'))
}

func writeTwice(t *testing.T, hashname string, classic hash.Hash, rolling rollinghash.Hash) {
	rolling.Write([]byte("hello "))
	rolling.Write([]byte("world"))

	classic.Write([]byte("hello world"))

	if sum64(rolling) != sum64(classic) {
		t.Errorf("Expected same results on r1 and r2")
	}
}

func writeRollWrite(t *testing.T, hashname string, classic hash.Hash, rolling rollinghash.Hash) {
	rolling.Write([]byte(" hello"))
	rolling.Roll(byte(' '))
	rolling.Write([]byte("world"))

	classic.Write([]byte("hello world"))

	if sum64(rolling) != sum64(classic) {
		t.Errorf("Expected same results on r1 and r2")
	}
}

func writeThenWriteNothing(t *testing.T, hashname string, classic hash.Hash, rolling rollinghash.Hash) {
	rolling.Write([]byte("hello"))
	rolling.Write([]byte(""))

	classic.Write([]byte("hello"))

	if sum64(rolling) != sum64(classic) {
		t.Errorf("Expected same results on r1 and r2")
	}
}

func writeNothing(t *testing.T, hashname string, classic hash.Hash, rolling rollinghash.Hash) {
	rolling.Write([]byte(""))

	if sum64(rolling) != sum64(classic) {
		t.Errorf("Expected same results on r1 and r2")
	}
}

func TestFoxDog(t *testing.T) {
	for _, h := range allHashes {
		h.classic.Reset()
		h.rolling.Reset()
		foxDog(t, h.name, h.classic, h.rolling)
	}
}

func TestBlackBox(t *testing.T) {
	for _, h := range allHashes {
		h.classic.Reset()
		h.rolling.Reset()
		blackBox(t, h.name, h.classic, h.rolling)
	}
}

func TestRollEmptyWindow(t *testing.T) {
	for _, h := range allHashes {
		h.classic.Reset()
		h.rolling.Reset()
		rollEmptyWindow(t, h.name, h.classic, h.rolling)
	}
}

func TestwriteTwice(t *testing.T) {
	for _, h := range allHashes {
		h.classic.Reset()
		h.rolling.Reset()
		writeTwice(t, h.name, h.classic, h.rolling)
	}
}

func TestwriteRollWrite(t *testing.T) {
	for _, h := range allHashes {
		h.classic.Reset()
		h.rolling.Reset()
		writeRollWrite(t, h.name, h.classic, h.rolling)
	}
}

func TestWriteThenWriteNothing(t *testing.T) {
	for _, h := range allHashes {
		h.classic.Reset()
		h.rolling.Reset()
		writeThenWriteNothing(t, h.name, h.classic, h.rolling)
	}
}

func TestWriteNothing(t *testing.T) {
	for _, h := range allHashes {
		h.classic.Reset()
		h.rolling.Reset()
		writeNothing(t, h.name, h.classic, h.rolling)
	}
}
<commit_msg>Better test reporting<commit_after>package rollinghash_test

import (
	"hash"
	"math/rand"
	"testing"

	"github.com/chmduquesne/rollinghash"
	_adler32 "github.com/chmduquesne/rollinghash/adler32"
	"github.com/chmduquesne/rollinghash/bozo32"
	"github.com/chmduquesne/rollinghash/buzhash32"
	"github.com/chmduquesne/rollinghash/buzhash64"
	"github.com/chmduquesne/rollinghash/rabinkarp64"
)

var allHashes = []struct {
	name    string
	classic hash.Hash
	rolling rollinghash.Hash
}{
	{"adler32", _adler32.New(), _adler32.New()},
	{"buzhash32", buzhash32.New(), buzhash32.New()},
	{"buzhash64", buzhash64.New(), buzhash64.New()},
	{"bozo32", bozo32.New(), bozo32.New()},
	{"rabinkarp64", rabinkarp64.New(), rabinkarp64.New()},
}

// Gets the hash sum as a uint64
func sum64(h hash.Hash) (res uint64) {
	buf := make([]byte, 0, 8)
	s := h.Sum(buf)
	for _, b := range s {
		res <<= 8
		res |= uint64(b)
	}
	return
}

// Compute the hash by creating a byte slice with an additionnal '\0' at
// the beginning, writing the slice without the last byte, and then
// rolling the last byte.
func SumByWriteAndRoll(h rollinghash.Hash, b []byte) uint64 {
	q := []byte("\x00")
	q = append(q, b...)

	h.Reset()
	h.Write(q[:len(q)-1])
	h.Roll(q[len(q)-1])
	return sum64(h)
}

// Compute the hash the classic way
func SumByWriteOnly(h hash.Hash, b []byte) uint64 {
	h.Reset()
	h.Write(b)
	return sum64(h)
}

// Create some random slice (length betwen 0 and 8KB, random content)
func RandomBytes() (res []byte) {
	n := rand.Intn(8192)
	res = make([]byte, n)
	rand.Read(res)
	return res
}

// Verify that, on random inputs, the classic hash and the rollinghash
// return the same values
func blackBox(t *testing.T, hashname string, classic hash.Hash, rolling rollinghash.Hash) {
	for i := 0; i < 1000; i++ {
		in := RandomBytes()
		if len(in) > 0 {
			sum := SumByWriteAndRoll(rolling, in)
			ref := SumByWriteOnly(classic, in)

			if ref != sum {
				t.Errorf("[%s] Expected 0x%x, got 0x%x", hashname, ref, sum)
			}
		}
	}
}

// Roll a window of 16 bytes with a classic hash and a rolling hash and
// compare the results
func foxDog(t *testing.T, hashname string, classic hash.Hash, rolling rollinghash.Hash) {
	s := []byte("The quick brown fox jumps over the lazy dog")

	// Window len
	n := 16

	// Load the window into the rolling hash
	rolling.Write(s[:n])

	// Roll it and compare the result with full re-calculus every time
	for i := n; i < len(s); i++ {

		// Reset and write the window in classic
		classic.Reset()
		classic.Write(s[i-n+1 : i+1])

		// Roll the incoming byte in rolling
		rolling.Roll(s[i])

		// Compare the hashes
		sumc := sum64(classic)
		sumr := sum64(rolling)
		if sumc != sumr {
			t.Errorf("[%s] %v: expected %x, got %x",
				hashname, s[i-n+1:i+1], sumc, sumr)
		}
	}
}

func rollEmptyWindow(t *testing.T, hashname string, classic hash.Hash, rolling rollinghash.Hash) {
	defer func() {
		if r := recover(); r == nil {
			t.Errorf("[%s] Rolling an empty window should cause a panic", hashname)
		}
	}()
	// This should panic
	rolling.Roll(byte('x'))
}

func writeTwice(t *testing.T, hashname string, classic hash.Hash, rolling rollinghash.Hash) {
	rolling.Write([]byte("hello "))
	rolling.Write([]byte("world"))

	classic.Write([]byte("hello world"))

	if sum64(rolling) != sum64(classic) {
		t.Errorf("[%s] Expected same results on rolling and classic", hashname)
	}
}

func writeRollWrite(t *testing.T, hashname string, classic hash.Hash, rolling rollinghash.Hash) {
	rolling.Write([]byte(" hello"))
	rolling.Roll(byte(' '))
	rolling.Write([]byte("world"))

	classic.Write([]byte("hello world"))

	if sum64(rolling) != sum64(classic) {
		t.Errorf("[%s] Expected same results on rolling and classic", hashname)
	}
}

func writeThenWriteNothing(t *testing.T, hashname string, classic hash.Hash, rolling rollinghash.Hash) {
	rolling.Write([]byte("hello"))
	rolling.Write([]byte(""))

	classic.Write([]byte("hello"))

	if sum64(rolling) != sum64(classic) {
		t.Errorf("[%s] Expected same results on rolling and classic", hashname)
	}
}

func writeNothing(t *testing.T, hashname string, classic hash.Hash, rolling rollinghash.Hash) {
	rolling.Write([]byte(""))

	if sum64(rolling) != sum64(classic) {
		t.Errorf("[%s] Expected same results on rolling and classic", hashname)
	}
}

func TestFoxDog(t *testing.T) {
	for _, h := range allHashes {
		h.classic.Reset()
		h.rolling.Reset()
		foxDog(t, h.name, h.classic, h.rolling)
	}
}

func TestBlackBox(t *testing.T) {
	for _, h := range allHashes {
		h.classic.Reset()
		h.rolling.Reset()
		blackBox(t, h.name, h.classic, h.rolling)
	}
}

func TestRollEmptyWindow(t *testing.T) {
	for _, h := range allHashes {
		h.classic.Reset()
		h.rolling.Reset()
		rollEmptyWindow(t, h.name, h.classic, h.rolling)
	}
}

func TestwriteTwice(t *testing.T) {
	for _, h := range allHashes {
		h.classic.Reset()
		h.rolling.Reset()
		writeTwice(t, h.name, h.classic, h.rolling)
	}
}

func TestwriteRollWrite(t *testing.T) {
	for _, h := range allHashes {
		h.classic.Reset()
		h.rolling.Reset()
		writeRollWrite(t, h.name, h.classic, h.rolling)
	}
}

func TestWriteThenWriteNothing(t *testing.T) {
	for _, h := range allHashes {
		h.classic.Reset()
		h.rolling.Reset()
		writeThenWriteNothing(t, h.name, h.classic, h.rolling)
	}
}

func TestWriteNothing(t *testing.T) {
	for _, h := range allHashes {
		h.classic.Reset()
		h.rolling.Reset()
		writeNothing(t, h.name, h.classic, h.rolling)
	}
}
<|endoftext|>


<commit_before>package models

import (
	"database/sql"
	"time"

	"github.com/keydotcat/backend/util"
)

type vaultUser struct {
	Team      string `scaneo:"pk"`
	Vault     string `scaneo:"pk"`
	User      string `scaneo:"pk"`
	Key       []byte
	CreatedAt time.Time
	UpdatedAt time.Time
}

func (tu *vaultUser) insert(tx *sql.Tx) error {
	now := time.Now().UTC()
	tu.CreatedAt = now
	tu.UpdatedAt = now
	_, err := tu.dbInsert(tx)
	if isDuplicateErr(err) {
		return util.NewErrorf("User %s is already in vault", tu.User)
	}
	if isErrOrPanic(err) {
		return util.NewErrorFrom(err)
	}
	return nil
}

func (v vaultUser) validate() error {
	errs := util.NewErrorFields().(*util.Error)
	if len(v.Team) == 0 {
		errs.SetFieldError("team", "missing")
	}
	if len(v.Vault) == 0 {
		errs.SetFieldError("vault", "missing")
	}
	if len(v.User) == 0 {
		errs.SetFieldError("user", "missing")
	}
	if len(v.Key) == 0 {
		errs.SetFieldError("key", "missing")
	}
	return errs.Camo()
}
<commit_msg>Forgot to add validate<commit_after>package models

import (
	"database/sql"
	"time"

	"github.com/keydotcat/backend/util"
)

type vaultUser struct {
	Team      string `scaneo:"pk"`
	Vault     string `scaneo:"pk"`
	User      string `scaneo:"pk"`
	Key       []byte
	CreatedAt time.Time
	UpdatedAt time.Time
}

func (tu *vaultUser) insert(tx *sql.Tx) error {
	if err := tu.validate(); err != nil {
		return err
	}
	now := time.Now().UTC()
	tu.CreatedAt = now
	tu.UpdatedAt = now
	_, err := tu.dbInsert(tx)
	if isDuplicateErr(err) {
		return util.NewErrorf("User %s is already in vault", tu.User)
	}
	if isErrOrPanic(err) {
		return util.NewErrorFrom(err)
	}
	return nil
}

func (v vaultUser) validate() error {
	errs := util.NewErrorFields().(*util.Error)
	if len(v.Team) == 0 {
		errs.SetFieldError("team", "missing")
	}
	if len(v.Vault) == 0 {
		errs.SetFieldError("vault", "missing")
	}
	if len(v.User) == 0 {
		errs.SetFieldError("user", "missing")
	}
	if len(v.Key) == 0 {
		errs.SetFieldError("key", "missing")
	}
	return errs.Camo()
}
<|endoftext|>


<commit_before>package configurator_test

import (
	"path/filepath"
	"runtime"
	"testing"

	"github.com/alecthomas/assert"
	"github.com/itchio/butler/configurator"
)

func Test_ConfigureWindows(t *testing.T) {
	root := filepath.Join("testdata", "windows")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")

	assert.EqualValues(t, 4, len(v.Candidates), "finds all candidates on first walk")

	v32 := *v
	(&v32).FilterPlatform("windows", "386")

	assert.EqualValues(t, 1, len(v32.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "launcher.bat", v32.Candidates[0].Path, "batch won")

	v64 := *v
	(&v64).FilterPlatform("windows", "amd64")

	assert.EqualValues(t, 1, len(v64.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "launcher.bat", v64.Candidates[0].Path, "batch won")
}

func Test_ConfigureWindowsHtml(t *testing.T) {
	root := filepath.Join("testdata", "windows-html")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")

	assert.EqualValues(t, 2, len(v.Candidates), "finds all candidates on first walk")

	v32 := *v
	(&v32).FilterPlatform("windows", "386")

	assert.EqualValues(t, 1, len(v32.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "game.exe", v32.Candidates[0].Path, "batch won")

	v64 := *v
	(&v64).FilterPlatform("windows", "amd64")

	assert.EqualValues(t, 1, len(v64.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "game.exe", v64.Candidates[0].Path, "batch won")
}

func Test_ConfigureDarwin(t *testing.T) {
	root := filepath.Join("testdata", "darwin")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 4, len(v.Candidates), "finds all candidates on first walk")

	fixed, err := v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")
	assert.EqualValues(t, 3, len(fixed), "had to fix some files")

	vcopy := *v
	(&vcopy).FilterPlatform("darwin", "amd64")

	assert.EqualValues(t, 1, len(vcopy.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "Some Grand Game.app", vcopy.Candidates[0].Path, "app wins")
}

func Test_ConfigureDarwinNested(t *testing.T) {
	root := filepath.Join("testdata", "darwin-nested")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 4, len(v.Candidates), "finds all candidates on first walk")

	_, err = v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")

	vcopy := *v
	(&vcopy).FilterPlatform("darwin", "amd64")

	assert.EqualValues(t, 1, len(vcopy.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "osx64/dragonjousting.app", vcopy.Candidates[0].Path, "app wins")
}

func Test_ConfigureDarwinGhost(t *testing.T) {
	root := filepath.Join("testdata", "darwin-ghost")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 3, len(v.Candidates), "finds both execs and one valid app bundle")

	_, err = v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")

	vcopy := *v
	(&vcopy).FilterPlatform("darwin", "amd64")

	assert.EqualValues(t, 1, len(vcopy.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "Awesome Stuff.app", vcopy.Candidates[0].Path, "valid app bundle wins")
}

func Test_ConfigureDarwinSymlink(t *testing.T) {
	root := filepath.Join("testdata", "darwin-symlink")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 1, len(v.Candidates), "finds all candidates on first walk")

	_, err = v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")

	vcopy := *v
	(&vcopy).FilterPlatform("darwin", "amd64")

	assert.EqualValues(t, 1, len(vcopy.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "hello.app", vcopy.Candidates[0].Path, "app wins")
}

func Test_ConfigureLinux(t *testing.T) {
	root := filepath.Join("testdata", "linux")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 8, len(v.Candidates), "finds all candidates on first walk")

	fixed, err := v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")
	// on windows it fixes 5 because reasons
	if runtime.GOOS != "windows" {
		assert.EqualValues(t, 4, len(fixed), "fixed some files")
	}

	vcopy := *v
	(&vcopy).FilterPlatform("linux", "amd64")

	assert.EqualValues(t, 1, len(vcopy.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "OpenHexagon", vcopy.Candidates[0].Path, "launcher script wins")
}

func Test_ConfigureLinuxDualArch(t *testing.T) {
	root := filepath.Join("testdata", "linux-dual-arch")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 2, len(v.Candidates), "finds all candidates on first walk")

	fixed, err := v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")
	assert.EqualValues(t, 2, len(fixed), "fixed some files")

	v32 := *v
	(&v32).FilterPlatform("linux", "386")

	assert.EqualValues(t, 1, len(v32.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "Game.x86", v32.Candidates[0].Path, "launcher script wins")

	v64 := *v
	(&v64).FilterPlatform("linux", "amd64")

	assert.EqualValues(t, 1, len(v64.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "Game.x86_64", v64.Candidates[0].Path, "launcher script wins")
}

func Test_ConfigureLinuxJarFallback(t *testing.T) {
	root := filepath.Join("testdata", "linux-jar-fallback")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 2, len(v.Candidates), "finds all candidates on first walk")

	fixed, err := v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")
	assert.EqualValues(t, 1, len(fixed), "fixed some files")

	v32 := *v
	(&v32).FilterPlatform("linux", "386")

	assert.EqualValues(t, 1, len(v32.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "binary", v32.Candidates[0].Path, "launcher script wins")

	v64 := *v
	(&v64).FilterPlatform("linux", "amd64")

	assert.EqualValues(t, 1, len(v64.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "hiddenjar.dat", v64.Candidates[0].Path, "launcher script wins")
}

func Test_ConfigureHtmlMany(t *testing.T) {
	root := filepath.Join("testdata", "html", "many")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 1, len(v.Candidates), "finds all candidates on first walk")

	_, err = v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")

	vcopy := *v
	(&vcopy).FilterPlatform("darwin", "amd64")

	assert.EqualValues(t, 1, len(vcopy.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "index.html", vcopy.Candidates[0].Path, "lowest won")
}

func Test_ConfigureHtmlNested(t *testing.T) {
	root := filepath.Join("testdata", "html", "nested")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 1, len(v.Candidates), "finds all candidates on first walk")

	_, err = v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")

	vcopy := *v
	(&vcopy).FilterPlatform("darwin", "amd64")

	assert.EqualValues(t, 1, len(vcopy.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "ThisContainsStuff/index.html", vcopy.Candidates[0].Path, "lowest won")
}

func Test_ConfigureBiggerIsBetter(t *testing.T) {
	root := filepath.Join("testdata", "bigger-is-better")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 3, len(v.Candidates), "finds all candidates on first walk")

	vcopy := *v
	(&vcopy).FilterPlatform("windows", "amd64")

	assert.EqualValues(t, 3, len(vcopy.Candidates), "three candidates left after filtering")
	assert.EqualValues(t, "tiled.exe", vcopy.Candidates[0].Path, "biggest wins")
}

func Test_ConfigureBlacklist(t *testing.T) {
	root := filepath.Join("testdata", "linux-nodewebkit")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 4, len(v.Candidates), "finds all candidates on first walk")

	vcopy := *v
	(&vcopy).FilterPlatform("linux", "amd64")

	assert.EqualValues(t, 3, len(vcopy.Candidates), "three candidates left after filtering")
	assert.EqualValues(t, "nw", vcopy.Candidates[0].Path, "non-nacl helper wins")
}
<commit_msg>guess we'll make libs executable now as well<commit_after>package configurator_test

import (
	"path/filepath"
	"runtime"
	"testing"

	"github.com/alecthomas/assert"
	"github.com/itchio/butler/configurator"
)

func Test_ConfigureWindows(t *testing.T) {
	root := filepath.Join("testdata", "windows")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")

	assert.EqualValues(t, 4, len(v.Candidates), "finds all candidates on first walk")

	v32 := *v
	(&v32).FilterPlatform("windows", "386")

	assert.EqualValues(t, 1, len(v32.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "launcher.bat", v32.Candidates[0].Path, "batch won")

	v64 := *v
	(&v64).FilterPlatform("windows", "amd64")

	assert.EqualValues(t, 1, len(v64.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "launcher.bat", v64.Candidates[0].Path, "batch won")
}

func Test_ConfigureWindowsHtml(t *testing.T) {
	root := filepath.Join("testdata", "windows-html")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")

	assert.EqualValues(t, 2, len(v.Candidates), "finds all candidates on first walk")

	v32 := *v
	(&v32).FilterPlatform("windows", "386")

	assert.EqualValues(t, 1, len(v32.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "game.exe", v32.Candidates[0].Path, "batch won")

	v64 := *v
	(&v64).FilterPlatform("windows", "amd64")

	assert.EqualValues(t, 1, len(v64.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "game.exe", v64.Candidates[0].Path, "batch won")
}

func Test_ConfigureDarwin(t *testing.T) {
	root := filepath.Join("testdata", "darwin")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 4, len(v.Candidates), "finds all candidates on first walk")

	fixed, err := v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")
	assert.EqualValues(t, 3, len(fixed), "had to fix some files")

	vcopy := *v
	(&vcopy).FilterPlatform("darwin", "amd64")

	assert.EqualValues(t, 1, len(vcopy.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "Some Grand Game.app", vcopy.Candidates[0].Path, "app wins")
}

func Test_ConfigureDarwinNested(t *testing.T) {
	root := filepath.Join("testdata", "darwin-nested")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 4, len(v.Candidates), "finds all candidates on first walk")

	_, err = v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")

	vcopy := *v
	(&vcopy).FilterPlatform("darwin", "amd64")

	assert.EqualValues(t, 1, len(vcopy.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "osx64/dragonjousting.app", vcopy.Candidates[0].Path, "app wins")
}

func Test_ConfigureDarwinGhost(t *testing.T) {
	root := filepath.Join("testdata", "darwin-ghost")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 3, len(v.Candidates), "finds both execs and one valid app bundle")

	_, err = v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")

	vcopy := *v
	(&vcopy).FilterPlatform("darwin", "amd64")

	assert.EqualValues(t, 1, len(vcopy.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "Awesome Stuff.app", vcopy.Candidates[0].Path, "valid app bundle wins")
}

func Test_ConfigureDarwinSymlink(t *testing.T) {
	root := filepath.Join("testdata", "darwin-symlink")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 1, len(v.Candidates), "finds all candidates on first walk")

	_, err = v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")

	vcopy := *v
	(&vcopy).FilterPlatform("darwin", "amd64")

	assert.EqualValues(t, 1, len(vcopy.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "hello.app", vcopy.Candidates[0].Path, "app wins")
}

func Test_ConfigureLinux(t *testing.T) {
	root := filepath.Join("testdata", "linux")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 8, len(v.Candidates), "finds all candidates on first walk")

	fixed, err := v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")
	// on windows it fixes 5 because reasons
	if runtime.GOOS != "windows" {
		assert.EqualValues(t, 7, len(fixed), "fixed some files")
	}

	vcopy := *v
	(&vcopy).FilterPlatform("linux", "amd64")

	assert.EqualValues(t, 1, len(vcopy.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "OpenHexagon", vcopy.Candidates[0].Path, "launcher script wins")
}

func Test_ConfigureLinuxDualArch(t *testing.T) {
	root := filepath.Join("testdata", "linux-dual-arch")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 2, len(v.Candidates), "finds all candidates on first walk")

	fixed, err := v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")
	assert.EqualValues(t, 2, len(fixed), "fixed some files")

	v32 := *v
	(&v32).FilterPlatform("linux", "386")

	assert.EqualValues(t, 1, len(v32.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "Game.x86", v32.Candidates[0].Path, "launcher script wins")

	v64 := *v
	(&v64).FilterPlatform("linux", "amd64")

	assert.EqualValues(t, 1, len(v64.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "Game.x86_64", v64.Candidates[0].Path, "launcher script wins")
}

func Test_ConfigureLinuxJarFallback(t *testing.T) {
	root := filepath.Join("testdata", "linux-jar-fallback")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 2, len(v.Candidates), "finds all candidates on first walk")

	fixed, err := v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")
	assert.EqualValues(t, 1, len(fixed), "fixed some files")

	v32 := *v
	(&v32).FilterPlatform("linux", "386")

	assert.EqualValues(t, 1, len(v32.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "binary", v32.Candidates[0].Path, "launcher script wins")

	v64 := *v
	(&v64).FilterPlatform("linux", "amd64")

	assert.EqualValues(t, 1, len(v64.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "hiddenjar.dat", v64.Candidates[0].Path, "launcher script wins")
}

func Test_ConfigureHtmlMany(t *testing.T) {
	root := filepath.Join("testdata", "html", "many")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 1, len(v.Candidates), "finds all candidates on first walk")

	_, err = v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")

	vcopy := *v
	(&vcopy).FilterPlatform("darwin", "amd64")

	assert.EqualValues(t, 1, len(vcopy.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "index.html", vcopy.Candidates[0].Path, "lowest won")
}

func Test_ConfigureHtmlNested(t *testing.T) {
	root := filepath.Join("testdata", "html", "nested")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 1, len(v.Candidates), "finds all candidates on first walk")

	_, err = v.FixPermissions(true)
	assert.NoError(t, err, "fixes permissions without problems")

	vcopy := *v
	(&vcopy).FilterPlatform("darwin", "amd64")

	assert.EqualValues(t, 1, len(vcopy.Candidates), "only one candidate left after filtering")
	assert.EqualValues(t, "ThisContainsStuff/index.html", vcopy.Candidates[0].Path, "lowest won")
}

func Test_ConfigureBiggerIsBetter(t *testing.T) {
	root := filepath.Join("testdata", "bigger-is-better")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 3, len(v.Candidates), "finds all candidates on first walk")

	vcopy := *v
	(&vcopy).FilterPlatform("windows", "amd64")

	assert.EqualValues(t, 3, len(vcopy.Candidates), "three candidates left after filtering")
	assert.EqualValues(t, "tiled.exe", vcopy.Candidates[0].Path, "biggest wins")
}

func Test_ConfigureBlacklist(t *testing.T) {
	root := filepath.Join("testdata", "linux-nodewebkit")

	v, err := configurator.Configure(root, true)
	assert.NoError(t, err, "walks without problems")
	assert.EqualValues(t, 4, len(v.Candidates), "finds all candidates on first walk")

	vcopy := *v
	(&vcopy).FilterPlatform("linux", "amd64")

	assert.EqualValues(t, 3, len(vcopy.Candidates), "three candidates left after filtering")
	assert.EqualValues(t, "nw", vcopy.Candidates[0].Path, "non-nacl helper wins")
}
<|endoftext|>


<commit_before>package tendermint

import (
	tm_config "github.com/tendermint/tendermint/config"
)

// Burrow's view on Tendermint's config. Since we operate as a Tendermint harness not all configuration values
// are applicable, we may not allow some values to specified, or we may not allow some to be set independently.
// So this serves as a layer of indirection over Tendermint's real config that we derive from ours.
type BurrowTendermintConfig struct {
	Seeds          string
	ListenAddress  string
	Moniker        string
	TendermintRoot string
}

func DefaultBurrowTendermintConfig() *BurrowTendermintConfig {
	tmDefaultConfig := tm_config.DefaultConfig()
	return &BurrowTendermintConfig{
		ListenAddress:  tmDefaultConfig.P2P.ListenAddress,
		TendermintRoot: ".burrow",
	}
}

func (btc *BurrowTendermintConfig) TendermintConfig() *tm_config.Config {
	conf := tm_config.DefaultConfig()
	if btc != nil {
		// We may need to expose more of the P2P/Consensus/Mempool options, but I'd like to keep the configuration
		// minimal
		conf.RootDir = btc.TendermintRoot
		conf.Consensus.RootDir = btc.TendermintRoot
		conf.Mempool.RootDir = btc.TendermintRoot
		conf.P2P.RootDir = btc.TendermintRoot
		conf.P2P.Seeds = btc.Seeds
		conf.P2P.ListenAddress = btc.ListenAddress
		conf.P2P.AuthEnc = false
		conf.Moniker = btc.Moniker
	}
	// Disable Tendermint RPC
	conf.RPC.ListenAddress = ""
	return conf
}
<commit_msg>Expose Tendermint PersistentPeers config<commit_after>package tendermint

import (
	tm_config "github.com/tendermint/tendermint/config"
)

// Burrow's view on Tendermint's config. Since we operate as a Tendermint harness not all configuration values
// are applicable, we may not allow some values to specified, or we may not allow some to be set independently.
// So this serves as a layer of indirection over Tendermint's real config that we derive from ours.
type BurrowTendermintConfig struct {
	// Initial peers we connect to for peer exchange
	Seeds           string
	// Peers to which we automatically connect
	PersistentPeers string
	ListenAddress   string
	Moniker         string
	TendermintRoot  string
}

func DefaultBurrowTendermintConfig() *BurrowTendermintConfig {
	tmDefaultConfig := tm_config.DefaultConfig()
	return &BurrowTendermintConfig{
		ListenAddress:  tmDefaultConfig.P2P.ListenAddress,
		TendermintRoot: ".burrow",
	}
}

func (btc *BurrowTendermintConfig) TendermintConfig() *tm_config.Config {
	conf := tm_config.DefaultConfig()
	if btc != nil {
		// We may need to expose more of the P2P/Consensus/Mempool options, but I'd like to keep the configuration
		// minimal
		conf.RootDir = btc.TendermintRoot
		conf.Consensus.RootDir = btc.TendermintRoot
		conf.Mempool.RootDir = btc.TendermintRoot
		conf.P2P.RootDir = btc.TendermintRoot
		conf.P2P.Seeds = btc.Seeds
		conf.P2P.PersistentPeers = btc.PersistentPeers
		conf.P2P.ListenAddress = btc.ListenAddress
		conf.P2P.AuthEnc = false
		conf.Moniker = btc.Moniker
	}
	// Disable Tendermint RPC
	conf.RPC.ListenAddress = ""
	return conf
}
<|endoftext|>


<commit_before>package livepkg

// jsreloader is the default file reloader
const jsreloader = `
var Reloader = {};
(function(Reloader){
	"use strict";

	Reloader.ReloadAfter = 2000;

	var xhr = new XMLHttpRequest();
	var src = (PkgJSON || document.currentScript.src.replace(".js", ".json"));
	xhr.open("GET", src);

	xhr.onreadystatechange = function(){
		if(xhr.readyState !== 4){ return; }

		if(xhr.status != 200){
			window.setTimeout(window.location.reload, Reloader.ReloadAfter);
			return;
		}

		var result = JSON.parse(xhr.responseText);
		LoadFiles(result.files);

		if(typeof WebSocket !== 'undefined'){
			ListenChanges(result.live);
		}
	};

	xhr.send();

	var loading = {};
	var unloaded = [];

	Reloader.loading = loading;
	Reloader.unloaded = unloaded;

	function LoadFiles(files){
		unloaded = files;
		flush();

		var loadMonitor = window.setInterval(flush, 100);

		// tries to load as many unblocked files as possible
		function flush(){
			// clear loaded
			for(var name in loading){
				var asset = document.getElementById("~" + name);
				if(typeof asset === 'undefined'){ continue; }
				if((asset.readyState === 'complete') ||
					(asset.readyState === 'loaded')){
					delete loading[name];
				}
			}

			// try load something new
			while(unloaded.length > 0){
				if(!tryLoad(unloaded[0])){
					return;
				};
				unloaded.shift();
			}

			// done?
			if(Object.keys(loading).length == 0){
				console.log("reloader", "+++");
				window.clearInterval(loadMonitor);
			}
		}

		// tries to load a file, returns true if it started loading
		function tryLoad(file){
			for(var i = 0; i < file.deps.length; i += 1){
				if(loading[file.deps[i]]){ return false; }
			}

			console.log("reloader", "+ " + file.path);
			loading[file.path] = true;
			var asset = injectFile(file);
			asset.onreadystatechange = flush;

			asset.onload = function(){
				delete loading[file.path];
				flush();
			};
			asset.onerror = function(){
				delete loading[file.path];
				flush();
			};
			return true;
		}
	}

	function makeDOMElement(file){
		switch(file.ext){
		case ".js":
			var asset = document.createElement("script");
			asset.src = file.path + "?" + Math.random();
			break;
		case ".css":
			var asset = document.createElement("link");
			asset.href = file.path + "?" + Math.random();
			asset.rel = "stylesheet";
			break;
		default:
			return;
		}
		asset.id = "~" + file.path;
		return asset;
	}

	function injectFile(file){
		var asset = makeDOMElement(file);
		document.getElementsByTagName('head')[0].appendChild(asset);
		return asset;
	}

	function removeFile(file){
		var previous = document.getElementById("~" + file.path);
		previous.parentNode.removeChild(previous);
	}

	function swapFile(prev, next){
		var next = makeDOMElement(next);
		var prev = document.getElementById(next.id);
		prev.parentNode.insertBefore(next, prev);
		setTimeout(function(){
			prev.parentNode.removeChild(prev);
		}, 20);
		return next;
	}

	function reload(){
		window.location.reload();
	}

	function onFileChanged(change){
		return function(){
			console.log("reloader", "%", change);
			Reloader.onchange && Reloader.onchange(change);
		};
	}

	var OnceConnected = false;
	var ConnectionDelay = 100;
	function ListenChanges(livepath){
		if(livepath == null){ return; }
		var ws = new WebSocket("ws://" + window.location.host + livepath);

		ws.addEventListener('message', function(ev){
			if(ev.data === "") { return; }
			var change = JSON.parse(ev.data);
			if(change.deps){
				reload();
				return;
			}

			if(change.prev == null){
				var asset = injectFile(change.next);
				asset.onload = onFileChanged(change);
			} else if(change.next == null){
				removeFile(change.prev);
			} else {
				var asset = swapFile(change.prev, change.next);
				asset.onload = onFileChanged(change);
			}
		});

		ws.addEventListener('open', function(){
			console.log("livepkg connected");
			if(OnceConnected){
				// server changed, force reload
				window.location.reload();
			}
			OnceConnected = true;
		});

		ws.addEventListener('close', function(ev){
			console.log("livepkg disconnected", ev);
			window.setTimeout(function(){ ListenChanges(livepath); }, ConnectionDelay);
			ConnectionDelay *= 2;
			if(ConnectionDelay > 5000){
				ConnectionDelay = 5000;
			}
		});
	}
})(Reloader);
`
<commit_msg>Keep Reloader.Change for back-comp.<commit_after>package livepkg

// jsreloader is the default file reloader
const jsreloader = `
var Reloader = {};
(function(Reloader){
	"use strict";

	Reloader.ReloadAfter = 2000;

	var xhr = new XMLHttpRequest();
	var src = (PkgJSON || document.currentScript.src.replace(".js", ".json"));
	xhr.open("GET", src);

	xhr.onreadystatechange = function(){
		if(xhr.readyState !== 4){ return; }

		if(xhr.status != 200){
			window.setTimeout(window.location.reload, Reloader.ReloadAfter);
			return;
		}

		var result = JSON.parse(xhr.responseText);
		LoadFiles(result.files);

		if(typeof WebSocket !== 'undefined'){
			ListenChanges(result.live);
		}
	};

	xhr.send();

	var loading = {};
	var unloaded = [];

	Reloader.loading = loading;
	Reloader.unloaded = unloaded;

	function LoadFiles(files){
		unloaded = files;
		flush();

		var loadMonitor = window.setInterval(flush, 100);

		// tries to load as many unblocked files as possible
		function flush(){
			// clear loaded
			for(var name in loading){
				var asset = document.getElementById("~" + name);
				if(typeof asset === 'undefined'){ continue; }
				if((asset.readyState === 'complete') ||
					(asset.readyState === 'loaded')){
					delete loading[name];
				}
			}

			// try load something new
			while(unloaded.length > 0){
				if(!tryLoad(unloaded[0])){
					return;
				};
				unloaded.shift();
			}

			// done?
			if(Object.keys(loading).length == 0){
				console.log("reloader", "+++");
				window.clearInterval(loadMonitor);
			}
		}

		// tries to load a file, returns true if it started loading
		function tryLoad(file){
			for(var i = 0; i < file.deps.length; i += 1){
				if(loading[file.deps[i]]){ return false; }
			}

			console.log("reloader", "+ " + file.path);
			loading[file.path] = true;
			var asset = injectFile(file);
			asset.onreadystatechange = flush;

			asset.onload = function(){
				delete loading[file.path];
				flush();
			};
			asset.onerror = function(){
				delete loading[file.path];
				flush();
			};
			return true;
		}
	}

	function makeDOMElement(file){
		switch(file.ext){
		case ".js":
			var asset = document.createElement("script");
			asset.src = file.path + "?" + Math.random();
			break;
		case ".css":
			var asset = document.createElement("link");
			asset.href = file.path + "?" + Math.random();
			asset.rel = "stylesheet";
			break;
		default:
			return;
		}
		asset.id = "~" + file.path;
		return asset;
	}

	function injectFile(file){
		var asset = makeDOMElement(file);
		document.getElementsByTagName('head')[0].appendChild(asset);
		return asset;
	}

	function removeFile(file){
		var previous = document.getElementById("~" + file.path);
		previous.parentNode.removeChild(previous);
	}

	function swapFile(prev, next){
		var next = makeDOMElement(next);
		var prev = document.getElementById(next.id);
		prev.parentNode.insertBefore(next, prev);
		setTimeout(function(){
			prev.parentNode.removeChild(prev);
		}, 20);
		return next;
	}

	function reload(){
		window.location.reload();
	}

	function onFileChanged(change){
		return function(){
			console.log("reloader", "%", change);
			Reloader.Change && Reloader.Change(change);
			Reloader.onchange && Reloader.onchange(change);
		};
	}

	var OnceConnected = false;
	var ConnectionDelay = 100;
	function ListenChanges(livepath){
		if(livepath == null){ return; }
		var ws = new WebSocket("ws://" + window.location.host + livepath);

		ws.addEventListener('message', function(ev){
			if(ev.data === "") { return; }
			var change = JSON.parse(ev.data);
			if(change.deps){
				reload();
				return;
			}

			if(change.prev == null){
				var asset = injectFile(change.next);
				asset.onload = onFileChanged(change);
			} else if(change.next == null){
				removeFile(change.prev);
			} else {
				var asset = swapFile(change.prev, change.next);
				asset.onload = onFileChanged(change);
			}
		});

		ws.addEventListener('open', function(){
			console.log("livepkg connected");
			if(OnceConnected){
				// server changed, force reload
				window.location.reload();
			}
			OnceConnected = true;
		});

		ws.addEventListener('close', function(ev){
			console.log("livepkg disconnected", ev);
			window.setTimeout(function(){ ListenChanges(livepath); }, ConnectionDelay);
			ConnectionDelay *= 2;
			if(ConnectionDelay > 5000){
				ConnectionDelay = 5000;
			}
		});
	}
})(Reloader);
`
<|endoftext|>


<commit_before>package repo

import (
	"io"
	"github.com/ipfs/go-ipfs/repo"
	"encoding/json"
	"io/ioutil"
	"github.com/OpenBazaar/go-libbitcoinclient"
	"encoding/base64"
	"github.com/pebbe/zmq4"
	"github.com/ipfs/go-ipfs/repo/config"
)

var DefaultBootstrapAddresses = []string{
	"/ip4/107.170.127.73/tcp/4001/ipfs/QmWZKgbSHzfkUMxLh7xRA4XaSeqxcTnw7rb9x3jMMkbQZr",
}

func GetLibbitcoinServers(cfgPath string) ([]libbitcoin.Server, error) {
	servers := []libbitcoin.Server{}
	file, err := ioutil.ReadFile(cfgPath)
	if err != nil {
		return servers, err
	}
	var cfg interface{}
	json.Unmarshal(file, &cfg)

	for _, s := range(cfg.(map[string]interface{})["LibbitcoinServers"].([]interface{})){
		encodedKey := s.(map[string]interface{})["PublicKey"].(string)
		if encodedKey != "" {
			b, _ := base64.StdEncoding.DecodeString(encodedKey)
			encodedKey = zmq4.Z85encode(string(b))
		}
		server := libbitcoin.Server{
			Url: s.(map[string]interface{})["Url"].(string),
			PublicKey: encodedKey,
		}
		servers = append(servers, server)
	}
	return  servers, nil
}

func GetDropboxApiToken(cfgPath string) (string, error) {
	file, err := ioutil.ReadFile(cfgPath)
	if err != nil {
		return "", err
	}
	var cfg interface{}
	json.Unmarshal(file, &cfg)

	token := cfg.(map[string]interface{})["Dropbox-api-token"].(string)

	return  token, nil
}

func extendConfigFile(r repo.Repo, key string, value interface{}) error {
	if err := r.SetConfigKey(key, value); err != nil {
		return err
	}
	return nil
}

func initConfig(out io.Writer) (*config.Config, error) {

	bootstrapPeers, err := config.ParseBootstrapPeers(DefaultBootstrapAddresses)
	if err != nil {
		return nil, err
	}

	datastore, err := datastoreConfig()
	if err != nil {
		return nil, err
	}

	conf := &config.Config{

		// setup the node's default addresses.
		// NOTE: two swarm listen addrs, one tcp, one utp.
		Addresses: config.Addresses{
			Swarm: []string{
				"/ip4/0.0.0.0/tcp/4001",
				"/ip4/0.0.0.0/udp/4001/utp",
				"/ip6/::/tcp/4001",
				"/ip6/::/udp/4001/utp",
			},
			API:     "",
			Gateway: "/ip4/127.0.0.1/tcp/8080",
		},

		Datastore: datastore,
		Bootstrap: config.BootstrapPeerStrings(bootstrapPeers),
		Discovery: config.Discovery{config.MDNS{
			Enabled:  false,
			Interval: 10,
		}},

		// setup the node mount points.
		Mounts: config.Mounts{
			IPFS: "/ipfs",
			IPNS: "/ipns",
		},

		Ipns: config.Ipns{
			ResolveCacheSize: 128,
			RecordLifetime: "7d",
			RepublishPeriod: "24h",
		},

		Gateway: config.Gateway{
			RootRedirect: "",
			Writable:     false,
			PathPrefixes: []string{},
		},
	}

	return conf, nil
}

func datastoreConfig() (config.Datastore, error) {
	dspath, err := config.DataStorePath("")
	if err != nil {
		return config.Datastore{}, err
	}
	return config.Datastore{
		Path:               dspath,
		Type:               "leveldb",
		StorageMax:         "10GB",
		StorageGCWatermark: 90, // 90%
		GCPeriod:           "1h",
	}, nil
}<commit_msg>Switch bootstrap peers<commit_after>package repo

import (
	"io"
	"github.com/ipfs/go-ipfs/repo"
	"encoding/json"
	"io/ioutil"
	"github.com/OpenBazaar/go-libbitcoinclient"
	"encoding/base64"
	"github.com/pebbe/zmq4"
	"github.com/ipfs/go-ipfs/repo/config"
)

var DefaultBootstrapAddresses = []string{
	"/ip4/107.170.133.32/tcp/4001/ipfs/QmboEn7ycZqb8sXH6wJunWE6d3mdT9iVD7XWDmCcKE9jZ5",
}

func GetLibbitcoinServers(cfgPath string) ([]libbitcoin.Server, error) {
	servers := []libbitcoin.Server{}
	file, err := ioutil.ReadFile(cfgPath)
	if err != nil {
		return servers, err
	}
	var cfg interface{}
	json.Unmarshal(file, &cfg)

	for _, s := range(cfg.(map[string]interface{})["LibbitcoinServers"].([]interface{})){
		encodedKey := s.(map[string]interface{})["PublicKey"].(string)
		if encodedKey != "" {
			b, _ := base64.StdEncoding.DecodeString(encodedKey)
			encodedKey = zmq4.Z85encode(string(b))
		}
		server := libbitcoin.Server{
			Url: s.(map[string]interface{})["Url"].(string),
			PublicKey: encodedKey,
		}
		servers = append(servers, server)
	}
	return  servers, nil
}

func GetDropboxApiToken(cfgPath string) (string, error) {
	file, err := ioutil.ReadFile(cfgPath)
	if err != nil {
		return "", err
	}
	var cfg interface{}
	json.Unmarshal(file, &cfg)

	token := cfg.(map[string]interface{})["Dropbox-api-token"].(string)

	return  token, nil
}

func extendConfigFile(r repo.Repo, key string, value interface{}) error {
	if err := r.SetConfigKey(key, value); err != nil {
		return err
	}
	return nil
}

func initConfig(out io.Writer) (*config.Config, error) {

	bootstrapPeers, err := config.ParseBootstrapPeers(DefaultBootstrapAddresses)
	if err != nil {
		return nil, err
	}

	datastore, err := datastoreConfig()
	if err != nil {
		return nil, err
	}

	conf := &config.Config{

		// setup the node's default addresses.
		// NOTE: two swarm listen addrs, one tcp, one utp.
		Addresses: config.Addresses{
			Swarm: []string{
				"/ip4/0.0.0.0/tcp/4001",
				"/ip4/0.0.0.0/udp/4001/utp",
				"/ip6/::/tcp/4001",
				"/ip6/::/udp/4001/utp",
			},
			API:     "",
			Gateway: "/ip4/127.0.0.1/tcp/8080",
		},

		Datastore: datastore,
		Bootstrap: config.BootstrapPeerStrings(bootstrapPeers),
		Discovery: config.Discovery{config.MDNS{
			Enabled:  false,
			Interval: 10,
		}},

		// setup the node mount points.
		Mounts: config.Mounts{
			IPFS: "/ipfs",
			IPNS: "/ipns",
		},

		Ipns: config.Ipns{
			ResolveCacheSize: 128,
			RecordLifetime: "7d",
			RepublishPeriod: "24h",
		},

		Gateway: config.Gateway{
			RootRedirect: "",
			Writable:     false,
			PathPrefixes: []string{},
		},
	}

	return conf, nil
}

func datastoreConfig() (config.Datastore, error) {
	dspath, err := config.DataStorePath("")
	if err != nil {
		return config.Datastore{}, err
	}
	return config.Datastore{
		Path:               dspath,
		Type:               "leveldb",
		StorageMax:         "10GB",
		StorageGCWatermark: 90, // 90%
		GCPeriod:           "1h",
	}, nil
}<|endoftext|>


<commit_before>package resolv_test

import (
	"testing"

	"github.com/miekg/dns"
	"github.com/vitalie/resolv"
	"golang.org/x/net/context"
)

var nss = []string{
	"ns1.luadns.net",
	"ns2.luadns.net",
	"ns3.luadns.net",
	"ns4.luadns.net",
	"ns5.luadns.net",
}

// Simple resolve benchmark, run with:
//	go test -bench=.
func BenchmarkResolve(b *testing.B) {
	r := resolv.NewResolver()
	req := resolv.NewRequest("ns1.luadns.net", "cherpec.com", dns.TypeA)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		resp := <-r.Resolve(req)
		if resp.Err != nil {
			b.Fatal(resp.Err)
		}
	}
}

func TestResolve(t *testing.T) {
	r := resolv.NewResolver()

	// UDP Mode
	req := resolv.NewRequest("ns1.luadns.net", "cherpec.com", dns.TypeA)
	resp := <-r.Resolve(req)
	if resp.Err != nil {
		t.Fatal(resp.Err)
	}

	// TCP Mode
	req = resolv.NewRequest("ns1.luadns.net", "cherpec.com", dns.TypeA, resolv.SetTCPMode)
	resp = <-r.Resolve(req)
	if resp.Err != nil {
		t.Fatal(resp.Err)
	}

	// CHAOS class
	req = resolv.NewRequest("ns1.linode.com", "version.bind", dns.TypeTXT, resolv.SetCHAOSClass)
	resp = <-r.Resolve(req)
	if resp.Err != nil {
		t.Fatal(resp.Err)
	}
}

func TestTimeout(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode.")
	}

	r := resolv.NewResolver()
	req := resolv.NewRequest("ns1.luadns.net", "google.com", dns.TypeA)
	resp := <-r.Resolve(req)
	if resp.Err != nil {
		err, ok := resp.Err.(*resolv.DNSError)
		if !ok {
			t.Errorf("expected DNSError got: %v", resp.Err)
		}

		if !err.Timeout() {
			t.Errorf("expected timeout got: %v", resp.Err)
		}
	}
}

func TestResolveTypes(t *testing.T) {
	r := resolv.NewResolver()

	// Query multiple types
	types := []uint16{dns.TypeA, dns.TypeNS, dns.TypeMX}
	c := r.ResolveTypes(context.Background(), "ns1.luadns.net", "cherpec.com", types)

	n := 0
	for resp := range c {
		if resp.Err != nil {
			t.Error(resp.Err)
		}
		n++
	}

	if n != len(types) {
		t.Errorf("responses missmatch: %v != %v", n, len(types))
	}
}

func TestResolveNames(t *testing.T) {
	r := resolv.NewResolver()

	// Query multiple names
	names := []string{"cherpec.com", "www.cherpec.com"}
	c := r.ResolveNames(context.Background(), "ns1.luadns.net", dns.TypeA, names)

	n := 0
	for resp := range c {
		if resp.Err != nil {
			t.Error(resp.Err)
		}
		n++
	}

	if n != len(names) {
		t.Errorf("responses missmatch: %v != %v", n, len(names))
	}
}

func TestDelegationIterator(t *testing.T) {
	rs := resolv.NewResolver()
	it := resolv.NewDelegation(rs)

	r1 := <-it.Resolve(context.Background(), ".")
	if r1.Err != nil {
		t.Fatal(r1.Err)
	}

	r2 := <-it.Resolve(context.Background(), "com.")
	if r2.Err != nil {
		t.Fatal(r2.Err)
	}

	r3 := <-it.Resolve(context.Background(), "cherpec.com.")
	if r3.Err != nil {
		t.Fatal(r3.Err)
	}
}
<commit_msg>Update test name<commit_after>package resolv_test

import (
	"testing"

	"github.com/miekg/dns"
	"github.com/vitalie/resolv"
	"golang.org/x/net/context"
)

var nss = []string{
	"ns1.luadns.net",
	"ns2.luadns.net",
	"ns3.luadns.net",
	"ns4.luadns.net",
	"ns5.luadns.net",
}

// Simple resolve benchmark, run with:
//	go test -bench=.
func BenchmarkResolve(b *testing.B) {
	r := resolv.NewResolver()
	req := resolv.NewRequest("ns1.luadns.net", "cherpec.com", dns.TypeA)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		resp := <-r.Resolve(req)
		if resp.Err != nil {
			b.Fatal(resp.Err)
		}
	}
}

func TestResolve(t *testing.T) {
	r := resolv.NewResolver()

	// UDP Mode
	req := resolv.NewRequest("ns1.luadns.net", "cherpec.com", dns.TypeA)
	resp := <-r.Resolve(req)
	if resp.Err != nil {
		t.Fatal(resp.Err)
	}

	// TCP Mode
	req = resolv.NewRequest("ns1.luadns.net", "cherpec.com", dns.TypeA, resolv.SetTCPMode)
	resp = <-r.Resolve(req)
	if resp.Err != nil {
		t.Fatal(resp.Err)
	}

	// CHAOS class
	req = resolv.NewRequest("ns1.linode.com", "version.bind", dns.TypeTXT, resolv.SetCHAOSClass)
	resp = <-r.Resolve(req)
	if resp.Err != nil {
		t.Fatal(resp.Err)
	}
}

func TestTimeout(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode.")
	}

	r := resolv.NewResolver()
	req := resolv.NewRequest("ns1.luadns.net", "google.com", dns.TypeA)
	resp := <-r.Resolve(req)
	if resp.Err != nil {
		err, ok := resp.Err.(*resolv.DNSError)
		if !ok {
			t.Errorf("expected DNSError got: %v", resp.Err)
		}

		if !err.Timeout() {
			t.Errorf("expected timeout got: %v", resp.Err)
		}
	}
}

func TestResolveTypes(t *testing.T) {
	r := resolv.NewResolver()

	// Query multiple types
	types := []uint16{dns.TypeA, dns.TypeNS, dns.TypeMX}
	c := r.ResolveTypes(context.Background(), "ns1.luadns.net", "cherpec.com", types)

	n := 0
	for resp := range c {
		if resp.Err != nil {
			t.Error(resp.Err)
		}
		n++
	}

	if n != len(types) {
		t.Errorf("responses missmatch: %v != %v", n, len(types))
	}
}

func TestResolveNames(t *testing.T) {
	r := resolv.NewResolver()

	// Query multiple names
	names := []string{"cherpec.com", "www.cherpec.com"}
	c := r.ResolveNames(context.Background(), "ns1.luadns.net", dns.TypeA, names)

	n := 0
	for resp := range c {
		if resp.Err != nil {
			t.Error(resp.Err)
		}
		n++
	}

	if n != len(names) {
		t.Errorf("responses missmatch: %v != %v", n, len(names))
	}
}

func TestDelegation(t *testing.T) {
	rs := resolv.NewResolver()
	it := resolv.NewDelegation(rs)

	r1 := <-it.Resolve(context.Background(), ".")
	if r1.Err != nil {
		t.Fatal(r1.Err)
	}

	r2 := <-it.Resolve(context.Background(), "com.")
	if r2.Err != nil {
		t.Fatal(r2.Err)
	}

	r3 := <-it.Resolve(context.Background(), "cherpec.com.")
	if r3.Err != nil {
		t.Fatal(r3.Err)
	}
}
<|endoftext|>