<commit_before>package model

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func fixtureEmptySlave() *Slave {
	return &Slave{
		Hostname:             "host1",
		Port:                 1,
		MongodPortRangeBegin: 2,
		MongodPortRangeEnd:   3,
		PersistentStorage:    true,
		Mongods:              []*Mongod{},
		ConfiguredState:      SlaveStateActive,
	}
}

func fixtureEmptyMongod() *Mongod {
	return &Mongod{
		Port:        8080,
		ReplSetName: "repl1",
	}
}

func fixtureEmptyRiskGroup() *RiskGroup {
	return &RiskGroup{
		Name:   "rg1",
		Slaves: []*Slave{},
	}
}

func fixtureEmptyReplicaSet() *ReplicaSet {
	return &ReplicaSet{
		Name: "repl1",
		PersistentMemberCount:           1,
		VolatileMemberCount:             2,
		ConfigureAsShardingConfigServer: false,
	}
}

////////////////////////////////////////////////////////////////////////////////

func TestCanInitializeDB(t *testing.T) {
	_, err := InitializeInMemoryDB("")
	assert.NoError(t, err)
}

/*
 This elaborate test demonstrates how resolving an association works in gorm.
 Check the assertions to learn about the behavior of gorm.
*/
func TestRelationshipMongodParentSlave(t *testing.T) {

	db, _ := InitializeInMemoryDB("")

	s := fixtureEmptySlave()

	db.Create(s)

	m := fixtureEmptyMongod()
	m.ParentSlave = s

	db.Create(m)

	assert.Equal(t, m.ParentSlaveID, s.ID)

	assert.Equal(t, s.Mongods, []*Mongod{})

	var sdb Slave

	// Check what happens when just SELECTing the slave
	err := db.First(&sdb).Error

	assert.NoError(t, err)
	assert.Nil(t, sdb.Mongods)

	// Now resolve the slave->mongod 1:n association
	err = db.Model(&sdb).Related(&sdb.Mongods, "Mongods").Error

	assert.NoError(t, err)
	assert.Equal(t, len(sdb.Mongods), 1)
	assert.Equal(t, sdb.Mongods[0].ReplSetName, m.ReplSetName)
	assert.Zero(t, sdb.Mongods[0].ParentSlave)
	assert.Equal(t, sdb.Mongods[0].ParentSlaveID, s.ID)

	// Now resolve the mongod->(parent)slave relation
	parentSlave := &Slave{}
	err = db.Model(&sdb.Mongods[0]).Related(parentSlave, "ParentSlave").Error
	assert.NoError(t, err)
	assert.NotZero(t, parentSlave)
	assert.Equal(t, s.ID, parentSlave.ID)

}

// Test RiskGroup Slave relationship
func TestRiskGroupSlaveRelationship(t *testing.T) {

	db, _ := InitializeInMemoryDB("")

	s := fixtureEmptySlave()
	r := fixtureEmptyRiskGroup()
	r.Slaves = []*Slave{s}

	err := db.Create(&r).Error
	assert.NoError(t, err)

	var rdb RiskGroup

	err = db.First(&rdb).Error

	assert.NoError(t, err)
	assert.Zero(t, rdb.Slaves)

	err = db.Model(&rdb).Related(&rdb.Slaves, "Slaves").Error
	assert.NoError(t, err)
	assert.NotZero(t, rdb.Slaves)
	assert.Equal(t, len(rdb.Slaves), 1)
	assert.Equal(t, rdb.Slaves[0].ID, s.ID)

}

// Test ReplicaSet - Mongod Relationship
func TestReplicaSetMongodRelationship(t *testing.T) {

	db, _ := InitializeInMemoryDB("")

	r := fixtureEmptyReplicaSet()
	m := fixtureEmptyMongod()
	r.Mongods = []*Mongod{m}

	err := db.Create(&r).Error
	assert.NoError(t, err)

	var rdb ReplicaSet

	err = db.First(&rdb).Error

	assert.NoError(t, err)
	assert.Zero(t, rdb.Mongods)

	err = db.Model(&rdb).Related(&rdb.Mongods, "Mongods").Error
	assert.NoError(t, err)
	assert.NotZero(t, rdb.Mongods)
	assert.Equal(t, len(rdb.Mongods), 1)
	assert.Equal(t, rdb.Mongods[0].ID, m.ID)

}

// Test Mongod - MongodState relationship
func TestMongodMongodStateRelationship(t *testing.T) {

	db, _ := InitializeInMemoryDB("")

	m := fixtureEmptyMongod()

	o := MongodState{
		IsShardingConfigServer: false,
		ExecutionState:         MongodExecutionStateNotRunning,
		ReplicaSetMembers:      []ReplicaSetMember{},
	}

	d := MongodState{
		IsShardingConfigServer: false,
		ExecutionState:         MongodExecutionStateRunning,
		ReplicaSetMembers:      []ReplicaSetMember{},
	}

	m.ObservedState = o
	m.DesiredState = d

	assert.NoError(t, db.Create(m).Error)

	var mdb Mongod

	// Observed
	assert.NoError(t, db.First(&mdb).Error)
	assert.Zero(t, mdb.ObservedState)

	assert.NoError(t, db.Model(&mdb).Related(&mdb.ObservedState, "ObservedState").Error)
	assert.NotZero(t, mdb.ObservedState)
	assert.Equal(t, mdb.ObservedState.ExecutionState, MongodExecutionStateNotRunning)

	assert.NoError(t, db.Model(&mdb).Related(&mdb.DesiredState, "DesiredState").Error)
	assert.NotZero(t, mdb.DesiredState)
	assert.Equal(t, mdb.DesiredState.ExecutionState, MongodExecutionStateRunning)

}

// Test MongodState - ReplicaSetMember relationship
func TestMongodStateReplicaSetMembersRelationship(t *testing.T) {
	db, _ := InitializeInMemoryDB("")

	m := ReplicaSetMember{Hostname: "h1"}

	s := MongodState{ReplicaSetMembers: []ReplicaSetMember{m}}

	assert.NoError(t, db.Create(&s).Error)

	var sdb MongodState

	assert.NoError(t, db.First(&sdb).Error)
	assert.Zero(t, sdb.ReplicaSetMembers)

	assert.NoError(t, db.Model(&sdb).Related(&sdb.ReplicaSetMembers, "ReplicaSetMembers").Error)
	assert.NotZero(t, sdb.ReplicaSetMembers)
	assert.Equal(t, len(sdb.ReplicaSetMembers), 1)
	assert.Equal(t, sdb.ReplicaSetMembers[0].Hostname, m.Hostname)

}

func TestDeleteBehavior(t *testing.T) {

	db, _ := InitializeInMemoryDB("")

	m := fixtureEmptyMongod()
	m.ID = 1000

	// Create it
	db.Create(&m)

	var mdb Mongod

	// Read it once
	d := db.First(&mdb)

	assert.NoError(t, d.Error)
	assert.Equal(t, mdb.ID, m.ID)

	// Destroy it once, by ID
	d = db.Delete(&Mongod{ID: 1000})

	assert.NoError(t, d.Error)
	assert.EqualValues(t, 1, d.RowsAffected)

	// Destroy it a second time.
	// No Error will occur, have to check RowsAffected if we deleted something
	d = db.Delete(&Mongod{ID: 1000})

	assert.NoError(t, d.Error)
	assert.EqualValues(t, 0, d.RowsAffected)

}
<commit_msg>ADD: model: test on gorm querying behavior.<commit_after>package model

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func fixtureEmptySlave() *Slave {
	return &Slave{
		Hostname:             "host1",
		Port:                 1,
		MongodPortRangeBegin: 2,
		MongodPortRangeEnd:   3,
		PersistentStorage:    true,
		Mongods:              []*Mongod{},
		ConfiguredState:      SlaveStateActive,
	}
}

func fixtureEmptyMongod() *Mongod {
	return &Mongod{
		Port:        8080,
		ReplSetName: "repl1",
	}
}

func fixtureEmptyRiskGroup() *RiskGroup {
	return &RiskGroup{
		Name:   "rg1",
		Slaves: []*Slave{},
	}
}

func fixtureEmptyReplicaSet() *ReplicaSet {
	return &ReplicaSet{
		Name: "repl1",
		PersistentMemberCount:           1,
		VolatileMemberCount:             2,
		ConfigureAsShardingConfigServer: false,
	}
}

////////////////////////////////////////////////////////////////////////////////

func TestCanInitializeDB(t *testing.T) {
	_, err := InitializeInMemoryDB("")
	assert.NoError(t, err)
}

/*
 This elaborate test demonstrates how resolving an association works in gorm.
 Check the assertions to learn about the behavior of gorm.
*/
func TestRelationshipMongodParentSlave(t *testing.T) {

	db, _ := InitializeInMemoryDB("")

	s := fixtureEmptySlave()

	db.Create(s)

	m := fixtureEmptyMongod()
	m.ParentSlave = s

	db.Create(m)

	assert.Equal(t, m.ParentSlaveID, s.ID)

	assert.Equal(t, s.Mongods, []*Mongod{})

	var sdb Slave

	// Check what happens when just SELECTing the slave
	err := db.First(&sdb).Error

	assert.NoError(t, err)
	assert.Nil(t, sdb.Mongods)

	// Now resolve the slave->mongod 1:n association
	err = db.Model(&sdb).Related(&sdb.Mongods, "Mongods").Error

	assert.NoError(t, err)
	assert.Equal(t, len(sdb.Mongods), 1)
	assert.Equal(t, sdb.Mongods[0].ReplSetName, m.ReplSetName)
	assert.Zero(t, sdb.Mongods[0].ParentSlave)
	assert.Equal(t, sdb.Mongods[0].ParentSlaveID, s.ID)

	// Now resolve the mongod->(parent)slave relation
	parentSlave := &Slave{}
	err = db.Model(&sdb.Mongods[0]).Related(parentSlave, "ParentSlave").Error
	assert.NoError(t, err)
	assert.NotZero(t, parentSlave)
	assert.Equal(t, s.ID, parentSlave.ID)

}

// Test RiskGroup Slave relationship
func TestRiskGroupSlaveRelationship(t *testing.T) {

	db, _ := InitializeInMemoryDB("")

	s := fixtureEmptySlave()
	r := fixtureEmptyRiskGroup()
	r.Slaves = []*Slave{s}

	err := db.Create(&r).Error
	assert.NoError(t, err)

	var rdb RiskGroup

	err = db.First(&rdb).Error

	assert.NoError(t, err)
	assert.Zero(t, rdb.Slaves)

	err = db.Model(&rdb).Related(&rdb.Slaves, "Slaves").Error
	assert.NoError(t, err)
	assert.NotZero(t, rdb.Slaves)
	assert.Equal(t, len(rdb.Slaves), 1)
	assert.Equal(t, rdb.Slaves[0].ID, s.ID)

}

// Test ReplicaSet - Mongod Relationship
func TestReplicaSetMongodRelationship(t *testing.T) {

	db, _ := InitializeInMemoryDB("")

	r := fixtureEmptyReplicaSet()
	m := fixtureEmptyMongod()
	r.Mongods = []*Mongod{m}

	err := db.Create(&r).Error
	assert.NoError(t, err)

	var rdb ReplicaSet

	err = db.First(&rdb).Error

	assert.NoError(t, err)
	assert.Zero(t, rdb.Mongods)

	err = db.Model(&rdb).Related(&rdb.Mongods, "Mongods").Error
	assert.NoError(t, err)
	assert.NotZero(t, rdb.Mongods)
	assert.Equal(t, len(rdb.Mongods), 1)
	assert.Equal(t, rdb.Mongods[0].ID, m.ID)

}

// Test Mongod - MongodState relationship
func TestMongodMongodStateRelationship(t *testing.T) {

	db, _ := InitializeInMemoryDB("")

	m := fixtureEmptyMongod()

	o := MongodState{
		IsShardingConfigServer: false,
		ExecutionState:         MongodExecutionStateNotRunning,
		ReplicaSetMembers:      []ReplicaSetMember{},
	}

	d := MongodState{
		IsShardingConfigServer: false,
		ExecutionState:         MongodExecutionStateRunning,
		ReplicaSetMembers:      []ReplicaSetMember{},
	}

	m.ObservedState = o
	m.DesiredState = d

	assert.NoError(t, db.Create(m).Error)

	var mdb Mongod

	// Observed
	assert.NoError(t, db.First(&mdb).Error)
	assert.Zero(t, mdb.ObservedState)

	assert.NoError(t, db.Model(&mdb).Related(&mdb.ObservedState, "ObservedState").Error)
	assert.NotZero(t, mdb.ObservedState)
	assert.Equal(t, mdb.ObservedState.ExecutionState, MongodExecutionStateNotRunning)

	assert.NoError(t, db.Model(&mdb).Related(&mdb.DesiredState, "DesiredState").Error)
	assert.NotZero(t, mdb.DesiredState)
	assert.Equal(t, mdb.DesiredState.ExecutionState, MongodExecutionStateRunning)

}

// Test MongodState - ReplicaSetMember relationship
func TestMongodStateReplicaSetMembersRelationship(t *testing.T) {
	db, _ := InitializeInMemoryDB("")

	m := ReplicaSetMember{Hostname: "h1"}

	s := MongodState{ReplicaSetMembers: []ReplicaSetMember{m}}

	assert.NoError(t, db.Create(&s).Error)

	var sdb MongodState

	assert.NoError(t, db.First(&sdb).Error)
	assert.Zero(t, sdb.ReplicaSetMembers)

	assert.NoError(t, db.Model(&sdb).Related(&sdb.ReplicaSetMembers, "ReplicaSetMembers").Error)
	assert.NotZero(t, sdb.ReplicaSetMembers)
	assert.Equal(t, len(sdb.ReplicaSetMembers), 1)
	assert.Equal(t, sdb.ReplicaSetMembers[0].Hostname, m.Hostname)

}

func TestDeleteBehavior(t *testing.T) {

	db, _ := InitializeInMemoryDB("")

	m := fixtureEmptyMongod()
	m.ID = 1000

	// Create it
	db.Create(&m)

	var mdb Mongod

	// Read it once
	d := db.First(&mdb)

	assert.NoError(t, d.Error)
	assert.Equal(t, mdb.ID, m.ID)

	// Destroy it once, by ID
	d = db.Delete(&Mongod{ID: 1000})

	assert.NoError(t, d.Error)
	assert.EqualValues(t, 1, d.RowsAffected)

	// Destroy it a second time.
	// No Error will occur, have to check RowsAffected if we deleted something
	d = db.Delete(&Mongod{ID: 1000})

	assert.NoError(t, d.Error)
	assert.EqualValues(t, 0, d.RowsAffected)

}

func TestGormFirstBehavior(t *testing.T) {
	db, _ := InitializeInMemoryDB("")
	var m Mongod
	assert.Error(t, db.First(&m).Error)
}

func TestGormFindBehavior(t *testing.T) {
	db, _ := InitializeInMemoryDB("")

	var ms []Mongod
	d := db.Find(&ms)

	assert.NoError(t, d.Error)
	assert.EqualValues(t, 0, d.RowsAffected) // RowsAffected does NOT indicate "nothing found"!!!!
	assert.Equal(t, 0, len(ms))              // Use this instead

}
<|endoftext|>


<commit_before>package model

import (
	"github.com/slyrz/newscat/html"
	"github.com/slyrz/newscat/util"
	// "fmt"
)

const (
	numChunkFeatureComp = 36
	numScoreFeatureComp = 10
)

var (
	goodQualClass = util.NewRegexFromWords(
		"article",
		"catchline",
		"content",
		"head",
		"intro",
		"introduction",
		"leadin",
		"main",
		"post",
		"story",
		"summary",
	)
	poorQualClass = util.NewRegexFromWords(
		"author",
		"blog",
		"byline",
		"caption",
		"col",
		"comment",
		"description",
		"email",
		"excerpt",
		"image",
		"info",
		"menu",
		"metadata",
		"nav",
		"photo",
		"small",
		"teaser",
		"widget",
	)
)

// Feature represents a feature vector.
type Feature []float32

type ChunkFeature [numChunkFeatureComp]float32
type ScoreFeature [numScoreFeatureComp]float32

// FeatureWriter writes values to a Feature array.
type FeatureWriter struct {
	Feature Feature
	Pos     int
}

func (fw *FeatureWriter) Assign(f Feature) {
	fw.Feature = f
	fw.Pos = 0
}

// Write a value of type int, float32 or bool at given offset and skip the
// requested amount of components afterwards.
func (fw *FeatureWriter) write(val interface{}, off int, skip int) {
	comp := &fw.Feature[fw.Pos+off]
	switch val := val.(type) {
	case int:
		*comp = float32(val)
	case float32:
		*comp = val
	case bool:
		if val {
			*comp = 1.0
		} else {
			*comp = 0.0
		}
	}
	if skip > 0 {
		fw.Skip(skip)
	}
}

// Write value at current position and move to the next.
func (fw *FeatureWriter) Write(val interface{}) {
	fw.write(val, 0, 1)
}

// Write value at offset, but don't move.
func (fw *FeatureWriter) WriteAt(val interface{}, off int) {
	fw.write(val, off, 0)
}

// Skip components.
func (fw *FeatureWriter) Skip(n int) {
	fw.Pos += n
}

type ChunkFeatureWriter struct {
	FeatureWriter
}

// Entries with a "plus comment" indicate that the next N elements share
// the same offset intentionally.
var elementTypes = map[string]int{
	"p":   0,
	"a":   1,
	"div": 2,
	"h1":  3, // +5
	"h2":  3,
	"h3":  3,
	"h4":  3,
	"h5":  3,
	"h6":  3,
}

func (fw *ChunkFeatureWriter) WriteElementType(chunk *html.Chunk) {
	// One hot encoding of the element type.
	fw.WriteAt(true, elementTypes[chunk.Base.Data])
	fw.Skip(4)
}

var parentTypes = map[string]int{
	"p":    0,
	"span": 1,
	"div":  2,
	"li":   3,
}

func (fw *ChunkFeatureWriter) WriteParentType(chunk *html.Chunk) {
	// One hot encoding of the chunk's parent's element type.
	if chunk.Base.Parent != nil {
		fw.WriteAt(true, parentTypes[chunk.Base.Parent.Data])
	}
	fw.Skip(4)
}

func (fw *ChunkFeatureWriter) WriteSiblingTypes(chunk *html.Chunk) {
	count := 0
	types := map[string]int{"a": 0, "p": 0, "img": 0}
	for _, siblingType := range chunk.GetSiblingTypes() {
		count += 1
		if val, ok := types[siblingType]; ok {
			types[siblingType] = val + 1
		}
	}
	fw.Write(count)
	fw.Write(types["a"])
	fw.Write(types["p"])
	fw.Write(types["img"])
	if count > 0 {
		fw.Write(float32(types["a"]) / float32(count))
		fw.Write(float32(types["p"]) / float32(count))
		fw.Write(float32(types["img"]) / float32(count))
	} else {
		fw.Skip(3)
	}
}

func (fw *ChunkFeatureWriter) WriteAncestors(chunk *html.Chunk) {
	fw.Write((chunk.Ancestors & html.AncestorArticle) != 0)
	fw.Write((chunk.Ancestors & html.AncestorAside) != 0)
	fw.Write((chunk.Ancestors & html.AncestorBlockquote) != 0)
	fw.Write((chunk.Ancestors & html.AncestorList) != 0)
}

func (fw *ChunkFeatureWriter) WriteTextStat(chunk *html.Chunk) {
	fw.Write(chunk.Text.Words)
	fw.Write(chunk.Text.Sentences)
	fw.Write(chunk.LinkText)
}

func (fw *ChunkFeatureWriter) WriteTextStatSiblings(chunk *html.Chunk) {
	if chunk.Prev != nil {
		fw.Write(chunk.Prev.Block == chunk.Block)
		fw.Write(chunk.Prev.Text.Words)
		fw.Write(chunk.Prev.Text.Sentences)
	} else {
		fw.Skip(3)
	}
	if chunk.Next != nil {
		fw.Write(chunk.Next.Block == chunk.Block)
		fw.Write(chunk.Next.Text.Words)
		fw.Write(chunk.Next.Text.Sentences)
	} else {
		fw.Skip(3)
	}
}

func (fw *ChunkFeatureWriter) WriteClassStat(chunk *html.Chunk, classes map[string]*html.TextStat) {
	var best *html.TextStat = nil
	for _, class := range chunk.Classes {
		if stat, ok := classes[class]; ok {
			if best == nil || (stat.Words/stat.Count) > (best.Words/best.Count) {
				best = stat
			}
		}
	}
	if best != nil {
		fw.Write(true)
		fw.Write(float32(best.Words) / float32(best.Count))
		fw.Write(float32(best.Sentences) / float32(best.Count))
	} else {
		fw.Write(false)
		fw.Skip(2)
	}
}

func (fw *ChunkFeatureWriter) WriteClusterStat(chunk *html.Chunk, clusters map[*html.Chunk]*html.TextStat) {
	if stat, ok := clusters[chunk]; ok {
		fw.Write(stat.Words)
		fw.Write(stat.Sentences)
		fw.Write(stat.Count)
		fw.Write(float32(stat.Words) / float32(stat.Count))
		fw.Write(float32(stat.Sentences) / float32(stat.Count))
	} else {
		fw.Skip(5)
	}
}

type ScoreFeatureWriter struct {
	FeatureWriter
}

func (fw *ScoreFeatureWriter) WriteChunk(chunk *html.Chunk) {
	goodQual := false
	poorQual := false
	for _, class := range chunk.Classes {
		goodQual = goodQual || goodQualClass.In(class)
		poorQual = poorQual || poorQualClass.In(class)
	}
	fw.Write(chunk.LinkText)
	fw.Write(chunk.Text.Words)
	fw.Write(chunk.Text.Sentences)
	fw.Write(goodQual)
	fw.Write(poorQual)
}

func (fw *ScoreFeatureWriter) WriteCluster(chunk *html.Chunk, cluster *Cluster) {
	i := 0
	for ; i < len(cluster.Chunks); i++ {
		if cluster.Chunks[i] == chunk {
			break
		}
	}
	fw.Write(cluster.Score())
	fw.Write(cluster.Scores[i])
	if i > 0 {
		fw.Write(cluster.Scores[i-1])
	} else {
		fw.Write(-10)
	}
	if i < len(cluster.Chunks)-2 {
		fw.Write(cluster.Scores[i+1])
	} else {
		fw.Write(-10)
	}
}

func (fw *ScoreFeatureWriter) WriteTitleSimilarity(chunk *html.Chunk, title *util.Text) {
	switch chunk.Base.Data {
	case "h1", "h2", "h3":
		fw.Write(chunk.Text.Similarity(title))
	default:
		fw.Skip(1)
	}
}
<commit_msg>removed uncommented import and rearranged code<commit_after>package model

import (
	"github.com/slyrz/newscat/html"
	"github.com/slyrz/newscat/util"
)

const (
	numChunkFeatureComp = 36
	numScoreFeatureComp = 10
)

// Feature represents a feature vector.
type Feature []float32

type ChunkFeature [numChunkFeatureComp]float32
type ScoreFeature [numScoreFeatureComp]float32

// FeatureWriter writes observations to feature vectors.
type FeatureWriter struct {
	Feature Feature
	Pos     int
}

func (fw *FeatureWriter) Assign(f Feature) {
	fw.Feature = f
	fw.Pos = 0
}

// Write a value of type int, float32 or bool at given offset and skip the
// requested amount of components afterwards.
func (fw *FeatureWriter) write(val interface{}, off int, skip int) {
	comp := &fw.Feature[fw.Pos+off]
	switch val := val.(type) {
	case int:
		*comp = float32(val)
	case float32:
		*comp = val
	case bool:
		if val {
			*comp = 1.0
		} else {
			*comp = 0.0
		}
	}
	if skip > 0 {
		fw.Skip(skip)
	}
}

// Write value at current position and move to the next.
func (fw *FeatureWriter) Write(val interface{}) {
	fw.write(val, 0, 1)
}

// Write value at offset, but don't move.
func (fw *FeatureWriter) WriteAt(val interface{}, off int) {
	fw.write(val, off, 0)
}

// Skip components.
func (fw *FeatureWriter) Skip(n int) {
	fw.Pos += n
}

type ChunkFeatureWriter struct {
	FeatureWriter
}

// Entries with a "plus comment" indicate that the next N elements share
// the same offset intentionally.
var elementTypes = map[string]int{
	"p":   0,
	"a":   1,
	"div": 2,
	"h1":  3, // +5
	"h2":  3,
	"h3":  3,
	"h4":  3,
	"h5":  3,
	"h6":  3,
}

func (fw *ChunkFeatureWriter) WriteElementType(chunk *html.Chunk) {
	// One hot encoding of the element type.
	fw.WriteAt(true, elementTypes[chunk.Base.Data])
	fw.Skip(4)
}

var parentTypes = map[string]int{
	"p":    0,
	"span": 1,
	"div":  2,
	"li":   3,
}

func (fw *ChunkFeatureWriter) WriteParentType(chunk *html.Chunk) {
	// One hot encoding of the chunk's parent's element type.
	if chunk.Base.Parent != nil {
		fw.WriteAt(true, parentTypes[chunk.Base.Parent.Data])
	}
	fw.Skip(4)
}

func (fw *ChunkFeatureWriter) WriteSiblingTypes(chunk *html.Chunk) {
	count := 0
	types := map[string]int{"a": 0, "p": 0, "img": 0}
	for _, siblingType := range chunk.GetSiblingTypes() {
		count += 1
		if val, ok := types[siblingType]; ok {
			types[siblingType] = val + 1
		}
	}
	fw.Write(count)
	fw.Write(types["a"])
	fw.Write(types["p"])
	fw.Write(types["img"])
	if count > 0 {
		fw.Write(float32(types["a"]) / float32(count))
		fw.Write(float32(types["p"]) / float32(count))
		fw.Write(float32(types["img"]) / float32(count))
	} else {
		fw.Skip(3)
	}
}

func (fw *ChunkFeatureWriter) WriteAncestors(chunk *html.Chunk) {
	fw.Write((chunk.Ancestors & html.AncestorArticle) != 0)
	fw.Write((chunk.Ancestors & html.AncestorAside) != 0)
	fw.Write((chunk.Ancestors & html.AncestorBlockquote) != 0)
	fw.Write((chunk.Ancestors & html.AncestorList) != 0)
}

func (fw *ChunkFeatureWriter) WriteTextStat(chunk *html.Chunk) {
	fw.Write(chunk.Text.Words)
	fw.Write(chunk.Text.Sentences)
	fw.Write(chunk.LinkText)
}

func (fw *ChunkFeatureWriter) WriteTextStatSiblings(chunk *html.Chunk) {
	if chunk.Prev != nil {
		fw.Write(chunk.Prev.Block == chunk.Block)
		fw.Write(chunk.Prev.Text.Words)
		fw.Write(chunk.Prev.Text.Sentences)
	} else {
		fw.Skip(3)
	}
	if chunk.Next != nil {
		fw.Write(chunk.Next.Block == chunk.Block)
		fw.Write(chunk.Next.Text.Words)
		fw.Write(chunk.Next.Text.Sentences)
	} else {
		fw.Skip(3)
	}
}

func (fw *ChunkFeatureWriter) WriteClassStat(chunk *html.Chunk, classes map[string]*html.TextStat) {
	var best *html.TextStat = nil
	for _, class := range chunk.Classes {
		if stat, ok := classes[class]; ok {
			if best == nil || (stat.Words/stat.Count) > (best.Words/best.Count) {
				best = stat
			}
		}
	}
	if best != nil {
		fw.Write(true)
		fw.Write(float32(best.Words) / float32(best.Count))
		fw.Write(float32(best.Sentences) / float32(best.Count))
	} else {
		fw.Write(false)
		fw.Skip(2)
	}
}

func (fw *ChunkFeatureWriter) WriteClusterStat(chunk *html.Chunk, clusters map[*html.Chunk]*html.TextStat) {
	if stat, ok := clusters[chunk]; ok {
		fw.Write(stat.Words)
		fw.Write(stat.Sentences)
		fw.Write(stat.Count)
		fw.Write(float32(stat.Words) / float32(stat.Count))
		fw.Write(float32(stat.Sentences) / float32(stat.Count))
	} else {
		fw.Skip(5)
	}
}

type ScoreFeatureWriter struct {
	FeatureWriter
}

var (
	goodQualClass = util.NewRegexFromWords(
		"article",
		"catchline",
		"content",
		"head",
		"intro",
		"introduction",
		"leadin",
		"main",
		"post",
		"story",
		"summary",
	)
	poorQualClass = util.NewRegexFromWords(
		"author",
		"blog",
		"byline",
		"caption",
		"col",
		"comment",
		"description",
		"email",
		"excerpt",
		"image",
		"info",
		"menu",
		"metadata",
		"nav",
		"photo",
		"small",
		"teaser",
		"widget",
	)
)

func (fw *ScoreFeatureWriter) WriteChunk(chunk *html.Chunk) {
	goodQual := false
	poorQual := false
	for _, class := range chunk.Classes {
		goodQual = goodQual || goodQualClass.In(class)
		poorQual = poorQual || poorQualClass.In(class)
	}
	fw.Write(chunk.LinkText)
	fw.Write(chunk.Text.Words)
	fw.Write(chunk.Text.Sentences)
	fw.Write(goodQual)
	fw.Write(poorQual)
}

func (fw *ScoreFeatureWriter) WriteCluster(chunk *html.Chunk, cluster *Cluster) {
	i := 0
	for ; i < len(cluster.Chunks); i++ {
		if cluster.Chunks[i] == chunk {
			break
		}
	}
	fw.Write(cluster.Score())
	fw.Write(cluster.Scores[i])
	if i > 0 {
		fw.Write(cluster.Scores[i-1])
	} else {
		fw.Write(-10)
	}
	if i < len(cluster.Chunks)-2 {
		fw.Write(cluster.Scores[i+1])
	} else {
		fw.Write(-10)
	}
}

func (fw *ScoreFeatureWriter) WriteTitleSimilarity(chunk *html.Chunk, title *util.Text) {
	switch chunk.Base.Data {
	case "h1", "h2", "h3":
		fw.Write(chunk.Text.Similarity(title))
	default:
		fw.Skip(1)
	}
}
<|endoftext|>


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

package vmware

import (
	"os/exec"
)

var vmrun string

func init() {
	var err error

	vmrun, err = exec.LookPath("vmrun")
	if err != nil {
		vmrun = VMRunPath // fallback the vmrun binary path
	}
}

// VMRun return the vmrun execute binary command with the app name.
//
// Usage: vmrun [AUTHENTICATION-FLAGS] COMMAND [PARAMETERS]
//
// AUTHENTICATION-FLAGS
// --------------------
// These must appear before the command and any command parameters.
//
//    -h <hostName>  (not needed for Fusion)
//    -P <hostPort>  (not needed for Fusion)
//    -T <hostType> (ws|fusion)
//    -u <userName in host OS>  (not needed for Fusion)
//    -p <password in host OS>  (not needed for Fusion)
//    -vp <password for encrypted virtual machine>
//    -gu <userName in guest OS>
//    -gp <password in guest OS>
func VMRun(app string, arg ...string) *exec.Cmd {
	cmd := exec.Command(vmrun, "-T", app)
	cmd.Args = append(cmd.Args, arg...)

	return cmd
}
<commit_msg>vmrun: change implements to run the cmd instead of return *exec.Cmd<commit_after>// Copyright 2017 The go-vm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vmware

import (
	"bytes"
	"fmt"
	"os/exec"
)

var vmrun string

func init() {
	var err error

	vmrun, err = exec.LookPath("vmrun")
	if err != nil {
		vmrun = VMRunPath // fallback the vmrun binary path
	}
}

// VMRun return the vmrun execute binary command with the app name.
//
// Usage: vmrun [AUTHENTICATION-FLAGS] COMMAND [PARAMETERS]
//
// AUTHENTICATION-FLAGS
// --------------------
// These must appear before the command and any command parameters.
//
//    -h <hostName>  (not needed for Fusion)
//    -P <hostPort>  (not needed for Fusion)
//    -T <hostType> (ws|fusion)
//    -u <userName in host OS>  (not needed for Fusion)
//    -p <password in host OS>  (not needed for Fusion)
//    -vp <password for encrypted virtual machine>
//    -gu <userName in guest OS>
//    -gp <password in guest OS>
func VMRun(app string, arg ...string) error {
	cmd := exec.Command(vmrun, "-T", app)
	cmd.Args = append(cmd.Args, arg...)

	var stdout bytes.Buffer
	cmd.Stdout = &stdout
	if runErr := cmd.Run(); runErr != nil {
		if err := runErr.(*exec.ExitError); err != nil {
			return fmt.Errorf(stdout.String())
		}
		return runErr
	}

	return nil
}
<|endoftext|>


<commit_before>/*
   Copyright 2012 John Asmuth

   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 wde

type Event int

type MouseEvent struct {
	Event
	X, Y int
}

type MouseMovedEvent struct {
	MouseEvent
	FromX, FromY int
}

type MouseButtonEvent struct {
	MouseEvent
	Button int
}

type MouseDownEvent MouseButtonEvent
type MouseUpEvent MouseButtonEvent
type MouseDraggedEvent MouseButtonEvent

type MouseEnteredEvent MouseMovedEvent
type MouseExitedEvent MouseMovedEvent

type KeyEvent struct {
	Code int
	Letter string
}

type KeyDownEvent KeyEvent
type KeyUpEvent KeyEvent
type KeyPressEvent KeyEvent
type KeyTypedEvent KeyEvent

type ResizeEvent struct {
	Width, Height int
}

type CloseEvent struct {}
<commit_msg>better event stuff<commit_after>/*
   Copyright 2012 John Asmuth

   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 wde

type Button int

const (
	LeftButton Button = 1<<iota
	MiddleButton
	RightButton
)

type Event int

type MouseEvent struct {
	Event
	X, Y int
}

type MouseMovedEvent struct {
	MouseEvent
	FromX, FromY int
}

type MouseButtonEvent struct {
	MouseEvent
	Which Button
}

type MouseDownEvent MouseButtonEvent
type MouseUpEvent MouseButtonEvent

type MouseDraggedEvent struct {
	MouseMovedEvent
	Which Button
}

type MouseEnteredEvent MouseMovedEvent
type MouseExitedEvent MouseMovedEvent

type KeyEvent struct {
	Code int
	Letter string
}

type KeyDownEvent KeyEvent
type KeyUpEvent KeyEvent
type KeyTypedEvent KeyEvent

type ResizeEvent struct {
	Width, Height int
}

type CloseEvent struct {}
<|endoftext|>


<commit_before>package context

import (
	"fmt"
	"github.com/francoishill/goangi2/utils/httpUtils"
	"github.com/francoishill/goangi2/utils/imageUtils"
	. "github.com/francoishill/goangi2/utils/loggingUtils"
	. "github.com/francoishill/goangi2/utils/osUtils"
	"io/ioutil"
	"mime/multipart"
	"os"
	"path/filepath"
	"strings"
)

var DefaultBaseAppContext *BaseAppContext

type BaseAppContext struct {
	Logger                  ILogger
	baseAppUrl_WithSlash    string
	baseAppUrl_NoSlash      string
	MaxUploadSizeMegaBytes  int64
	MaxProfilePicWidth      uint
	UploadDirectory         string
	ProfilePicsDirectory    string
	UploadedImagesDirectory string
}

func (this *BaseAppContext) checkError(err error) {
	if err != nil {
		panic(err)
	}
}

func CreateBaseAppContext(logger ILogger, baseAppUrl string, maxUploadSizeMegaBytes int64, maxProfilePicWidth uint, uploadDir, profilePicsDir, uploadedImagesDir string) *BaseAppContext {
	baseAppUrlNoSlash := strings.TrimRight(baseAppUrl, "/")

	if !DirectoryExists(uploadDir) {
		panic("Uploads directory does not exist: " + uploadDir)
	}

	if !DirectoryExists(profilePicsDir) {
		panic("Profile pics directory does not exist: " + profilePicsDir)
	}

	if !DirectoryExists(uploadedImagesDir) {
		panic("Upload images directory does not exist: " + uploadedImagesDir)
	}

	return &BaseAppContext{
		Logger:                  logger,
		baseAppUrl_WithSlash:    baseAppUrlNoSlash + "/",
		baseAppUrl_NoSlash:      baseAppUrlNoSlash,
		MaxUploadSizeMegaBytes:  maxUploadSizeMegaBytes,
		MaxProfilePicWidth:      maxProfilePicWidth,
		UploadDirectory:         uploadDir,
		ProfilePicsDirectory:    profilePicsDir,
		UploadedImagesDirectory: uploadedImagesDir,
	}
}

func (this *BaseAppContext) GenerateAppRelativeUrl(partAfterBaseUrl string) string {
	if partAfterBaseUrl == "" {
		return this.baseAppUrl_NoSlash
	}

	if partAfterBaseUrl[0] == '/' {
		return this.baseAppUrl_NoSlash + partAfterBaseUrl
	} else {
		return this.baseAppUrl_WithSlash + partAfterBaseUrl
	}
}

func (this *BaseAppContext) getTempImageFileFullPath(fileNameOnly string) string {
	return filepath.Join(this.UploadDirectory, fileNameOnly)
}

func (this *BaseAppContext) getProfilePicFileFullPath(userId int64) string {
	return filepath.Join(this.ProfilePicsDirectory, fmt.Sprintf("%d", userId))
}

func (this *BaseAppContext) getUploadedImagePermanentFullPath(imageFileName string) string {
	return filepath.Join(this.UploadedImagesDirectory, fmt.Sprintf("%s", imageFileName))
}

func (this *BaseAppContext) ReadTempImageFileBytes(fileNameOnly string) []byte {
	fullTempFilePath := this.getTempImageFileFullPath(fileNameOnly)
	fileBytes, err := ioutil.ReadFile(fullTempFilePath)
	this.checkError(err)
	return fileBytes
}

func (this *BaseAppContext) ReadPermanentImageFileBytes(fileNameOnly string) []byte {
	fullTempFilePath := this.getUploadedImagePermanentFullPath(fileNameOnly)
	fileBytes, err := ioutil.ReadFile(fullTempFilePath)
	this.checkError(err)
	return fileBytes
}

func (this *BaseAppContext) DeleteTempImageFile(fileNameOnly string) {
	fullTempFilePath := this.getTempImageFileFullPath(fileNameOnly)
	err := os.Remove(fullTempFilePath)
	this.checkError(err)
}

func (this *BaseAppContext) UploadAndResizeImageToTempUploadDir(file multipart.File, originalFilenamePrefix, resizedFilenamePrefix string, maxImageWidth uint) string {
	originalTempFile, err := httpUtils.AcceptUploadedFileAndSaveToFolder(originalFilenamePrefix, this.UploadDirectory, file)
	this.checkError(err)

	resizedTempFilePathObj, err := ioutil.TempFile(filepath.Dir(originalTempFile), resizedFilenamePrefix)
	this.checkError(err)
	resizedTempFilePathObj.Close()

	resizedTempFilePath, err := filepath.Abs(resizedTempFilePathObj.Name())
	this.checkError(err)

	func() {
		defer func() {
			if r := recover(); r != nil {
				//If something goes wrong inside Resize, we must delete the 0-byte created temp file `resizedTempFilePath`
				os.Remove(resizedTempFilePath)
				panic(r)
			}
		}()
		alwaysRemoveSourceFile := true
		imageUtils.ResizeImageFile(originalTempFile, resizedTempFilePath, this.MaxUploadSizeMegaBytes, maxImageWidth, alwaysRemoveSourceFile)
	}()

	return resizedTempFilePath
}

func (this *BaseAppContext) UploadResizedProfilePic(file multipart.File) string {
	origImageFilenamePrefix := "temp-profilepic-origsize-"
	resizedImageFilenamePrefix := "temp-profilepic-resized-"
	return this.UploadAndResizeImageToTempUploadDir(file, origImageFilenamePrefix, resizedImageFilenamePrefix, this.MaxProfilePicWidth)
}

func (this *BaseAppContext) MoveTempProfilePicToPermanentFolder(profilePicFileNameOnly string, userId int64) {
	origTempFullFilePath := this.getTempImageFileFullPath(profilePicFileNameOnly)
	newPermanentFullFilePath := this.getProfilePicFileFullPath(userId)

	err := os.Rename(origTempFullFilePath, newPermanentFullFilePath)
	this.checkError(err)
}

func (this *BaseAppContext) MoveTempImageFileToPermanentFolder(tempFileNameOnly, finalImageName string) {
	origTempFullFilePath := this.getTempImageFileFullPath(tempFileNameOnly)
	newPermanentFullFilePath := this.getUploadedImagePermanentFullPath(finalImageName)

	err := os.Rename(origTempFullFilePath, newPermanentFullFilePath)
	this.checkError(err)
}
<commit_msg>Added method `ReadProfilePicFileBytes`.<commit_after>package context

import (
	"fmt"
	"github.com/francoishill/goangi2/utils/httpUtils"
	"github.com/francoishill/goangi2/utils/imageUtils"
	. "github.com/francoishill/goangi2/utils/loggingUtils"
	. "github.com/francoishill/goangi2/utils/osUtils"
	"io/ioutil"
	"mime/multipart"
	"os"
	"path/filepath"
	"strings"
)

var DefaultBaseAppContext *BaseAppContext

type BaseAppContext struct {
	Logger                  ILogger
	baseAppUrl_WithSlash    string
	baseAppUrl_NoSlash      string
	MaxUploadSizeMegaBytes  int64
	MaxProfilePicWidth      uint
	UploadDirectory         string
	ProfilePicsDirectory    string
	UploadedImagesDirectory string
}

func (this *BaseAppContext) checkError(err error) {
	if err != nil {
		panic(err)
	}
}

func CreateBaseAppContext(logger ILogger, baseAppUrl string, maxUploadSizeMegaBytes int64, maxProfilePicWidth uint, uploadDir, profilePicsDir, uploadedImagesDir string) *BaseAppContext {
	baseAppUrlNoSlash := strings.TrimRight(baseAppUrl, "/")

	if !DirectoryExists(uploadDir) {
		panic("Uploads directory does not exist: " + uploadDir)
	}

	if !DirectoryExists(profilePicsDir) {
		panic("Profile pics directory does not exist: " + profilePicsDir)
	}

	if !DirectoryExists(uploadedImagesDir) {
		panic("Upload images directory does not exist: " + uploadedImagesDir)
	}

	return &BaseAppContext{
		Logger:                  logger,
		baseAppUrl_WithSlash:    baseAppUrlNoSlash + "/",
		baseAppUrl_NoSlash:      baseAppUrlNoSlash,
		MaxUploadSizeMegaBytes:  maxUploadSizeMegaBytes,
		MaxProfilePicWidth:      maxProfilePicWidth,
		UploadDirectory:         uploadDir,
		ProfilePicsDirectory:    profilePicsDir,
		UploadedImagesDirectory: uploadedImagesDir,
	}
}

func (this *BaseAppContext) GenerateAppRelativeUrl(partAfterBaseUrl string) string {
	if partAfterBaseUrl == "" {
		return this.baseAppUrl_NoSlash
	}

	if partAfterBaseUrl[0] == '/' {
		return this.baseAppUrl_NoSlash + partAfterBaseUrl
	} else {
		return this.baseAppUrl_WithSlash + partAfterBaseUrl
	}
}

func (this *BaseAppContext) getTempImageFileFullPath(fileNameOnly string) string {
	return filepath.Join(this.UploadDirectory, fileNameOnly)
}

func (this *BaseAppContext) getProfilePicFileFullPath(userId int64) string {
	return filepath.Join(this.ProfilePicsDirectory, fmt.Sprintf("%d", userId))
}

func (this *BaseAppContext) getUploadedImagePermanentFullPath(imageFileName string) string {
	return filepath.Join(this.UploadedImagesDirectory, fmt.Sprintf("%s", imageFileName))
}

func (this *BaseAppContext) ReadTempImageFileBytes(fileNameOnly string) []byte {
	fullTempFilePath := this.getTempImageFileFullPath(fileNameOnly)
	fileBytes, err := ioutil.ReadFile(fullTempFilePath)
	this.checkError(err)
	return fileBytes
}

func (this *BaseAppContext) ReadPermanentImageFileBytes(fileNameOnly string) []byte {
	fullTempFilePath := this.getUploadedImagePermanentFullPath(fileNameOnly)
	fileBytes, err := ioutil.ReadFile(fullTempFilePath)
	this.checkError(err)
	return fileBytes
}

func (this *BaseAppContext) ReadProfilePicFileBytes(userId int64) []byte {
	fullFilePath := this.getProfilePicFileFullPath(userId)
	fileBytes, err := ioutil.ReadFile(fullFilePath)
	this.checkError(err)
	return fileBytes
}

func (this *BaseAppContext) DeleteTempImageFile(fileNameOnly string) {
	fullTempFilePath := this.getTempImageFileFullPath(fileNameOnly)
	err := os.Remove(fullTempFilePath)
	this.checkError(err)
}

func (this *BaseAppContext) UploadAndResizeImageToTempUploadDir(file multipart.File, originalFilenamePrefix, resizedFilenamePrefix string, maxImageWidth uint) string {
	originalTempFile, err := httpUtils.AcceptUploadedFileAndSaveToFolder(originalFilenamePrefix, this.UploadDirectory, file)
	this.checkError(err)

	resizedTempFilePathObj, err := ioutil.TempFile(filepath.Dir(originalTempFile), resizedFilenamePrefix)
	this.checkError(err)
	resizedTempFilePathObj.Close()

	resizedTempFilePath, err := filepath.Abs(resizedTempFilePathObj.Name())
	this.checkError(err)

	func() {
		defer func() {
			if r := recover(); r != nil {
				//If something goes wrong inside Resize, we must delete the 0-byte created temp file `resizedTempFilePath`
				os.Remove(resizedTempFilePath)
				panic(r)
			}
		}()
		alwaysRemoveSourceFile := true
		imageUtils.ResizeImageFile(originalTempFile, resizedTempFilePath, this.MaxUploadSizeMegaBytes, maxImageWidth, alwaysRemoveSourceFile)
	}()

	return resizedTempFilePath
}

func (this *BaseAppContext) UploadResizedProfilePic(file multipart.File) string {
	origImageFilenamePrefix := "temp-profilepic-origsize-"
	resizedImageFilenamePrefix := "temp-profilepic-resized-"
	return this.UploadAndResizeImageToTempUploadDir(file, origImageFilenamePrefix, resizedImageFilenamePrefix, this.MaxProfilePicWidth)
}

func (this *BaseAppContext) MoveTempProfilePicToPermanentFolder(profilePicFileNameOnly string, userId int64) {
	origTempFullFilePath := this.getTempImageFileFullPath(profilePicFileNameOnly)
	newPermanentFullFilePath := this.getProfilePicFileFullPath(userId)

	err := os.Rename(origTempFullFilePath, newPermanentFullFilePath)
	this.checkError(err)
}

func (this *BaseAppContext) MoveTempImageFileToPermanentFolder(tempFileNameOnly, finalImageName string) {
	origTempFullFilePath := this.getTempImageFileFullPath(tempFileNameOnly)
	newPermanentFullFilePath := this.getUploadedImagePermanentFullPath(finalImageName)

	err := os.Rename(origTempFullFilePath, newPermanentFullFilePath)
	this.checkError(err)
}
<|endoftext|>


<commit_before>/*                          _       _
 *__      _____  __ ___   ___  __ _| |_ ___
 *\ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
 * \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
 *  \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
 *
 * Copyright © 2016 - 2019 Weaviate. All rights reserved.
 * LICENSE: https://github.com/creativesoftwarefdn/weaviate/blob/develop/LICENSE.md
 * DESIGN & CONCEPT: Bob van Luijt (@bobvanluijt)
 * CONTACT: hello@creativesoftwarefdn.org
 */
package contextionary

// //// #include <string.h>
// //import "C"

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"os"
	"syscall"
)

type Wordlist struct {
	vectorWidth   uint64
	numberOfWords uint64
	metadata      map[string]interface{}

	file         os.File
	startOfTable int
	mmap         []byte
}

func LoadWordlist(path string) (*Wordlist, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, fmt.Errorf("Can't open the wordlist at %s: %+v", path, err)
	}

	file_info, err := file.Stat()
	if err != nil {
		return nil, fmt.Errorf("Can't stat the wordlist at %s: %+v", path, err)
	}

	mmap, err := syscall.Mmap(int(file.Fd()), 0, int(file_info.Size()), syscall.PROT_READ, syscall.MAP_SHARED)
	if err != nil {
		return nil, fmt.Errorf("Can't mmap the file %s: %+v", path, err)
	}

	nrWordsBytes := mmap[0:8]
	vectorWidthBytes := mmap[8:16]
	metadataLengthBytes := mmap[16:24]

	nrWords := binary.LittleEndian.Uint64(nrWordsBytes)
	vectorWidth := binary.LittleEndian.Uint64(vectorWidthBytes)
	metadataLength := binary.LittleEndian.Uint64(metadataLengthBytes)

	metadataBytes := mmap[24 : 24+metadataLength]
	var metadata map[string]interface{}

	json.Unmarshal(metadataBytes, &metadata)

	// Compute beginning of word list lookup table.
	var start_of_table int = 24 + int(metadataLength)
	var offset int = 4 - (start_of_table % 4)
	start_of_table += offset

	return &Wordlist{
		vectorWidth:   vectorWidth,
		numberOfWords: nrWords,
		metadata:      metadata,
		startOfTable:  start_of_table,
		mmap:          mmap,
	}, nil
}

func (w *Wordlist) GetNumberOfWords() ItemIndex {
	return ItemIndex(w.numberOfWords)
}

func (w *Wordlist) FindIndexByWord(_needle string) ItemIndex {
	var needle = string([]byte(_needle))
	needle += "\x00"

	var bytes_needle = []byte(needle)

	var low ItemIndex = 0
	var high ItemIndex = ItemIndex(w.numberOfWords)

	for low <= high {
		var midpoint ItemIndex = (low + high) / 2

		// ignore the first 8 bytes as they are reserved for occurrence
		word_ptr := w.getWordPtr(midpoint)[8 : 8+len(bytes_needle)]

		var cmp = bytes.Compare(bytes_needle, word_ptr)

		if cmp == 0 {
			return midpoint
		} else if cmp < 0 {
			high = midpoint - 1
		} else {
			low = midpoint + 1
		}
	}

	return -1
}

func (w *Wordlist) getWordPtr(index ItemIndex) []byte {
	entry_addr := ItemIndex(w.startOfTable) + index*8
	word_address_bytes := w.mmap[entry_addr : entry_addr+8]
	word_address := binary.LittleEndian.Uint64(word_address_bytes)
	return w.mmap[word_address:]
}

func (w *Wordlist) getWord(index ItemIndex) (string, uint64) {
	ptr := w.getWordPtr(index)
	occurrence := binary.LittleEndian.Uint64(ptr[0:8])
	for i := 8; i < len(ptr); i++ {
		if ptr[i] == '\x00' {
			return string(ptr[8:i]), occurrence
		}
	}

	return "", 0
}
<commit_msg>gh-849: prevent OOB error if search term is longer than last word in idx<commit_after>/*                          _       _
 *__      _____  __ ___   ___  __ _| |_ ___
 *\ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
 * \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
 *  \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
 *
 * Copyright © 2016 - 2019 Weaviate. All rights reserved.
 * LICENSE: https://github.com/creativesoftwarefdn/weaviate/blob/develop/LICENSE.md
 * DESIGN & CONCEPT: Bob van Luijt (@bobvanluijt)
 * CONTACT: hello@creativesoftwarefdn.org
 */
package contextionary

// //// #include <string.h>
// //import "C"

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"os"
	"syscall"
)

type Wordlist struct {
	vectorWidth   uint64
	numberOfWords uint64
	metadata      map[string]interface{}

	file         os.File
	startOfTable int
	mmap         []byte
}

func LoadWordlist(path string) (*Wordlist, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, fmt.Errorf("Can't open the wordlist at %s: %+v", path, err)
	}

	file_info, err := file.Stat()
	if err != nil {
		return nil, fmt.Errorf("Can't stat the wordlist at %s: %+v", path, err)
	}

	mmap, err := syscall.Mmap(int(file.Fd()), 0, int(file_info.Size()), syscall.PROT_READ, syscall.MAP_SHARED)
	if err != nil {
		return nil, fmt.Errorf("Can't mmap the file %s: %+v", path, err)
	}

	nrWordsBytes := mmap[0:8]
	vectorWidthBytes := mmap[8:16]
	metadataLengthBytes := mmap[16:24]

	nrWords := binary.LittleEndian.Uint64(nrWordsBytes)
	vectorWidth := binary.LittleEndian.Uint64(vectorWidthBytes)
	metadataLength := binary.LittleEndian.Uint64(metadataLengthBytes)

	metadataBytes := mmap[24 : 24+metadataLength]
	var metadata map[string]interface{}

	json.Unmarshal(metadataBytes, &metadata)

	// Compute beginning of word list lookup table.
	var start_of_table int = 24 + int(metadataLength)
	var offset int = 4 - (start_of_table % 4)
	start_of_table += offset

	return &Wordlist{
		vectorWidth:   vectorWidth,
		numberOfWords: nrWords,
		metadata:      metadata,
		startOfTable:  start_of_table,
		mmap:          mmap,
	}, nil
}

func (w *Wordlist) GetNumberOfWords() ItemIndex {
	return ItemIndex(w.numberOfWords)
}

func (w *Wordlist) FindIndexByWord(_needle string) ItemIndex {
	var needle = string([]byte(_needle))
	needle += "\x00"

	var bytes_needle = []byte(needle)

	var low ItemIndex = 0
	var high ItemIndex = ItemIndex(w.numberOfWords)

	for low <= high {
		var midpoint ItemIndex = (low + high) / 2

		ptr := w.getWordPtr(midpoint)

		// if the last word in the index is shorter than our needle, we would panic
		// by accessing a non-existing adress. To prevent this, the higher boundary
		// can never be higher than the len(index)-1
		endPos := 8 + len(bytes_needle)
		if endPos >= len(ptr) {
			endPos = len(ptr) - 1
		}

		// ignore the first 8 bytes as they are reserved for occurrence
		word := ptr[8:endPos]

		var cmp = bytes.Compare(bytes_needle, word)

		if cmp == 0 {
			return midpoint
		} else if cmp < 0 {
			high = midpoint - 1
		} else {
			low = midpoint + 1
		}
	}

	return -1
}

func (w *Wordlist) getWordPtr(index ItemIndex) []byte {
	entry_addr := ItemIndex(w.startOfTable) + index*8
	word_address_bytes := w.mmap[entry_addr : entry_addr+8]
	word_address := binary.LittleEndian.Uint64(word_address_bytes)
	return w.mmap[word_address:]
}

func (w *Wordlist) getWord(index ItemIndex) (string, uint64) {
	ptr := w.getWordPtr(index)
	occurrence := binary.LittleEndian.Uint64(ptr[0:8])
	for i := 8; i < len(ptr); i++ {
		if ptr[i] == '\x00' {
			return string(ptr[8:i]), occurrence
		}
	}

	return "", 0
}
<|endoftext|>


<commit_before>package mockingbird_test

import (
	"io/ioutil"

	. "github.com/lazywei/mockingbird"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Tokenzier", func() {
	Describe("extract tokens", func() {

		It("should skip string literals", func() {
			expectedResult := []string{"print"}

			Expect(ExtractTokens(`print ""`)).To(Equal(expectedResult))
			Expect(ExtractTokens(`print "Josh"`)).To(Equal(expectedResult))
			Expect(ExtractTokens(`print 'Josh'`)).To(Equal(expectedResult))
			Expect(ExtractTokens(`print "Hello \"Josh\""`)).To(Equal(expectedResult))
			Expect(ExtractTokens(`print 'Hello \'Josh\''`)).To(Equal(expectedResult))
			Expect(ExtractTokens(`print "Hello", "Josh"`)).To(Equal(expectedResult))
			Expect(ExtractTokens(`print 'Hello', 'Josh'`)).To(Equal(expectedResult))
			Expect(ExtractTokens(`print "Hello", "", "Josh"`)).To(Equal(expectedResult))
			Expect(ExtractTokens(`print 'Hello', '', 'Josh'`)).To(Equal(expectedResult))
		})

		It("should skip number literals", func() {
			Expect(ExtractTokens(`1 + 1`)).To(Equal([]string{`+`}))
			Expect(ExtractTokens(`add(123, 45)`)).To(Equal([]string{`add`, `(`, `)`}))
			Expect(ExtractTokens(`0x01 | 0x10`)).To(Equal([]string{`|`}))
			Expect(ExtractTokens(`500.42 * 1.0`)).To(Equal([]string{`*`}))
		})

		It("should extract common operators", func() {
			Expect(ExtractTokens("1 + 1")).To(Equal([]string{`+`}))
			Expect(ExtractTokens("1 - 1")).To(Equal([]string{`-`}))
			Expect(ExtractTokens("1 * 1")).To(Equal([]string{`*`}))
			Expect(ExtractTokens("1 / 1")).To(Equal([]string{`/`}))
			Expect(ExtractTokens("2 % 5")).To(Equal([]string{`%`}))
			Expect(ExtractTokens("1 & 1")).To(Equal([]string{`&`}))
			Expect(ExtractTokens("1 && 1")).To(Equal([]string{`&&`}))
			Expect(ExtractTokens("1 | 1")).To(Equal([]string{`|`}))
			Expect(ExtractTokens("1 || 1")).To(Equal([]string{`||`}))
			Expect(ExtractTokens("1 < 0x01")).To(Equal([]string{`<`}))
			Expect(ExtractTokens("1 << 0x01")).To(Equal([]string{`<<`}))
		})

		It("should skip comments", func() {

			cmtTests := []struct {
				str    string
				tokens []string
			}{
				{"foo\n# Comment", []string{`foo`}},
				{"foo\n# Comment\nbar", []string{`foo`, `bar`}},
				{"foo\n// Comment", []string{`foo`}},
				{"foo\n-- Comment", []string{`foo`}},
				{"foo\n\" Comment", []string{`foo`}},
				{"foo /* Comment */", []string{`foo`}},
				{"foo /* \nComment\n */", []string{`foo`}},
				{"foo ", []string{`foo`}},
				{"foo {- Comment -}", []string{`foo`}},
				{"foo (* Comment *)", []string{`foo`}},
				{"2 % 10\n% Comment", []string{`%`}},
				{"foo\n\"\"\"\nComment\n\"\"\"\nbar", []string{`foo`, `bar`}},
				{"foo\n'''\nComment\n'''\nbar", []string{`foo`, `bar`}},
			}

			for _, cmtTest := range cmtTests {
				Expect(ExtractTokens(cmtTest.str)).To(Equal(cmtTest.tokens))
			}

		})

		It("should extract SGML tokens", func() {

			sgmlTests := []struct {
				str    string
				tokens []string
			}{
				{"", []string{"", ""}},
				{"

", []string{"
", "id", "
"}},
				{"

", []string{"
", "id=", "
"}},
				{"

", []string{"
", "id", "class", "
"}},
				{"

", []string{"
", "id=", "
"}},
				{"

", []string{"
", "id=", "
"}},
				{"<?xml version=\"1.0\"?>", []string{"<?xml>", "version="}},
			}

			for _, sgmlTest := range sgmlTests {
				Expect(ExtractTokens(sgmlTest.str)).To(Equal(sgmlTest.tokens))
			}
		})

	})

	Describe("respect language tokens", func() {

		It("should extract C tokens", func() {

			tokenTests := []struct {
				file   string
				tokens []string
			}{
				{"test_samples/C/hello.h", []string{
					`#ifndef`, `HELLO_H`, `#define`,
					`HELLO_H`, `void`, `hello`,
					`(`, `)`, `;`, `#endif`}},

				{"test_samples/C/hello.c", []string{
					`#include`, `<stdio.h>`, `int`,
					`main`, `(`, `)`,
					`{`, `printf`, `(`,
					`)`, `;`, `return`, `;`, `}`}},
			}

			for _, tokenTest := range tokenTests {
				fileContent, err := ioutil.ReadFile(tokenTest.file)
				if err != nil {
					panic(err)
				}
				Expect(ExtractTokens(string(fileContent))).To(Equal(tokenTest.tokens))
			}
		})

	})
})
<commit_msg>Add C++ testing.<commit_after>package mockingbird_test

import (
	"io/ioutil"

	. "github.com/lazywei/mockingbird"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Tokenzier", func() {
	Describe("extract tokens", func() {

		It("should skip string literals", func() {
			expectedResult := []string{"print"}

			Expect(ExtractTokens(`print ""`)).To(Equal(expectedResult))
			Expect(ExtractTokens(`print "Josh"`)).To(Equal(expectedResult))
			Expect(ExtractTokens(`print 'Josh'`)).To(Equal(expectedResult))
			Expect(ExtractTokens(`print "Hello \"Josh\""`)).To(Equal(expectedResult))
			Expect(ExtractTokens(`print 'Hello \'Josh\''`)).To(Equal(expectedResult))
			Expect(ExtractTokens(`print "Hello", "Josh"`)).To(Equal(expectedResult))
			Expect(ExtractTokens(`print 'Hello', 'Josh'`)).To(Equal(expectedResult))
			Expect(ExtractTokens(`print "Hello", "", "Josh"`)).To(Equal(expectedResult))
			Expect(ExtractTokens(`print 'Hello', '', 'Josh'`)).To(Equal(expectedResult))
		})

		It("should skip number literals", func() {
			Expect(ExtractTokens(`1 + 1`)).To(Equal([]string{`+`}))
			Expect(ExtractTokens(`add(123, 45)`)).To(Equal([]string{`add`, `(`, `)`}))
			Expect(ExtractTokens(`0x01 | 0x10`)).To(Equal([]string{`|`}))
			Expect(ExtractTokens(`500.42 * 1.0`)).To(Equal([]string{`*`}))
		})

		It("should extract common operators", func() {
			Expect(ExtractTokens("1 + 1")).To(Equal([]string{`+`}))
			Expect(ExtractTokens("1 - 1")).To(Equal([]string{`-`}))
			Expect(ExtractTokens("1 * 1")).To(Equal([]string{`*`}))
			Expect(ExtractTokens("1 / 1")).To(Equal([]string{`/`}))
			Expect(ExtractTokens("2 % 5")).To(Equal([]string{`%`}))
			Expect(ExtractTokens("1 & 1")).To(Equal([]string{`&`}))
			Expect(ExtractTokens("1 && 1")).To(Equal([]string{`&&`}))
			Expect(ExtractTokens("1 | 1")).To(Equal([]string{`|`}))
			Expect(ExtractTokens("1 || 1")).To(Equal([]string{`||`}))
			Expect(ExtractTokens("1 < 0x01")).To(Equal([]string{`<`}))
			Expect(ExtractTokens("1 << 0x01")).To(Equal([]string{`<<`}))
		})

		It("should skip comments", func() {

			cmtTests := []struct {
				str    string
				tokens []string
			}{
				{"foo\n# Comment", []string{`foo`}},
				{"foo\n# Comment\nbar", []string{`foo`, `bar`}},
				{"foo\n// Comment", []string{`foo`}},
				{"foo\n-- Comment", []string{`foo`}},
				{"foo\n\" Comment", []string{`foo`}},
				{"foo /* Comment */", []string{`foo`}},
				{"foo /* \nComment\n */", []string{`foo`}},
				{"foo ", []string{`foo`}},
				{"foo {- Comment -}", []string{`foo`}},
				{"foo (* Comment *)", []string{`foo`}},
				{"2 % 10\n% Comment", []string{`%`}},
				{"foo\n\"\"\"\nComment\n\"\"\"\nbar", []string{`foo`, `bar`}},
				{"foo\n'''\nComment\n'''\nbar", []string{`foo`, `bar`}},
			}

			for _, cmtTest := range cmtTests {
				Expect(ExtractTokens(cmtTest.str)).To(Equal(cmtTest.tokens))
			}

		})

		It("should extract SGML tokens", func() {

			sgmlTests := []struct {
				str    string
				tokens []string
			}{
				{"", []string{"", ""}},
				{"

", []string{"
", "id", "
"}},
				{"

", []string{"
", "id=", "
"}},
				{"

", []string{"
", "id", "class", "
"}},
				{"

", []string{"
", "id=", "
"}},
				{"

", []string{"
", "id=", "
"}},
				{"<?xml version=\"1.0\"?>", []string{"<?xml>", "version="}},
			}

			for _, sgmlTest := range sgmlTests {
				Expect(ExtractTokens(sgmlTest.str)).To(Equal(sgmlTest.tokens))
			}
		})

	})

	Describe("respect language tokens", func() {

		It("should extract C tokens", func() {

			tokenTests := []struct {
				file   string
				tokens []string
			}{
				{"test_samples/C/hello.h", []string{
					`#ifndef`, `HELLO_H`, `#define`,
					`HELLO_H`, `void`, `hello`,
					`(`, `)`, `;`, `#endif`}},

				{"test_samples/C/hello.c", []string{
					`#include`, `<stdio.h>`, `int`,
					`main`, `(`, `)`,
					`{`, `printf`, `(`,
					`)`, `;`, `return`, `;`, `}`}},
			}

			for _, tokenTest := range tokenTests {
				fileContent, err := ioutil.ReadFile(tokenTest.file)
				if err != nil {
					panic(err)
				}
				Expect(ExtractTokens(string(fileContent))).To(Equal(tokenTest.tokens))
			}
		})

		It("should extract C++ tokens", func() {

			tokenTests := []struct {
				file   string
				tokens []string
			}{
				{"test_samples/C++/bar.h", []string{
					`class`, `Bar`, `{`,
					`protected`, `char`,
					`*name`, `;`, `public`,
					`void`, `hello`, `(`, `)`, `;`, `}`}},

				{"test_samples/C++/hello.cpp", []string{
					`#include`, `<iostream>`, `using`,
					`namespace`, `std`, `;`,
					`int`, `main`, `(`, `)`, `{`,
					`cout`, `<<`, `<<`, `endl`, `;`, `}`}},
			}

			for _, tokenTest := range tokenTests {
				fileContent, err := ioutil.ReadFile(tokenTest.file)
				if err != nil {
					panic(err)
				}
				Expect(ExtractTokens(string(fileContent))).To(Equal(tokenTest.tokens))
			}
		})

	})
})
<|endoftext|>


<commit_before>package users

import (
	"encoding/json"
	"log"

	"github.com/eynstudio/gobreak"
	"github.com/eynstudio/gobreak/db"
	"github.com/eynstudio/gobreak/db/filter"
	"github.com/eynstudio/gobreak/orm"
	"github.com/eynstudio/gox/di"
)

func init() {
	log.Println(di.Reg(&UserCtx{}))
}

type UserCtx struct {
	*orm.Orm `di:"*"`
}

func (p *UserCtx) Get(id gobreak.GUID) (m AuthUser, ok bool) {
	ok = p.Orm.WhereId(id).GetJson2(&m)
	return
}
func (p *UserCtx) GetByMcPwd(mc, pwd string) (m AuthUser, ok bool) {
	ok = p.Orm.Where(`json->>'Mc'=? and json->>'Pwd'=?`, mc, pwd).GetJson2(&m)
	return
}
func (p *UserCtx) All() (lst []AuthUser, err error) {
	err = p.Orm.AllJson(&lst)
	return
}
func (p *UserCtx) UserCountByGroup(gid gobreak.GUID) (n int) {
	//p.Orm.Where(`json->'Groups'@>[]`)
	//	err = p.Orm.AllJson(&lst)
	return
}
func (p *UserCtx) PageUser(page *filter.PageFilter) (m *db.Paging, err error) {
	lst := []UserLine{}
	s := p.Orm.From("AuthUser")
	if page.Search() != "" {
		str := "%" + page.Search() + "%"
		s.Where(`json->>'Mc' like ? or json->>'Nc' like ?`, str, str)
	}
	m = s.Select(`id ,json->>'Mc' mc,json->>'Nc' nc`).Page2(&lst, page)
	err = s.Err
	return
}

func (p *UserCtx) PageGroupUser(gid gobreak.GUID, page *filter.PageFilter) (m *db.Paging, err error) {
	lst := []UserLine{}
	s := p.Orm.From("AuthUser")
	args := db.NewAgrs(`json->'Groups' @> ?`, gid)
	if page.Search() != "" {
		str := "%" + page.Search() + "%"
		args.Append(`and (json->>'Mc' like ? or json->>'Nc' like ?)`, str, str)
	}
	m = s.Where(args.Sql, args.Args...).Select(`id ,json->>'Mc' mc,json->>'Nc' nc`).PageJson2(&lst, page)
	err = s.Err
	return
}

func (p *UserCtx) PageGroupUserSelect(gid gobreak.GUID, page *filter.PageFilter) (m *db.Paging, err error) {
	log.Println(gid, page)

	lst0 := []gobreak.GUID{gid}
	lst2, _ := json.Marshal(lst0)

	lst := []UserLine{}
	s := p.Orm.From("AuthUser")
	args := db.NewAgrs(`not json->'Groups' @> ?`, lst2)
	if page.Search() != "" {
		str := "%" + page.Search() + "%"
		args.Append(`and (json->>'Mc' like ? or json->>'Nc' like ?)`, str, str)
	}
	m = s.Where(args.Sql, args.Args...).Select(`id, json->>'Mc' mc,json->>'Nc' nc`).Page2(&lst, page)
	err = s.Err
	return
}

func (p *UserCtx) AddUserGroup(uid, gid gobreak.GUID) error {
	log.Println(uid, gid)
	return nil
}

func (p *UserCtx) Save(m *AuthUser) gobreak.IStatus {
	err := p.Orm.SaveJson(m.Id, m)
	return gobreak.NewStatusErr(err, "保存成功", "保存失败")
}

func (p *UserCtx) Del(id gobreak.GUID) gobreak.IStatus {
	err := p.Orm.DelId(&AuthUser{}, id)
	return gobreak.NewStatusErr(err, "保存成功", "保存失败")
}
<commit_msg>update auth<commit_after>package users

import (
	"encoding/json"
	"log"

	"github.com/eynstudio/gobreak"
	"github.com/eynstudio/gobreak/db"
	"github.com/eynstudio/gobreak/db/filter"
	"github.com/eynstudio/gobreak/orm"
	"github.com/eynstudio/gox/di"
)

func init() {
	log.Println(di.Reg(&UserCtx{}))
}

type UserCtx struct {
	*orm.Orm `di:"*"`
}

func (p *UserCtx) Get(id gobreak.GUID) (m AuthUser, ok bool) {
	ok = p.Orm.WhereId(id).GetJson2(&m)
	return
}
func (p *UserCtx) GetByMcPwd(mc, pwd string) (m AuthUser, ok bool) {
	ok = p.Orm.Where(`json->>'Mc'=? and json->>'Pwd'=?`, mc, pwd).GetJson2(&m)
	return
}
func (p *UserCtx) All() (lst []AuthUser, err error) {
	err = p.Orm.AllJson(&lst)
	return
}
func (p *UserCtx) UserCountByGroup(gid gobreak.GUID) (n int) {
	//p.Orm.Where(`json->'Groups'@>[]`)
	//	err = p.Orm.AllJson(&lst)
	return
}
func (p *UserCtx) PageUser(page *filter.PageFilter) (m *db.Paging, err error) {
	lst := []UserLine{}
	s := p.Orm.From("AuthUser")
	if page.Search() != "" {
		str := "%" + page.Search() + "%"
		s.Where(`json->>'Mc' like ? or json->>'Nc' like ?`, str, str)
	}
	m = s.Select(`id ,json->>'Mc' mc,json->>'Nc' nc`).Page2(&lst, page)
	err = s.Err
	return
}

func (p *UserCtx) PageGroupUser(gid gobreak.GUID, page *filter.PageFilter) (m *db.Paging, err error) {
	return p.pageGroupUser(gid, page, true)
}

func (p *UserCtx) PageGroupUserSelect(gid gobreak.GUID, page *filter.PageFilter) (m *db.Paging, err error) {
	return p.pageGroupUser(gid, page, false)
}

func (p *UserCtx) pageGroupUser(gid gobreak.GUID, page *filter.PageFilter, in bool) (m *db.Paging, err error) {
	lst := []UserLine{}
	lst2, _ := json.Marshal(gid)
	s := p.Orm.From("AuthUser")

	sql := `json->'Groups' @> ?`
	if !in {
		sql += "not "
	}
	args := db.NewAgrs(sql, lst2)
	if page.Search() != "" {
		str := "%" + page.Search() + "%"
		args.Append(`and (json->>'Mc' like ? or json->>'Nc' like ?)`, str, str)
	}
	m = s.Where(args.Sql, args.Args...).Select(`id, json->>'Mc' mc,json->>'Nc' nc`).Page2(&lst, page)
	err = s.Err
	return
}

func (p *UserCtx) AddUserGroup(uid, gid gobreak.GUID) error {
	log.Println(uid, gid)
	if u, ok := p.Get(uid); ok {
		u.AddGroup(gid)
		return p.Orm.SaveJson(u.Id, u)
	}
	return nil
}

func (p *UserCtx) Save(m *AuthUser) gobreak.IStatus {
	err := p.Orm.SaveJson(m.Id, m)
	return gobreak.NewStatusErr(err, "保存成功", "保存失败")
}

func (p *UserCtx) Del(id gobreak.GUID) gobreak.IStatus {
	err := p.Orm.DelId(&AuthUser{}, id)
	return gobreak.NewStatusErr(err, "保存成功", "保存失败")
}
<|endoftext|>


<commit_before>package lib

import "github.com/jh-bate/fantail-bot/Godeps/_workspace/src/github.com/tucnak/telebot"

const (
	default_script = "default"
	stickers_chat  = "chat"
)

type (
	Info struct {
		App       []string `json:"appInfo"`
		Reminders []string `json:"remindersInfo"`
		Chat      []string `json:"chatInfo"`
		Said      []string `json:"saidInfo"`
	}

	QProcess struct {
		s *session
		p Action
	}
)

func NewQProcess(b *telebot.Bot, s *Storage) *QProcess {
	q := &QProcess{s: newSession(b, s)}
	return q
}

func (this *QProcess) Run(input <-chan telebot.Message) {
	for msg := range input {

		in := newIncoming(msg, this.p)

		in.getAction(this.s).firstUp().askQuestion()

		this.p = in.action

	}
}
<commit_msg>cleanup<commit_after>package lib

import "github.com/jh-bate/fantail-bot/Godeps/_workspace/src/github.com/tucnak/telebot"

const (
	default_script = "default"
	stickers_chat  = "chat"
)

type (
	Info struct {
		App       []string `json:"appInfo"`
		Reminders []string `json:"remindersInfo"`
		Chat      []string `json:"chatInfo"`
		Said      []string `json:"saidInfo"`
	}

	QProcess struct {
		s *session
		p Action
	}
)

func NewQProcess(b *telebot.Bot, s *Storage) *QProcess {
	q := &QProcess{s: newSession(b, s)}
	return q
}

func (this *QProcess) Run(input <-chan telebot.Message) {
	for msg := range input {

		in := newIncoming(msg, this.p)

		in.getAction(this.s).firstUp().askQuestion()

		this.p = in.getAction(this.s)

	}
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes 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 testing

import (
	"fmt"
	"math/rand"
	"strconv"
	"sync"
	"testing"

	"github.com/stretchr/testify/assert"

	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	runtime "k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	serializer "k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/watch"
)

func getArbitraryResource(s schema.GroupVersionResource, name, namespace string) *unstructured.Unstructured {
	return &unstructured.Unstructured{
		Object: map[string]interface{}{
			"kind":       s.Resource,
			"apiVersion": s.Version,
			"metadata": map[string]interface{}{
				"name":            name,
				"namespace":       namespace,
				"generateName":    "test_generateName",
				"uid":             "test_uid",
				"resourceVersion": "test_resourceVersion",
				"selfLink":        "test_selfLink",
			},
			"data": strconv.Itoa(rand.Int()),
		},
	}
}

func TestWatchCallNonNamespace(t *testing.T) {
	testResource := schema.GroupVersionResource{Group: "", Version: "test_version", Resource: "test_kind"}
	testObj := getArbitraryResource(testResource, "test_name", "test_namespace")
	accessor, err := meta.Accessor(testObj)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	ns := accessor.GetNamespace()
	scheme := runtime.NewScheme()
	codecs := serializer.NewCodecFactory(scheme)
	o := NewObjectTracker(scheme, codecs.UniversalDecoder())
	watch, err := o.Watch(testResource, ns)
	if err != nil {
		t.Fatalf("test resource watch failed in %s: %v ", ns, err)
	}
	go func() {
		err := o.Create(testResource, testObj, ns)
		if err != nil {
			t.Errorf("test resource creation failed: %v", err)
		}
	}()
	out := <-watch.ResultChan()
	assert.Equal(t, testObj, out.Object, "watched object mismatch")
}

func TestWatchCallAllNamespace(t *testing.T) {
	testResource := schema.GroupVersionResource{Group: "", Version: "test_version", Resource: "test_kind"}
	testObj := getArbitraryResource(testResource, "test_name", "test_namespace")
	accessor, err := meta.Accessor(testObj)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	ns := accessor.GetNamespace()
	scheme := runtime.NewScheme()
	codecs := serializer.NewCodecFactory(scheme)
	o := NewObjectTracker(scheme, codecs.UniversalDecoder())
	w, err := o.Watch(testResource, "test_namespace")
	if err != nil {
		t.Fatalf("test resource watch failed in test_namespace: %v", err)
	}
	wAll, err := o.Watch(testResource, "")
	if err != nil {
		t.Fatalf("test resource watch failed in all namespaces: %v", err)
	}
	go func() {
		err := o.Create(testResource, testObj, ns)
		assert.NoError(t, err, "test resource creation failed")
	}()
	out := <-w.ResultChan()
	outAll := <-wAll.ResultChan()
	assert.Equal(t, watch.Added, out.Type, "watch event mismatch")
	assert.Equal(t, watch.Added, outAll.Type, "watch event mismatch")
	assert.Equal(t, testObj, out.Object, "watched created object mismatch")
	assert.Equal(t, testObj, outAll.Object, "watched created object mismatch")
	go func() {
		err := o.Update(testResource, testObj, ns)
		assert.NoError(t, err, "test resource updating failed")
	}()
	out = <-w.ResultChan()
	outAll = <-wAll.ResultChan()
	assert.Equal(t, watch.Modified, out.Type, "watch event mismatch")
	assert.Equal(t, watch.Modified, outAll.Type, "watch event mismatch")
	assert.Equal(t, testObj, out.Object, "watched updated object mismatch")
	assert.Equal(t, testObj, outAll.Object, "watched updated object mismatch")
	go func() {
		err := o.Delete(testResource, "test_namespace", "test_name")
		assert.NoError(t, err, "test resource deletion failed")
	}()
	out = <-w.ResultChan()
	outAll = <-wAll.ResultChan()
	assert.Equal(t, watch.Deleted, out.Type, "watch event mismatch")
	assert.Equal(t, watch.Deleted, outAll.Type, "watch event mismatch")
	assert.Equal(t, testObj, out.Object, "watched deleted object mismatch")
	assert.Equal(t, testObj, outAll.Object, "watched deleted object mismatch")
}

func TestWatchCallMultipleInvocation(t *testing.T) {
	cases := []struct {
		name string
		op   watch.EventType
		ns   string
	}{
		{
			"foo",
			watch.Added,
			"test_namespace",
		},
		{
			"bar",
			watch.Added,
			"test_namespace",
		},
		{
			"baz",
			watch.Added,
			"",
		},
		{
			"bar",
			watch.Modified,
			"test_namespace",
		},
		{
			"baz",
			watch.Modified,
			"",
		},
		{
			"foo",
			watch.Deleted,
			"test_namespace",
		},
		{
			"bar",
			watch.Deleted,
			"test_namespace",
		},
		{
			"baz",
			watch.Deleted,
			"",
		},
	}

	scheme := runtime.NewScheme()
	codecs := serializer.NewCodecFactory(scheme)
	testResource := schema.GroupVersionResource{Group: "", Version: "test_version", Resource: "test_kind"}

	o := NewObjectTracker(scheme, codecs.UniversalDecoder())
	watchNamespaces := []string{
		"",
		"",
		"test_namespace",
		"test_namespace",
	}
	var wg sync.WaitGroup
	wg.Add(len(watchNamespaces))
	for idx, watchNamespace := range watchNamespaces {
		i := idx
		watchNamespace := watchNamespace
		w, err := o.Watch(testResource, watchNamespace)
		if err != nil {
			t.Fatalf("test resource watch failed in %s: %v", watchNamespace, err)
		}
		go func() {
			assert.NoError(t, err, "watch invocation failed")
			for _, c := range cases {
				if watchNamespace == "" || c.ns == watchNamespace {
					fmt.Printf("%#v %#v\n", c, i)
					event := <-w.ResultChan()
					accessor, err := meta.Accessor(event.Object)
					if err != nil {
						t.Errorf("unexpected error: %v", err)
						break
					}
					assert.Equal(t, c.op, event.Type, "watch event mismatched")
					assert.Equal(t, c.name, accessor.GetName(), "watched object mismatch")
					assert.Equal(t, c.ns, accessor.GetNamespace(), "watched object mismatch")
				}
			}
			wg.Done()
		}()
	}
	for _, c := range cases {
		switch c.op {
		case watch.Added:
			obj := getArbitraryResource(testResource, c.name, c.ns)
			o.Create(testResource, obj, c.ns)
		case watch.Modified:
			obj := getArbitraryResource(testResource, c.name, c.ns)
			o.Update(testResource, obj, c.ns)
		case watch.Deleted:
			o.Delete(testResource, c.ns, c.name)
		}
	}
	wg.Wait()
}

func TestWatchAddAfterStop(t *testing.T) {
	testResource := schema.GroupVersionResource{Group: "", Version: "test_version", Resource: "test_kind"}
	testObj := getArbitraryResource(testResource, "test_name", "test_namespace")
	accessor, err := meta.Accessor(testObj)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	ns := accessor.GetNamespace()
	scheme := runtime.NewScheme()
	codecs := serializer.NewCodecFactory(scheme)
	o := NewObjectTracker(scheme, codecs.UniversalDecoder())
	watch, err := o.Watch(testResource, ns)
	if err != nil {
		t.Errorf("watch creation failed: %v", err)
	}

	// When the watch is stopped it should ignore later events without panicking.
	defer func() {
		if r := recover(); r != nil {
			t.Errorf("Watch panicked when it should have ignored create after stop: %v", r)
		}
	}()

	watch.Stop()
	err = o.Create(testResource, testObj, ns)
	if err != nil {
		t.Errorf("test resource creation failed: %v", err)
	}
}

func TestPatchWithMissingObject(t *testing.T) {
	nodesResource := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "nodes"}

	scheme := runtime.NewScheme()
	codecs := serializer.NewCodecFactory(scheme)
	o := NewObjectTracker(scheme, codecs.UniversalDecoder())
	reaction := ObjectReaction(o)
	action := NewRootPatchSubresourceAction(nodesResource, "node-1", types.StrategicMergePatchType, []byte(`{}`))
	handled, node, err := reaction(action)
	assert.True(t, handled)
	assert.Nil(t, node)
	assert.EqualError(t, err, `nodes "node-1" not found`)
}

func TestGetWithExactMatch(t *testing.T) {
	scheme := runtime.NewScheme()
	codecs := serializer.NewCodecFactory(scheme)

	constructObject := func(s schema.GroupVersionResource, name, namespace string) (*unstructured.Unstructured, schema.GroupVersionResource) {
		obj := getArbitraryResource(s, name, namespace)
		gvks, _, err := scheme.ObjectKinds(obj)
		assert.NoError(t, err)
		gvr, _ := meta.UnsafeGuessKindToResource(gvks[0])
		return obj, gvr
	}

	var err error
	// Object with empty namespace
	o := NewObjectTracker(scheme, codecs.UniversalDecoder())
	nodeResource := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "node"}
	node, gvr := constructObject(nodeResource, "node", "")

	assert.Nil(t, o.Add(node))

	// Exact match
	_, err = o.Get(gvr, "", "node")
	assert.NoError(t, err)

	// Unexpected namespace provided
	_, err = o.Get(gvr, "ns", "node")
	assert.Error(t, err)
	errNotFound := errors.NewNotFound(gvr.GroupResource(), "node")
	assert.EqualError(t, err, errNotFound.Error())

	// Object with non-empty namespace
	o = NewObjectTracker(scheme, codecs.UniversalDecoder())
	podResource := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pod"}
	pod, gvr := constructObject(podResource, "pod", "default")
	assert.Nil(t, o.Add(pod))

	// Exact match
	_, err = o.Get(gvr, "default", "pod")
	assert.NoError(t, err)

	// Missing namespace
	_, err = o.Get(gvr, "", "pod")
	assert.Error(t, err)
	errNotFound = errors.NewNotFound(gvr.GroupResource(), "pod")
	assert.EqualError(t, err, errNotFound.Error())
}
<commit_msg>Add test<commit_after>/*
Copyright 2015 The Kubernetes 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 testing

import (
	"fmt"
	"math/rand"
	"strconv"
	"sync"
	"testing"

	"github.com/stretchr/testify/assert"

	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	runtime "k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	serializer "k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/watch"
)

func getArbitraryResource(s schema.GroupVersionResource, name, namespace string) *unstructured.Unstructured {
	return &unstructured.Unstructured{
		Object: map[string]interface{}{
			"kind":       s.Resource,
			"apiVersion": s.Version,
			"metadata": map[string]interface{}{
				"name":            name,
				"namespace":       namespace,
				"generateName":    "test_generateName",
				"uid":             "test_uid",
				"resourceVersion": "test_resourceVersion",
				"selfLink":        "test_selfLink",
			},
			"data": strconv.Itoa(rand.Int()),
		},
	}
}

func TestWatchCallNonNamespace(t *testing.T) {
	testResource := schema.GroupVersionResource{Group: "", Version: "test_version", Resource: "test_kind"}
	testObj := getArbitraryResource(testResource, "test_name", "test_namespace")
	accessor, err := meta.Accessor(testObj)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	ns := accessor.GetNamespace()
	scheme := runtime.NewScheme()
	codecs := serializer.NewCodecFactory(scheme)
	o := NewObjectTracker(scheme, codecs.UniversalDecoder())
	watch, err := o.Watch(testResource, ns)
	if err != nil {
		t.Fatalf("test resource watch failed in %s: %v ", ns, err)
	}
	go func() {
		err := o.Create(testResource, testObj, ns)
		if err != nil {
			t.Errorf("test resource creation failed: %v", err)
		}
	}()
	out := <-watch.ResultChan()
	assert.Equal(t, testObj, out.Object, "watched object mismatch")
}

func TestWatchCallAllNamespace(t *testing.T) {
	testResource := schema.GroupVersionResource{Group: "", Version: "test_version", Resource: "test_kind"}
	testObj := getArbitraryResource(testResource, "test_name", "test_namespace")
	accessor, err := meta.Accessor(testObj)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	ns := accessor.GetNamespace()
	scheme := runtime.NewScheme()
	codecs := serializer.NewCodecFactory(scheme)
	o := NewObjectTracker(scheme, codecs.UniversalDecoder())
	w, err := o.Watch(testResource, "test_namespace")
	if err != nil {
		t.Fatalf("test resource watch failed in test_namespace: %v", err)
	}
	wAll, err := o.Watch(testResource, "")
	if err != nil {
		t.Fatalf("test resource watch failed in all namespaces: %v", err)
	}
	go func() {
		err := o.Create(testResource, testObj, ns)
		assert.NoError(t, err, "test resource creation failed")
	}()
	out := <-w.ResultChan()
	outAll := <-wAll.ResultChan()
	assert.Equal(t, watch.Added, out.Type, "watch event mismatch")
	assert.Equal(t, watch.Added, outAll.Type, "watch event mismatch")
	assert.Equal(t, testObj, out.Object, "watched created object mismatch")
	assert.Equal(t, testObj, outAll.Object, "watched created object mismatch")
	go func() {
		err := o.Update(testResource, testObj, ns)
		assert.NoError(t, err, "test resource updating failed")
	}()
	out = <-w.ResultChan()
	outAll = <-wAll.ResultChan()
	assert.Equal(t, watch.Modified, out.Type, "watch event mismatch")
	assert.Equal(t, watch.Modified, outAll.Type, "watch event mismatch")
	assert.Equal(t, testObj, out.Object, "watched updated object mismatch")
	assert.Equal(t, testObj, outAll.Object, "watched updated object mismatch")
	go func() {
		err := o.Delete(testResource, "test_namespace", "test_name")
		assert.NoError(t, err, "test resource deletion failed")
	}()
	out = <-w.ResultChan()
	outAll = <-wAll.ResultChan()
	assert.Equal(t, watch.Deleted, out.Type, "watch event mismatch")
	assert.Equal(t, watch.Deleted, outAll.Type, "watch event mismatch")
	assert.Equal(t, testObj, out.Object, "watched deleted object mismatch")
	assert.Equal(t, testObj, outAll.Object, "watched deleted object mismatch")
}

func TestWatchCallMultipleInvocation(t *testing.T) {
	cases := []struct {
		name string
		op   watch.EventType
		ns   string
	}{
		{
			"foo",
			watch.Added,
			"test_namespace",
		},
		{
			"bar",
			watch.Added,
			"test_namespace",
		},
		{
			"baz",
			watch.Added,
			"",
		},
		{
			"bar",
			watch.Modified,
			"test_namespace",
		},
		{
			"baz",
			watch.Modified,
			"",
		},
		{
			"foo",
			watch.Deleted,
			"test_namespace",
		},
		{
			"bar",
			watch.Deleted,
			"test_namespace",
		},
		{
			"baz",
			watch.Deleted,
			"",
		},
	}

	scheme := runtime.NewScheme()
	codecs := serializer.NewCodecFactory(scheme)
	testResource := schema.GroupVersionResource{Group: "", Version: "test_version", Resource: "test_kind"}

	o := NewObjectTracker(scheme, codecs.UniversalDecoder())
	watchNamespaces := []string{
		"",
		"",
		"test_namespace",
		"test_namespace",
	}
	var wg sync.WaitGroup
	wg.Add(len(watchNamespaces))
	for idx, watchNamespace := range watchNamespaces {
		i := idx
		watchNamespace := watchNamespace
		w, err := o.Watch(testResource, watchNamespace)
		if err != nil {
			t.Fatalf("test resource watch failed in %s: %v", watchNamespace, err)
		}
		go func() {
			assert.NoError(t, err, "watch invocation failed")
			for _, c := range cases {
				if watchNamespace == "" || c.ns == watchNamespace {
					fmt.Printf("%#v %#v\n", c, i)
					event := <-w.ResultChan()
					accessor, err := meta.Accessor(event.Object)
					if err != nil {
						t.Errorf("unexpected error: %v", err)
						break
					}
					assert.Equal(t, c.op, event.Type, "watch event mismatched")
					assert.Equal(t, c.name, accessor.GetName(), "watched object mismatch")
					assert.Equal(t, c.ns, accessor.GetNamespace(), "watched object mismatch")
				}
			}
			wg.Done()
		}()
	}
	for _, c := range cases {
		switch c.op {
		case watch.Added:
			obj := getArbitraryResource(testResource, c.name, c.ns)
			o.Create(testResource, obj, c.ns)
		case watch.Modified:
			obj := getArbitraryResource(testResource, c.name, c.ns)
			o.Update(testResource, obj, c.ns)
		case watch.Deleted:
			o.Delete(testResource, c.ns, c.name)
		}
	}
	wg.Wait()
}

func TestWatchAddAfterStop(t *testing.T) {
	testResource := schema.GroupVersionResource{Group: "", Version: "test_version", Resource: "test_kind"}
	testObj := getArbitraryResource(testResource, "test_name", "test_namespace")
	accessor, err := meta.Accessor(testObj)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	ns := accessor.GetNamespace()
	scheme := runtime.NewScheme()
	codecs := serializer.NewCodecFactory(scheme)
	o := NewObjectTracker(scheme, codecs.UniversalDecoder())
	watch, err := o.Watch(testResource, ns)
	if err != nil {
		t.Errorf("watch creation failed: %v", err)
	}

	// When the watch is stopped it should ignore later events without panicking.
	defer func() {
		if r := recover(); r != nil {
			t.Errorf("Watch panicked when it should have ignored create after stop: %v", r)
		}
	}()

	watch.Stop()
	err = o.Create(testResource, testObj, ns)
	if err != nil {
		t.Errorf("test resource creation failed: %v", err)
	}
}

func TestPatchWithMissingObject(t *testing.T) {
	nodesResource := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "nodes"}

	scheme := runtime.NewScheme()
	codecs := serializer.NewCodecFactory(scheme)
	o := NewObjectTracker(scheme, codecs.UniversalDecoder())
	reaction := ObjectReaction(o)
	action := NewRootPatchSubresourceAction(nodesResource, "node-1", types.StrategicMergePatchType, []byte(`{}`))
	handled, node, err := reaction(action)
	assert.True(t, handled)
	assert.Nil(t, node)
	assert.EqualError(t, err, `nodes "node-1" not found`)
}

func TestGetWithExactMatch(t *testing.T) {
	scheme := runtime.NewScheme()
	codecs := serializer.NewCodecFactory(scheme)

	constructObject := func(s schema.GroupVersionResource, name, namespace string) (*unstructured.Unstructured, schema.GroupVersionResource) {
		obj := getArbitraryResource(s, name, namespace)
		gvks, _, err := scheme.ObjectKinds(obj)
		assert.NoError(t, err)
		gvr, _ := meta.UnsafeGuessKindToResource(gvks[0])
		return obj, gvr
	}

	var err error
	// Object with empty namespace
	o := NewObjectTracker(scheme, codecs.UniversalDecoder())
	nodeResource := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "node"}
	node, gvr := constructObject(nodeResource, "node", "")

	assert.Nil(t, o.Add(node))

	// Exact match
	_, err = o.Get(gvr, "", "node")
	assert.NoError(t, err)

	// Unexpected namespace provided
	_, err = o.Get(gvr, "ns", "node")
	assert.Error(t, err)
	errNotFound := errors.NewNotFound(gvr.GroupResource(), "node")
	assert.EqualError(t, err, errNotFound.Error())

	// Object with non-empty namespace
	o = NewObjectTracker(scheme, codecs.UniversalDecoder())
	podResource := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pod"}
	pod, gvr := constructObject(podResource, "pod", "default")
	assert.Nil(t, o.Add(pod))

	// Exact match
	_, err = o.Get(gvr, "default", "pod")
	assert.NoError(t, err)

	// Missing namespace
	_, err = o.Get(gvr, "", "pod")
	assert.Error(t, err)
	errNotFound = errors.NewNotFound(gvr.GroupResource(), "pod")
	assert.EqualError(t, err, errNotFound.Error())
}

func Test_resourceCovers(t *testing.T) {
	type args struct {
		resource string
		action   Action
	}
	tests := []struct {
		name string
		args args
		want bool
	}{
		{
			args: args{
				resource: "*",
				action:   ActionImpl{},
			},
			want: true,
		},
		{
			args: args{
				resource: "serviceaccounts",
				action:   ActionImpl{},
			},
			want: false,
		},
		{
			args: args{
				resource: "serviceaccounts",
				action: ActionImpl{
					Resource: schema.GroupVersionResource{
						Resource: "serviceaccounts",
					},
				},
			},
			want: true,
		},
		{
			args: args{
				resource: "serviceaccounts/token",
				action: ActionImpl{
					Resource: schema.GroupVersionResource{},
				},
			},
			want: false,
		},
		{
			args: args{
				resource: "serviceaccounts/token",
				action: ActionImpl{
					Resource: schema.GroupVersionResource{
						Resource: "serviceaccounts",
					},
				},
			},
			want: false,
		},
		{
			args: args{
				resource: "serviceaccounts/token",
				action: ActionImpl{
					Resource:    schema.GroupVersionResource{},
					Subresource: "token",
				},
			},
			want: false,
		},
		{
			args: args{
				resource: "serviceaccounts/token",
				action: ActionImpl{
					Resource: schema.GroupVersionResource{
						Resource: "serviceaccounts",
					},
					Subresource: "token",
				},
			},
			want: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := resourceCovers(tt.args.resource, tt.args.action); got != tt.want {
				t.Errorf("resourceCovers() = %v, want %v", got, tt.want)
			}
		})
	}
}
<|endoftext|>