Skip to content

Commit

Permalink
feat: encode yes/no votes to allow recording overvotes
Browse files Browse the repository at this point in the history
This is a BREAKING CHANGE in the CVR format.

Refs votingworks/vxmail#37
  • Loading branch information
eventualbuddha committed Jun 1, 2020
1 parent 65dbe60 commit 11537be
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 32 deletions.
36 changes: 20 additions & 16 deletions apps/module-scan/src/endToEndHmpb.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ test('going through the whole process works', async () => {
const CVRs: CastVoteRecord[] = exportResponse.text
.split('\n')
.map((line) => JSON.parse(line))
const p1CVR = CVRs.find((cvr) => cvr['us-senate'])!
const p1CVR = CVRs.find(
(cvr) => Array.isArray(cvr['us-senate']) && cvr['us-senate'].length > 0
)!
const p2CVR = CVRs.find((cvr) => cvr !== p1CVR)!

delete p1CVR._ballotId
Expand All @@ -102,17 +104,17 @@ test('going through the whole process works', async () => {
"_ballotStyleId": "77",
"_precinctId": "42",
"_testBallot": false,
"dallas-city-council": "",
"dallas-county-commissioners-court-pct-3": "",
"dallas-county-proposition-r": "",
"dallas-county-retain-chief-justice": "",
"dallas-city-council": Array [],
"dallas-county-commissioners-court-pct-3": Array [],
"dallas-county-proposition-r": Array [],
"dallas-county-retain-chief-justice": Array [],
"dallas-county-sheriff": Array [
"chad-prda",
],
"dallas-county-tax-assessor": Array [
"john-ames",
],
"dallas-mayor": "",
"dallas-mayor": Array [],
"texas-house-district-111": Array [
"writein",
],
Expand All @@ -132,19 +134,21 @@ test('going through the whole process works', async () => {
"_ballotStyleId": "77",
"_precinctId": "42",
"_testBallot": false,
"dallas-city-council": "",
"dallas-city-council": Array [],
"dallas-county-commissioners-court-pct-3": Array [
"andrew-jewell",
],
"dallas-county-proposition-r": "no",
"dallas-county-retain-chief-justice": "",
"dallas-county-sheriff": "",
"dallas-county-tax-assessor": "",
"dallas-mayor": "",
"texas-house-district-111": "",
"texas-sc-judge-place-6": "",
"us-house-district-30": "",
"us-senate": "",
"dallas-county-proposition-r": Array [
"no",
],
"dallas-county-retain-chief-justice": Array [],
"dallas-county-sheriff": Array [],
"dallas-county-tax-assessor": Array [],
"dallas-mayor": Array [],
"texas-house-district-111": Array [],
"texas-sc-judge-place-6": Array [],
"us-house-district-30": Array [],
"us-senate": Array [],
}
`)
}
Expand Down
20 changes: 10 additions & 10 deletions apps/module-scan/src/interpreter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,13 @@ test('interprets marks on a HMPB', async () => {
expect.objectContaining({
_ballotStyleId: '77',
_precinctId: '42',
'dallas-city-council': '',
'dallas-county-commissioners-court-pct-3': '',
'dallas-county-proposition-r': '',
'dallas-county-retain-chief-justice': '',
'dallas-city-council': [],
'dallas-county-commissioners-court-pct-3': [],
'dallas-county-proposition-r': [],
'dallas-county-retain-chief-justice': [],
'dallas-county-sheriff': ['chad-prda'],
'dallas-county-tax-assessor': ['john-ames'],
'dallas-mayor': '',
'dallas-mayor': [],
'texas-house-district-111': ['writein'],
'texas-sc-judge-place-6': ['jane-bland'],
'us-house-district-30': ['eddie-bernice-johnson'],
Expand Down Expand Up @@ -115,13 +115,13 @@ test('interprets marks on an upside-down HMPB', async () => {
expect.objectContaining({
_ballotStyleId: '77',
_precinctId: '42',
'dallas-city-council': '',
'dallas-county-commissioners-court-pct-3': '',
'dallas-county-proposition-r': '',
'dallas-county-retain-chief-justice': '',
'dallas-city-council': [],
'dallas-county-commissioners-court-pct-3': [],
'dallas-county-proposition-r': [],
'dallas-county-retain-chief-justice': [],
'dallas-county-sheriff': ['chad-prda'],
'dallas-county-tax-assessor': ['john-ames'],
'dallas-mayor': '',
'dallas-mayor': [],
'texas-house-district-111': ['writein'],
'texas-sc-judge-place-6': ['jane-bland'],
'us-house-district-30': ['eddie-bernice-johnson'],
Expand Down
12 changes: 6 additions & 6 deletions apps/module-scan/src/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,17 @@ import {
Election,
getContests,
Optional,
OptionalYesNoVote,
YesNoVote,
} from '@votingworks/ballot-encoder'
import { Interpreter as HMPBInterpreter } from '@votingworks/hmpb-interpreter'
import { detect as qrdetect } from '@votingworks/qrdetect'
import makeDebug from 'debug'
import { readFile as readFileCallback } from 'fs'
import { decode as decodeJpeg } from 'jpeg-js'
import { decode as quircDecode } from 'node-quirc'
import { promisify } from 'util'
import { CastVoteRecord } from './types'

import makeDebug from 'debug'

const debug = makeDebug('module-scan:interpreter')

export interface InterpretFileParams {
Expand All @@ -47,7 +46,6 @@ interface InterpretBallotStringParams {
function ballotToCastVoteRecord(
ballot: CompletedBallot
): CastVoteRecord | undefined {
// TODO: Replace all this with a `CompletedBallot` -> `CastVoteRecord` mapper.
const { election, ballotStyle, precinct, ballotId, isTestBallot } = ballot

// figure out the contests
Expand All @@ -64,11 +62,13 @@ function ballotToCastVoteRecord(
for (const contest of contests) {
// no answer for a particular contest is recorded in our final dictionary as an empty string
// not the same thing as undefined.
let cvrForContest: string | string[] = ''
let cvrForContest: string[] = []
const vote = ballot.votes[contest.id]

if (contest.type === 'yesno') {
cvrForContest = (vote as OptionalYesNoVote) || ''
if (vote) {
cvrForContest = [vote as YesNoVote]
}
} else if (contest.type === 'candidate') {
// selections for this question
const candidates = vote as Optional<CandidateVote>
Expand Down

0 comments on commit 11537be

Please sign in to comment.