feat: allow filling a proposal tally with a default grade

Building brick for future tally balancers, can already be used as-is.
main
Dominique Merle 3 years ago
parent 7b4642d832
commit 7cacd78ac9

@ -4,14 +4,19 @@ import "fmt"
type PollTally struct {
AmountOfJudges uint64 // Helps balancing tallies using default judgments.
Proposals []*ProposalTally // Tallies of each proposal. The order is preserved in the result.
Proposals []*ProposalTally // Tallies of each proposal. Its order is preserved in the result.
}
type ProposalTally struct {
//Total uint64 // Total amount of judgments received by this proposal, including all grades.
Tally []uint64 // Amount of judgments received for each grade, from "worst" grade to "best" grade.
}
func (proposalTally *ProposalTally) Analyze() (_ *ProposalAnalysis) {
analysis := &ProposalAnalysis{}
analysis.Run(proposalTally, true)
return analysis
}
func (proposalTally *ProposalTally) Copy() (_ *ProposalTally) {
// There might exist an elegant one-liner to copy a slice of uint64
intTally := make([]uint64, 0, 8)
@ -37,7 +42,7 @@ func (proposalTally *ProposalTally) CountAvailableGrades() (_ uint8) {
return uint8(len(proposalTally.Tally))
}
// This mutates the proposalTally.
// Mutates the proposalTally.
func (proposalTally *ProposalTally) RegradeJudgments(fromGrade uint8, intoGrade uint8) (err error) {
if fromGrade == intoGrade {
return nil
@ -57,8 +62,22 @@ func (proposalTally *ProposalTally) RegradeJudgments(fromGrade uint8, intoGrade
return nil
}
func (proposalTally *ProposalTally) Analyze() (_ *ProposalAnalysis) {
analysis := &ProposalAnalysis{}
analysis.Run(proposalTally, true)
return analysis
// Mutates the proposalTally
func (proposalTally *ProposalTally) FillWithStaticDefault(upToAmount uint64, defaultGrade uint8) (err error) {
// More silent integer casting awkwardness… ; we need to fix this
missingAmount := int(upToAmount) - int(proposalTally.CountJudgments())
if missingAmount < 0 {
return fmt.Errorf("FillWithStaticDefault() upToAmount is lower than the actual amount of judgments")
} else if missingAmount == 0 {
return nil
}
if defaultGrade >= proposalTally.CountAvailableGrades() {
return fmt.Errorf("FillWithStaticDefault() defaultGrade is higher than the amount of available grades")
}
proposalTally.Tally[defaultGrade] += uint64(missingAmount)
return nil
}

@ -1,6 +1,7 @@
package judgment
import (
"fmt"
"github.com/stretchr/testify/assert"
"testing"
)
@ -33,7 +34,7 @@ func TestProposalTally_RegradeJudgmentsIntoSelf(t *testing.T) {
func TestProposalTally_RegradeJudgments_Failure1(t *testing.T) {
proposalTally := ProposalTally{Tally: []uint64{1, 2, 3, 4, 5, 6, 7}}
err := proposalTally.RegradeJudgments(0, 60)
err := proposalTally.RegradeJudgments(0, uint8(len(proposalTally.Tally)))
assert.Error(t, err, "Regrading should fail")
assert.Equal(t, uint64(1), proposalTally.Tally[0])
assert.Equal(t, uint64(2), proposalTally.Tally[1])
@ -56,3 +57,53 @@ func TestProposalTally_RegradeJudgments_Failure2(t *testing.T) {
assert.Equal(t, uint64(6), proposalTally.Tally[5])
assert.Equal(t, uint64(7), proposalTally.Tally[6])
}
func TestProposalTally_FillWithStaticDefault(t *testing.T) {
proposalTally := ProposalTally{Tally: []uint64{1, 2, 3, 4, 5, 6, 7}}
expectedTally := ProposalTally{Tally: []uint64{3, 2, 3, 4, 5, 6, 7}}
err := proposalTally.FillWithStaticDefault(30, 0)
assert.NoError(t, err, "Filling should succeed")
for i := 0; i < 7; i++ {
assert.Equal(t, expectedTally.Tally[i], proposalTally.Tally[i], fmt.Sprintf("Grade #%d", i))
}
}
func TestProposalTally_FillWithStaticDefaultNotZero(t *testing.T) {
proposalTally := ProposalTally{Tally: []uint64{0, 1, 0, 1, 0, 0, 1}}
expectedTally := ProposalTally{Tally: []uint64{0, 1, 1, 1, 0, 0, 1}}
err := proposalTally.FillWithStaticDefault(4, 2)
assert.NoError(t, err, "Filling should succeed")
for i := 0; i < 7; i++ {
assert.Equal(t, expectedTally.Tally[i], proposalTally.Tally[i], fmt.Sprintf("Grade #%d", i))
}
}
func TestProposalTally_FillWithStaticDefaultNoop(t *testing.T) {
proposalTally := ProposalTally{Tally: []uint64{0, 1, 2, 1, 0, 0, 1}}
expectedTally := ProposalTally{Tally: []uint64{0, 1, 2, 1, 0, 0, 1}}
err := proposalTally.FillWithStaticDefault(5, 5)
assert.NoError(t, err, "Filling should succeed")
for i := 0; i < 7; i++ {
assert.Equal(t, expectedTally.Tally[i], proposalTally.Tally[i], fmt.Sprintf("Grade #%d", i))
}
}
func TestProposalTally_FillWithStaticDefaultFailureGradeTooHigh(t *testing.T) {
proposalTally := ProposalTally{Tally: []uint64{0, 1, 0, 1, 2, 3, 4}}
expectedTally := ProposalTally{Tally: []uint64{0, 1, 0, 1, 2, 3, 4}}
err := proposalTally.FillWithStaticDefault(12, 200)
assert.Error(t, err, "Filling should fail")
for i := 0; i < 7; i++ {
assert.Equal(t, expectedTally.Tally[i], proposalTally.Tally[i], fmt.Sprintf("Grade #%d", i))
}
}
func TestProposalTally_FillWithStaticDefaultFailureAmountToLow(t *testing.T) {
proposalTally := ProposalTally{Tally: []uint64{0, 1, 0, 1, 2, 3, 4}}
expectedTally := ProposalTally{Tally: []uint64{0, 1, 0, 1, 2, 3, 4}}
err := proposalTally.FillWithStaticDefault(5, 0)
assert.Error(t, err, "Filling should fail")
for i := 0; i < 7; i++ {
assert.Equal(t, expectedTally.Tally[i], proposalTally.Tally[i], fmt.Sprintf("Grade #%d", i))
}
}

Loading…
Cancel
Save