This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Quizzes & Exams

Quiz and Exam info will appear on this page.

1 - Quiz 1

Study guide for Quiz 1.

Format and Rules

  • The quiz is in class, Thursday, September 11.
  • A mix of multiple choice, fill-in-the-blank, and long answer questions.
  • You will not be programming in PyCharm, but you will be asked to edit or analyze code by hand.
  • You may bring 1 side of 1 sheet of letter paper with your own hand-written notes. No other resources are permitted.
  • An Honor Code violation on any quiz or exam results in a course grade of F.
  • Failure to submit a quiz or exam results in a course grade of F.

Content

  • Key terms from slides and labs. Look for boldfaced, underlined terms in slides and emphasized terms in labs.
  • Knowledge Checks from labs.
  • Programming Practice syntax and concepts: hand-written code (without IDE) syntax and explaining/analyzing such code.

Topics

  • Describing Operating Systems concepts (week 2).
  • CLI commands (week 2)
  • Describing the phases of the Software Lifecycle (week 3).
  • Debugging concepts and basic debugger controls (week 3).
  • Syntax and usage of programming structures from the Week 2 Programming Practice:
    • variable declaration and assignment.
    • print statements.
    • selection using if-else statements, logical operators (not, or, and), and comparison operators (<, <=, >=, >, ==, !=).
    • using a for-loop to iterate n times.
    • using a for-loop to iterate over all the elements in a list.
    • accessing the elements of a list by index.
    • defining a function with 0 or more parameters.
    • calling a function and using its return result.

2 - Quiz 2

Study guide and sample long-form problems for Quiz 2.

Format and Rules

  • The quiz is in class, Thursday, October 2.
  • A mix of multiple choice, fill-in-the-blank, and long answer questions.
  • You will not be programming in PyCharm, but you may be asked to write or edit code snippets by hand.
  • You may bring 1 side of 1 sheet of letter paper with your own hand-written notes.
  • An Honor Code violation on any quiz or exam results in a course grade of F.
  • Failure to submit a quiz or exam results in a course grade of F.

Content

  • Study key terms from slides and labs. Look for boldfaced, underlined terms in slides and emphasized terms in labs.
  • Study Knowledge Checks from labs.
  • Writing a good Problem Statement when provided a high-level description of the program goals. (week 4)
  • Testing concepts (terms) and application (weeks 4-6), including:
    • Creating a control flow graph for a given function and identifying all unique program paths.
    • Writing or analyzing unit tests for a given function, including:
      • assert statements
      • testing if exceptions are raised using pytest functions
      • writing tests that cover all unique program paths from a CFG.

Sample CFG and Testing problems

You will be asked to draw CFGs and write test cases that cover all program paths.

Disclaimer: You will have other knowledge check questions beyond these types of questions.

Sample 1

1
2
3
4
5
6
7
def is_prime(number):
    if number < 2:
        return False
    for i in range(2, int(number ** 0.5) + 1):
        if number % i == 0:
            return False
    return True
  1. Draw the CFG for this code using the conventions from class.
  2. List the unique program paths.
  3. Add assert statements to the following test case that exercise all unique program paths.
    def test_is_prime():
       # Your code here.
    

Solution

CFG for is_prime()
unique program paths

The unique edges in the path are highlighted. You do not need to highlight the unique edges on the quiz.

  1. (1, 2, 3)
  2. (1, 2, 4, 7)
  3. (1, 2, 4, 5, 6)
  4. (1, 2, 4, 5, 4, 7) or (1, 2, 4, 5, 4, 5, 6)
test case
def test_is_prime():
   # Some paths can be exercised with multiple input values. 
   # The goal is to exercise all program paths.

   assert is_prime(1) == True  # tests path (1, 2, 3)
   assert is_prime(2) == True  # path (1, 2, 4, 7)
   assert is_prime(4) == False  # path (1, 2, 4, 5, 6)
   assert is_prime(5) == True  # path (1, 2, 4, 5, 4, 7)

Sample 2

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def generate_fibonacci(n):
    if n <= 0:
        return "Error: Number of terms must be a positive integer"
    
    fibonacci_sequence = [1]
    a = 1
    b = 2
    count = 1
    
    while count < n:
        fibonacci_sequence.append(a)
        # Update values of a and b to the next numbers in the sequence
        a, b = b, a + b
        count += 1

    return fibonacci_sequence
  1. Draw the CFG for this code using the conventions from class.
  2. List the unique program paths.
  3. Add assert statements to the following test case that exercise all unique program paths.
    def test_generate_fibonacci():
       # Your code here.
    

Solution

CFG for generate_fibonacci()
unique program paths

The unique edges in the path are highlighted. You do not need to highlight the unique edges on the quiz.

  1. (14, 15, 16)
  2. (14, 15, 18-21, 23, 29)
  3. (14, 15, 18-21, 23, 24-27, 23, 29)
test case
def test_generate_fibonnaci():
   # Some paths can be exercised with multiple input values. 
   # The goal is to exercise all program paths.

   assert generate_fibonnaci(0) == "Error: Number of terms must be a positive integer"  # tests path (14, 15, 16)
   assert generate_fibonnaci(1) == [1]  # path (14, 15, 18-21, 23, 29)
   assert generate_fibonnaci(6) == [1, 1, 2, 3, 5, 8]  # path (14, 15, 18-21, 23, 24-27, 23, 29)

Sample 3

36
37
38
39
40
41
42
43
44
45
def factorial(n):
    # Input validation
    if not isinstance(n, int) or n < 0:
        return "Error: Input must be a non-negative integer"
    
    # Use iterative approach
    result = 1
    for i in range(1, n + 1):
        result *= i
    return result
  1. Draw the CFG for this code using the conventions from class.
  2. List the unique program paths.
  3. Add assert statements to the following test case that exercise all unique program paths.
    def test_factorial():
       # Your code here.
    

Solution

CFG for factorial()
unique program paths

The unique edges in the path are highlighted. You do not need to highlight the unique edges on the quiz.

  1. (36, 38, 39)
  2. (36, 38, 42, 43, 45)
  3. (36, 38, 42, 43, 44, 43, 45)
test case
def test_factorial():
   # Some paths can be exercised with multiple input values. 
   # The goal is to exercise all program paths.

   assert factorial("Alice") == "Error: Number of terms must be a positive integer"  # tests path(36, 38, 39)
   assert factorial(-1) == "Error: Number of terms must be a positive integer"  # also tests path(36, 38, 39)
   assert factorial(0) == 1  # tests path(36, 38, 42, 43, 45)
   assert factorial(5) == 120  # tests path(36, 38, 42, 43, 44, 43, 45)

3 - Quiz 3

Study guide for Quiz 3

Format and Rules

  • The quiz is in class, Thursday, Oct 30.
  • A mix of multiple choice, fill-in-the-blank, and long answer questions.
  • You will not be programming in PyCharm, but you may be asked to write or edit code snippets by hand.
  • You may bring 1 side of 1 sheet of letter paper with your own hand-written notes. No other resources are permitted.
  • An Honor Code violation on any quiz or exam results in a course grade of F.
  • Failure to submit a quiz or exam results in a course grade of F.

Content

  • Study key terms from slides and labs. Look for boldfaced, underlined terms in slides and emphasized terms in labs.
  • Study Knowledge Checks from labs.
  • Code Conventions and Documentation: Week 7 on Canvas + Labs.
    • Write a valid Python docstring for a provided function including the essential elements: description, parameters, return values, and exceptions. Syntax need not be perfect but needs to be very close.
    • Identify and correct violations of PEP8 coding conventions in provided Python code. Emphasis will be on naming conventions and whitespace within lines.
    • Given a Python function, be prepared to add type hints to function parameters and return values.
  • Filling in the blanks on a visual diagram like this one showing the state of Git repos (a) after running a set of Git commands, or (b) based on git log output.
  • Provide the appropriate git command or sequence of commands for common scenarios, including:
    • creating a new local repository
    • creating a new version
    • viewing the status of a branch
    • viewing the history of a branch
    • staging changes
    • creating a new branch
    • merging one branch into another
    • sending and retrieving changes from the remote repository
  • Explain whether or not a merge conflict would occur given a scenario.
  • Demonstrate how to resolve merge conflicts while preserving functionality.
  • The following topics from earlier in the semester are also on the table:
    • Testing concepts (terms) and application (weeks 4-6), including:
      • Writing or analyzing unit tests for a given function
      • Writing assert statements
      • Testing if exceptions are raised using pytest functions

4 - Quiz 4

Study guide for Quiz 4

Format and Rules

  • The quiz is in class, Tuesday, November 25.
  • This quiz is a mix of short & long answer questions on Canvas plus coding in PyCharm.
  • This quiz will include optional extra credit involving coding.
  • You may bring 1 double-sided sheet of letter paper with your own hand-written notes.
  • An Honor Code violation on any quiz or exam results in a course grade of F.
  • Failure to submit a quiz or exam results in a course grade of F.

Content

  • Study key terms from slides and labs. Look for boldfaced, underlined terms in slides and emphasized terms in labs.
  • Study Knowledge Checks from labs.
  • 5 Low-level program design rules: (Weeks 11-13 + accompanying Lab)
    • You do not need to know PyGame.
    • Be prepared to define the 5 rules and explain them.
    • Be prepared to analyze a given block of Python code and identify design rule violations.
    • Be prepared to fix a block of Python code that violates a design rule.
  • Designing and writing unit tests code (Weeks 5-6), including:
    • Running pytest. I will provide instructions for setting up a virtual environment and installing pytest on the lab computers.
    • Writing assert statements.
    • testing if exceptions are raised using pytest.
    • Achieving a required amount of branch coverage. I will provide instructions for generating a coverage report.
    • Identifying unique program paths through the source code. This will help you to achieve 100% branch coverage.
  • Extra credit will involve expanding on the topics above: analyzing and correcting design rule violations, and writing test cases.

Sample design problems

Design sample problem 1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def process_order(order_amount):
    if order_amount < 0:
        raise Exception("Bad value!")

    if order_amount > 1000:
        shipping = 25
    else:
        shipping = 10
    
    tax = order_amount * 0.07
    return order_amount + shipping + tax
  1. Identify which design rules are violated.
    Answer
    • 0.07, 1000, 25, and 10 are magic literals, violating Rule #1: Avoid magic literals.
    • A generic Exception is raised without specifying what was wrong, violating Rule #5: Raise specific errors and define your own if needed.
  2. Modify the code to bring it into compliance with the design rules.
    Answer
    • Assign the literals to “constant” variables, and use the variables in the computations, e.g., SHIPPING_THRESHOLD = 1000. Then later: if order_amount > SHIPPING_THRESHOLD:
    • Alternately, you could transform the literal values into function parameters, e.g., def process_order(order_amount: float, shipping_threshold: int, low_ship: int, high_ship: int, tax_rate: float):
    • Raise a more specific exception type with a better message, like raise ValueError('order amount must be greater than 0'). You could also define a custom error class and raise it.

Design sample problem 2

1
2
3
4
5
6
7
8
def create_user_profile():
    name = input("Enter your name: ")
    age = int(input("Enter your age: "))
    
    with open("profiles.txt", "a") as file:  # append to the file.
        file.write(f"{name},{age}\n")
    
    print("Profile saved.")
  1. Identify which design rules are violated.
    Answer
    • This function violates Rule #1: Avoid magic literals. The string literal profiles.txt is hardcoded.
    • This function performs input gathering, data formatting, file writing, and output display all at once. This is a violation of Rule #2: Functions should have a single responsibility.
    • You could also make some argument that the function is violating Rule #4 by not handling errors at the lowest sensible level. Since the user interface is included in this code, it would be reasonable to check that you are able to append to the file.
  2. Modify the code to bring it into compliance with the design rules.
    Answer
    • Make the filename to write to into a function parameter.
    • You should separate the code into at least two functions: a user interface and a function to write the data. Or, you could do three functions: one for input, one to write the data, and one to produce output.
    • If you want to make the code more robust, you can add some error handling and retry for a FileNotFoundError.
    • Note: There is one more input error that can occur. Can you spot it? How would you handle it?
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    def save_user_profile(name: str, age: int, filename: str):
        with open(filepath, "a") as file:  # open() will raise a FileNotFoundError if filepath doesn't exist.
            file.write(f"{name},{age}\n")
    
    def create_user_profile():
        name = input("Enter your name: ")
        age = int(input("Enter your age: "))
    
        filename = ''
        while filename == '':  # you could also say while not filename:
            try:
                filename = input("Enter the filename to append to: ")
                save_user_profile(name, age, filename)
            except FileNotFoundError:
                print("Could not find that file. Try again.")
     
        print("Profile saved.")
    

Design sample problem 3

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
def apply_clearance_discount(price: float) -> float:
    if price >= 100:
        discount = price * 0.40
    else:
        discount = price * 0.60
    return price - discount


def apply_loyalty_discount(price: float) -> float:
    if price >= 100:
        discount = price * 0.20
    else:
        discount = price * 0.10
    return price - discount


def run_discount_menu():
    while True:
        print("\n--- Discount Menu ---")
        print("1. Clearance Discount")
        print("2. Loyalty Discount")
        print("3. Exit")
        choice = input("Choose a discount type (1-3): ")

        if choice == "3":
            print("Goodbye!")
            break

        try:
            price = float(input("Enter the original price: $"))
        except ValueError:
            print("Invalid price. Please enter a number.")
            continue

        if choice == "1":
            final = apply_clearance_discount(price)
            print(f"Applying Clearance discount. Final price: ${final:.2f}")
        elif choice == "2":
            final = apply_loyalty_discount(price)
            print(f"Applying Loyalty discount. Final price: ${final:.2f}")
        else:
            print("Invalid option. Try again.")

if __name__ == "__main__":
    run_discount_menu()
  1. Identify which design rules are violated.
    Answer
    • Again we violate Rule #1: Avoid magic literals. 100 and all the float values are magic literals.
    • Of course, there are many other string literals in the user prompts and user output messages. We generally ignore these as magic literals, until you care about internationalization (i18n) and accessibility (a11y) in production systems.
    • This code clearly violates Rule #3: Don’t repeat yourself (DRY) as the functions apply_clearance_discount and apply_loyalty_discount are nearly identical.
    • You could make the argument that run_discount_menu is doing too much between showing the menu, getting user input, and displaying user output, possibly violating Rule #2: Functions should have a single responsibility. I think you could argue either way.
  2. Modify the code to bring it into compliance with the design rules.
    Answer
    • In this case, we should provide “constant” variables for the literals in our calculation to solve #1.
    • To fix Rule #3, we should combine the two discount functions and parameterize the parts that vary.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    
     def apply_discount(price: float, discount_threshold: int, above_discount: float, below_discount: float) -> float:
         if price >= discount_threshold:
             discount = price * above_discount
         else:
             discount = price * below_discount
         return price - discount
    
    
     DISCOUNT_THRESHOLD = 100
     CLEARANCE_ABOVE = 0.4
     CLEARANCE_BELOW = 0.6
     LOYALTY_ABOVE = 0.2
     LOYALTY_BELOW = 0.1
    
     def run_discount_menu():
        while True:
           print("\n--- Discount Menu ---")
           print("1. Clearance Discount")
           print("2. Loyalty Discount")
           print("3. Exit")
           choice = input("Choose a discount type (1-3): ")
    
           if choice == "3":
               print("Goodbye!")
               break
    
           try:
               price = float(input("Enter the original price: $"))
           except ValueError:
               print("Invalid price. Please enter a number.")
               continue
    
           if choice == "1":
               final = apply_discount(price, DISCOUNT_THRESHOLD, CLEARANCE_ABOVE, CLEARANCE_BELOW)
               print(f"Applying Clearance discount. Final price: ${final:.2f}")
           elif choice == "2":
               final = apply_discount(price, DISCOUNT_THRESHOLD, LOYALTY_ABOVE, LOYALTY_BELOW)
               print(f"Applying Loyalty discount. Final price: ${final:.2f}")
           else:
               print("Invalid option. Try again.")
    
     if __name__ == "__main__":
         run_discount_menu()
    

Sample Testing problems

These sample problems are the same as from Midterm 1. I will not ask you to write Control Flow Graphs for this exam, however, you may benefit from creating them to ensure you test all paths.

Testing Sample Problem 1

1
2
3
4
5
6
7
def is_prime(number):
    if number < 2:
        return False
    for i in range(2, int(number ** 0.5) + 1):
        if number % i == 0:
            return False
    return True
  • Add assert statements to the following test case that exercise all unique program paths.
    def test_is_prime():
       # Your code here.
    

Solution

unique program paths

The unique edges in the path are highlighted. You do not need to highlight the unique edges on the quiz.

  1. (1, 2, 3)
  2. (1, 2, 4, 7)
  3. (1, 2, 4, 5, 6)
  4. (1, 2, 4, 5, 4, 7) or (1, 2, 4, 5, 4, 5, 6)
test case
def test_is_prime():
   # Some paths can be exercised with multiple input values. 
   # The goal is to exercise all program paths.

   assert is_prime(1) == True  # tests path (1, 2, 3)
   assert is_prime(2) == True  # path (1, 2, 4, 7)
   assert is_prime(4) == False  # path (1, 2, 4, 5, 6)
   assert is_prime(5) == True  # path (1, 2, 4, 5, 4, 7)

Testing Sample Problem 2

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def generate_fibonacci(n):
    if n <= 0:
        return "Error: Number of terms must be a positive integer"
    
    fibonacci_sequence = [1]
    a = 1
    b = 2
    count = 1
    
    while count < n:
        fibonacci_sequence.append(a)
        # Update values of a and b to the next numbers in the sequence
        a, b = b, a + b
        count += 1

    return fibonacci_sequence
  1. List the unique program paths.
  2. Add assert statements to the following test case that exercise all unique program paths.
    def test_generate_fibonacci():
       # Your code here.
    

Solution

unique program paths

The unique edges in the path are highlighted. You do not need to highlight the unique edges on the quiz.

  1. (14, 15, 16)
  2. (14, 15, 18-21, 23, 29)
  3. (14, 15, 18-21, 23, 24-27, 23, 29)
test case
def test_generate_fibonnaci():
   # Some paths can be exercised with multiple input values. 
   # The goal is to exercise all program paths.

   assert generate_fibonnaci(0) == "Error: Number of terms must be a positive integer"  # tests path (14, 15, 16)
   assert generate_fibonnaci(1) == [1]  # path (14, 15, 18-21, 23, 29)
   assert generate_fibonnaci(6) == [1, 1, 2, 3, 5, 8]  # path (14, 15, 18-21, 23, 24-27, 23, 29)

Testing Sample Problem 3

36
37
38
39
40
41
42
43
44
45
def factorial(n):
    # Input validation
    if not isinstance(n, int) or n < 0:
        return "Error: Input must be a non-negative integer"
    
    # Use iterative approach
    result = 1
    for i in range(1, n + 1):
        result *= i
    return result
  1. List the unique program paths.
  2. Add assert statements to the following test case that exercise all unique program paths.
    def test_factorial():
       # Your code here.
    

Solution

unique program paths

The unique edges in the path are highlighted. You do not need to highlight the unique edges on the quiz.

  1. (36, 38, 39)
  2. (36, 38, 42, 43, 45)
  3. (36, 38, 42, 43, 44, 43, 45)
test case
def test_factorial():
   # Some paths can be exercised with multiple input values. 
   # The goal is to exercise all program paths.

   assert factorial("Alice") == "Error: Number of terms must be a positive integer"  # tests path(36, 38, 39)
   assert factorial(-1) == "Error: Number of terms must be a positive integer"  # also tests path(36, 38, 39)
   assert factorial(0) == 1  # tests path(36, 38, 42, 43, 45)
   assert factorial(5) == 120  # tests path(36, 38, 42, 43, 44, 43, 45)