For project 2, you will gain experience with using the git
distributed version control system and associated collaboration tools
on GitHub. Your task will be to correct a bug in a repository of basic
Python programs.
Often as a software engineer, you will be tasked with addressing issues that are reported by other users and developers. Depending on the nature of the project (e.g., you are contributing to an open-source project in your spare time), you might not have write permissions to the repository. In this case, you will need to use the tools discussed in class to construct a Pull Request to contribute your changes to the project. This project gives you an opportunity to practice using these tools in a low-stakes environment.
As part of this project, you must:
You may use outside resources to assist you on this assignment, but you may not use a resource that already (or nearly) solves the problem. This also means that your use of AI is restricted to assisting you with problem-solving, understanding git actions, and proofreading your commit messages. You should not be asking AI to write your commits for you. When reviewing a peer's work, your feedback should be based on your own analysis. While AI can help you understand a teammate's logic, the final evaluation of their commit organization and fix correctness must be your own.
Instead, you may use AI to give you hints about the quality of tests you write, correctness of your solution, or what an error message might mean. You are encouraged to include instructions in your AI prompts that strictly forbid it from giving you code samples but rather focuses on high-level examples and suggestions. You can also use AI to help you find typos in your commit messages and report, but you should do this to refine writing that you have already constructed yourself.
The main repository for this project is located at
https://github.com/kevinaangstadt/CS340-S26-Repo. Be sure that you are looking at the main
branch and not one that we might have used for class exercises.
This repository contains a number of python files that contain
bugs. For each python file, there is a corresponding
test_ file that contains some testing functions.
These tests are not high quality. Indeed, they miss the bugs in
the python files.
Note that you do not have write access to this repository, nor will you be granted write access to this repository. This means that you cannot push to this repository. Instead, you will need to make contributions following the techniques we discussed in class.
To get started, begin looking through the issues in the main project repository. Select one that you think you can address and comment on it to indicate that you are working on it. Your instructor will then officially "assign" you to that issue using the built-in GitHub tools. If you try to work on an issue without commenting on it first, your contributions will be rejected. You don't need to wait for the official assignment as long as you verify that you are first to comment on an issue.
Make a fork of the main project repository and clone your fork to your cloud vm. Try running all of the existing test cases to ensure things are working:
python3 -m unittest discover --verbose
(out)
(out)test_negative_input (test_absolute_flipper.TestAbsoluteFlipper.test_negative_input) ... ok
(out)test_zero_input (test_absolute_flipper.TestAbsoluteFlipper.test_zero_input) ... ok
(out)test_adult (test_age_classifier.TestAgeClassifier.test_adult) ... ok
(out)test_child (test_age_classifier.TestAgeClassifier.test_child) ... ok
(out)test_mid_teen (test_age_classifier.TestAgeClassifier.test_mid_teen) ... ok
(out)test_average_basic (test_average_calculator.TestAverageCalculator.test_average_basic) ... ok
(out)test_average_floats (test_average_calculator.TestAverageCalculator.test_average_floats) ... ok
(out)test_insufficient_funds (test_bank_transaction.TestBankTransaction.test_insufficient_funds) ... ok
(out)test_valid_withdrawal (test_bank_transaction.TestBankTransaction.test_valid_withdrawal) ... ok
(out)test_unit_dimensions (test_bmi_calculator.TestBMICalculator.test_unit_dimensions) ... ok
(out)test_freezing_point (test_celsius_converter.TestCelsiusConverter.test_freezing_point) ... ok
(out)test_radius_two (test_circle_area.TestCircleArea.test_radius_two) ... ok
(out)test_black (test_color_converter.TestColorConverter.test_black) ... ok
(out)test_white (test_color_converter.TestColorConverter.test_white) ... ok
(out)test_start_one (test_countdown_generator.TestCountdownGenerator.test_start_one) ... ok
(out)test_basic_split (test_csv_stripper.TestCSVStripper.test_basic_split) ... ok
(out)test_fifty_percent_discount (test_discount_applier.TestDiscountApplier.test_fifty_percent_discount) ... ok
(out)test_no_t (test_dna_transcriber.TestDNATranscriber.test_no_t) ... ok
(out)test_uppercase_transcription (test_dna_transcriber.TestDNATranscriber.test_uppercase_transcription) ... ok
(out)test_valid_email (test_email_extractor.TestEmailExtractor.test_valid_email) ... ok
(out)test_empty_list (test_even_filter.TestEvenFilter.test_empty_list) ... ok
(out)test_factorial_zero_one (test_factorial_calculator.TestFactorialCalculator.test_factorial_zero_one) ... ok
(out)test_path_with_slash (test_file_path_builder.TestFilePathBuilder.test_path_with_slash) ... ok
(out)test_buzz (test_fizzbuzz_utils.TestFizzBuzz.test_buzz) ... ok
(out)test_fizz (test_fizzbuzz_utils.TestFizzBuzz.test_fizz) ... ok
(out)test_number (test_fizzbuzz_utils.TestFizzBuzz.test_number) ... ok
(out)test_failing_score (test_grade_passer.TestGradePasser.test_failing_score) ... ok
(out)test_high_score (test_grade_passer.TestGradePasser.test_high_score) ... ok
(out)test_find_middle_item (test_inventory_lookup.TestInventoryLookup.test_find_middle_item) ... ok
(out)test_item_not_found (test_inventory_lookup.TestInventoryLookup.test_item_not_found) ... ok
(out)test_non_leap_year (test_leap_year_check.TestLeapYear.test_non_leap_year) ... ok
(out)test_simple_leap_year (test_leap_year_check.TestLeapYear.test_simple_leap_year) ... ok
(out)test_zero_element (test_list_doubler.TestListDoubler.test_zero_element) ... ok
(out)test_mixed_numbers (test_list_max_finder.TestListMaxFinder.test_mixed_numbers) ... ok
(out)test_positive_numbers (test_list_max_finder.TestListMaxFinder.test_positive_numbers) ... ok
(out)test_remove_separated_occurrences (test_list_modifier.TestListModifier.test_remove_separated_occurrences) ... ok
(out)test_remove_single_occurrence (test_list_modifier.TestListModifier.test_remove_single_occurrence) ... ok
(out)test_longer_sorted_list (test_median_finder.TestMedianFinder.test_longer_sorted_list) ... ok
(out)test_sorted_list (test_median_finder.TestMedianFinder.test_sorted_list) ... ok
(out)test_empty_names (test_name_combiner.TestNameCombiner.test_empty_names) ... ok
(out)test_single_name (test_name_combiner.TestNameCombiner.test_single_name) ... ok
(out)test_non_palindrome (test_palindrome_checker.TestPalindromeChecker.test_non_palindrome) ... ok
(out)test_simple_palindrome (test_palindrome_checker.TestPalindromeChecker.test_simple_palindrome) ... ok
(out)test_strong_password (test_password_validator.TestPasswordValidator.test_strong_password) ... ok
(out)test_weak_password (test_password_validator.TestPasswordValidator.test_weak_password) ... ok
(out)test_power_of_one (test_power_calculator.TestPowerCalculator.test_power_of_one) ... ok
(out)test_two_squared (test_power_calculator.TestPowerCalculator.test_two_squared) ... ok
(out)test_composite_four (test_prime_checker.TestPrimeChecker.test_composite_four) ... ok
(out)test_prime_seven (test_prime_checker.TestPrimeChecker.test_prime_seven) ... ok
(out)test_zero_dimensions (test_rectangle_geometry.TestRectangleGeometry.test_zero_dimensions) ... ok
(out)test_admin_access (test_role_checker.TestRoleChecker.test_admin_access) ... ok
(out)test_identical_sets (test_set_merger.TestSetMerger.test_identical_sets) ... ok
(out)test_free_shipping (test_shipping_calculator.TestShippingCalculator.test_free_shipping) ... ok
(out)test_standard_shipping (test_shipping_calculator.TestShippingCalculator.test_standard_shipping) ... ok
(out)test_empty_cart (test_shopping_cart.TestShoppingCart.test_empty_cart) ... ok
(out)test_single_item (test_shopping_cart.TestShoppingCart.test_single_item) ... ok
(out)test_repeat_positive (test_string_repeater.TestStringRepeater.test_repeat_positive) ... ok
(out)test_repeat_zero (test_string_repeater.TestStringRepeater.test_repeat_zero) ... ok
(out)test_long_string (test_string_truncator.TestStringTruncator.test_long_string) ... ok
(out)test_zero_rate (test_tax_adder.TestTaxAdder.test_zero_rate) ... ok
(out)test_zero_celsius (test_temperature_converter.TestTemperatureConverter.test_zero_celsius) ... ok
(out)test_returns_number (test_temperature_utils.TestTemperatureUtils.test_returns_number) ... ok
(out)test_too_short (test_username_validator.TestUsernameValidator.test_too_short) ... ok
(out)test_valid_username (test_username_validator.TestUsernameValidator.test_valid_username) ... ok
(out)test_lowercase_vowels (test_vowel_counter.TestVowelCounter.test_lowercase_vowels) ... ok
(out)test_no_vowels (test_vowel_counter.TestVowelCounter.test_no_vowels) ... ok
(out)test_simple_sentence (test_word_counter.TestWordCounter.test_simple_sentence) ... ok
(out)test_single_word (test_word_counter.TestWordCounter.test_single_word) ... ok
(out)
(out)----------------------------------------------------------------------
(out)Ran 68 tests in 0.001s
(out)
(out)OK
This just ran all the unit tests that Python could find in the project repository. You can also run a single test file (e.g., for when you are developing your own test cases):
python3 -m unittest test_age_classifier.py --verbose
(out)
(out)test_adult (test_age_classifier.TestAgeClassifier.test_adult) ... ok
(out)test_child (test_age_classifier.TestAgeClassifier.test_child) ... ok
(out)test_mid_teen (test_age_classifier.TestAgeClassifier.test_mid_teen) ... ok
(out)
(out)----------------------------------------------------------------------
(out)Ran 3 tests in 0.001s
(out)
(out)OK
Now, it's time to get started on your fix. Be sure to create and checkout a new branch for your fix. PRs submitted from the main branch of your repository will be rejected. Begin by adding a new test (or tests) to the test file associated with your issue. Confirm that the code now fails the test (thereby demonstrating the reported bug). We call this approach test-driven development. Then, work on a fix to the code that resolves the bug (passes the test) while also passing all the existing tests.
As you proceed, be sure to commit your changes and follow best practices for your commit messages!
You will be contributing to the main project repository through both issues and pull requests.
When responding to issues, please be sure to provide descriptive prose of the issue you are discussing.
You do not have write access to the main project repository. Therefore, you must make a fork of the repository and submit your contributions as pull requests. Recall our discussion of pull requests from class: you will want to provide a meaningful message with your pull request and also follow best practices for organizing your commits. Please refer to the High-Quality Commit Messages section for more details.
Create your pull requests from non-main branches. That is, create
a new branch with a descriptive name before committing your
contributions to your fork. Failure to open a pull request from a
separate branch will result in your pull request being rejected.
Note that in real projects, this isn't always necessary, but this
project is giving you a chance to practice with using
git.
Similarly, your pull request will be rejected if there are merge conflicts with the main project repository. This means you might need to update your PR to address other changes that are contributed to the repository.
As part of this project, you will be assigned one pull request from a peer to review. Your job in reviewing this PR is to:
Note that you may lose points if you approve a contribution that does not meet our guidelines or fail to adequately justify your decision.
As part of this project, you will be graded on the quality of your commit messages. Further, the quality of your commits will also be judged.
In general, we will be following the guidelines laid out here (and inlined below).
Further, look through Open Stack's Git Commit Practices for tips on how to break up commits in reasonable ways. This guide also provides some examples of high- and low-quality commit messages.
This assignment is perhaps different from any of your other CS assignments.
In some sense, we're less interested in the content
you create and more interested in the process
you follow. Further, git can be frustrating to use,
so this project gives you a fairly low-stakes venue to practice.
We are using very basic python programs so that your focus can be
on the git workflows rather than very complicated code.
You might note that your score does not actually reflect directly the quality of code that you are contributing. Instead, our focus is on the quality of the commits, issue comments, and pull request that you create. It is still in your best interest to create high-quality bug fixes, otherwise your pull request is likely to be denied. This more closely mimics the reality of a job (or grad school) where producing high-quality work is an iterative process.
While you are working on this project, keep some notes about things you learn or struggle with. This information will help you as you are writing your final reflection.
Recall that you can reorganize your commits by using git rebase
and git cherry-pick.
unittest Assertions
When writing tests with the unittest, we must use
assertion methods to trigger tests for correctness.
Depending on the nature of the bug you are addressing, you might
need to use a different assertion method than those already in the
test files. You can find a list of assertion methods in the Python documentation. For example, the following example makes sure that someFunction() produces a value that is less than 10:
self.assertLess(someFunction(), 10)
Working with floating point numbers can be challenging (take
CS-220 to understand why). Essentially, there will frequently be
rounding error. unittest allows us to handle this
with "fuzzy" matching using self.assertAlmostEqual(a, b,
places=c). For example, to check that
someFloatFunction() is approximately equal to
b within 2 decimal places, we would write:
self.assertAlmostEqual(someFloatFunction(), b, places=2)
Note that it is also reasonable to validate the return
type of a function. For example, if we want to check that
someFunction() returns a string, we could write:
self.assertIsInstance(someFunction(), str)
If you need to check that a piece of code raises an exception, you
can use the assertRaises method (see here for more details).
Using this method is different from using the
assertEqual method.
We use it as part of a context manager, which is a
special type of block in Python that allows us to set up some
context for the code we are testing. The syntax looks like this:
with self.assertRaises(SomeException):
# code that should raise SomeException goes here
doTheBadThing()
In this example, we are asserting that the code inside the
with block raises an exception of type
SomeException. If the code does not raise an
exception, or if it raises a different type of exception, then the
test will fail.
In addition to peer feedback (part of Checkpoint 2) and instructor feedback, the main project repository is configured to provide automated feedback on your pull request. When you create a pull request (and for any subsequent push), GitHub will run some basic checks on your contribution. You can see the results of these checks in the feed for your PR. If any of these checks fail, you will need to address the issues before your PR can be merged. You can click on the details for any failed check to get more information about what went wrong.
This automation will check for:
Note that just because your code passes these automated checks does not necessarily mean that your contribution is correct. You should still be sure to review your code and test cases carefully before submitting your pull request.
You must also write a short two-paragraph report reflecting on your
experience contributing to a git repository. In addition to these
two paragraphs, your report should also contain references for any
resources you used to help complete this assignment.
The first paragraph should contain an overview of the issue you selected, the nature of the bug you repaired, and the additional tests you developed to reveal the bug.
The second paragraph should address the challenges you faced and concepts you learned. Rather than write this as a chronological narrative, organize your prose around key themes. If a particular task took you a while or took you multiple tries to get correct, focus some of your description here.
Finally, your written report should contain your list of references used for completing this assignment.
Submit this report as a PDF on Gradescope. Any other format may cause you to lose points on this asignment.
By the checkpoint deadline:
You do not need to submit any files to Gradescope for the checkpoint. You will be graded based on your contributions to the main project repository.
By the checkpoint deadline:
You do not need to submit any files to Gradescope for the checkpoint. You will be graded based on your contributions to the main project repository.
For the final project submission, you should submit your written report on Gradescope.
P2 Grading (out of 45 points):