--- tags: hw, spr22 --- # Homework 1C (CS 17/111/112/19): Lists and Mutation :::info In order to complete this assignment, you must have already completed HW1B. In this homework, we'll be building on top of classes that we've created in the previous homeworks, and you will need to copy your class implementations from previous assignments. ::: :::info We will open this assignment for submission in Gradescope sometime Tuesday. We are still finishing configuring the autograder around the changed assignment contents. ::: ### Due: Friday, February 11th, 2022 at 11:59pm ET **Collaboration Policy:** *You may collaborate as much as you want on this assignment* (this is more flexible than the normal course policy). The goal is to get everyone up to speed on functional programming. You are required to turn this in, but it will be weighted lightly in final grades. That said, we strongly encourage you to actively try writing these on your own while collaborating, as assignments after we come back together will assume you can do these sorts of problems on your own. ## Learning Objectives - To practice working with Java's built-in lists - To practice structuring code around access modifiers - To practice using Java types to control the ability to perform certain computations ## Setup Using [this GitHub Classroom link](https://classroom.github.com/a/0polb0UK), accept the assignment and clone on your machine. If you're having trouble with IntelliJ, our [First Time Setup Guide](https://hackmd.io/7azYQstzS4a6udptmaADCw) includes a common bugs/FAQ section. Please make sure to read [our Gradescope submission guide](https://hackmd.io/oTbF1IUuRs27VgVJF4z2rA) before handing in your assignment! ## Style Expectations For all future assignments, including this one, we expect your code to conform to the [CS200 Java Style Guide](https://hackmd.io/io7Gock2TZqC6UnBwpjP2w). # Problems In the last assignment, we created a `GradeReport` class. Now, it's time to set up the gradebook for an entire class, as well as the ability to manage (and update) grades. We also want to support `Faculty` teaching multiple courses. ### More Courses **Task:** Edit your `Faculty` class so that the field that stores what they are teaching could be a `LinkedList` of `Course` rather than a single `Course`. You'll have to update the constructor and perhaps other methods that worked on the previous field type as well. *If you need to check whether a specific `Course` object is in a faculty member's list of courses, use the `LinkedList` method `contains` which takes an object and returns a boolean.* ### [Creating a Gradebook](https://www.youtube.com/watch?v=UECeJzd-G30&ab_channel=BethDittoVEVO) **Task:** Add a `gradebook` field to the `Course` class. It should be of type `LinkedList<GradeReport>`. This field should be initialized to an empty list within the `Course` constructor. Reminder that to use this, you will need the following import statement at the top of your `Course.java`: ```=java import java.util.LinkedList; ``` ### Adding Grades **Task:** Add a method named `storeGrade` to the `Course` class. The method should take in a`Student` and a valid grade (`LetterGrade` or `SNCGrade` from assignment 1B). The method should result in updating the `Course`'s `gradebook` to include a `GradeReport` for the corresponding student. You may assume that the student doesn't already have a grade in the Gradebook. ### Looking up GradeReports **Task:** Create a method`findGradeReport` in the `Course` class that takes the name of a student and returns the `gradeReport` of the named student in the course. The method should return `null` if the student is not in the course. Mark this method as `private` (replacing `public` with `private` at the start of the method header.) <!-- You can access helpful methods in the LinkedList documentation [at this link](https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html). --> ### Updating Grades **Task:** Add a method named `updateGrade` to the `Course` class. The method should take in the name of a student (String) and a valid grade. The method should result in the new grade being stored in the gradebook for the given student. If the student does not have a grade, throw a `RuntimeException` with the message `"no grade for student"`. **Note:** Java has different kinds of exceptions for different kinds of errors. For now, we will use a `RuntimeException` for any error related to the logic of the program or system being represented (as opposed to `IllegalArgumentException` which we use when an input is not from an expected set of values). ```=java throw new RuntimeException(<insert error message>); ``` ***Hint:** Use previous problems as helpers!* ### Finding Students in a Gradebook **Task:** Add a method called `gradeLookup` to the `Course` class. The method should take a `Faculty` or `TA` object and a student name as input. * If `gradebook` has a `GradeReport` for the given student name, the method should return a `String` representation of the grade. * If the given `Faculty` or `TA` is not teaching the course, throw a `RuntimeException` with the message ``"permission denied"``. * If no such grade is found, a `RuntimeException` with the message `"student <NAME> not found"` should be thrown (where `"<NAME>"` is replaced with the student name being searched for). In cases where both exceptions would apply, throw the permission denied exception. *Part of the point of the question is for you to think about how to take an argument that can be `Faculty` or `TA`, but not a general `Student`. (We've covered everything you need in order to do this. **You may NOT use `instanceOf`**).* ### Identifying Students in Trouble **Task:** Add a method `reportsWithC` to the `Course` class. The method should return a list of `GradeReport` from the course `gradebook` in which the grade is the letter `C`. *The point of this question is for you to practice using good object-oriented code organization to check attribute of objects. **You should NOT use getters to do this**.* **Note:** In order to write this, you will need to be able to check whether two grades are the same. Lab 2 gave a quick introduction to writing `equals` methods, but IntelliJ will also generate `equals` methods for you automatically. If you start typing `public boolean equals` in a class, IntelliJ will give you a popup that asks whether it should generate "equals and hashcode methods". Click through doing that (just ignore or delete the generated `hashcode` method). You can also grab the equals methods by expanding the below spoiler arrow. :::spoiler Equals methods for `LetterGrade` and `SNCGrade` Note: you may have to edit the field names in these methods, depending on what you used in your class. Those edits would be in the last line of each of these methods. For `LetterGrade.java` ```=java @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || this.getClass() != o.getClass()) return false; LetterGrade that = (LetterGrade) o; return this.grade == that.grade; } ``` For `SNCGrade.java` ```=java @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || this.getClass() != o.getClass()) return false; SNCGrade sncGrade = (SNCGrade) o; return this.pass == sncGrade.pass && this.passDistinction == sncGrade.passDistinction; } ``` ::: ### Protecting Grade Information Grade information is sensitive, and hence should be kept private. Other information may also be sensitive. Mark all of the fields in `GradeReport`, `Student`, `Faculty`, and `Course` as `private`. If this breaks some of your existing code, create additional methods as needed to restore your code to working. ***Hint:** Do this in stages: mark a couple of fields private and make sure your code will still run. Repeat until you've marked all of the fields. If you followed the "no getters" rule until now, your code should work without anything breaking.* :::info You will learn about `private` annotations in lab this week. In a nutshell, marking a field `private` means that the field cannot simply be accessed from outside the class by writing `object.field`. Instead, you have to provide a method in the field's class that will perform the desired computation (you should not just hand the field out through a simple "getter" method, for those who already know that term). ::: <!-- THIS IS MOVING TO LAB ### [Course Equality](https://www.youtube.com/watch?v=WpYeekQkAdc&ab_channel=BlackEyedPeasVEVO) :::spoiler Click here for a small review on the difference between `==` and an `equals` method We have been using the `==` operator to check for equality between two objects. The way Java handles this in the back is by checking whether the object on the left hand side holds the same place in memory as the object on the right hand side. This can cause some unexpected behavior. For example, ```=java Course course1 = new Course("CSCI", 200); Course course2 = new Course("CSCI", 200); course1 == course2; // false ``` For our purposes, this isn't what we mean when we ask if two courses are equal (the same). Therefore, Java allows us to write an `equals` method to give our own conditions to check if two objects are equal. *Adapted from an EdStem post written by Isabel Lai* ::: **Task:** Write an `equals` method on `Course` that checks only the department and number. We've provided the generic format for an `equals` method below to get you started. Modify the below `equals` method for `Course` class so that it returns `true` if the input object is a `Course` and has the same department and number as the `Course` object the method is being called on. ```=Java @Override public boolean equals(Object obj) { // This is the generic format for an equals method. You will learn more about // this format in class. For now, all you have to worry about is the final // return statement. if (obj == this) { return true; } if (!(obj instanceof Course)) { return false; } Course m = (Course) obj; // TODO: modify the following return statement. You don't want this to always // return false! You should be comparing this course to Course m. return false; } ``` **Note:** make sure to change uses of `==` with `Course`s (like in `Student` or `TA`) to `.equals()` now that you have implemented an `equals` method for `Course`! ### [Mutation/aliasing example](https://www.youtube.com/watch?v=jwWR1cQTKyw&ab_channel=TaylorSwiftVEVO) :::warning @Kathi @Milda We're unsure about this task in regards how we should write this test (e.g. which methods we expect students to use) ::: Two faculty teaching the same course. Two ways to construct it (two different course objects vs a shared course object). Write a test that can tell the two situations apart.[REWORD] --> ## [Testing](https://www.youtube.com/watch?v=CduA0TULnow) :::info **Note**: When writing your test suite, you should test only the methods we have asked you to write in this handout. Do not reference in your tests fields or methods that are not required by the assignment, or the autograder may fail. ::: Put your testing in the file `Homework1CTest.java`. You will submit this file to the **Homework 1C (17/111/112/19): Testing** assignment on Gradescope. See [our gradescope submission guide](https://hackmd.io/oTbF1IUuRs27VgVJF4z2rA) for an explanation on how we are grading your tests, and how you can use the Testing assignment on Gradescope to get a better understanding of the assignment. **Task:** Write a thorough set of tests for `gradeLookup`. We will grade your tests on this problem in particular detail. We will do this by using your tests to try to detect flawed solutions (that we have written). We will also run your tests on multiple good solutions, to make sure that your tests work on good solutions other than your own. ::: spoiler More on how we grade your tests Edit Feb. 10: Tests will be graded manually this assignment, sorry for the confusion! Autograded wheats and chaffs will begin next assignment. We'll have a more detailed guide on how to deal with those soon after the assignment is released. ~~We are autograding your test suites by running it against a series of chaffs (bad implementations) of the solution to see if your testsuite catches the bugs in those implementations. You do not need to catch every chaff. Instead, we are looking to see if your tests are covering relevant areas of the code. The chaffs are labeled with what area of the code their bug is in, and we want to see that your tests are catching at least a few chaffs in most of these areas of the code. A chaff might have an incorrect arithmetic formula, return the wrong value in an if statement, make an assumption about inputs (such as an arbitrary string input only getting lowercase strings), and so on (this list isn’t exhaustive). Our goal in using chaffs is to help you get better at developing good sets of tests for programs.~~ ::: ### **Task:** Develop a set of tests that check the expected interactions among `storeGrade`, `updateGrade`, `gradeLookup`, and `reportsWithC`. What do we mean? One might expect that `namesWithC` (for example) would return a different output after a call to `updateGrade`. Good test suites therefore test the interactions between methods when the changes made by one should affect (or not!) the output that comes from the other. We're asking you to develop a set of such interaction tests for these four functions. :::info **Note:** that **you cannot test `private` methods in `Homework1CTest.java`** (because the test class cannot "see" private methods). You may want to test that method before you make it private, but do not include tests for private methods in your `Homework1CTest.java` file. ::: :::info **Pro Tip:** If you find that you need to set up the same courses, students, etc for multiple tests, you can write a single method to set up your data and tell JUnit to run it before each test method. Here's an example: ```=java public class Homework1CTest { Course c1, c2; @Before public void setup() { this.c1 = new Course("VISA", 100, 1) this.c2 = new Course("HIST", 310, 1) } @Test public void testDept() { Assert.assertEquals(c1.department,"VISA"); } } ``` We create the variables for data as fields outside the methods. The `@Before` annotation tells JUnit to run that method before running every test. This way, your tests can focus just on the conditions to check, and you can set up the data just one time. This also restores the values of `c1`, etc before each test, in case you have a test that needs to modify your data. ::: ## [Handing In](https://www.youtube.com/watch?v=yQaARXcsa2U) Begin by cloning the GitHub repository found by clicking the above GitHub Classroom link. The following files should be in the `sol` directory. You can move the files you wrote in 1B into this directory. * `Course.java` containing public class `Course` * `Faculty.java` containing public class `Faculty` * `Student.java` containing public class `Student` * `Person.java` containing public abstract class `Person` * `TA.java` containing public class `TA` * `GradeReport.java` containing public class `GradeReport` * `IGrade.java` containing public interface `IGrade` * `Letter.java` containing public enum `Letter` * `LetterGrade.java` containing public class `LetterGrade` * `SNC.java` containing public enum `SNC` * `SNCGrade.java` containing public class * `Homework1CTest.java` containing public class `Homework1CTest` * `TestRunner.java` containing public class `TestRunner` * `AutograderCompatibility.java` containing public class `AutograderCompatibility` After completing this assignment, you should be ready to turn in (at least) the following solution files: * `Course.java` containing public class `Course` * `Faculty.java` containing public class `Faculty` * `Student.java` containing public class `Student` * `Person.java` containing public abstract class `Person` * `TA.java` containing public class `TA` * `GradeReport.java` containing public class `GradeReport` * `IGrade.java` containing public interface `IGrade` * `Letter.java` containing public enum `Letter` * `LetterGrade.java` containing public class `LetterGrade` * `SNC.java` containing public enum `SNC` * `SNCGrade.java` containing public class `SNCGrade` * `Homework1CTest.java` containing public class `Homework1CTest` :::info **You may also include other classes, interfaces, and abstract classes.** ::: Once you have handed in your homework, you should receive an email, more or less immediately, confirming that fact. If you don’t receive this email, try handing in again, or ask the TAs what went wrong. **Note:** There should be a class in the stencil code named `AutograderCompatibility`. Using this class is required to ensure that your submission is working correctly with the autograder. You will be penalized if your code does not work with the autograder. If Gradescope gives you message *“The autograder failed to execute correctly. Please ensure that your submission is valid. Contact your course staff for help in debugging this issue. Make sure to include a link to this page so that they can help you most effectively,"* uncomment the main method of `AutograderCompatibility` and check that it compiles and runs. If it still doesn't work, come to hours or post on Ed for help. **Congratulations!** You have just finished Homework 1. Now it is time for us to say good[bye, bye, bye](https://www.youtube.com/watch?v=Eo-KmOd3i7s&ab_channel=NSYNCVEVO). At least until next time. ## FAQ **For examples of tests, see the [Homework 1A FAQ](https://hackmd.io/xHXBAqnORz6BN7xrl-uCmQ?view#FAQ). If you have other questions, feel free to post on Ed or come to hours.** --- *Please let us know if you find any mistakes, inconsistencies, or confusing language in this or any other CS200 document by filling out our [anonymous feedback form](https://forms.gle/JipS5Y32eRUdZcSZ6)!*