University of Virginia, Department of Computer Science
CS201J: Engineering Software, Fall 2003

Exam 1 Out: 16 October 2003
Due: Tuesday, 21 October 2003, 12:30pm
No exams will be accepted (without prior arrangement) after 12:31pm Tuesday

Name: _________________________________________________________

Section:

___ 10 am

___ 11 am

___ noon

Comments on Exam 1

Collaboration Policy (read carefully)

Work alone. You may consult any material you want including the course notes, text and additional sources (including anything you find on the Web). If you use a source other than the course materials or text, you should cite the source in your answer.

You may not discuss this exam with any human, other than the course staff (who will answer clarification questions only). You may not use a Java compiler during this exam.

Answer all 9 questions (100 points total). Write your answers on this exam. You should not need more space than is provided to write good answers, but if you want more space you may attach extra sheets. If you do, make sure the answers are clearly marked.

There is no time limit on this exam, but it should not take more than a few hours to complete.

Background

LiveMeek Inc., is designing software for electronic voting machines. The software should:
  1. Read in a ballot description from a file. The ballot description file specifies the offices and their candidates for a particular election.
  2. Allow voters to cast ballots using a graphical user interface. A voter interacts with the software through a touch-screen display in a voting booth. For each race the voter may select zero or one candidates.
  3. Provide a count of the total number of votes cast for each candidate at the end of the election.
A modular dependency diagram for the voting machine software is shown below:
The modules are:

Design Dependencies

1. (10) If the specification of the Office class changes, which other modules need to be reconsidered?

Implementing Data Abstractions

Here is a partial implementation for the Office datatype:
import java.util.Vector;

public class Office {
   // OVERVIEW: An Office is a mutable datatype that represents an
   //     office in an election.  A typical Office is:
   //           < name, [ candidate_0, candidate_1, ..., candidate_n-1 ] >
   //     where name is a String and each candidate is a String.

   // Rep:
   private String name;
   private Vector candidates; // Vector of Strings

   // Abstraction Function:
   //   AF (r) = < name, candidates > where 
   //      name = r.name
   //      candidates = [ r.candidates[0], ..., r.candidates[r.size() - 1] ]
   // Rep Invariant:
   //   RI (r) = name != null
   //            candidates does not contain duplicates
   //                (that is, if candidates[i].equals (candidates[j]) then 
   //                 i must equal j)

   public Office (String n)
      // EFFECTS: Initializes this to < n, [ ] >.
   {
      name = n;
      candidates = new Vector ();
   }

   public void addCandidate (String c)
      // MODIFIES: this
      // EFFECTS: Adds candidate c to this.
   {
      candidates.add (c);
   }

    public Enumeration candidates () 
	// EFFECTS: Returns an enumeration that produces each candidate of this.
    { 
        // implementation not shown
    }

   public int numberOfCandidates () 
      // EFFECTS: Returns the number of candidates in this.
   {
      return candidates.size ();
   }
}
2. (10) Explain why the implementation of the addCandidate method is incorrect.







3. (10) Explain how you could change the specification of addCandidate to make the provided implementation correct.

Specifying Procedures

The ElectionResults class is partially specified below:
public class ElectionResults {
   // OVERVIEW: ElectionResults is a mutable datatype for recording the
   //    results of an election.  A typical ElectionResults is:
   //        [ < office_0, results_0 >, < office_1, results_1 >, 
   //           ..., < office_n-1, results_n-1 > ]
   //    where office_i is the name of the ith office on the ballot and
   //        results_i = [ < candidate_i_0, votes_i_0 > , 
   //                      ..., < candidate_i_m-1, votes_i_m-1 > ]
   //     is a list of the candidates for office_i and the number of
   //     votes they received.
   //
   //     For example, 
   //        [ < "Sheriff", [ < "Officer Krispy", 2043 >, < "Alice Enforcer", 3024 > ] >,
   //          < "Dog Catcher", [ < "Spot", 23 >, < "Muffy", 12 > ] > ]
   //     describes an election with two offices.  

   public void addOffice (Office o) 
      // REQUIRES: this does not contain an office with the same name as o.
      // EFFECTS: Adds the office o to this election.

   public void recordVote (String office, String candidate) 
	throws NoSuchOfficeException, InvalidCandidateException
      // MODIFIES: this
      // EFFECTS: If office does not match the name of an office in this,
      //    throws InvalidOfficeException.  If candidate does not match
      //    the name of a candidate for office, throws
      //    InvalidCandidataException.  Otherwise, increments the number
      //    of votes for candidate for office by 1.
      // 
      //    For example, if this_pre = 
      //        [ < "Sheriff", [ < "Officer Krispy", 0 >, < "Alice Enforcer", 0 > ] >,
      //          < "Dog Catcher", [ < "Spot", 3 >, < "Muffy", 4 > ] > ]
      //     and office = "Dog Catcher" and candidate = "Muffy", then
      //     this_post = 
      //        [ < "Sheriff", [ < "Officer Krispy", 0 >, < "Alice Enforcer", 0 > ] >,
      //          < "Dog Catcher", [ < "Spot", 3 >, < "Muffy", 5 > ] > ]

   public int getVotes (String office, String candidate) 
       throws NoSuchOfficeException, InvalidCandidateException 
      // EFFECTS: If office does not match the name of an office in this,
      //    throws NoSuchOfficeException.  If candidate does not match
      //    the name of a candidate for office, throws 
      //    InvalidCandidateException.  Otherwise, returns the number
      //    of votes for candidate for office.
      // 
      //    For example, if this_pre = 
      //        [ < "Sheriff", [ < "Officer Krispy", 3 >, < "Alice Enforcer", 12 > ] >,
      //          < "Dog Catcher", [ < "Spot", 3 >, < "Muffy", 4 > ] > ]
      //    getVotes ("Sheriff", "Alice Enforcer") returns 12,
      //    getVotes ("Dog Catcher", "Officer Krispy") throws InvalidCandidateException, and
      //    getVotes ("Guvernor", "Arnold S.") throws NoSuchOfficeException.
4. (10) Write a specification for a method getWinner that takes the name of an office as a parameter and returns the name of the winning candidate for office if there is one. Make sure your specification handles all possible situations.










Semantics

Below is a test client for ElectionResults datatype:
public class TestClient {
   static public void main (String args[]) {
     try {
	ElectionResults e1 = new ElectionResults ();
	Office sheriff = new Office ("Sheriff");
	sheriff.addCandidate ("Officer Krispy");
	sheriff.addCandidate ("Alice Enforcer");
	e1.addOffice (sheriff);
	Office catcher = new Office ("Dog Catcher");
	catcher.addCandidate ("Spot");
	catcher.addCandidate ("Muffy");
	e1.addOffice (catcher);
	e1.recordVote ("Dog Catcher", "Spot");
	e1.recordVote ("Dog Catcher", "Spot");
	
	ElectionResults e2 = e1;
	e2.recordVote ("Dog Catcher", "Spot");
	
	System.err.println ("Votes for Spot: " + e1.getVotes ("Dog Catcher", "Spot"));
	System.err.println ("Votes for Alice: " + e1.getVotes ("Sheriff", "Alice Enforcer"));
	System.err.println ("Votes for Bob: " + e1.getVotes ("Sheriff", "Bob Bobulus"));
     } catch (NoSuchOfficeException nso) {
	 System.err.println ("No such office!");
     } catch (InvalidCandidateException ice) {
	 System.err.println ("Invalid candidate!");
     }
  }
}

5. (10) If all code is implemented correctly according to its specification, what is the expected output of the TestClient program?

Implementing Data Abstractions

A partial implemenatation of ElectionResults (which uses two helper datatypes, CandidateRecord and OfficeResult) follows. It includes an implementation of the specification A version of recordVote. (There is a lot of code here, but you don't need to understand it all. You should read the questions first, and examine the code as necessary to answer them.)
import java.util.Vector;
import java.util.Enumeration;

class CandidateRecord {
    // OVERVIEW: A mutable datatype that records the number of votes for a 
    //     candidate.  A typical CandidateRecord is < name, votes > where
    //     name is a String that is the name of the candidate, and votes
    //     is a non-negative number that is the number of votes for the
    //     candidate.
    
    private String name;
    private int votes;
    
    // Rep invariant: 
    //     RI (r) = r.votes >= 0 && r.name != null
    
    // Abstraction function:
    //     AF (r) = < name, votes >
    
    public CandidateRecord (String n) 
	// EFFECTS: Initializes this to < n, 0 >.
    {
	name = n;
	votes = 0;
    }
    
    public void recordVote ()
	// MODIFIES: this
	// EFFECTS: Adds one vote to the vote count for this.  
	//    If this_pre = < n, c > then this_post = < n, c + 1 >.
    {
	votes++;  
    }
    
    public String getName () 
	// EFFECTS: Returns the name of this.
    {
	return name;
    }
    
    public int getVotes () 
	// EFFECTS: Returns the number of votes of this.
    {
	return votes;
    }  
}

class OfficeResult {
    // OVERVIEW: A mutable datatype that represents the result for one
    //    race.  A typical OfficeResult is
    //       < office, [ < candidate_0, votes_0 >, ..., < candidate_n-1, votes_n-1 > ] >
    
    // Rep:
    private String office;
    private Vector candidates; // A vector of CandidateRecord objects
    
    // Rep Invariant
    //   RI(r) =    r.office != null
    //           && r.candidates != null
    //           && r.candidates.elementType == \type(CandidateRecord)
    //           && no duplicate candidate names in r.candidates
    
    // Abstraction Function
    //    AF(r) = < office, [ , ..., < candidate_n-1, votes_n-1 > ] >
    //      where candidate_i = r.candidates[i].name
    //            votes_i = r.candidates[i].votes
    
    public OfficeResult (String o) 
	// EFFECTS: Initializes this to < o, [ ] >.
    {
	office = o;
	candidates = new Vector ();
    }
    
    public void addCandidate (String c) 
	// REQUIRES: c does not match the name of a candidate in this.
	// EFFECTS: Adds the candidate c to this with no votes.
	//      If this_pre = 
	//           < office, [ < candidate_0, votes_0 >, 
        //                       ..., < candidate_n-1, votes_n-1 > ]
	//      then this_post = 
	//           < office, [ < candidate_0, votes_0 >, 
        //                       ..., < candidate_n-1, votes_n-1 >, < c, 0 > ]
    {
	candidates.add (new CandidateRecord (c));
    }
    
    private CandidateRecord getRecord (String c) throws InvalidCandidateException
	// EFFECTS: If c matches the name of a candidate in this, returns 
	//     the CandidateRecord in this.candidates whos name matches c.
    {
	for (int i = 0; i < candidates.size (); i++) {
	    CandidateRecord cr = (CandidateRecord) candidates.get (i);
	    if (cr.getName ().equals (c)) {
		return cr;
	    }
	}
	
	throw new InvalidCandidateException ();
    }
    
    public String getOffice () {
	// EFFECTS: Returns the office of this.
	return office;
    }
    
    public void recordVote (String c) throws InvalidCandidateException
        // EFFECTS: If c matches the name of a candidate in this, records
	//     a vote for c.  Otherwise, throws InvalidCandidateException.
        //     If candidate_i = c, this_post.votes_i = this_pre.votes_i + 1.
    {
	try {
	    getRecord (c).recordVote ();
	} catch (InvalidCandidateException e) {
	    throw e;
	}
    }
    
    public int getVotes (String c) throws InvalidCandidateException 
        // EFFECTS: If c matches the name of a candidate in this, returns
	//     the number of votes for c.  Otherwise, throws
        //     InvalidCandidateException.  If candidate_i = c, returns
        //     votes_i.
    {
	try {
	    return getRecord (c).getVotes ();
	} catch (InvalidCandidateException e) {
	    throw e;
	}
    }
}       

public class ElectionResults {
    // OVERVIEW: ElectionResults is a mutable datatype for recording the
    //    results of an election.  A typical ElectionResults is:
    //        [ < office_0, results_0 >, < office_1, results_1 >, 
    //          ..., < office_n-1, results_n-1 > ]
    //    where office_i is the name of the ith office on the ballot and
    //        results_i = [ < candidate_i_0, votes_i_0 > , 
    //                      ..., < candidate_i_m-1, votes_i_m-1 > ]
    //     is a list of the candidates for office_i and the number of
    //     votes they received.
    //
    //     For example, 
    //        [ < "Sheriff", [ < "Officer Krispy", 2043 >, < "Alice Enforcer", 3024 > ] >,
    //          < "Dog Catcher", [ < "Spot", 23 >, < "Muffy", 12 > ] > ]
    //     describes an election with two offices.  
    
    // Rep:
    private Vector results; // A vector of OfficeResult objects
    
    // Rep Invariant:
    //     < missing >
    //
    // Abstraction Function:
    //     AF (r) = [ , ...,  ]
    //     where office_i = results[i].office
    //       and results_i = [ < candidate_i_0, votes_i_0 > ,
    //                         ..., < candidate_i_m-1, votes_i_m-1 > ]
    //            where candidate_i_0 = results[i].candidate_i
    //                  votes_i_0 = results[i].votes_i
    
    public ElectionResults ()
	// EFFECTS: Initializes this to an election with no offices.
    {
	results = new Vector ();
    }
    
    public ElectionResults (BallotDefinition bd) { } // not shown
    
    public void addOffice (Office o) 
	// REQUIRES: this does not contain an office with the same name as o.
	// EFFECTS: Adds the office o to this election.
    {
	OfficeResult or = new OfficeResult (o.getName ());
	for (Enumeration candidates = o.candidates (); candidates.hasMoreElements (); ) {
	    or.addCandidate ((String) candidates.nextElement ());
	}

	results.add (or);
    }
    
    private OfficeResult lookupOffice (String s) throws NoSuchOfficeException
	// EFFECTS: If s is the name of an office in this election,
	//    returns the OfficeResult object associated with s.
	//    Otherwise, throws NoSuchOfficeException.
							
    {
	for (Enumeration offices = results.elements (); offices.hasMoreElements (); ) {
	    OfficeResult or = (OfficeResult) offices.nextElement ();
	    if (or.getOffice ().equals (s)) {
		return or;
	    }
	}
	
	throw new NoSuchOfficeException ();
    }
    
    public void recordVote (String office, String candidate) 
	throws NoSuchOfficeException, InvalidCandidateException
       // MODIFIES: this
       // EFFECTS: If office does not match the name of an office in this,
       //    throws NoSuchOfficeException.  If candidate does not match
       //    the name of a candidate for office, throws
       //    InvalidCandidataException.  Otherwise, increments the number
       //    of votes for candidate for office by 1.
       // 
       //    For example, if this_pre = 
       //        [ < "Sheriff", [ < "Officer Krispy", 0 >, < "Alice Enforcer", 0 > ] >,
       //          < "Dog Catcher", [ < "Spot", 3 >, < "Muffy", 4 > ] > ]
       //     and office = "Dog Catcher" and candidate = "Muffy", then
       //     this_post = 
       //        [ < "Sheriff", [ < "Officer Krispy", 0 >, < "Alice Enforcer", 0 > ] >,
       //          < "Dog Catcher", [ < "Spot", 3 >, < "Muffy", 5 > ] > ]
    {
	try {
	    OfficeResult ofr = lookupOffice (office);
	    ofr.recordVote (candidate);
	} catch (NoSuchOfficeException e) {
	    throw e;
	} catch (InvalidCandidateException e) {
	    throw e;
	}
    }
    
    public int getVotes (String office, String candidate) 
        throws NoSuchOfficeException, InvalidCandidateException 
        // EFFECTS: If office does not match the name of an office in this,
        //    throws NoSuchOfficeException.  If candidate does not match
        //    the name of a candidate for office, throws 
        //    InvalidCandidateException.  Otherwise, returns the number
        //    of votes for candidate for office.
        // 
        //    For example, if this_pre = 
        //        [ < "Sheriff", [ < "Officer Krispy", 3 >, < "Alice Enforcer", 12 > ] >,
        //          < "Dog Catcher", [ < "Spot", 3 >, < "Muffy", 4 > ] > ]
        //    getVotes ("Sheriff", "Alice Enforcer") returns 12,
        //    getVotes ("Dog Catcher", "Officer Krispy") throws InvalidCandidateException, and
        //    getVotes ("Guvernor", "Arnold S.") throws NoSuchOfficeException.
    { 
	try {
	    OfficeResult ofr = lookupOffice (office);
	    return ofr.getVotes (candidate);
	} catch (NoSuchOfficeException e) {
	    throw e;
	} catch (InvalidCandidateException e) {
	    throw e;
	}
    }

    // ... other methods
}

6. (10) The rep invariant for ElectionResults below is not sufficiently strong. What term should be added to the rep invariant? (You may express your answer informally, but precisely.)
// Rep Invariant:
//    RI (r) =    r.results != null
//             && r.results.elementType == \type (OfficeResult)
//             && r.results.containsNull == false

7. (20) Implement the getWinner method you specified in question 4. Your implementation should be correct Java code, but will not lose points for minor syntax errors.

8. (10) Is it possible to perform path complete testing on your getWinner method? If so, provide a list of test cases. If not, explain why and suggest a good testing strategy.























9. (10) Mooch the Pit Bull Terrier has been assigned the task of implementing the ElectionResults module. Mooch is a good programmer, but has a strong interest in making sure Spot does not win the Dog Catcher election. You can run as many tests you want on the ElectionResults class Mooch provides, but cannot inspect the code. Either describe a sequence of black box tests you would run to verify the module is trustworthy to use in the election, or explain why it is impossible to obtain adequate confidence in Mooch's code.










10. (Optional, no credit) Do you feel your performance on this exam will fairly reflect your understanding of the course material so far? If not, explain why.







CS201J University of Virginia
Department of Computer Science
CS 201J: Engineering Software
Sponsored by the
National Science Foundation
cs201j-staff@cs.virginia.edu