Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring of contracts/evoting/types/ballots_test.go : #184

Merged
merged 5 commits into from
Oct 17, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions contracts/evoting/types/ballots.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ import (
"golang.org/x/xerrors"
)

const (
selectStr = "select"
rankStr = "rank"
textStr = "text"
)

// Ballot contains all information about a simple ballot
type Ballot struct {

Expand Down Expand Up @@ -81,7 +87,7 @@ func (b *Ballot) Unmarshal(marshalledBallot string, election Election) error {

switch question[0] {

case "select":
case selectStr:
selections := strings.Split(question[2], ",")

selectQ := Select{
Expand All @@ -100,7 +106,7 @@ func (b *Ballot) Unmarshal(marshalledBallot string, election Election) error {
b.SelectResultIDs = append(b.SelectResultIDs, ID(questionID))
b.SelectResult = append(b.SelectResult, results)

case "rank":
case rankStr:
ranks := strings.Split(question[2], ",")

rankQ := Rank{
Expand All @@ -118,7 +124,7 @@ func (b *Ballot) Unmarshal(marshalledBallot string, election Election) error {
b.RankResultIDs = append(b.RankResultIDs, ID(questionID))
b.RankResult = append(b.RankResult, results)

case "text":
case textStr:
texts := strings.Split(question[2], ",")

textQ := Text{
Expand Down Expand Up @@ -311,21 +317,21 @@ func (s *Subject) MaxEncodedSize() int {

//TODO : optimise by computing max size according to number of choices and maxN
for _, rank := range s.Ranks {
size += len("rank::")
size += len(rank.GetString() + "::")
size += len(rank.ID)
// at most 3 bytes (128) + ',' per choice
size += len(rank.Choices) * 4
}

for _, selection := range s.Selects {
size += len("select::")
size += len(selection.GetString() + "::")
size += len(selection.ID)
// 1 bytes (0/1) + ',' per choice
size += len(selection.Choices) * 2
}

for _, text := range s.Texts {
size += len("text::")
size += len(text.GetString() + "::")
size += len(text.ID)

// at most 4 bytes per character + ',' per answer
Expand Down Expand Up @@ -401,6 +407,7 @@ type Question interface {
GetMaxN() uint
GetMinN() uint
GetChoicesLength() int
GetString() string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case GetID() string feels more appropriate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then, you can rename selectStr to selectID, same for rank and text.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, same thing for the constants in the test file, right ?

}

func isValid(q Question) bool {
Expand All @@ -418,6 +425,11 @@ type Select struct {
Choices []string
}

// GetString implements Question
func (s Select) GetString() string {
return selectStr
}

// GetMaxN implements Question
func (s Select) GetMaxN() uint {
return s.MaxN
Expand Down Expand Up @@ -478,6 +490,10 @@ type Rank struct {
Choices []string
}

func (r Rank) GetString() string {
return rankStr
}

// GetMaxN implements Question
func (r Rank) GetMaxN() uint {
return r.MaxN
Expand Down Expand Up @@ -548,6 +564,10 @@ type Text struct {
Choices []string
}

func (t Text) GetString() string {
return textStr
}

// GetMaxN implements Question
func (t Text) GetMaxN() uint {
return t.MaxN
Expand Down
171 changes: 93 additions & 78 deletions contracts/evoting/types/ballots_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,32 @@ import (
"github.com/stretchr/testify/require"
)

var ballot1 = string("select:" + encodedQuestionID(1) + ":1,0,1\n" +
"rank:" + encodedQuestionID(2) + ":1,2,0,,\n" +
"select:" + encodedQuestionID(3) + ":1,0,1,1\n" +
"text:" + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")

var ballot2 = string("select:" + encodedQuestionID(1) + ":0,0,0\n" +
"rank:" + encodedQuestionID(2) + ":128,128,128,128\n" +
"select:" + encodedQuestionID(3) + ":0,0,0,0,0\n" +
"text:" + encodedQuestionID(4) + ":xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx," +
const (
selectStringTest = "select:"
rankStringTest = "rank:"
textStringTest = "text:"
unmarshalingRankString = "could not unmarshal rank answers: "
unmarshalingTextStringTest = "could not unmarshal text answers: "
)

// Creating a ballot for the first question, which is a select question.
var ballot1 = string(selectStringTest + encodedQuestionID(1) + ":1,0,1\n" +
rankStringTest + encodedQuestionID(2) + ":1,2,0,,\n" +
selectStringTest + encodedQuestionID(3) + ":1,0,1,1\n" +
textStringTest + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")

// Creating a ballot with the following questions:
// 1. Select one of three options
// 2. Rank four options
// 3. Select one of five options
// 4. Write two text answers
// 5. Write one text answer
var ballot2 = string(selectStringTest + encodedQuestionID(1) + ":0,0,0\n" +
rankStringTest + encodedQuestionID(2) + ":128,128,128,128\n" +
selectStringTest + encodedQuestionID(3) + ":0,0,0,0,0\n" +
textStringTest + encodedQuestionID(4) + ":xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx," +
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n" +
"text:" + encodedQuestionID(5) + ":xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,,\n\n")
textStringTest + encodedQuestionID(5) + ":xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,,\n\n")

func encodedQuestionID(i int) ID {
return ID(base64.StdEncoding.EncodeToString([]byte("Q" + strconv.Itoa(i))))
Expand Down Expand Up @@ -105,28 +120,28 @@ func TestBallot_Unmarshal(t *testing.T) {
require.EqualError(t, err, "a line in the ballot has length != 3: x")

// with ID not encoded in base64
ballotWrongID := string("select:" + "aaa" + ":1,0,1\n" +
"rank:" + encodedQuestionID(2) + ":1,2,0,,\n" +
"select:" + encodedQuestionID(3) + ":1,0,1,1\n" +
"text:" + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")
ballotWrongID := string(selectStringTest + "aaa" + ":1,0,1\n" +
rankStringTest + encodedQuestionID(2) + ":1,2,0,,\n" +
selectStringTest + encodedQuestionID(3) + ":1,0,1,1\n" +
textStringTest + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")

err = b.Unmarshal(ballotWrongID, election)
require.EqualError(t, err, "could not decode question ID: illegal base64 data at input byte 0")

// with question ID not from the election
ballotUnknownID := string("select:" + encodedQuestionID(0) + ":1,0,1\n" +
"rank:" + encodedQuestionID(2) + ":1,2,0,,\n" +
"select:" + encodedQuestionID(3) + ":1,0,1,1\n" +
"text:" + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")
ballotUnknownID := string(selectStringTest + encodedQuestionID(0) + ":1,0,1\n" +
rankStringTest + encodedQuestionID(2) + ":1,2,0,,\n" +
selectStringTest + encodedQuestionID(3) + ":1,0,1,1\n" +
textStringTest + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")

err = b.Unmarshal(ballotUnknownID, election)
require.EqualError(t, err, "wrong question ID: the question doesn't exist")

// with too many answers in select question
ballotWrongSelect := string("select:" + encodedQuestionID(1) + ":1,0,1,0,0\n" +
"rank:" + encodedQuestionID(2) + ":1,2,0,,\n" +
"select:" + encodedQuestionID(3) + ":1,0,1,1\n" +
"text:" + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")
ballotWrongSelect := string(selectStringTest + encodedQuestionID(1) + ":1,0,1,0,0\n" +
rankStringTest + encodedQuestionID(2) + ":1,2,0,,\n" +
selectStringTest + encodedQuestionID(3) + ":1,0,1,1\n" +
textStringTest + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")

election.BallotSize = len(ballotWrongSelect)

Expand All @@ -136,10 +151,10 @@ func TestBallot_Unmarshal(t *testing.T) {
" of answers: expected 3 got 5")

// with wrong format answers in select question
ballotWrongSelect = string("select:" + encodedQuestionID(1) + ":1,0,wrong\n" +
"rank:" + encodedQuestionID(2) + ":1,2,0,,\n" +
"select:" + encodedQuestionID(3) + ":1,0,1,1\n" +
"text:" + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")
ballotWrongSelect = string(selectStringTest + encodedQuestionID(1) + ":1,0,wrong\n" +
rankStringTest + encodedQuestionID(2) + ":1,2,0,,\n" +
selectStringTest + encodedQuestionID(3) + ":1,0,1,1\n" +
textStringTest + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")

election.BallotSize = len(ballotWrongSelect)

Expand All @@ -149,10 +164,10 @@ func TestBallot_Unmarshal(t *testing.T) {
"ParseBool: parsing \"wrong\": invalid syntax")

// with too many selected answers in select question
ballotWrongSelect = string("select:" + encodedQuestionID(1) + ":1,1,1\n" +
"rank:" + encodedQuestionID(2) + ":1,2,0,,\n" +
"select:" + encodedQuestionID(3) + ":1,0,1,1\n" +
"text:" + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")
ballotWrongSelect = string(selectStringTest + encodedQuestionID(1) + ":1,1,1\n" +
rankStringTest + encodedQuestionID(2) + ":1,2,0,,\n" +
selectStringTest + encodedQuestionID(3) + ":1,0,1,1\n" +
textStringTest + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")

election.BallotSize = len(ballotWrongSelect)

Expand All @@ -161,10 +176,10 @@ func TestBallot_Unmarshal(t *testing.T) {
"failed to check number of answers: question Q1 has too many selected answers")

// with not enough selected answers in select question
ballotWrongSelect = string("select:" + encodedQuestionID(1) + ":1,0,0\n" +
"rank:" + encodedQuestionID(2) + ":1,2,0,,\n" +
"select:" + encodedQuestionID(3) + ":1,0,1,1\n" +
"text:" + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")
ballotWrongSelect = string(selectStringTest + encodedQuestionID(1) + ":1,0,0\n" +
rankStringTest + encodedQuestionID(2) + ":1,2,0,,\n" +
selectStringTest + encodedQuestionID(3) + ":1,0,1,1\n" +
textStringTest + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")

election.BallotSize = len(ballotWrongSelect)

Expand All @@ -173,114 +188,114 @@ func TestBallot_Unmarshal(t *testing.T) {
"failed to check number of answers: question Q1 has not enough selected answers")

// with not enough answers in rank question
ballotWrongRank := string("select:" + encodedQuestionID(1) + ":1,0,1\n" +
"rank:" + encodedQuestionID(2) + ":1,2,0\n" +
"select:" + encodedQuestionID(3) + ":1,0,1,1\n" +
"text:" + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")
ballotWrongRank := string(selectStringTest + encodedQuestionID(1) + ":1,0,1\n" +
rankStringTest + encodedQuestionID(2) + ":1,2,0\n" +
selectStringTest + encodedQuestionID(3) + ":1,0,1,1\n" +
textStringTest + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")

err = b.Unmarshal(ballotWrongRank, election)
require.EqualError(t, err, "could not unmarshal rank answers: question"+
" Q2 has a wrong number of answers: expected 5 got 3")

// with wrong format answers in rank question
ballotWrongRank = string("select:" + encodedQuestionID(1) + ":1,0,1\n" +
"rank:" + encodedQuestionID(2) + ":1,x,0,,\n" +
"select:" + encodedQuestionID(3) + ":1,0,1,1\n" +
"text:" + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")
ballotWrongRank = string(selectStringTest + encodedQuestionID(1) + ":1,0,1\n" +
rankStringTest + encodedQuestionID(2) + ":1,x,0,,\n" +
selectStringTest + encodedQuestionID(3) + ":1,0,1,1\n" +
textStringTest + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")

election.BallotSize = len(ballotWrongRank)

err = b.Unmarshal(ballotWrongRank, election)
require.EqualError(t, err, "could not unmarshal rank answers: "+
require.EqualError(t, err, unmarshalingRankString+
"could not parse rank value for Q.Q2: strconv.ParseInt: parsing \"x\": invalid syntax")

// with too many selected answers in rank question
ballotWrongRank = string("select:" + encodedQuestionID(1) + ":1,0,1\n" +
"rank:" + encodedQuestionID(2) + ":1,2,0,3,4\n" +
"select:" + encodedQuestionID(3) + ":1,0,1,1\n" +
"text:" + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")
ballotWrongRank = string(selectStringTest + encodedQuestionID(1) + ":1,0,1\n" +
rankStringTest + encodedQuestionID(2) + ":1,2,0,3,4\n" +
selectStringTest + encodedQuestionID(3) + ":1,0,1,1\n" +
textStringTest + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")

election.BallotSize = len(ballotWrongRank)

err = b.Unmarshal(ballotWrongRank, election)
require.EqualError(t, err, "could not unmarshal rank answers: "+
require.EqualError(t, err, unmarshalingRankString+
"invalid rank not in range [0, MaxN[: 3")

// with valid ranks but one is selected twice
ballotWrongRank = string("select:" + encodedQuestionID(1) + ":1,0,1\n" +
"rank:" + encodedQuestionID(2) + ":1,2,0,2,2\n" +
"select:" + encodedQuestionID(3) + ":1,0,1,1\n" +
"text:" + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")
ballotWrongRank = string(selectStringTest + encodedQuestionID(1) + ":1,0,1\n" +
rankStringTest + encodedQuestionID(2) + ":1,2,0,2,2\n" +
selectStringTest + encodedQuestionID(3) + ":1,0,1,1\n" +
textStringTest + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")

election.BallotSize = len(ballotWrongRank)

err = b.Unmarshal(ballotWrongRank, election)
require.EqualError(t, err, "could not unmarshal rank answers: "+
require.EqualError(t, err, unmarshalingRankString+
"failed to check number of answers: question Q2 has too many selected answers")

// with not enough selected answers in rank question
ballotWrongRank = string("select:" + encodedQuestionID(1) + ":1,0,1\n" +
"rank:" + encodedQuestionID(2) + ":1,,0,,\n" +
"select:" + encodedQuestionID(3) + ":1,0,1,1\n" +
"text:" + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")
ballotWrongRank = string(selectStringTest + encodedQuestionID(1) + ":1,0,1\n" +
rankStringTest + encodedQuestionID(2) + ":1,,0,,\n" +
selectStringTest + encodedQuestionID(3) + ":1,0,1,1\n" +
textStringTest + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")

election.BallotSize = len(ballotWrongRank)

err = b.Unmarshal(ballotWrongRank, election)
require.EqualError(t, err, "could not unmarshal rank answers: "+
require.EqualError(t, err, unmarshalingRankString+
"failed to check number of answers: question"+
" Q2 has not enough selected answers")

// with not enough answers in text question
ballotWrongText := string("select:" + encodedQuestionID(1) + ":1,0,1\n" +
"rank:" + encodedQuestionID(2) + ":1,2,0,,\n" +
"select:" + encodedQuestionID(3) + ":1,0,1,1\n" +
"text:" + encodedQuestionID(4) + ":Y2VzdG1vaUVtaQ==\n\n")
ballotWrongText := string(selectStringTest + encodedQuestionID(1) + ":1,0,1\n" +
rankStringTest + encodedQuestionID(2) + ":1,2,0,,\n" +
selectStringTest + encodedQuestionID(3) + ":1,0,1,1\n" +
textStringTest + encodedQuestionID(4) + ":Y2VzdG1vaUVtaQ==\n\n")

election.BallotSize = len(ballotWrongText)

err = b.Unmarshal(ballotWrongText, election)
require.EqualError(t, err, "could not unmarshal text answers: "+
require.EqualError(t, err, unmarshalingTextStringTest+
"question Q4 has a wrong number of answers: expected 2 got 1")

// with wrong encoding in text question
ballotWrongText = string("select:" + encodedQuestionID(1) + ":1,0,1\n" +
"rank:" + encodedQuestionID(2) + ":1,2,0,,\n" +
"select:" + encodedQuestionID(3) + ":1,0,1,1\n" +
"text:" + encodedQuestionID(4) + ":wrongEncoding,Y2VzdG1vaUVtaQ==\n\n")
ballotWrongText = string(selectStringTest + encodedQuestionID(1) + ":1,0,1\n" +
rankStringTest + encodedQuestionID(2) + ":1,2,0,,\n" +
selectStringTest + encodedQuestionID(3) + ":1,0,1,1\n" +
textStringTest + encodedQuestionID(4) + ":wrongEncoding,Y2VzdG1vaUVtaQ==\n\n")

election.BallotSize = len(ballotWrongText)

err = b.Unmarshal(ballotWrongText, election)
require.EqualError(t, err, "could not unmarshal text answers: "+
require.EqualError(t, err, unmarshalingTextStringTest+
"could not decode text for Q.Q4: illegal base64 data at input byte 12")

// with too many selected answers in text question
election.Configuration.Scaffold[0].Texts[0].MaxN = 1

ballotWrongText = string("select:" + encodedQuestionID(1) + ":1,0,1\n" +
"rank:" + encodedQuestionID(2) + ":1,2,0,,\n" +
"select:" + encodedQuestionID(3) + ":1,0,1,1\n" +
"text:" + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")
ballotWrongText = string(selectStringTest + encodedQuestionID(1) + ":1,0,1\n" +
rankStringTest + encodedQuestionID(2) + ":1,2,0,,\n" +
selectStringTest + encodedQuestionID(3) + ":1,0,1,1\n" +
textStringTest + encodedQuestionID(4) + ":YmxhYmxhYmxhZg==,Y2VzdG1vaUVtaQ==\n\n")

election.BallotSize = len(ballotWrongText)

err = b.Unmarshal(ballotWrongText, election)
require.EqualError(t, err, "could not unmarshal text answers: "+
require.EqualError(t, err, unmarshalingTextStringTest+
"failed to check number of answers: question Q4 has too many selected answers")

election.Configuration.Scaffold[0].Texts[0].MaxN = 2

// with not enough elected answers in text question
ballotWrongText = string("select:" + encodedQuestionID(1) + ":1,0,1\n" +
"rank:" + encodedQuestionID(2) + ":1,2,0,,\n" +
"select:" + encodedQuestionID(3) + ":1,0,1,1\n" +
"text:" + encodedQuestionID(4) + ":,Y2VzdG1vaUVtaQ==\n\n")
ballotWrongText = string(selectStringTest + encodedQuestionID(1) + ":1,0,1\n" +
rankStringTest + encodedQuestionID(2) + ":1,2,0,,\n" +
selectStringTest + encodedQuestionID(3) + ":1,0,1,1\n" +
textStringTest + encodedQuestionID(4) + ":,Y2VzdG1vaUVtaQ==\n\n")

election.BallotSize = len(ballotWrongText)

err = b.Unmarshal(ballotWrongText, election)
require.EqualError(t, err, "could not unmarshal text answers: "+
require.EqualError(t, err, unmarshalingTextStringTest+
"failed to check number of answers: question Q4 has not enough selected answers")

// with unknown question type
Expand Down