func (suite *ReputationTestSuite) TestComputeNewRepDataGTEZero() {
	repData := reputationData{
		consumption: NewInt(0),
		hold:        NewInt(0),
		reputation:  NewInt(0),
	}
	consumptions := consumptionInfo{
		seed:    NewInt(1000),
		other:   NewInt(10000),
		seedIF:  NewInt(0),
		otherIF: NewInt(3333),
	}
	rep := suite.rep
	newrep := rep.computeNewRepData(repData, consumptions)
	suite.True(newrep.reputation.Cmp(NewInt(0)) >= 0)
	suite.True(newrep.hold.Cmp(NewInt(0)) >= 0)
	suite.True(newrep.hold.Cmp(NewInt(0)) >= 0)
}
reputation values are greater than zero even if data does not make sense.
package repv2
import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"time"
	"github.com/lino-network/lino/x/reputation/repv2/internal"
	"github.com/stretchr/testify/suite"
)
type ReputationTestSuite struct {
	suite.Suite
	store                ReputationStore
	rep                  ReputationImpl
	roundDurationSeconds int64
	bestN                int
	userMaxN             int
	time                 time.Time
}
func TestReputationTestSuite(t *testing.T) {
	suite.Run(t, &ReputationTestSuite{})
}
func (suite *ReputationTestSuite) SetupTest() {
	suite.roundDurationSeconds = 25 * 3600
	suite.bestN = 30
	suite.userMaxN = 10
	suite.store = NewReputationStore(internal.NewMockStore(), DefaultInitialReputation)
	suite.rep = NewReputation(
		suite.store, suite.bestN, suite.userMaxN,
		DefaultRoundDurationSeconds, DefaultSampleWindowSize, DefaultDecayFactor,
	).(ReputationImpl)
	suite.time = time.Date(1995, time.February, 5, 11, 11, 0, 0, time.UTC)
}
func (suite *ReputationTestSuite) MoveToNewRound() {
	suite.time = suite.time.Add(time.Duration(suite.roundDurationSeconds) * time.Second)
	suite.rep.Update(Time(suite.time.Unix()))
}
func (suite *ReputationTestSuite) EqualZero(a Int, args ...interface{}) {
	suite.Equal(0, a.Cmp(NewInt(0)), "%d is not Int zero", a.Int64())
}
func (suite *ReputationTestSuite) TestUpdateTime() {
	suite.MoveToNewRound()
	t := suite.time
	rep := suite.rep
	r, rt := rep.GetCurrentRound()
	suite.Equal(RoundId(2), r)
	suite.Equal(Time(t.Unix()), rt)
	t2 := t.Add(time.Duration(10*3600) * time.Second)
	rep.Update(Time(t2.Unix()))
	r, rt = rep.GetCurrentRound()
	suite.Equal(RoundId(2), r)
	suite.Equal(Time(t.Unix()), rt)
	t3 := t2.Add(time.Duration(16*3600) * time.Second)
	rep.Update(Time(t3.Unix()))
	r, rt = rep.GetCurrentRound()
	suite.Equal(RoundId(3), r)
	suite.Equal(Time(t3.Unix()), rt)
	t4 := t3.Add(time.Duration(10*3600) * time.Second)
	rep.Update(Time(t4.Unix()))
	r, rt = rep.GetCurrentRound()
	suite.Equal(RoundId(3), r)
	suite.Equal(Time(t3.Unix()), rt)
}
func (suite *ReputationTestSuite) TestExportImportFile() {
	rep := suite.rep
	var user1 Uid = "user1"
	var user2 Uid = "user2"
	var post1 Pid = "post1"
	var post2 Pid = "post2"
	rep.IncFreeScore(user1, NewInt(10000))
	rep.IncFreeScore(user2, NewInt(10000))
	rep.DonateAt(user1, post1, NewInt(100000))
	rep.DonateAt(user1, post1, NewInt(1000))
	rep.DonateAt(user2, post1, NewInt(100000))
	rep.DonateAt(user2, post2, NewInt(1000))
	suite.MoveToNewRound()
	rep.DonateAt(user1, post1, NewInt(3333))
	rep.DonateAt(user1, post1, NewInt(4444))
	rep.DonateAt(user2, post1, NewInt(5555))
	rep.DonateAt(user2, post2, NewInt(1324))
	suite.MoveToNewRound()
	suite.MoveToNewRound()
	suite.Require().Equal(NewInt(10920), suite.rep.GetReputation("user1"))
	suite.Require().Equal(NewInt(10910), suite.rep.GetReputation("user2"))
	dir, err := ioutil.TempDir("", "example")
	suite.Require().Nil(err)
	defer os.RemoveAll(dir)  
	tmpfn := filepath.Join(dir, "tmpfile")
	suite.MoveToNewRound()
	err = rep.ExportToFile(tmpfn)
	suite.Nil(err)
	imported := NewReputation(
		NewReputationStore(internal.NewMockStore(), DefaultInitialReputation),
		suite.bestN, suite.userMaxN,
		DefaultRoundDurationSeconds, DefaultSampleWindowSize, DefaultDecayFactor,
	).(ReputationImpl)
	err = imported.ImportFromFile(tmpfn)
	suite.Nil(err)
	suite.Equal(suite.rep.GetReputation("user1"), imported.GetReputation("user1"))
	suite.Equal(suite.rep.GetReputation("user2"), imported.GetReputation("user2"))
}
func (suite *ReputationTestSuite) TestExtractConsumptionInfo() {
	newset := func(ids []Pid) map[Pid]bool {
		rst := make(map[Pid]bool)
		for _, id := range ids {
			rst[id] = true
		}
		return rst
	}
	cases := []struct {
		user     *userMeta
		seedSet  map[Pid]bool
		expected consumptionInfo
	}{
		{
			&userMeta{
				Unsettled: []Donation{
					{
						Pid:    "a",
						Amount: NewInt(333),
						Impact: NewInt(333),
					},
					{
						Pid:    "qf93f",
						Amount: NewInt(999),
						Impact: NewInt(222),
					},
					{
						Pid:    "b",
						Amount: NewInt(55555),
						Impact: NewInt(1),
					},
				},
			},
			newset([]Pid{"a", "b", "c", "ddd"}),
			consumptionInfo{
				seed:    NewInt(55888),
				other:   NewInt(999),
				seedIF:  NewInt(334),
				otherIF: NewInt(222),
			},
		},
		{
			&userMeta{
				Unsettled: []Donation{
					{
						Pid:    "not",
						Amount: NewInt(1),
						Impact: NewInt(1),
					},
				},
			},
			newset([]Pid{"a", "b", "c", "ddd"}),
			consumptionInfo{
				seed:    NewInt(0),
				other:   NewInt(1),
				seedIF:  NewInt(0),
				otherIF: NewInt(1),
			},
		},
	}
	for i, v := range cases {
		suite.Equal(v.expected, suite.rep.extractConsumptionInfo(v.user, v.seedSet), "case: %d", i)
	}
}
func (suite *ReputationTestSuite) TestGetSeedSet() {
	rep := suite.rep
	var user1 Uid = "user1"
	var user2 Uid = "user2"
	var post1 Pid = "post1"
	var post2 Pid = "post2"
	rep.IncFreeScore(user1, NewInt(10000))
	rep.IncFreeScore(user2, NewInt(10000))
	rep.DonateAt(user1, post1, NewInt(100000))
	rep.DonateAt(user1, post1, NewInt(1000))
	rep.DonateAt(user2, post1, NewInt(100000))
	rep.DonateAt(user2, post2, NewInt(1000))
	suite.MoveToNewRound()
	set := rep.getSeedSet(1)
	suite.Equal(1, len(set))
	suite.True(set[post1])
	suite.False(set[post2])
	rep.DonateAt(user1, post1, NewInt(10000))
	rep.DonateAt(user2, post2, NewInt(10000))
	suite.MoveToNewRound()
	set = rep.getSeedSet(2)
	suite.Equal(2, len(set))
	suite.True(set[post1])
	suite.True(set[post2])
	suite.False(set["other"])
}
func (suite *ReputationTestSuite) TestComputeReputation() {
	rep := suite.rep
	suite.EqualZero(rep.computeReputation(NewInt(0), NewInt(1000)))
	suite.Equal(NewInt(969), rep.computeReputation(NewInt(999), NewInt(3)))
}
func (suite *ReputationTestSuite) TestComputeNewRepData() {
	cases := []struct {
		repData     reputationData
		consumption consumptionInfo
		repeat      int
		expected    reputationData
	}{
		{
			reputationData{
				consumption: NewInt(1),
				hold:        NewInt(0),
				reputation:  NewInt(1),
			},
			consumptionInfo{
				seed:    NewInt(10000 * 100000),
				other:   NewInt(333 * 100000),
				seedIF:  NewInt(1),
				otherIF: NewInt(0),
			},
			5,
			reputationData{
				consumption: NewInt(409510000),
				hold:        NewInt(32804999),
				reputation:  NewInt(81460010),
			},
		},
		{
			reputationData{
				consumption: NewInt(1000 * 100000),
				hold:        NewInt(10 * 100000),
				reputation:  NewInt(900 * 100000),
			},
			consumptionInfo{
				seed:    NewInt(10 * 100000),
				other:   NewInt(600 * 100000),
				seedIF:  NewInt(10 * 100000),
				otherIF: NewInt(600 * 100000),
			},
			13,
			reputationData{
				consumption: NewInt(37860000),
				hold:        NewInt(10 * 100000),
				reputation:  NewInt(27860000),
			},
		},
	}
	rep := suite.rep
	for i, c := range cases {
		data := c.repData
		for j := 0; j < c.repeat; j++ {
			data = rep.computeNewRepData(data, c.consumption)
		}
		suite.Equal(c.expected, data, "case: %d", i)
	}
}
func (suite *ReputationTestSuite) TestComputeNewRepDataDecreaseToZero() {
	repData := reputationData{
		consumption: NewInt(1),
		hold:        NewInt(0),
		reputation:  NewInt(1),
	}
	consumptions := consumptionInfo{
		seed:    NewInt(0),
		other:   NewInt(1),
		seedIF:  NewInt(0),
		otherIF: NewInt(1),
	}
	rep := suite.rep
	newrep := rep.computeNewRepData(repData, consumptions)
	suite.EqualZero(newrep.reputation)
}