Pyret Testing Design and Clarity Guide

Testing

  1. All functions require examples/test cases, including helper functions. Functions that output images require examples; all other functions require test cases.
  2. Examples/test cases should reflect various input scenarios so that you exercise the possible main behaviors of your function
  3. Even if your function does not work as expected, you can still write examples/test cases for it and receive full testing credit.

Example of good testing:

fun abs-val(x :: Number) -> Number:
  doc: "Give the absolute value of the input number"
  ... # i never figured this function out
where:
  abs-val(-4) is 4 # test the first branch of the if
  abs-val(0) is 0  # 0 is an "edge case"
  abs-val(3) is 3  # test the else branch of the if
end

A handin with this work would receive full testing points.

Design

  1. Use constants where appropriate. rectangle(500, 300, "solid", "green") should be rewritten to:
    width = 500
    rectangle(width, 3/5 * width, "solid", "green")
    
  2. Use helper functions where appropriate.
    stairs = beside-align("bottom", rectangle(50, 50, "solid", "gray"),
     beside-align("bottom", rectangle(50, 100, "solid", "gray"),
       beside-align("bottom", rectangle(50, 150, "solid", "gray"),
         rectangle(50, 200, "solid", "gray"))))
    

could be rewritten as:

stair-width = 50
fun stair(height :: Number) -> Image:
  doc: "make an individual stair given its height"
  rectangle(stair-width, height, "solid", "gray")
end

stairs = beside-align("bottom", stair(50),
  beside-align("bottom", stair(100),
    beside-align("bottom", stair(150), stair(200))))
  1. Make sure your helper functions and constants are not redundant.
    There is no point in making this function:
    fun string-lower(s :: String) -> String:
      string-to-lower(s)
    end
    
    since you could always use string-to-lower instead.

Clarity

  1. Write docstrings for all functions, including helper and nested functions.
    A good docstring gives a qualitative description of the function, including its input(s) and output.

  2. Give constants and helper functions useful names.

    n1 = 3.1415
    n2 = 500
    n3 = 30
    fun helper(x):
      x + 3
    end
    

    should be rewritten as (for example)

    pi = 3.1415
    flag-width = 500
    circle-radius = 30
    fun add-3(x):
      x + 3
    end
    
  3. All functions require type annotations on both inputs and output.

  4. Names of constants and functions should be lower case and dash separated. For configuration constants (for example the height of a character) it is acceptable to use all caps dash-separated names.

    # Good Pyret Style:
    flag-width = 500
    width-to-height-ratio = 3/5
    CHARACTER-HEIGHT = 40
    
    # Bad Pyret Style:
    flag_width = 500
    widthHeightRatio = 3/5
    CharacterHeight = 40
    
  5. Keep lines under 80 characters. You will at some point see a vertical dashed blue line in Pyret.
    img

    If you see this line, your lines are too long and you need to add linebreaks (press enter at places in your code).

    The 80 character limit applies even when you have long strings and/or docstrings. Long docstrings can be written using the backtick (`) button:

    fun f()
      doc: ``` this is a really
           long docstring, I don't know
           what the point is but... at least it's
           under 80 characters :) ```
      2
    end
    
  6. Indent your code properly. You can do this by pressing ctrl-a then tab on Windows and Linux, or cmd-a then tab on Mac.