コード例 #1
0
        public void AddBallotTest()
        {
            // add a ballot style with 3 contests (5 cands, 6 cands and 7 cands
            // respectively)
            objTest.AddStpBallotBallot(1, new int[] { 5, 6, 7 }, 0, 0);

            // add a second ballot style with 1 contest (100 candidates)
            // for contest ids, start from 3 since, there are already 3 contests
            // for candidate ids, start from (5+6+7) since that's the number of
            // candidates already in the collection
            objTest.AddStpBallotBallot(2, new int[] { 100 }, 3, 5 + 6 + 7);

            // add header texts for the contests of the first ballot style
            // (2 texts, 1 text and 2 texts respectively)
            objTest.AddStpContBallot(new int[] { 2, 1, 2 }, 0);
            objTest.AddStpContBallot(new[] { 3 }, 3);

            // add candidate texts for all candidates
            objTest.AddStpCandBallot(5 + 6 + 7 + 100);

            // load parameters from DB
            objTest.LoadStpParams();
            this.objTest.SetTarget(0.12, 0.08, 0, 0, 0.0035, 100);

            int         selectedId = 1;
            PaperBallot ballot     = new PaperBallot(
                objTest.ballots, objTest.contests, objTest.candidates,
                objTest.parameters, objTest.target, selectedId);

            Ballot doBallot = ballot.ExportPositions();

            Assert.IsNotEmpty(doBallot.Cards[0].Faces);

            DefinitionBinder binder = new DefinitionBinder();

            binder.AddBallot(doBallot);

            // assert that the first ballot has at least 1 card
            // this proves that the binder properly created a ballot
            // (domain object) for the specified paper ballot and added a
            // card to it
            Assert.IsNotNull(binder.Ballots[0].Cards[0]);

            // but that card has no faces even though the exported ballot
            // (doBallot) has faces there
            Assert.IsNull(binder.Ballots[0].Cards[0].Faces);

            // assert that the cards collection is not empty
            // This proves the binder extracted the cards from the given ballot
            // and populated the card collection
            Assert.IsNotEmpty(binder.Cards);

            // assert that the faces collection is not empty
            // This proves the binder properly extracted the faces from the
            // given ballot and
            Assert.IsNotEmpty(binder.Faces);
        }
コード例 #2
0
        public void ExportPositionsTest()
        {
            this.mockData.AddStpBallotBallot(1, new int[] { 5, 6, 7 }, 0, 0);
            this.mockData.AddStpBallotBallot(
                2, new int[] { 100 }, 3, 5 + 6 + 7);

            this.mockData.AddStpContBallot(new int[] { 2, 1, 2 }, 0);
            this.mockData.AddStpContBallot(new[] { 3 }, 3);

            this.mockData.AddStpCandBallot(5 + 6 + 7 + 100);

            this.mockData.LoadStpParams();
            BallotPdfTestObject.SetIdentifierFace(
                this.mockData.parameters, PaperSide.Front);

            this.mockData.SetTarget(0.12, 0.08, 0, 0, 0.0035, 100);

            int         selectedId = 1;
            PaperBallot ballot     = new PaperBallot(
                this.mockData.ballots,
                this.mockData.contests,
                this.mockData.candidates,
                this.mockData.parameters,
                this.mockData.target,
                selectedId);

            Ballot doBallot = ballot.ExportPositions();

            Assert.IsNotNull(doBallot);
            Assert.IsNotEmpty(doBallot.Cards);
            Assert.AreEqual(doBallot.BallotStyleId, selectedId);
            Assert.IsNotEmpty(doBallot.Cards[0].Faces);
            Assert.AreEqual(doBallot.Cards[0].Faces[0].Marks.Count, 5 + 6 + 7);

            List <int> markIds   = new List <int>();
            bool       uniqueIds = true;

            foreach (Card card in doBallot.Cards)
            {
                foreach (Face face in card.Faces)
                {
                    markIds.Clear();
                    uniqueIds = true;
                    foreach (Mark mark in face.Marks)
                    {
                        uniqueIds = uniqueIds &&
                                    (markIds.Contains(mark.Id) == false);
                        markIds.Add(mark.Id);
                    }

                    Assert.IsTrue(uniqueIds);
                }
            }
        }
コード例 #3
0
        /// <summary>
        ///     Generates the PDF files for all ballots.
        /// </summary>
        /// <param name="outputFolder">The output folder.</param>
        /// <param name="bar">The progress bar.</param>
        /// <externalUnit/>
        /// <revision revisor="dev11" date="2/26/2009" version="1.0.8.0901">
        ///     Member Created
        /// </revision>
        /// <revision revisor="dev11" date="03/04/2009" version="1.0.8.1501">
        ///     Added progress bar support
        /// </revision>
        private void GeneratePdfFiles(string outputFolder, ProgressBar bar)
        {
            // a given paper ballot
            PaperBallot ballot;

            // the file name of every page (PDF file name)
            string[] files;

            // the pages to print for the current paper ballot
            List <int> pages = new List <int>();

            // set the progress bar if available
            // step is the progress value
            int step = 0;

            if (bar != null)
            {
                // each key corresponds to a ballot that is generated
                ProgressBar_SetMaximum(bar, this.dicBallots.Keys.Count);
            }

            foreach (KeyValuePair <PaperBallot, string[]> pair in
                     this.dicBallots)
            {
                ballot = pair.Key;
                files  = pair.Value;
                pages.Clear();
                for (int i = 0; i < files.Length; i = i + 1)
                {
                    if (!File.Exists(Path.Combine(outputFolder, files[i])))
                    {
                        // do not generate the same PDF twice. Each PDF is for
                        // just 1 page
                        pages.Add(i);
                    }
                }

                ballot.Draw(
                    outputFolder,
                    PaperBallot.GetPdfFilename(ballot),
                    pages.ToArray());

                // update progress bar if available
                if (bar != null)
                {
                    step = step + 1;
                    ProgressBar_SetValue(bar, step);
                }
            }
        }
コード例 #4
0
        /// <summary>
        ///     Adds a ballot to the binder. This method identifies common
        ///     faces, so that they can be reused reducing the final set of PDFs
        /// </summary>
        /// <param name="ballot">The ballot.</param>
        /// <externalUnit/>
        /// <revision revisor="dev11" date="2/25/2009" version="1.0.8.0801">
        ///     Member Created
        /// </revision>
        public void AddBallot(PaperBallot ballot)
        {
            // get the faces of this ballot
            List <PaperFace> faces = PaperBallot.GetFaces(ballot);

            // get the filenames for all the faces of the ballot
            PaperFace face;

            string[] files = Pdf.CreatePdfFilenames(
                PaperBallot.GetPdfFilename(ballot),
                faces.Count);
            string md5, filename;

            // for each face, find it in the lookup dictionary. If it is found,
            // it means that an identical face has already been created, so
            // don't include it when generating the PDF files and replace the
            // filename for the exisiting one
            if (this.dicBallots.ContainsKey(ballot) == false)
            {
                // add the ballot to the dictionary along with its set of
                // file names
                this.dicBallots.Add(ballot, files);
            }

            for (int i = 0; i < faces.Count; i = i + 1)
            {
                // PaperFace <-->  filename
                // faces[0]  <-->  files[0]
                // faces[1]  <-->  files[1]
                // ...
                face     = faces[i];
                filename = files[i];
                md5      = BitConverter.ToString(ObjectMD5.Generate(face));
                if (this.dicFaces.ContainsKey(md5) == false)
                {
                    // this is a new face that up to this point no other ballot
                    // has, so add it to the dictionary for future comparison
                    // to subsequent ballots
                    this.dicFaces.Add(md5, filename);
                }
                else
                {
                    // an identical face is already in use, so to the current
                    // ballot assign that face and replace the duplicate
                    files[i] = this.dicFaces[md5];
                }
            }
        }
コード例 #5
0
        /// <summary>
        ///     Generates the CSV map.
        /// </summary>
        /// <param name="outputFolder">The output folder.</param>
        /// <externalUnit/>
        /// <revision revisor="dev11" date="2/26/2009" version="1.0.8.0901">
        ///     Member Created
        /// </revision>
        private void GenerateCsvMap(string outputFolder)
        {
            StreamWriter strWriter =
                File.CreateText(Path.Combine(outputFolder, this.csvFilename));

            // a given paper ballot
            PaperBallot ballot;

            // the file name of every page (PDF file name)
            string[] files;

            // write the column headers
            string line = "Ballot,Files";

            strWriter.WriteLine(line);

            // now for each ballot, add a line to the file
            foreach (KeyValuePair <PaperBallot, string[]> pair in
                     this.dicBallots)
            {
                ballot = pair.Key;
                files  = pair.Value;

                line = PaperBallot.GetPdfFilename(ballot);

                foreach (string file in files)
                {
                    line = line + "," + file;
                }

                strWriter.WriteLine(line);
            }

            strWriter.Flush();
            strWriter.Close();
        }
コード例 #6
0
        public void ConstructorTest()
        {
            this.mockData.AddStpBallotBallot(1, new int[] { 5, 6, 7 }, 0, 0);
            this.mockData.AddStpBallotBallot(
                2, new int[] { 100 }, 3, 5 + 6 + 7);

            this.mockData.AddStpContBallot(new int[] { 2, 1, 2 }, 0);
            this.mockData.AddStpContBallot(new[] { 3 }, 3);

            this.mockData.AddStpCandBallot(5 + 6 + 7 + 100);

            this.mockData.LoadStpParams();
            this.mockData.SetTarget(0.12, 0.08, 0, 0, 0.0035, 100);

            PaperBallot ballot = new PaperBallot(
                this.mockData.ballots,
                this.mockData.contests,
                this.mockData.candidates,
                this.mockData.parameters,
                this.mockData.target,
                1);

            Assert.IsTrue(true);
        }
コード例 #7
0
        public void FaceReductionTest_OddFacesWithBarcodeInTheBack()
        {
            // add a ballot style with 2 contests, each contest has 2 candidates
            // ballot style 3
            // contest 1
            // candidate 1
            // candidate 2
            // contest 2
            // candidate 3
            // candidate 4
            this.mockData.AddStpBallotContest(3, 1, 1, 0, 2, 1);

            // add a page break on this contest to place it entirely on another
            // face. (contest display format == 1 means page break)
            this.mockData.AddStpBallotContest(3, 2, 2, 1, 2, 3);

            // add a second ballot style
            // ballot style 4
            // contest 1
            // candidate 1
            // candidate 2
            // contest 3
            // candidate 5
            // candidate 6
            this.mockData.AddStpBallotContest(4, 1, 1, 0, 2, 1);

            // add a page break on this contest to place it entirely on another
            // face. At this point, front faces are identical for both ballots
            // back faces are not
            this.mockData.AddStpBallotContest(4, 3, 3, 1, 2, 5);

            // add a third face to test that a 4th empty face is added just for
            // the barcode
            this.mockData.AddStpBallotContest(4, 4, 4, 1, 10, 7);

            // now add header texts for all contests
            // 4 contests, 1 text per contest, first id is 1
            this.mockData.AddStpContBallot(new int[] { 1, 1, 1, 1 }, 1);

            // add candidate texts for all candidates
            // 16 candidates total, first candidate id is 1
            this.mockData.AddStpCandBallot(16, 1);

            // load parameters from DB
            this.mockData.LoadStpParams();
            this.mockData.SetTarget(0.12, 0.08, 0, 0, 0.0035, 100);

            // make sure the barcode location is on the back of the paper
            BallotPdfTestObject.SetIdentifierFace(
                this.mockData.parameters, PaperSide.Back);

            // make sure that at least 1 field is included on the barcode
            BallotPdfTestObject.SetIdentifierMask(this.mockData.parameters, 1);

            int cardCount = 0, faceCount = 0;

            // create paper ballot objects for both ballot styles
            PaperBallot ballot1 = new PaperBallot(
                this.mockData.ballots,
                this.mockData.contests,
                this.mockData.candidates,
                this.mockData.parameters,
                this.mockData.target,
                3,
                cardCount,
                faceCount);

            // for the second ballot, we already have 1 card and 2 faces
            cardCount += ballot1.CardCount;
            faceCount += ballot1.FaceCount;
            PaperBallot ballot2 = new PaperBallot(
                this.mockData.ballots,
                this.mockData.contests,
                this.mockData.candidates,
                this.mockData.parameters,
                this.mockData.target,
                4,
                cardCount,
                faceCount);

            // create a paper binder
            PaperBinder binder = new PaperBinder();

            binder.AddBallot(ballot1);
            binder.AddBallot(ballot2);

            binder.Generate(OutputFolder);

            // wait a few seconds to let the PDF library flush all docs
            System.Threading.Thread.Sleep(4000);

            string[] files = Directory.GetFiles(OutputFolder, "*.pdf");

            // 1 face is reused, and 1 blank face is added so 5 files
            // should be found
            Assert.AreEqual(5, files.Length);
        }
コード例 #8
0
        public void FaceReductionTest_AllDifferent()
        {
            // add a ballot style with 2 contests, each contest has 2 candidates
            // ballot style 1
            // contest 1
            // candidate 1
            // candidate 2
            // contest 2
            // candidate 3
            // candidate 4
            this.mockData.AddStpBallotContest(1, 1, 1, 0, 2, 1);

            // add a page break on this contest to place it entirely on another
            // face. (contest display format == 1 means page break)
            this.mockData.AddStpBallotContest(1, 2, 2, 1, 2, 3);

            // add a second ballot style
            // ballot style 2
            // contest 1
            // candidate 1
            // candidate 2
            // contest 3
            // candidate 5
            // candidate 6
            this.mockData.AddStpBallotContest(2, 1, 1, 0, 2, 1);

            // add a page break on this contest to place it entirely on another
            // face. At this point, front faces are identical for both ballots
            // back faces are not
            this.mockData.AddStpBallotContest(2, 3, 3, 1, 2, 5);

            // now add header texts for all contests
            // 3 contests, 1 text per contest, first id is 1
            this.mockData.AddStpContBallot(new int[] { 1, 1, 1 }, 1);

            // add candidate texts for all candidates
            // 6 candidates total, first candidate id is 1
            this.mockData.AddStpCandBallot(6, 1);

            // load parameters from DB
            this.mockData.LoadStpParams();
            this.mockData.SetTarget(0.12, 0.08, 0, 0, 0.0035, 100);

            // make sure the barcode location is on the front of the paper
            // take the parameters entry set and set the IdentifierLocation
            // parameter to Front
            BallotPdfTestObject.SetIdentifierFace(
                this.mockData.parameters, PaperSide.Front);

            // make sure that at least 1 field is included on the barcode
            BallotPdfTestObject.SetIdentifierMask(this.mockData.parameters, 1);

            // create paper ballot objects for both ballot styles
            PaperBallot ballot1 = new PaperBallot(
                this.mockData.ballots,
                this.mockData.contests,
                this.mockData.candidates,
                this.mockData.parameters,
                this.mockData.target,
                1,
                0,
                0),

            // for the second ballot, we already have 1 card and
            // 2 faces
                        ballot2 = new PaperBallot(
                this.mockData.ballots,
                this.mockData.contests,
                this.mockData.candidates,
                this.mockData.parameters,
                this.mockData.target,
                2,
                1,
                2);

            // create a paper binder
            PaperBinder binder = new PaperBinder();

            binder.AddBallot(ballot1);
            binder.AddBallot(ballot2);

            binder.Generate(OutputFolder);

            // wait a few seconds to let the PDF library flush all docs
            System.Threading.Thread.Sleep(4000);

            string[] files = Directory.GetFiles(OutputFolder, "*.pdf");
            Assert.AreEqual(4, files.Length);
        }
コード例 #9
0
        public void DrawTest()
        {
            this.mockData.AddStpBallotBallot(1, new int[] { 5, 6, 7 }, 0, 0);
            this.mockData.AddStpBallotBallot(
                2, new int[] { 100 }, 3, 5 + 6 + 7);

            this.mockData.AddStpContBallot(new int[] { 2, 1, 2 }, 0);
            this.mockData.AddStpContBallot(new[] { 3 }, 3);

            this.mockData.AddStpCandBallot(5 + 6 + 7 + 100);

            this.mockData.LoadStpParams();
            mockData.SetParameter("TargetType", 2);
            mockData.SetParameter("TargetLayout", "Right");
            this.mockData.SetTarget(0.12, 0.08, 0, 0, 0.003, 100);

            PaperBallot ballot = new PaperBallot(
                this.mockData.ballots,
                this.mockData.contests,
                this.mockData.candidates,
                this.mockData.parameters,
                this.mockData.target,
                2);

            ballot.ElectionInfo =
                new PaperBallotElectionInfo(
                    BallotPdfTestObject.ConnectionString);

            fileName = "myballot.pdf";
            if (File.Exists(fileName))
            {
                File.Delete(fileName);
            }

            ballot.Draw(fileName);
            Assert.IsTrue(File.Exists(fileName));

            string path = Path.Combine(
                AppDomain.CurrentDomain.BaseDirectory,
                @"..\..\TestData\"),
                   otherFileName = "myOtherBallot";

            fullPath = Path.Combine(path, otherFileName + "_01.pdf");

            if (File.Exists(fullPath))
            {
                File.Delete(fullPath);
            }

            ballot.Draw(path, otherFileName + ".pdf");
            Assert.IsTrue(File.Exists(fullPath));

            otherFileName = "myOtherTxmlBallot";
            fullPath      = Path.Combine(path, otherFileName + "_01.pdf");
            PaperBallotRichTextTemplate template =
                new PaperBallotRichTextTemplate(
                    @"..\..\..\BallotPdf\BallotTemplates.xml");

            ballot.Template        = template;
            ballot.BallotStyleName = "MyMunicipality";
            ballot.PrecinctName    = "MyPrecinct";

            if (File.Exists(fullPath))
            {
                File.Delete(fullPath);
            }

            ballot.Draw(path, otherFileName + ".pdf");
            Assert.IsTrue(File.Exists(fullPath));

            ballot.IsAudioBallot = true;
            ballot.Draw(path, "audioballot.pdf");
        }
コード例 #10
0
        public void FaceReductionTest_OddFacesWithBarcodeInTheBack()
        {
            // add a ballot style with 2 contests, each contest has 2 candidates
            // ballot style 1
            // contest 1
            // candidate 1
            // candidate 2
            // contest 2
            // candidate 3
            // candidate 4
            this.objTest.AddStpBallotContest(1, 1, 1, 0, 2, 1);

            // add a page break on this contest to place it entirely on another
            // face. (contest display format == 1 means page break)
            this.objTest.AddStpBallotContest(1, 2, 2, 1, 2, 3);

            // add a second ballot style
            // ballot style 2
            // contest 1
            // candidate 1
            // candidate 2
            // contest 3
            // candidate 5
            // candidate 6
            this.objTest.AddStpBallotContest(2, 1, 1, 0, 2, 1);

            // add a page break on this contest to place it entirely on another
            // face. At this point, front faces are identical for both ballots
            // back faces are not
            this.objTest.AddStpBallotContest(2, 3, 3, 1, 2, 5);

            // add a third face to test that a 4th empty face is added just for
            // the barcode
            this.objTest.AddStpBallotContest(2, 4, 4, 1, 10, 7);

            // now add header texts for all contests
            // 4 contests, 1 text per contest, first id is 1
            this.objTest.AddStpContBallot(new int[] { 1, 1, 1, 1 }, 1);

            // add candidate texts for all candidates
            // 16 candidates total, first candidate id is 1
            this.objTest.AddStpCandBallot(16, 1);

            // load parameters from DB
            this.objTest.LoadStpParams();
            this.objTest.SetTarget(0.12, 0.08, 0, 0, 0.0035, 100);

            // make sure the barcode location is on the back of the paper
            BallotPdfTestObject.SetIdentifierFace(
                this.objTest.parameters, PaperSide.Back);

            // make sure that at least 1 field is included on the barcode
            BallotPdfTestObject.SetIdentifierMask(this.objTest.parameters, 1);

            // create paper ballot objects for both ballot styles
            PaperBallot ballot1 = new PaperBallot(
                this.objTest.ballots,
                this.objTest.contests,
                this.objTest.candidates,
                this.objTest.parameters,
                this.objTest.target,
                1,
                1,
                1),

            // for the second ballot, we already have 1 card and
            // 2 faces
                        ballot2 = new PaperBallot(
                this.objTest.ballots,
                this.objTest.contests,
                this.objTest.candidates,
                this.objTest.parameters,
                this.objTest.target,
                2,
                2,
                3);

            ballot1.Precinct = 1;
            ballot2.Precinct = 2;

            // create a definition binder and add both ballots
            // the definition binder should be smart enough to notice that the
            // first face of both ballot cards are identical, resulting in only
            // 3 faces for 2 cards, 1 card per ballot
            DefinitionBinder binder = new DefinitionBinder();

            binder.AddBallot(ballot1.ExportPositions());
            binder.AddBallot(ballot2.ExportPositions());

            // generated PDFs to manually compare barcodes
            PaperBinder binder2 = new PaperBinder();

            binder2.AddBallot(ballot1);
            binder2.AddBallot(ballot2);
            binder2.Generate(@"..\..\TestData");

            // save files for further inspection
            this.objTest.Serialize(
                @"..\..\TestData\Ballots.B.xml",
                binder.Ballots,
                typeof(BallotList));
            this.objTest.Serialize(
                @"..\..\TestData\Cards.B.xml", binder.Cards, typeof(CardList));
            this.objTest.Serialize(
                @"..\..\TestData\Faces.B.xml", binder.Faces, typeof(FaceList));

            // check the results
            // 3 faces expected, not 4 even though there are 2 cards,
            // 2 faces each
            Assert.AreEqual(5, binder.Faces.Count);

            // 3 cards, 1 + 2
            Assert.AreEqual(3, binder.Cards.Count);

            // the second face of both cards are the same
            Assert.AreEqual(binder.Cards[0].Faces[1].Id,
                            binder.Cards[1].Faces[1].Id);

            // verify face ids
            Assert.AreEqual(1, binder.Cards[0].Faces[0].Id);
            Assert.AreEqual(2, binder.Cards[0].Faces[1].Id);

            // the second card reuses the first face
            Assert.AreEqual(3, binder.Cards[1].Faces[0].Id);
            Assert.AreEqual(2, binder.Cards[1].Faces[1].Id);
            Assert.AreEqual(5, binder.Cards[2].Faces[0].Id);

            // an additional blank face just for the barcode
            Assert.AreEqual(6, binder.Cards[2].Faces[1].Id);

            // verify card ids
            Assert.AreEqual(1, binder.Cards[0].Id);
            Assert.AreEqual(2, binder.Cards[1].Id);
            Assert.AreEqual(3, binder.Cards[2].Id);

            // verify ballot ids
            Assert.AreEqual(1, binder.Ballots[0].Id);
            Assert.AreEqual(2, binder.Ballots[1].Id);
        }
コード例 #11
0
        public void FaceReductionTest()
        {
            // add a ballot style with 2 contests, each contest has 2 candidates
            // ballot style 1
            // contest 1
            // candidate 1
            // candidate 2
            // contest 2
            // candidate 3
            // candidate 4
            this.objTest.AddStpBallotContest(1, 1, 1, 0, 2, 1);

            // add a page break on this contest to place it entirely on another
            // face. (contest display format == 1 means page break)
            this.objTest.AddStpBallotContest(1, 2, 2, 1, 2, 3);

            // add a second ballot style
            // ballot style 2
            // contest 1
            // candidate 1
            // candidate 2
            // contest 3
            // candidate 5
            // candidate 6
            this.objTest.AddStpBallotContest(2, 1, 1, 0, 2, 1);

            // add a page break on this contest to place it entirely on another
            // face. At this point, front faces are identical for both ballots
            // back faces are not
            this.objTest.AddStpBallotContest(2, 3, 3, 1, 2, 5);

            // now add header texts for all contests
            // 3 contests, 1 text per contest, first id is 1
            this.objTest.AddStpContBallot(new int[] { 1, 1, 1 }, 1);

            // add candidate texts for all candidates
            // 6 candidates total, first candidate id is 1
            this.objTest.AddStpCandBallot(6, 1);

            // load parameters from DB
            this.objTest.LoadStpParams();
            this.objTest.SetTarget(0.12, 0.08, 0, 0, 0.0035, 100);

            // make sure the barcode location is on the front of the paper
            BallotPdfTestObject.SetIdentifierFace(
                this.objTest.parameters, PaperSide.Front);

            // create paper ballot objects for both ballot styles
            PaperBallot ballot1 = new PaperBallot(
                this.objTest.ballots,
                this.objTest.contests,
                this.objTest.candidates,
                this.objTest.parameters,
                this.objTest.target,
                1,
                0,
                0),

            // for the second ballot, we already have 1 card and
            // 2 faces
                        ballot2 = new PaperBallot(
                this.objTest.ballots,
                this.objTest.contests,
                this.objTest.candidates,
                this.objTest.parameters,
                this.objTest.target,
                2,
                1,
                2);

            // create a definition binder and add both ballots
            // the definition binder should be smart enough to notice that the
            // first face of both ballot cards are identical, resulting in only
            // 3 faces for 2 cards, 1 card per ballot
            DefinitionBinder binder = new DefinitionBinder();

            binder.AddBallot(ballot1.ExportPositions());
            binder.AddBallot(ballot2.ExportPositions());

            // save files for further inspection
            this.objTest.Serialize(
                @"..\..\TestData\Ballots.xml",
                binder.Ballots,
                typeof(BallotList));
            this.objTest.Serialize(
                @"..\..\TestData\Cards.xml", binder.Cards, typeof(CardList));
            this.objTest.Serialize(
                @"..\..\TestData\Faces.xml", binder.Faces, typeof(FaceList));

            // check the results
            // 3 faces expected, not 4 even though there are 2 cards, 2 \
            // faces each
            Assert.AreEqual(3, binder.Faces.Count);

            // 2 cards, 1 for each ballot style
            Assert.AreEqual(2, binder.Cards.Count);

            // the first face of both cards are the same
            Assert.AreEqual(
                binder.Cards[0].Faces[0].Id,
                binder.Cards[1].Faces[0].Id);

            // verify face ids
            Assert.AreEqual(0, binder.Cards[0].Faces[0].Id);
            Assert.AreEqual(1, binder.Cards[0].Faces[1].Id);
            Assert.AreEqual(0, binder.Cards[1].Faces[0].Id);
            Assert.AreEqual(3, binder.Cards[1].Faces[1].Id);

            // verify card ids
            Assert.AreEqual(0, binder.Cards[0].Id);
            Assert.AreEqual(1, binder.Cards[1].Id);

            // verify ballot ids
            Assert.AreEqual(1, binder.Ballots[0].Id);
            Assert.AreEqual(2, binder.Ballots[1].Id);

            // verify ballot style ids
            Assert.AreEqual(1, binder.Ballots[0].BallotStyleId);
            Assert.AreEqual(2, binder.Ballots[1].BallotStyleId);
        }