func newSearcher(r index.IndexReader, maybeWrap bool) *ts.AssertingIndexSearcher {
	random := Random()
	var err error
	if maybeWrap {
		r, err = maybeWrapReader(r)
		assert(err == nil)
	}
	if random.Intn(2) == 0 {
		ss := ts.NewAssertingIndexSearcher(random, r)
		ss.SetSimilarity(ClassEnvRule.similarity)
		return ss
	}
	ss := ts.NewAssertingIndexSearcherFromContext(random, r.Context())
	ss.SetSimilarity(ClassEnvRule.similarity)
	return ss
}
/*
Create a new searcher over the reader. This searcher might randomly
use threads. If maybeWrap is true, this searcher migt wrap the reader
with one that return nil for sequentialSubReaders.
package test_framework
import (
	"fmt"
	"github.com/balzaczyy/golucene/core/analysis"
	. "github.com/balzaczyy/golucene/core/codec/spi"
	docu "github.com/balzaczyy/golucene/core/document"
	"github.com/balzaczyy/golucene/core/index"
	"github.com/balzaczyy/golucene/core/search"
	"github.com/balzaczyy/golucene/core/store"
	"github.com/balzaczyy/golucene/core/util"
	ti "github.com/balzaczyy/golucene/test_framework/index"
	ts "github.com/balzaczyy/golucene/test_framework/search"
	. "github.com/balzaczyy/golucene/test_framework/util"
	. "github.com/balzaczyy/gounit"
	"io"
	"log"
	"math"
	"math/rand"
	"os"
	"reflect"
)
var TEST_VERSION_CURRENT = util.VERSION_45
var TEST_THROTTLING = either(TEST_NIGHTLY, THROTTLING_SOMETIMES, THROTTLING_NEVER).(Throttling)
func either(flag bool, value, orValue interface{}) interface{} {
	if flag {
		return value
	}
	return orValue
}
var ClassEnvRule = &TestRuleSetupAndRestoreClassEnv{}
func NewIndexWriterConfig(v util.Version, a analysis.Analyzer) *index.IndexWriterConfig {
	return newRandomIndexWriteConfig(Random(), v, a)
}
func newRandomIndexWriteConfig(r *rand.Rand, v util.Version, a analysis.Analyzer) *index.IndexWriterConfig {
	c := index.NewIndexWriterConfig(v, a)
	c.SetSimilarity(ClassEnvRule.similarity)
	if VERBOSE {
		c.SetInfoStream(newThreadNameFixingPrintStreamInfoStream(os.Stdout))
	}
	if r.Intn(2) == 0 {
		c.SetMergeScheduler(index.NewSerialMergeScheduler())
	} else if Rarely(r) {
		log.Println("Use ConcurrentMergeScheduler")
		maxRoutineCount := NextInt(Random(), 1, 4)
		maxMergeCount := NextInt(Random(), maxRoutineCount, maxRoutineCount+4)
		cms := index.NewConcurrentMergeScheduler()
		cms.SetMaxMergesAndRoutines(maxMergeCount, maxRoutineCount)
		c.SetMergeScheduler(cms)
	}
	if r.Intn(2) == 0 {
		if Rarely(r) {
			log.Println("Use crazy value for buffered docs")
			c.SetMaxBufferedDocs(NextInt(r, 2, 15))
		} else {
			c.SetMaxBufferedDocs(NextInt(r, 16, 1000))
		}
	}
	c.SetMergePolicy(newMergePolicy(r))
	if Rarely(r) {
		log.Println("Use SimpleMergedSegmentWarmer")
		c.SetMergedSegmentWarmer(index.NewSimpleMergedSegmentWarmer(c.InfoStream()))
	}
	c.SetUseCompoundFile(r.Intn(2) == 0)
	c.SetReaderPooling(r.Intn(2) == 0)
	c.SetReaderTermsIndexDivisor(NextInt(r, 1, 4))
	return c
}
func newMergePolicy(r *rand.Rand) index.MergePolicy {
	if Rarely(r) {
		log.Println("Use MockRandomMergePolicy")
		return ti.NewMockRandomMergePolicy(r)
	} else if r.Intn(2) == 0 {
		return newTieredMergePolicy(r)
	} else if r.Intn(5) == 0 {
		return newAlcoholicMergePolicy(r  )
	} else {
		return newLogMergePolicy(r)
	}
}
func newTieredMergePolicy(r *rand.Rand) *index.TieredMergePolicy {
	tmp := index.NewTieredMergePolicy()
	if Rarely(r) {
		log.Println("Use crazy value for max merge at once")
		tmp.SetMaxMergeAtOnce(NextInt(r, 2, 9))
		tmp.SetMaxMergeAtOnceExplicit(NextInt(r, 2, 9))
	} else {
		tmp.SetMaxMergeAtOnce(NextInt(r, 10, 50))
		tmp.SetMaxMergeAtOnceExplicit(NextInt(r, 10, 50))
	}
	if Rarely(r) {
		log.Println("Use crazy value for max merge segment MB")
		tmp.SetMaxMergedSegmentMB(0.2 + r.Float64()*100)
	} else {
		tmp.SetMaxMergedSegmentMB(r.Float64() * 100)
	}
	tmp.SetFloorSegmentMB(0.2 + r.Float64()*2)
	tmp.SetForceMergeDeletesPctAllowed(0 + r.Float64()*30)
	if Rarely(r) {
		log.Println("Use crazy value for max merge per tire")
		tmp.SetSegmentsPerTier(float64(NextInt(r, 2, 20)))
	} else {
		tmp.SetSegmentsPerTier(float64(NextInt(r, 10, 50)))
	}
	configureRandom(r, tmp)
	tmp.SetReclaimDeletesWeight(r.Float64() * 4)
	return tmp
}
func newAlcoholicMergePolicy(r *rand.Rand  ) *ti.AlcoholicMergePolicy {
	return ti.NewAlcoholicMergePolicy(rand.New(rand.NewSource(r.Int63())))
}
func newLogMergePolicy(r *rand.Rand) *index.LogMergePolicy {
	var logmp *index.LogMergePolicy
	if r.Intn(2) == 0 {
		logmp = index.NewLogDocMergePolicy()
	} else {
		logmp = index.NewLogByteSizeMergePolicy()
	}
	if Rarely(r) {
		log.Println("Use crazy value for merge factor")
		logmp.SetMergeFactor(NextInt(r, 2, 9))
	} else {
		logmp.SetMergeFactor(NextInt(r, 10, 50))
	}
	configureRandom(r, logmp)
	return logmp
}
func configureRandom(r *rand.Rand, mergePolicy index.MergePolicy) {
	if r.Intn(2) == 0 {
		mergePolicy.SetNoCFSRatio(0.1 + r.Float64()*0.8)
	} else if r.Intn(2) == 0 {
		mergePolicy.SetNoCFSRatio(1.0)
	} else {
		mergePolicy.SetNoCFSRatio(0)
	}
	if Rarely(r) {
		log.Println("Use crazy value for max CFS segment size MB")
		mergePolicy.SetMaxCFSSegmentSizeMB(0.2 + r.Float64()*2)
	} else {
		mergePolicy.SetMaxCFSSegmentSizeMB(math.Inf(1))
	}
}
func NewDirectory() BaseDirectoryWrapper {
	return newDirectoryWithSeed(Random())
}
func newDirectoryWithSeed(r *rand.Rand) BaseDirectoryWrapper {
	return wrapDirectory(r, newDirectoryImpl(r, TEST_DIRECTORY), Rarely(r))
}
func wrapDirectory(random *rand.Rand, directory store.Directory, bare bool) BaseDirectoryWrapper {
	if Rarely(random) {
		log.Println("Use NRTCachingDirectory")
		directory = store.NewNRTCachingDirectory(directory, random.Float64(), random.Float64())
	}
	if Rarely(random) {
		maxMBPerSec := 10 + 5*(random.Float64()-0.5)
		if VERBOSE {
			log.Printf("LuceneTestCase: will rate limit output IndexOutput to %v MB/sec", maxMBPerSec)
		}
		rateLimitedDirectoryWrapper := store.NewRateLimitedDirectoryWrapper(directory)
		switch random.Intn(10) {
		case 3:  
			rateLimitedDirectoryWrapper.SetMaxWriteMBPerSec(maxMBPerSec, store.IO_CONTEXT_TYPE_FLUSH)
		case 2:  
			rateLimitedDirectoryWrapper.SetMaxWriteMBPerSec(maxMBPerSec, store.IO_CONTEXT_TYPE_FLUSH)
			rateLimitedDirectoryWrapper.SetMaxWriteMBPerSec(maxMBPerSec, store.IO_CONTEXT_TYPE_MERGE)
		default:
			rateLimitedDirectoryWrapper.SetMaxWriteMBPerSec(maxMBPerSec, store.IO_CONTEXT_TYPE_MERGE)
		}
		directory = rateLimitedDirectoryWrapper
	}
	if bare {
		base := NewBaseDirectoryWrapper(directory)
		CloseAfterSuite(NewCloseableDirectory(base, SuiteFailureMarker))
		return base
	} else {
		mock := NewMockDirectoryWrapper(random, directory)
		mock.SetThrottling(TEST_THROTTLING)
		CloseAfterSuite(NewCloseableDirectory(mock, SuiteFailureMarker))
		return mock
	}
}
func NewTextField(name, value string, stored bool) *docu.Field {
	flag := docu.TEXT_FIELD_TYPE_STORED
	if !stored {
		flag = docu.TEXT_FIELD_TYPE_NOT_STORED
	}
	return NewField(Random(), name, value, flag)
}
func NewField(r *rand.Rand, name, value string, typ *docu.FieldType) *docu.Field {
	panic("not implemented yet")
}
func newDirectoryImpl(random *rand.Rand, clazzName string) store.Directory {
	if clazzName == "random" {
		if Rarely(random) {
			switch random.Intn(1) {
			case 0:
				clazzName = "SimpleFSDirectory"
			}
		} else {
			clazzName = "RAMDirectory"
		}
	}
	if clazzName == "RAMDirectory" {
		return store.NewRAMDirectory()
	} else {
		path := TempDir("index")
		if err := os.MkdirAll(path, os.ModeTemporary); err != nil {
			panic(err)
		}
		switch clazzName {
		case "SimpleFSDirectory":
			d, err := store.NewSimpleFSDirectory(path)
			if err != nil {
				panic(err)
			}
			return d
		}
		panic(fmt.Sprintf("not supported yet: %v", clazzName))
	}
}
func NewDefaultIOContext(r *rand.Rand) store.IOContext {
	return NewIOContext(r, store.IO_CONTEXT_DEFAULT)
}
func NewIOContext(r *rand.Rand, oldContext store.IOContext) store.IOContext {
	randomNumDocs := r.Intn(4192)
	size := r.Int63n(512) * int64(randomNumDocs)
	if oldContext.FlushInfo != nil {
		if size < oldContext.FlushInfo.EstimatedSegmentSize {
			size = oldContext.FlushInfo.EstimatedSegmentSize
		}
		return store.NewIOContextForFlush(&store.FlushInfo{randomNumDocs, size})
	} else if oldContext.MergeInfo != nil {
		if size < oldContext.MergeInfo.EstimatedMergeBytes {
			size = oldContext.MergeInfo.EstimatedMergeBytes
		}
		return store.NewIOContextForMerge(
			&store.MergeInfo{randomNumDocs, size, r.Intn(2) == 0, NextInt(r, 1, 100)})
	} else {
		switch r.Intn(5) {
		case 1:
			return store.IO_CONTEXT_READ
		case 2:
			return store.IO_CONTEXT_READONCE
		case 3:
			return store.NewIOContextForMerge(&store.MergeInfo{randomNumDocs, size, true, -1})
		case 4:
			return store.NewIOContextForFlush(&store.FlushInfo{randomNumDocs, size})
		default:
			return store.IO_CONTEXT_DEFAULT
		}
	}
}
func maybeWrapReader(r index.IndexReader) (index.IndexReader, error) {
	random := Random()
	if Rarely(random) {
		panic("not implemented yet")
	}
	return r, nil
}
func NewSearcher(r index.IndexReader) *ts.AssertingIndexSearcher {
	return newSearcher(r, true)
}