Specify and implement election structure.
Showing
3 changed files
with
122 additions
and
6 deletions
... | @@ -10,12 +10,14 @@ | ... | @@ -10,12 +10,14 @@ |
10 | * | 10 | * |
11 | * @constructor | 11 | * @constructor |
12 | * @property {Candidate[]} candidateList | 12 | * @property {Candidate[]} candidateList |
13 | * @property {String[]} votes | ||
13 | * @property {Number} numberOfCandidates | 14 | * @property {Number} numberOfCandidates |
14 | * | 15 | * |
15 | */ | 16 | */ |
16 | function RelativePlacement() { | 17 | function RelativePlacement() { |
17 | Object.defineProperties(this, { | 18 | Object.defineProperties(this, { |
18 | candidateList: {value: {}}, | 19 | candidateList: {value: {}}, |
20 | votes: {value: []}, | ||
19 | numberOfCandidates: {get: () => Object.keys(this.candidateList).length} | 21 | numberOfCandidates: {get: () => Object.keys(this.candidateList).length} |
20 | }); | 22 | }); |
21 | } | 23 | } |
... | @@ -43,15 +45,50 @@ | ... | @@ -43,15 +45,50 @@ |
43 | } | 45 | } |
44 | }; | 46 | }; |
45 | 47 | ||
46 | RelativePlacement.prototype.addVote = function () {}; | 48 | /** |
49 | * @name addVote | ||
50 | * @param {String[]} vote | ||
51 | * @methodOf RelativePlacement | ||
52 | * @this RelativePlacement | ||
53 | */ | ||
54 | RelativePlacement.prototype.addVote = function (vote) { | ||
55 | if(vote.length != this.numberOfCandidates) | ||
56 | throw new Error('The vote and the candidate list have not the same size.'); | ||
57 | |||
58 | var candidates = Object.keys(this.candidateList); | ||
59 | var controlMask = Math.pow(2,candidates.length)-1; | ||
60 | var checkMask = 0; | ||
61 | |||
62 | for(let i = 0; i < vote.length; i++){ | ||
63 | var index = candidates.indexOf(vote[i]); | ||
64 | if(index == -1) throw new Error('The candidate "'+vote[i]+"' is not present in candidate list."); | ||
65 | checkMask |= Math.pow(2, index); | ||
66 | } | ||
67 | |||
68 | if(checkMask != controlMask) throw new Error('Candidate must be unique in each vote.'); | ||
69 | |||
70 | this.votes.push(vote); | ||
71 | for(let i = 0; i < vote.length; i++){ | ||
72 | let candidate = this.candidateList[vote[i]]; | ||
73 | candidate.votes.push(i); | ||
74 | } | ||
75 | }; | ||
47 | RelativePlacement.prototype.addVotes = function () {}; | 76 | RelativePlacement.prototype.addVotes = function () {}; |
48 | RelativePlacement.prototype.getResult = function () {}; | 77 | RelativePlacement.prototype.getResult = function () {}; |
49 | 78 | ||
79 | /** | ||
80 | * | ||
81 | * @param name | ||
82 | * @constructor | ||
83 | * @property {String} name | ||
84 | * @property {Number[]} votes | ||
85 | * @property {Number[]} placements | ||
86 | */ | ||
50 | function Candidate(name) { | 87 | function Candidate(name) { |
51 | Object.defineProperties(this, { | 88 | Object.defineProperties(this, { |
52 | name: {value: name, enumerable: true}, | 89 | name: {value: name, enumerable: true}, |
53 | votes: {value:[], enumerable: true}, | 90 | votes: {value:[], enumerable: true}, |
54 | placement: {value:[], enumerable: false} | 91 | placements: {value:[], enumerable: true, writable: true} |
55 | }); | 92 | }); |
56 | } | 93 | } |
57 | 94 | ... | ... |
... | @@ -32,9 +32,9 @@ describe('RelativePlacement', () => { | ... | @@ -32,9 +32,9 @@ describe('RelativePlacement', () => { |
32 | assert.equal(1, election.numberOfCandidates); | 32 | assert.equal(1, election.numberOfCandidates); |
33 | assert.deepEqual({ | 33 | assert.deepEqual({ |
34 | name: 'foo', | 34 | name: 'foo', |
35 | votes:[] | 35 | votes:[], |
36 | placements: [] | ||
36 | }, election.candidateList['foo']); | 37 | }, election.candidateList['foo']); |
37 | assert.deepEqual([], election.candidateList['foo'].placement); | ||
38 | }); | 38 | }); |
39 | 39 | ||
40 | it('should add some candidates', () => { | 40 | it('should add some candidates', () => { |
... | @@ -44,16 +44,86 @@ describe('RelativePlacement', () => { | ... | @@ -44,16 +44,86 @@ describe('RelativePlacement', () => { |
44 | 44 | ||
45 | assert.deepEqual({ | 45 | assert.deepEqual({ |
46 | name: 'foo', | 46 | name: 'foo', |
47 | votes:[] | 47 | votes:[], |
48 | placements: [] | ||
48 | }, election.candidateList['foo']); | 49 | }, election.candidateList['foo']); |
49 | assert.deepEqual({ | 50 | assert.deepEqual({ |
50 | name: 'bar', | 51 | name: 'bar', |
51 | votes:[] | 52 | votes:[], |
53 | placements: [] | ||
52 | }, election.candidateList['bar']); | 54 | }, election.candidateList['bar']); |
53 | }); | 55 | }); |
54 | 56 | ||
55 | it('should not add a same candidate multiple time', () => { | 57 | it('should not add a same candidate multiple time', () => { |
58 | assert.equal(0, election.numberOfCandidates); | ||
59 | election.addCandidate('foo'); | ||
60 | assert.equal(1, election.numberOfCandidates); | ||
61 | assert.throws(()=>{ | ||
62 | election.addCandidate('foo'); | ||
63 | }, (err) => { | ||
64 | return err instanceof Error && /already exist/.test(err.message); | ||
65 | }, | ||
66 | 'unexpected error' | ||
67 | ); | ||
68 | assert.equal(1, election.numberOfCandidates); | ||
69 | }); | ||
70 | }); | ||
71 | |||
72 | describe('Add votes', () => { | ||
73 | var election; | ||
74 | |||
75 | beforeEach(()=> { | ||
76 | election = new RelativePlacement(); | ||
77 | election.addCandidates(['A','B','C']); | ||
78 | }); | ||
79 | |||
80 | it('should add a vote to each candidates', () => { | ||
81 | var vote = ['A','B','C']; | ||
82 | election.addVote(['A','B','C']); | ||
83 | for(let i = 0; i < vote.length; i++){ | ||
84 | let candidate = election.candidateList[vote[i]]; | ||
85 | assert.equal(candidate.votes.length, 1, 'number of candidates vote'); | ||
86 | assert.equal(candidate.votes[0], i, 'value of candidates vote'); | ||
87 | } | ||
88 | }); | ||
89 | |||
90 | it('should has same sizes between candidate list and vote', () => { | ||
91 | assert.throws(() => { | ||
92 | election.addVote(['A','B']); | ||
93 | }, | ||
94 | err => err instanceof Error && /same size/.test(err.message), | ||
95 | 'smaller vote' | ||
96 | ); | ||
97 | assert.equal(election.votes.length, 0, 'no vote registered'); | ||
98 | assert.equal(election.candidateList['A'].votes.length, 0, 'no vote registered in candidate'); | ||
99 | |||
100 | assert.throws(() => { | ||
101 | election.addVote(['A','B','C','D']); | ||
102 | }, | ||
103 | err => err instanceof Error && /same size/.test(err.message), | ||
104 | 'bigger vote' | ||
105 | ); | ||
106 | assert.equal(election.votes.length, 0, 'no vote registered'); | ||
107 | assert.equal(election.candidateList['A'].votes.length, 0, 'no vote registered in candidate'); | ||
108 | }); | ||
109 | |||
110 | it('should not has unknown candidate in vote', () => { | ||
111 | assert.throws(() => { | ||
112 | election.addVote(['A','B','D']); | ||
113 | }, | ||
114 | err => err instanceof Error && /not present/.test(err.message)); | ||
115 | |||
116 | assert.equal(election.votes.length, 0, 'no vote registered'); | ||
117 | assert.equal(election.candidateList['A'].votes.length, 0, 'no vote registered in candidate'); | ||
118 | }); | ||
56 | 119 | ||
120 | it('should has an unique vote by candidate', () => { | ||
121 | assert.throws(() => { | ||
122 | election.addVote(['A','B','A']); | ||
123 | }, | ||
124 | err => err instanceof Error && /unique/.test(err.message)); | ||
125 | assert.equal(election.votes.length, 0, 'no vote registered'); | ||
126 | assert.equal(election.candidateList['A'].votes.length, 0, 'no vote registered in candidate'); | ||
57 | }); | 127 | }); |
58 | }); | 128 | }); |
59 | }); | 129 | }); |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
-
Please register or sign in to post a comment