Learning Outcomes:

  • Gain more confidence programming in Java.
  • Design an object-oriented programming (OOP) solution to a problem.
  • Apply OOP concepts such as inheritance, polymorphism, and encapsulation (information hiding).




Warning about static fields

You should not need to use static fields in this assignment. If you are using static fields, you will encounter lots of problems.

If you use static fields, you will notice a weird behaviour that your test cases will pass when executed one at a time, but mostly fail when executed in one go. This is because the static field values are shared across all test cases, and the test cases are executed with this persistant value. This is not the behaviour you want.

So, be sure to always test your final submission using the command we have provided below, as this is how you will be marked:

./mvnw clean compile test for Unix/Mac OS or .\mvnw.cmd clean compile test for Windows




Table of Contents





Full Test Cases

You can find the full test cases used for marking below.

Download ‘MainTest.java’ for Checkpoint #1 (Task 1 only)


Recommended Approach

To make sure that your machine is properly set for doing the assignment (and all assignments in this course), refer to the FAQ on the course website.

Then it’s a matter of:

  • Clone the GitHub repository.
  • Use Visual Studio Code for doing the assignment.
  • Use the graphical “Testing” view in Visual Studio Code to run the tests (details below).
  • As a final check before submitting, use the Maven wrapper to check that everything compiles and the test cases pass (details below).

To help you get started, you might want to watch the following video:

Update to video:

The video near the end mentions using the tasks.json file to create buttons in the status bar to run the program and/or tests. I forgot to mention the instructions on installing the extension needed. The instructions for this are in the resources VS Code tasks page on the website.


Let’s begin!


Clone the GitHub repository

Edit

STOP! You MUST use the same GitHub account that you used in the Hello GitHub assignment!

Clone the assignment repository by accepting the following GitHub Classroom invitation:

https://classroom.github.com/a/NhfUBmT9




The Venue Hire System

Edit


Venue hire systems can be complex. In this assignment, you will be asked to design and implement a simple venue hire system. The system will be able to store information about venues and their bookings.

The system you develop is one that the venue hire company will use to manage their venues and bookings. The system will be used by the venue hire company’s staff to:

  • View details of all the venues,
  • Create new venues,
  • View details of all the bookings for a venue,
  • Create new bookings for a venue,
  • Add catering, music, and floral services to a booking,
  • View the invoice for a booking.

Due to the venue hire company’s limited budget (it’s apparently tough being a venue hire company), we will only design for them a terminal-driven interface. This means that the system will be controlled by a menu system that will be displayed on the terminal. The menu will allow the staff member to select from a list of commands. The staff member will be able to select a command by typing its code, and any arguments it expects. Some commands require additional options, which are prompted by the system one at a time. The system will then execute the appropriate action.

The menu of commands will be displayed on the terminal as follows:

PRINT_VENUES    [no args]       Print details of all the venues
CREATE_VENUE    [4 arguments]   Create a new venue with the given <VENUE_NAME>, <VENUE_CODE>, <VENUE_CAPACITY>, and <HIRE_FEE>
SET_DATE        [1 argument]    Set the system's date to the specified date in DD/MM/YYYY format
PRINT_DATE      [no args]       Print the system's current date
MAKE_BOOKING    [no args]       Request a new booking
PRINT_BOOKINGS  [1 argument]    Print all bookings for the specified <VENUE_CODE>
ADD_CATERING    [1 argument]    Add catering service to the specified <BOOKING_REFERENCE>
ADD_MUSIC       [1 argument]    Add music service to the specified <BOOKING_REFERENCE>
ADD_FLORAL      [1 argument]    Add floral service to the specified <BOOKING_REFERENCE>
VIEW_INVOICE    [1 argument]    View full invoice details for the specified <BOOKING_REFERENCE>
HELP            [no args]       Print usage
EXIT            [no args]       Exit the application


You have been given an incomplete implementation of the system, with only the command line interface implemented. You need to implement the commands using Object-Oriented Programming!


Here’s the solution in action (for Task 1 only), to give you an idea of what you are expected to implement:




Files Provided

Below is a list of the files provided to you for this assignment. You should not modify any of the files provided to you, except for the VenueHireSystem.java file (where you will need to implement the logic for the commands), and the MainTest.java file (where you can add your own test cases if you wish).




Edit src/main/java/nz/ac/auckland/se281/Main.java

This class implements the command line interface (CLI).

You should not modify this class.




Edit src/main/java/nz/ac/auckland/se281/MessageCli.java

This class declares most of the messages of the system.

You should not modify this class, but you are encouraged to use it.

You are encouraged to refer to these messages in the code you write, as it will be easier for you to avoid spelling and formatting issues that might otherwise cause you to fail test cases.

There are two ways to use these messages in your code:

  • Get the message so that you can print it yourself by calling the getMessage() method, or
  • Request for the message to be printed directly by calling the printMessage() method.

You will notice that most of the messages have %s placeholders in their values. For example, have a look at the definition of the PROFILE_CREATED message:

public enum MessageCli {
	// ...
	VENUE_SUCCESSFULLY_CREATED("Successfully created venue '%s' (%s)."),
	// ...
}

There are two %s placeholders, which means this message expects you to pass two arguments when you want to getMessage() or printMessage() it.

For example, consider you want to construct the message "Successfully created venue 'Frugal Fiesta Hall' (FFH)."

If you want to get the message to print it yourself, you would do:

String message = MessageCli.VENUE_SUCCESSFULLY_CREATED.getMessage("Frugal Fiesta Hall", "FFH");  // get the message
System.out.println(message);  // print it yourself

But, of course, it will often be easier to just print the message directly:

MessageCli.VENUE_SUCCESSFULLY_CREATED.printMessage("Frugal Fiesta Hall", "FFH");  // print the message directly

Be sure to dedicate time to understand how this works, as it will be very useful to use and make your job easier. You should already be familiar with this concept from how printf() works in C.




Edit src/main/java/nz/ac/auckland/se281/VenueHireSystem.java

This class declares the methods that are invoked by the command line interface (Main.java). This is where you need to start your coding.

You must NOT change the signature of the existing methods of this class (such as changing method names, parameters, and return types).

Of course, you can (and you should) add instance fields and new methods of your own.

If you need to instantiate/initialise fields of the VenueHireSystem instance, you can only use the provided zero-parameter constructor (public VenueHireSystem()). You should not create other constructors in the VenueHireSystem class, as they will not be used by the command line or test cases.




Edit src/main/java/nz/ac/auckland/se281/BookingReferenceGenerator.java

This Java file contains the generateBookingReference() method, which you will need for Task 2 and Task 3 (you can safely ignore it for Task 1). This method generates a random booking reference, which is a string of 8 characters. You must use this method to generate booking references for your bookings, so that you get the correct output when you run the test cases.

Here is an example of how to use this method to get the next random booking reference, stored to a variable called bookingReference:

String bookingReference = BookingReferenceGenerator.generateBookingReference();



If you would like to see the actual sequence of random numbers generated by this method, you can run the main() method inside this class. This will print the sequence of random numbers generated by the generateBookingReference() method. You can run the main() method by right-clicking on the BookingReferenceGenerator.java file in VS Code (in the Explorer tab), and then selecting Run Java from the context menu.

For your convenience, the first 20 random booking references generated by this method are in the following order:

HUD14D8O
ZP4HRCZ4
28GJARMV
ISXW7L6G
ALR0TCXE
ZI0F2V54
GMIHMQQ6
EQF27GQA
ZFJY9VYJ
GO9LDOS9
5IF4ZESQ
DPDD57HZ
DL7F8EMO
B697W6RY
5NVRH0C4
D0VAYSI1
NFW6ML28
CX35JSRW
3AJV498R
CKDAXDL2


You should not modify anything in the BookingReferenceGenerator.java file.

You should also NOT use the reset() method. The reset() method is used by the testing framework to reset the random number generator to a known state between test cases, so that the test cases can be executed multiple times without the random number generator affecting the results.




Edit src/main/java/nz/ac/auckland/se281/Types.java

This Java file contains the following enum types:

  • CateringType
  • FloralType

These enum types are used to represent the different types of catering and floral services that can be added to a booking. You will need to use these enum types in Task 3.

You should not modify anything in the Types.java file.




Edit src/test/java/nz/ac/auckland/se281/MainTest.java

This Java file contains the JUnit test cases for this assignment. These test cases make sure that you have implemented most of the assignment correctly.

Making sure that your program passes all of the provided tests will not guarantee that you will get full marks for this assignment, but it will mean that you should get at least half of the marks for the parts that work according to those tests. In fact, we only provided to you half of the test cases that we will use for marking your assignment. You should also note that the test cases we will use for marking your assignment will use slightly different inputs, to ensure you are not hardcoding the expected outputs.

The way that these test cases work is the same as you have seen in the Hello GitHub assignment. You can run them in the same way, either using the Maven wrapper or the Test Runner for Java extension in VS Code.

Writing your own tests or extending the ones you have been given is strongly recommended. Add them inside MainTest.YourTests, which you can find at the bottom of the MainTest.java class. You also need to uncomment each Suite Class near the top of this file:

@RunWith(Suite.class)
@SuiteClasses({MainTest.Task1.class,
				// MainTest.Task2.class,
				// MainTest.Task3.class,
				// MainTest.YourTests.class, // <-- uncomment this line
})

You can easily write a test using the helper methods runCommands(), assertContains() and assertDoesNotContain(). (which are implemented by us—they are not standard JUnit).

First, with runCommands() you specify the commands to be executed (separated by a comma). Then, with assertContains(), you specify what is the text that you expect to see on the console after executing all the commands. For example, this test case checks that two new venues are correctly created and added into the system:

@Test
public void second_venue_saved() throws Exception {
	runCommands(
			CREATE_VENUE, "'Frugal Fiesta Hall'", "FFH", "80", "150", CREATE_VENUE, "'Comfy Corner Events Centre'",	"CCEC",	"120", "250",	PRINT_VENUES);

	assertContains("Successfully created venue 'Frugal Fiesta Hall' (FFH).");
	assertContains("Successfully created venue 'Comfy Corner Events Centre' (CCEC).");
	assertContains("There are two venues in the system:");
	assertContains("Frugal Fiesta Hall (FFH) - 80 people - $150 base hire fee");
	assertContains("Comfy Corner Events Centre (CCEC) - 120 people - $250 base hire fee");
}

Sometimes it is easier to follow the test case by forcing breaklines with // at the end of each line. For example, the previous test case could be written as:

@Test
public void second_venue_saved() throws Exception {
	runCommands( //
		CREATE_VENUE, "'Frugal Fiesta Hall'", "FFH", "80", "150", //
		CREATE_VENUE, "'Comfy Corner Events Centre'",	"CCEC",	"120", "250", //
		PRINT_VENUES //
	);
	assertContains("Successfully created venue 'Frugal Fiesta Hall' (FFH).");
	assertContains("Successfully created venue 'Comfy Corner Events Centre' (CCEC).");
	assertContains("There are two venues in the system:");
	assertContains("Frugal Fiesta Hall (FFH) - 80 people - $150 base hire fee");
	assertContains("Comfy Corner Events Centre (CCEC) - 120 people - $250 base hire fee");
}

This way, even if your IDE attempts to auto-format the code, it will not change the way the test case is laid out. It makes it easier in the second case to see we executed three commands (CREATE_VENUE, CREATE_VENUE, and PRINT_VENUES), and then we checked that the output contains the lines we would expect to see as a result of those commands executing.

While you can add as many tests as you want, we will not consider them when marking your assignment. Be aware that your code must still work with the original version of the MainTest.java file, where we will reuse the test cases initially provided to you (with slightly different values), while also adding new test cases not visible to you.




Edit src/test/java/nz/ac/auckland/se281/CliTest.java

You should not modify this file.

This Java file is used by the testing framework.




Edit Various “hidden” files

Note: We also provide additional “hidden” files (those starting with “.”). You would need to change the folder options to be able to see them. We provide a .gitignore file that specifies intentionally-untracked files that Git should ignore, and a .mvn folder containing the Maven wrapper. You should not change these files, and you should not delete them.




Checkpoints

To help you tackle this assignment, we have split it into two checkpoints (Task 1 and Tasks 2+3).

You will need to submit your code for each checkpoint to your GitHub repository before each checkpoint’s respective deadline. The due dates for each checkpoint are listed at the top of this page. Make sure that you have pushed your commits and that they appear in the remote GitHub repository before the deadline. Refer to the instructions at the bottom of this page (Final Submission on GitHub) for more information on how to submit your code.




Checkpoint #1

This checkpoint is about applying basic Java OOP concepts, such as:

  • Using collections
  • Using loops
  • Using classes

Inside the MainTest.java file, you will find the relevant test cases for this checkpoint are contained within:

  • The MainTest.Task1 class

Please note that the marks for Checkpoint #1 (i.e., test cases in Task 1) will only be based on the code you submit before the end of the Checkpoint #1 deadline. Any changes you make to your code after the Checkpoint #1 deadline (which might pass more test cases in Task 1), will not be considered for marks towards Checkpoint #1 (regardless of whether you pass more or fewer test cases in Task 1 by the end of Checkpoint #2). This includes the hidden Task 1 test cases that we will use for marking your assignment.

Please also note that there is no “late submission” opportunities for Checkpoint #1. This also means we cannot support individual “extensions” for Checkpoint #1 (even if you were to provide a medical certificate).

This is because:

  • We will be releasing the hidden test cases for Task 1 soon after Checkpoint #1 deadline passes, so you can take these into consideration if you wish (they might help for implementation towards Checkpoint #2), and
  • We will be using the same repository for the entire assignment, meaning it will be impossible to distinguish between the code you intended to target Task 1 versus code you are writing that targets Task 2 and Task 3.




Checkpoint #2

This checkpoint is about applying slightly more advanced OOP concepts:

  • Using inheritance
  • Using polymorphism
  • Using abstract classes

Inside the MainTest.java file, you will find the relevant test cases for this checkpoint are contained within:

  • The MainTest.Task2 class
  • The MainTest.Task3 class

Just like there are hidden test cases for Task 1, there will also be hidden test cases for Task 2 and Task 3. They will be released soon after the Checkpoint #2 deadline passes, after preliminary marking has been completed to make sure the test cases were fair and reasonable.




OOP Requirements

For this assignment, you should use the OOP concepts we covered in class. As such, you should not implement all your code inside the VenueHireSystem class. You should create appropriate classes. We are giving you complete freedom on how to do the OO design. You will decide how many and which Java classes to create.

Inheritance (Checkpoint #2)

You should make sure that you are using inheritance for Checkpoint #2. There, we will check for the following:

  • Your code should have at least one abstract class, and
  • Your code should have at least three (sub)classes that extend class(es) that you have created.

Note that not all the sub-classes necessarily need to extend the abstract class. It is up to you.

For example, you meet the requirement if you create an abstract class public abstract class A, a public class B, and if you have three (sub)classes public class C extends A, public class D extends B, and public class E extends B:

Edit


As another example, you meet the requirement if you create an abstract class public abstract class A, and if you have three (sub)classes public class B extends A, public class C extends A, and public class D extends A. You can of course, create more classes on top of these, depending on your OO design choices:

Edit


It goes without saying that just creating the classes is not sufficient. Your code has to make use of the classes.




The Commands

Before proceeding with the tasks, read the code provided to you and start to familiarise yourself with the command-line interface.

To run the application in VS Code in an interactive mode, run the Main class using the Maven wrapper through VS Code’s built-in terminal. If the terminal window is not open, you can open it by clicking on the Terminal menu, then New Terminal. Then type the following command:

./mvnw clean compile exec:java@run for Unix/Mac OS or .\mvnw.cmd clean compile exec:java@run for Windows

You should see the following output:

Edit

Now you can try some of the commands!

Note: The commands are not case sensitive. Also, you can use underscores or hyphens interchangeably.

For example, the following are all correct and equivalent:

  • print-venues
  • print_venues
  • PRINT_VENUES
  • PRINT-VENUES
  • PrInT_vEnUeS
  • print-VENUES
  • Print-Venues


Try the HELP command to see the list of available commands:

Edit

You can also try the EXIT command to exit the system:

Edit

Only the HELP and EXIT commands are implemented for you. You will need to implement the rest of the commands.




Commands with no arguments

The following commands do not require any arguments:

PRINT_VENUES    [no args]       Print details of all the venues
PRINT_DATE      [no args]       Print the system's current date
MAKE_BOOKING    [no args]       Request a new booking
HELP            [no args]       Print usage
EXIT            [no args]       Exit the application

This means you can just type them in the command line, press Enter or Return, and they will be executed. For example, if you use the PRINT_VENUES command and press Enter or Return, you should see the following:

Edit

Obviously, nothing got printed since you need to implement the logic. But notice that no error was reported, since you did not add arguments (as the command expects).

If you were to use the PRINT_VENUES command followed by some arguments, you would get an error message:

Edit

This is because the command expects no arguments, but you provided some (in this case, added, extra, things).




Commands with arguments

The following commands require arguments:

CREATE_VENUE    [4 arguments]   Create a new venue with the given <VENUE_NAME>, <VENUE_CODE>, <VENUE_CAPACITY>, and <HIRE_FEE>
SET_DATE        [1 argument]    Set the system's date to the specified date in DD/MM/YYYY format
PRINT_BOOKINGS  [1 argument]    Print all bookings for the specified <VENUE_CODE>
ADD_CATERING    [1 argument]    Add catering service to the specified <BOOKING_REFERENCE>
ADD_MUSIC       [1 argument]    Add music service to the specified <BOOKING_REFERENCE>
ADD_FLORAL      [1 argument]    Add floral service to the specified <BOOKING_REFERENCE>
VIEW_INVOICE    [1 argument]    View full invoice details for the specified <BOOKING_REFERENCE>

This means you must provide the required number of arguments before pressing Enter or Return for them to be executed. For example, if you use the CREATE_VENUE command without arguments (or the wrong number of arguments) and press Enter or Return, you should see the following:

Edit

To use it correctly, you need to provide the correct number of arguments:

Edit

Obviously, nothing got printed since you need to implement the logic. But notice that no error was reported, since you provided four arguments (as the command expects).




Tasks

To guide you through the assignment, we have divided it into three tasks. Task 1 corresponds to Checkpoint #1, while Task 2 and Task 3 together correspond to Checkpoint #2.

For each task, we provide a number of test cases (in MainTest.java) that you can use to test your code.




Task 1 (Checkpoint #1) [Worth 6%]

Initial test results

As soon as you compile and run the tests, you will notice the following output…

With the Maven wrapper:

./mvnw clean compile test for Unix/Mac OS or .\mvnw.cmd clean compile test for Windows:

Edit


With the Test Runner for Java extension in VS Code:

From the left side of VS Code, click on the Testing icon: Edit

You will then see all the test cases. You might need to expand to see them all:

Edit


Tip: Running a single test case at a time…

Running a single test at a time will help you focus on one test at a time, and will make it easier to understand what is going on.

Option 1: Using the command line

If you wanted to use the command line to run a single test case, you can do so by specifying the test case name. For example, to run the first test case, you would use the following command:

./mvnw compile -Dtest=nz.ac.auckland.se281.MainTest\$Task1#T1_01_name_of_test_case_method test for Unix/Mac OS or
.\mvnw.cmd compile -Dtest=nz.ac.auckland.se281.MainTest\$Task1#T1_01_name_of_test_case_method test for Windows

Note that you need to change two things:

  • The name of the Task (e.g., Task1), and
  • The name of the test case’s method (e.g., T1_01_name_of_test_case_method).

However, we recommend you use the Test Runner for Java extension in VS Code, as it is much easier to use and allows you to debug your code more easily. See the next section here.

We recommend you use the Test Runner for Java extension in VS Code. It is a very useful tool that will help you run and debug your tests. It will give you control to run all tests at the same time (as in the example above), or run a single test at a time, for example:

Edit

It will also make it easier to debug your code, as you can set breakpoints and step through your code.

When you are trying to pass a particular test case, you will find the Debug Console tab in VS Code very useful. Here, you will see the output of your program after the test you selected has finished running:

Edit

For more help on how to debug your code in VS Code, see the VS Code debugging resource. In particular, there is a section called “Debugging for the Test Cases in the Assignments”.


If you are having issues running tests in Test Runner

If you attempt to run the tests via the Test Runner, and it gives you some problems (e.g., there’s some weird error, or the tests don’t actually appear to run), then try running the tests via the command line first:

./mvnw clean compile test for Unix/Mac OS or .\mvnw.cmd clean compile test for Windows

This should then allow you to run the tests via the Test Runner as expected.


In either case, the examples above are telling you that 8 test cases were run, none of them passed, and all of them failed. In the output, you will find more details on why the test cases failed.

Hint: Look at the numbering of the test cases to guide you in the recommended order to tackle them, in this case the first test case is T1_01_no_venues().

For example, let’s consider the first test case as shown in the terminal, for when you use the Maven wrapper:

Edit


The same information is present in the Test Runner for Java extension in VS Code. You can click on the red x (Edit) to see the details of the failed test:

Edit


The important message to read is:

java.lang.AssertionError: The test is expecting the following output in the console, but it was not there: 
 "There are no venues in the system. Please create a venue first."


This means that the test is expecting the output There are no venues in the system. Please create a venue first. to be printed in the console, but it was not there. This is because you have not implemented the logic for the PRINT_VENUES command yet.


Let’s try something. Go to the printVenues() method inside VenueHireSystem.java, and add the following code:

public void printVenues() {
	// TODO implement this method
	System.out.println("There are no venues in the system. Please create a venue first.");
}


Run your test again, and you should see the following:

Edit


Or, from the terminal, we see that now only 7 of the 8 tests are failing:

Edit


Now, of course the edit we did was a hack to demonstrate how the tests work. We will very soon have a non-empty list of venues, and this hard-coded print statement will cause all those other test cases to fail! We therefore need to implement the correct logic as described in the following sections.


Creating a new venue (CREATE_VENUE and PRINT_VENUES)

Task 1 will require you to implement (some of) the logic for the CREATE_VENUE and PRINT_VENUES commands.

The CREATE_VENUE command creates a new venue with the specified venue name, venue code, venue capacity, and venue hire fee (passed as arguments to the CREATE_VENUE command). If any invalid input is provided, an error message should be printed (details below).

The PRINT_VENUES command prints the details of all the venues in the system.

If there are no venues in the system, it prints just the following header:

There are no venues in the system. Please create a venue first.


If there is one venue in the system, it prints the following header and the one itemised venue:

There is one venue in the system:
  * Frugal Fiesta Hall (FFH) - 80 people - $150 base hire fee. Next available on %s

Notice that the sentence Next available on appears to be incomplete (it is). This is perfectly fine for Task 1. We will complete this sentence in Task 2. For now, it doesn’t matter what appears after Next available on (for now you can make it say Next available on %s, or Next available on TODO, or anything else you want). You will notice that the test cases in Task 1 are not checking for this part of the output, so you can leave it as is.


If the system has more than one venue (but less than 10 venues), it prints the following header and the itemised list of all venues. For example, assume there are two venues in the system:

There are two venues in the system:
  * Frugal Fiesta Hall (FFH) - 80 people - $150 base hire fee. Next available on
  * Comfy Corner Events Centre (CCEC) - 120 people - $250 base hire fee. Next available on


If the system has 10 (or more) venues, it prints the following header and the itemised list of all venues. For example, assume there are 10 venues in the system:

There are 10 venues in the system:
  ... // itemised lists the venues

So, if there were 13 venues, it would print There are 13 venues in the system: followed by the itemised list of all 13 venues.


Take note of the differences between the different cases above:

  • In the first example, the quantity is “no”, “venues” is plural, and the sentence ends with a period (“.”)
  • In the second example, it uses “is”, the quantity is a word, “venue” is singular, and the sentence ends with a colon (“:”)
  • In the third example, it uses “are”, the quantity is a word, “venues” is plural, and the sentence ends with a colon (“:”)
  • In the fourth example, it uses “are”, the quantity is a digit, “venues” is plural, and the sentence ends with a colon (“:”)

Hint: Have a look at the MessageCli.NUMBER_VENUES message template:

NUMBER_VENUES("There %s %s venue%s in the system:")

This message template has three %s placeholders:

  • The first %s is for the quantity (i.e., “is” or “are”)
  • The second %s is for the number of venues (e.g., “one”, “two”, “10”, etc.)
  • The third %s is for the word “venue”, whether you want it to be singular or plural (i.e., “venue” or “venues”)

To get the message "There are two venues in the system:", you can do one of the following:

MessageCli.NUMBER_VENUES.getMessage("are", "two", "s");    // Using the getMessage() method
MessageCli.NUMBER_VENUES.printMessage("are", "two", "s");  // Using the printMessage() method


In addition to the header, if there is at least one venue in the system, the PRINT_VENUES should also print the following for every venue in the system:

 * <VENUE_NAME> (<VENUE_CODE>) - <VENUE_CAPACITY> people - $<VENUE_HIRE_FEE> base hire fee. Next available on %s

Hint: See the MessageCli.VENUE_ENTRY message template.

When a new venue is created, it should be added to the system. The arguments have the following requirements:

Edit <VENUE_NAME>

  • Cannot be empty (i.e., cannot be '' or ' ' or any other combination of spaces).
  • You will notice the use of single quotes in the test cases. This is because the venue name can be a single word (in which case the single quotes are optional), or multiple words (in which case the single quotes are required). You don’t need to worry about this, as the code provided already handles this and gives you the full name regardless.

Edit <VENUE_CODE>

  • Must be unique across all other venue codes currently in the system.

Edit <VENUE_CAPACITY>

  • Must be a whole integer, positive, over zero, numeric/digits.

Edit <HIRE_FEE>

  • Must be a whole integer, positive, over zero, numeric/digits.

✭ You do not need to worry about the user typing in too many or too few arguments. For example, you do not need to worry about the user typing in CREATE_VENUE 'Frugal Fiesta Hall' FFH 80 150 extra or CREATE_VENUE Without Quotes Hall WQH 80 150. You can assume that the user will always type in a command that has the correct number of arguments.

✭ You do not need to worry about test cases where there are multiple errors in the same command. For example, you do not need to worry about the user typing in CREATE_VENUE 'Already Exists Hall' AEH -10 150 (i.e., the venue capacity is not a positive integer, and venue code already exists). You can assume that the user will always type in a command that has only one error.

As a general rule, if there is nothing explicitly mentioned in this handout, then you do not have to take it into account. We have purposely limited the number of “corner cases” you need to consider, to make the assignment easier to complete. Otherwise, you will be forever anticipating every single possible input, and you will never finish the assignment. If we don’t mention it, you don’t have to worry about it. There won’t be any “hidden” test cases that will test for something we didn’t mention.


When a successful venue is created, a success message should be printed:

Successfully created venue '<VENUE_NAME>' (<VENUE_CODE>).

For example:

281-venue-hire> CREATE_VENUE 'Frugal Fiesta Hall' FFH 80 150
Successfully created venue 'Frugal Fiesta Hall' (FFH).

The format of this message is very strict. Make sure you check for an appropriate message template in MessageCli to help you.


If there was something wrong, then the above success message should not be printed. Instead, one of the following messages gets printed.

If the venue name is empty, then the following message gets printed:

281-venue-hire> CREATE_VENUE '' NA 80 150
Venue not created: venue name must not be empty.


If the venue code already exists, then the following message gets printed:

281-venue-hire> CREATE_VENUE 'Frugal Fiesta Hall' FFH 80 150
Successfully created venue 'Frugal Fiesta Hall' (FFH).
281-venue-hire> CREATE_VENUE 'Frugal Fiesta Hall' FFH 80 150
Venue not created: code 'FFH' is already used for 'Frugal Fiesta Hall'.


If the hire fee (or capacity) is not a number, then the following message gets printed:

281-venue-hire> CREATE_VENUE 'Frugal Fiesta Hall' FFH 80 fifty
Venue not created: hire fee must be a number.

For our purposes, something is a number only if it can be parsed with Integer.parseInt() (see the Java docs) or this YouTube video to learn how to parse a string into an integer).


If the capacity (or hire fee) is not a positive integer, then the following message gets printed:

281-venue-hire> CREATE_VENUE 'Frugal Fiesta Hall' FFH -1 150
Venue not created: capacity must be a positive number.


Once you have implemented all the logic for Task 1, you should see all your test cases pass:

Edit


Or, from the terminal view:

Edit


As explained at the end of this document, we only provide you with half the test cases from each task. So, even though you have passed all 8 test cases, there are 7 more hidden test cases that we will add to these for Task 1. So, make sure you have implemented all the logic, and read the requirements carefully.




Task 2 (Checkpoint #2) [Worth 6%]

Now that the system supports creating venues, it is time to manage those venues. This will include setting the system’s date, making bookings, updating the next available date, and printing bookings.

Go to the top of the MainTest.java file, and uncomment the following line:

@RunWith(Suite.class)
@SuiteClasses({
  MainTest.Task1.class,
  // MainTest.Task2.class, // <-- uncomment this line to get started on Task 2
  // MainTest.Task3.class,
  // MainTest.YourTests.class,
})


You will see 15 new test cases, all of which are failing. Follow the same process as Task 1 to get them all passing, and carefully read the requirements below so you consider scenarios where test cases are not provided.




Setting (and printing) the system’s date

Before we can make bookings, we need to set the system’s date. The SET_DATE command sets the system’s date to the specified date (provided in DD/MM/YYYY format) and prints a confirmation message, for example:

281-venue-hire> SET_DATE 26/02/2024
System date set to 26/02/2024.

You don’t have to worry about handling invalid dates, or dates specified in a different format. You can assume that the user will always type in a valid date in the correct format.


The PRINT_DATE command prints the system’s current date (assuming it was previously set with SET_DATE), for example:

281-venue-hire> SET_DATE 26/02/2024
System date set to 26/02/2024.
281-venue-hire> PRINT_DATE
Current system date is 26/02/2024.


If the system’s date has not been set, then the following message gets printed:

281-venue-hire> PRINT_DATE
Current system date is not set.




Making bookings

Now it’s time to actually make some bookings! But, understandably, a few conditions need to be met before we can make a booking. These conditions are:

  • The system’s date must be set,
  • There must be at least one venue in the system,
  • The venue code must exist,
  • The venue must be available on the specified date, and
  • The booking date must not be in the past (today or later is OK in terms of the current system date).

If any of these conditions are not met, then the booking cannot be made. In this case, an error message should be printed, and the booking is not made.


The MAKE_BOOKING command makes a booking for the specified venue code and date, and prints a confirmation message.

However, you will notice that the MAKE_BOOKING command has zero arguments! This is because the required information will be prompted after the command is executed, and we call these “options”. These options will be prompted for by the system one at a time. For example:

281-venue-hire> MAKE_BOOKING
	Venue code: FFH
	Requested date in DD/MM/YYYY format: 26/02/2024
	Customer email: client001@email.com
	Number of attendees: 70


Collecting these options is handled for you. Once collected, they are placed into an array of strings (i.e., the String[] options parameter in the VenueHireSystem.makeBooking() method).

For the example above, the options array would contain the following:

options[0] = "FFH"
options[1] = "26/02/2024"
options[2] = "client001@email.com"
options[3] = "70"



To see this in your code, you can easily print each value out in your makeBooking() method:

public void makeBooking(String[] options) {
	for (int i = 0; i < options.length; i++) {
		String value = options[i];
		System.out.println("option " + i + " = " + value);
	}
}



To extract the day, month, and year from the date string, you can use the String.split() method. For example:

String date = "26/02/2024";
String[] dateParts = date.split("/");

String day = dateParts[0];   // "26"
String month = dateParts[1]; // "02"
String year = dateParts[2];  // "2024"

See the Java documentations for more details.



To simplify the implementation for making bookings, you do not need to worry about validating the format of the options. For example, you do not need to worry about validating the date format, or the email format, or the number of attendees being a number, etc. You can assume that the user will always type in a correct format. In fact, this is done for you. We will always use valid option types for marking, and you only need to consider the explicitly mentioned scenarios.

When a booking is successfully made, a success message should be printed:

"Successfully created booking '<BOOKING_REFERENCE>' for '<VENUE_NAME>' on <BOOKING_DATE> for <NUMBER_OF_ATTENDEES> people."

For example:

281-venue-hire> SET_DATE 27/02/2024
System date set to 27/02/2024.
281-venue-hire> MAKE_BOOKING
	Venue code: GGG
	Requested date in DD/MM/YYYY format: 27/02/2024
	Customer email: client001@email.com
	Number of attendees: 230
Successfully created booking 'HUD14D8O' for 'Grand Gala Gardens' on 27/02/2024 for 230 people.

The above example shows a successful booking. The information provided should be stored with that booking.

Notice that the booking reference (HUD14D8O) was not provided as an option, and was instead auto-generated by the system. This is a randomly generated booking reference, and you should use the BookingReferenceGenerator.generateBookingReference() method to generate it. You do not need to worry about how this method works, just use it.



The first 20 random booking references generated by this method are in the following order:

HUD14D8O
ZP4HRCZ4
28GJARMV
ISXW7L6G
ALR0TCXE
ZI0F2V54
GMIHMQQ6
EQF27GQA
ZFJY9VYJ
GO9LDOS9
5IF4ZESQ
DPDD57HZ
DL7F8EMO
B697W6RY
5NVRH0C4
D0VAYSI1
NFW6ML28
CX35JSRW
3AJV498R
CKDAXDL2


There are some cases when the options provided might not be ideal, but they aren’t enough to stop a booking from being made. This will be the case when the number of attendees is less than 25% of the venue capacity, or more than 100% of the venue capacity. In these cases, the booking will still be made, but the number of attendees will be adjusted to be 25% or 100% of the venue capacity, respectively. When this happens, the following message should be printed:

Number of attendees adjusted from <ORIGINAL_NUMBER_OF_ATTENDEES> to <NEW_NUMBER_OF_ATTENDEES>, as the venue capacity is <VENUE_CAPACITY>.

For example, when too few attendees are specified:

281-venue-hire> MAKE_BOOKING
	Venue code: GGG
	Requested date in DD/MM/YYYY format: 28/05/2024
	Customer email: client999@email.com
	Number of attendees: 20
Number of attendees adjusted from 20 to 65, as the venue capacity is 260.
Successfully created booking 'HUD14D8O' for 'Grand Gala Gardens' on 28/05/2024 for 65 people.

Similar thing when too many attendees are specified, the number of attendees is adjusted to be 100% of the venue capacity.

You don’t have to worry about rounding up or down. We won’t have test cases where 25% results in a decimal number, and we won’t have test cases where the venue capacity is less than 4 (since 25% of 4 is 1, and 100% of 4 is 4).


Below are scenarios where a booking should not be made, and an error message should be printed instead. This means your system should not print any success message, and the booking should not be stored when the list of bookings for a given venue is printed.


If the system’s date has not been set, then the following message gets printed:

Booking not made: system date not set. Set the date first.


If there are no venues in the system, then the following message gets printed:

Booking not made: there are no venues in the system. Create one first.


If the venue code does not exist, then the following message gets printed:

281-venue-hire> MAKE_BOOKING
	Venue code: FAKE
	Requested date in DD/MM/YYYY format: 02/06/2024
	Customer email: client001@email.com
	Number of attendees: 50
Booking not made: there is no venue with code 'FAKE'.


If the booking date is in the past, then the following message gets printed, regardless of whether the venue was available or not:

Booking not made: '01/01/2021' is in the past (system date is 01/05/2024).


Finally, given the time to prepare and clean venues between bookings, the system should ensure that only one booking can be made per day for a given venue. This means that if a booking is made for a given venue on a given date, then no other bookings can be made for that venue on that date. If a booking is attempted to be made for a given venue on a given date, but there is already a booking for that venue on that date, then the following message gets printed:

Booking not made: venue 'Grand Gala Gardens' is already booked on 27/02/2024.




Updating the next available date**

Once you’ve got your bookings working, you need to update the next available date for a given venue.

When a booking is made, the next available date for that venue should be updated. This is the date that is printed when printing the list of venues. For example, assume that the system date is 01/01/2024:

  • If there are no bookings for the venue yet, then it’s next available date is 01/01/2024 (today).
  • If a booking already exists for 01/01/2024 (today), then the next available date is 02/01/2024 (tomorrow).
  • If a booking already exists for today and tomorrow, then the next available date is 03/01/2024.
  • If there is one booking 01/01/2024 (today), and the next one is 5 days away, then the next available date is 02/01/2024 (tomorrow).

The next available date will also need updating when the system time changes. For example, assume that the system date is 01/01/2024:

  • If the system date moves forward to 20/01/2024, and there are no bookings for the venue yet, then it’s next available date is 20/01/2024 (the new today).

This is all tested against the output from the PRINT_VENUES command. For example:

281-venue-hire> SET_DATE 03/02/2024
System date set to 03/02/2024.
281-venue-hire> PRINT_VENUES
There are 10 venues in the system:
  * Frugal Fiesta Hall (FFH) - 80 people - $250 base hire fee. Next available on 03/02/2024
  * Comfy Corner Events Centre (CCEC) - 120 people - $500 base hire fee. Next available on 03/02/2024
	...



When you update your PRINT_VENUES command to include the next available date, you might find that your earlier test cases from Task 1 are no longer passing, since they are generating an Error (which is different from a Failure).

A failure is when the test case fails, but the program does not crash. For example, if you run the PRINT_VENUES command, and it prints the wrong output, then the test case will fail, but the program will not crash.

An error is when the program crashes. For example, if you run the PRINT_VENUES command, and it crashes with a NullPointerException, then the test case will error, and the program will crash. You can think of it as if the test case didn’t have a chance to finish running, because the program crashed before it could finish making all the needed checks.

From the terminal, you will see something like this:

Edit

From the Test Runner for Java extension in VS Code, you will see something like this:

Edit


So now that you added extra logic for the next available date, your program needs to cater for there not being a current system date sent (so that it doesn’t crash). We won’t actually have test cases for it (from Task 2 onwards), but you will need to handle it so that your Task 1 logic continues to work.





Printing bookings

Now that we can make bookings, we need to be able to print them.

The PRINT_BOOKINGS command prints all the bookings for a given venue (past and future bookings). It first prints the header that includes the venue name, and then prints the list of bookings for that venue along with their booking reference and event date. For example:

281-venue-hire> PRINT_BOOKINGS GGG
Bookings for 'Grand Gala Gardens':
  * 'HUD14D8O' on 27/03/2024
  * 'ZP4HRCZ4' on 28/05/2024


If there are no bookings for the specified venue (but the venue exists), then the same header is printed but with the following note below the header:

Bookings for 'Grand Gala Gardens':
  * No bookings for 'Grand Gala Gardens'.


If the venue code does not exist, then the following message gets printed:

281-venue-hire> PRINT_BOOKINGS ABC
Nothing to print: there is no venue with code 'ABC'.


If there are no venues in the system, then it suffices to print the same message as the venue code not existing. You do not need to worry about printing a different message for when there are no venues in the system.




Task 3 (Checkpoint #2) [Worth 6%]

Now that the system supports making bookings, it is time to manage those bookings. This will include adding services to a booking, and viewing invoices.

Go to the top of the MainTest.java file, and uncomment the following line:

@RunWith(Suite.class)
@SuiteClasses({
	MainTest.Task1.class,	
	MainTest.Task2.class,
	// MainTest.Task3.class, // <-- uncomment this line to get started on Task 3
	// MainTest.YourTests.class,
})


You will see 15 new test cases, all of which are failing. Follow the same process as Task 1 and Task 2 to get them all passing, and carefully read the requirements below so you consider scenarios where test cases are not provided.




Services

The currently-supported services include Catering, Music, and Floral. Each service has a different cost, and can be added to a booking.

When a service is added, it is added to a specific booking. A booking might have multiple services. To add a service, you need to specify the booking reference (which was generated when the booking was made).

When adding a service, the only check is that the booking reference exists. It doesn’t matter if there are venues or not, as the main check is that the actual booking reference exists (and it might not exist since there are no bookings in the system at all). In the case that the booking reference does not exist, a message gets printed for the service type (e.g., Catering, Music, or Floral), along with the booking reference that was provided. For example:

Catering service not added: there is no booking with reference 'HUD14D8O' in the system.

The impact of adding a service to the booking ultimately affects the cost of that booking (more on that below).

To make it easier, you do not need to worry about error checking the input in terms of validity of options for the services. Assume that the user will always enter the correct format for options when adding a service. In fact, this is done for you and you should be using the enums provided (see the CateringType and FloralType enums declared in the Types class).




Adding Catering services to a booking

The ADD_CATERING command adds a catering service to a booking. The booking reference is provided as an argument to the command, while the catering type is prompted for after the command is executed.

Here’s an example of the message that gets printed when a catering service is added to a booking:

281-venue-hire> ADD_CATERING HUD14D8O
	Select type (B/L/D/X/BL/LD/BLD): B
Successfully added Catering (Breakfast) service to booking 'HUD14D8O'.


For the catering services, you will need to use the CateringType enum declared in the Types class. It is used to represent the different types of catering services that can be added to a booking, and a value will be provided to you in the addCateringService() method in the VenueHireSystem class.

This enum has the following values:

  • BREAKFAST: Breakfast, costing $15 per person
  • LUNCH: Lunch, costing $20 per person
  • DINNER: Dinner, costing $30 per person
  • DRINKS: Drinks, costing $10 per person
  • TWO_COURSE_BL: Two Course (Breakfast+Lunch), costing $45 per person
  • TWO_COURSE_LD: Two Course (Lunch+Dinner), costing $60 per person
  • THREE_COURSE: Three Course, costing $75 per person



You will want to use the getName() and getCostPerPerson() methods to get the name and cost of the catering type. For example:

// Example variable
CateringType cateringType = Types.CateringType.BREAKFAST;

// Get the name of the catering type
String cateringTypeName = cateringType.getName();

// Get the cost of the catering type
int cateringTypeCost = cateringType.getCostPerPerson();




Adding Music services to a booking

The ADD_MUSIC command adds a music service to a booking. The booking reference is provided as an argument to the command. There are no options to select from, as there is only one music service available.

Here’s an example of the message that gets printed when a music service is added to a booking:

281-venue-hire> ADD_MUSIC HUD14D8O
Successfully added Music service to booking 'HUD14D8O'.


All music services cost $500, and there is only one music service available.




Adding Floral services to a booking

The ADD_FLORAL command adds a floral service to a booking. The booking reference is provided as an argument to the command, while the user is prompted to upgrade to deluxe floral after the command is executed.

Here’s an example of the message that gets printed when a floral service is added to a booking:

281-venue-hire> ADD_FLORAL HUD14D8O
	Upgrade to deluxe? (y/n): n
Successfully added Floral (Standard) service to booking 'HUD14D8O'.


For the floral services, you will need to use the FloralType enum declared in the Types class. It is used to represent the two types of floral services that can be added to a booking, and a value will be provided to you in the addServiceFloral() method in the VenueHireSystem class.

This enum has the following values:

  • STANDARD: Standard, costing $550
  • DELUXE: Deluxe, costing $1000



You will want to use the getName() and getCost() methods to get the name and cost of the catering type. For example:

// Example variable
FloralType floralType = Types.FloralType.STANDARD;

// Get the name of the floral type
String floralTypeName = floralType.getName();

// Get the cost of the floral type
int floralTypeCost = floralType.getCost();




Viewing invoices

Now that we can add services to bookings, we need to be able to view the invoices for those bookings. This will allow us to print and send the invoices to the clients (of course you don’t have to implement that last part!).

The VIEW_INVOICE command prints the full invoice details of a specific Booking, including the services, number of attendees being charged, the total cost, booking reference, client’s email, etc.

Here’s an example invoice:

281-venue-hire> VIEW_INVOICE ZP4HRCZ4

===============================================================
                          INVOICE
           -------------------------------------

Booking Reference: #ZP4HRCZ4

Booking Details:
Customer Email: client001@email.com
Date of Booking: 26/02/2024

Event Details:
Party Date: 28/07/2024
Number of Guests: 150
Venue: Refined Radiance Venue

Cost Breakdown:
  * Venue hire - $500
  * Catering (Two Course Breakfast/Lunch) - $6750
  * Floral (Deluxe) - $1000
Total Amount: $8250

Thank you for choosing 281 Venue Hire!
For any inquiries, please contact support@281venuehire.co.nz.
===============================================================


You’ll noticed there are two dates captured on the invoice:

  • Date of Booking: This is the date that the booking was made (different from the date of the event). This is effectively the system date when the booking was made.
  • Party Date: This is the date of the event (i.e., the date that the booking is for).


To help you print the invoice, have a look at the INVOICE_CONTENT_xxx values in the MessageCli class. These are the templates for the invoice, and you can use them to help you print the invoice:

  • INVOICE_CONTENT_TOP_HALF
  • INVOICE_CONTENT_VENUE_FEE
  • INVOICE_CONTENT_CATERING_ENTRY
  • INVOICE_CONTENT_MUSIC_ENTRY
  • INVOICE_CONTENT_FLORAL_ENTRY
  • INVOICE_CONTENT_BOTTOM_HALF


As you’ll notice, there’s quite a number of %s placeholders to be filled in for the invoice template.

Remember that catering costs are determined by the number of attendees (which is minimum 25% venue capacity, and maximum 100% venue capacity).

It doesn’t matter what order that you list of the various services, as long as the total cost is correct, and all the required elements are listed on the invoice.


Obviously, if the booking reference does not exist, then the following message gets printed:

Invoice not printed: there is no booking with reference 'ZP4HRCZ4' in the system.




Your Tests (optional)

You can add your own test cases in the MainTest.YourTests class, in a similar way to how the test cases are written in the MainTest.Task1, MainTest.Task2, and MainTest.Task3 classes.

These won’t be marked (in fact, they will be ignored during marking), but they are useful for you to test your code. Furthermore, knowing how to write test cases (and getting into the good habit of doing so) will help you write better code and gets you into the problem-solving mindset, which is extremely useful for your future career as an engineer.




Marking Scheme

Item Value Due Note
Task 1 6% Checkpoint #1
Task 2 6% Checkpoint #2
Task 3 6% Checkpoint #2
OO Design 3% Checkpoint #2
Code Style 2% Checkpoint #2
Git Etiquette 2% Checkpoint #2
Total 25%


Important Notes: In order to get these marks, you need to make a genuine attempt on the assignment:

We have provided you with half of the test cases used for marking each of the tasks. However, you should not hard-code any logic in order to pass these given test cases as we will change them to have slightly different values. Such hard-coded test cases will naturally fail and get you no marks. See the section below “Does passing test cases mean I have completed the assignment?” for more information.

The classes you create must actually be used, and not be “dummy classes”. You need to create and use at least one abstract class, and at least three (sub)classes that extend a class that you have created. You also need to pass at least 20% of test cases (in Task 2 and 3) in order to get the marks for this item (in other words, these classes need to actually contribute to the functionality of the program).

If you did not pass at least 20% of the total test cases, you will get zero marks for this component. You will not get these marks if you only cloned the repo and pretty much only “submit” the code we provided you.

This is checked and marked at the end of Checkpoint #2, but it’s recommended you clean up your code as you go along rather than at the very end. Make use of the Code Style tool frequently, and learn from it. View required Code Style conventions here.

Although this is marked at the end of Checkpoint #2, there is no opportunity to “fix” past mistakes since you can’t tamper/change your Git history. With that said, we will provide some leniency so you can still get full marks if you made the odd mistake and not too often. We will share reports throughout the assignment so you can see how you’re tracking with this, so you can view any mistakes you might have made and not repeat them. View required Git Etiquette conventions here.





Edit

Important Instructions

Please read the following information carefully before you begin your assignment.


Does passing test cases mean I have completed the assignment?

You will see that we provide some test cases to help guide you. In most cases, these test cases are not comprehensive. They are not designed to test all possible inputs. They are designed to help you get started.

What’s more, you should make sure you do not hard code your logic to pass the specific test cases we provide. You should write your code in a way that it will work for any input.

For example, if we provide a test case that checks if the method checkIfIsEven returns true when the input is 2:

@Test
public void testIsEven() {
  checkIfIsEven(2);
  assertContains("true");
}

You should not write your code like this:

public void checkIfIsEven(int number) {
  if (number == 2) {
    System.out.println("true");
  } else {
    System.out.println("false");
  }
}

This is because in the actual marking, we will use different values for the test cases. For example, we may use the test case:

@Test
public void testIsEven() {
  checkIfIsEven(280);
  assertContains("true");
}

If you have hard coded your logic to pass the test case checkIfIsEven(2), then your code will not pass the test case checkIfIsEven(280) and you will therefore not get the marks for that test case.


Code Style Tool

Note: You should have received an email (from “GradeStyle”) with your personal access token. If you didn’t, it’s most likely because you have not associated your GitHub username with your identity when you accepted one of the assignments. In that case, please email Nasser and let him know what GitHub username you used for Hello GitHub.

There will be marks allocated to your code style. Please see the Java Conventions and Best Practices page for more information on code style relevant to this course.

To provide you with feedback on your code style, we will be using a tool we have developed. This tool will check your code for common code style issues, and email you a report on your code style. This email report will let you know what you need to fix.

After the assignment deadline has passed, we will use the same tool to mark code style for your submission.

To benefit from this tool, you need to have your commits pushed to the remote GitHub repository. The tool will extract the code from there, analyse your code, and email you the report.

To use the tool, a codestyle.config file is needed in to the root directory (where the pom.xml file is). Inside it, you should include two things:

email: "student@aucklanduni.ac.nz"
accessToken: "token-that-was-emailed-to-you"

Note: You will notice that the codestyle.config file is added to the .gitignore file. It is good practice to never track credentials in a repository.

The access token will be emailed to you, and is unique for you.

In the assignment repo, you will find a codestyle_SAMPLE.config for your convenience. You can copy-and-paste it, change the name (to codestyle.config), and fill the email and accessToken values with your credentials.

To invoke the actual tool, you will run:

./mvnw clean compile exec:java@style for Unix/Mac OS or .\mvnw.cmd clean compile exec:java@style for Windows

You will receive an email with the feedback.

Some notes about running the tool:

  • We limit the number of times you can run the tool (currently once per 30 minutes). With a large number of students, we cannot afford to run the tool on every commit. To make the most of the tool, we therefore recommend you start the assignment early on, and run the tool frequently. If you leave it too late, you will not be able to run the tool as many times as you might like.
  • The tool runs on code you have pushed to the remote repository. It does not run on your local repository. Therefore, if you want to generate a new report on your latest code, you will need to do a git commit and a git push to the remote repository. The tool will decline to run if you have not pushed your latest code to the remote repository.
  • Some of the code style aspects might require your code to compile. So, make sure you have a working code before running the tool. If you have a compilation error, the tool will not run (and it will still count as one of your runs). So, remember to do a ./mvnw clean compile for Unix/Mac OS or .\mvnw.cmd clean compile for Windows (or include the clean compile in your exec:java@style command) before running the tool.
  • The tool will use the GitHub username that was registered in the first Hello GitHub assignment you completed. If you did not associate your name with a GitHub username in GitHub Classroom, you would not have received an email with the access token. If you have a GitHub username associated with your name in GitHub Classroom, but you did not receive an email with the access token, please contact us.
  • If you are using a different GitHub username (compared to the one you used in the Hello GitHub assignment), then the tool will not be able to find your repo, and therefore will not be able to run. Try to re-accept the GitHub Classroom invitation link (for the assignment) using the same GitHub account you registered earlier.


Here’s an example of running the Code Style tool:


Academic Honesty


You MUST use the GitHub repository created from the GitHub Classroom invitation link provided.

NEVER use your own repository, or copy your code to another repository to work from.

Doing so means your assignment will not be accepted for marking.

  • The work done on this assignment must be your own work. Think carefully about any problems you come across, and try to solve them yourself before you ask anyone for help (struggling a little with it will help you learn, especially if you end up solving it). If you still need help, check on Ed Discussion (if it is about interpreting the assignment specifications) or ask in the Drop-In help clinics (if you would like more personal help with Java). Under no circumstances should you take or pay for an electronic copy of someone else’s work.
  • All submitted code will be checked using software similarity tools. Submissions with suspicious similarity will result in action taken following the University’s Guidelines for Academic Misconduct, and forwarded to the Disciplinary Committee.
  • Penalties for copying will be severe. In most cases, this is ZERO for the assignment in question. To avoid being caught copying, don’t do it. Please note the same penalty applies to both the person who copied and the person who was copied from.
  • The University has recently taken a much stricter stance on academic misconduct and streamlined the process for dealing with it. In a nutshell, it takes a non-negotiation approach — no longer requiring a thorough investigation. You will therefore simply be informed, and find the penalty applied to the assignment. This is why it’s important to not only copy from others, but also not to show your work to others.
  • You must not attempt to tamper with your GitHub commits. This means all commits must be preserved, including the one that is automatically created by GitHub Classroom. Disregarding this will result in major penalties. See the section on Tampering with your Git commit history for more information.
  • To ensure you are not identified for potential plagiarism, you should follow these points:
    • Always do individual assignments by yourself.
    • Never show or give another person your code.
    • Make sure you are doing plenty of commits and pushes to GitHub. This will help you to track your progress and also to ensure that you have a backup of your work. It also makes it easier for us to see that you have not been copying from someone else.
      • Do not share your GitHub account with anyone.
      • Never put your code in a public place (e.g. Reddit, public GitHub repository, forums, your website, etc).
    • Never leave your computer unattended. You are responsible for the security of your account.
    • Ensure that you always remove your USB flash drive from any public computer before you log off from it.
    • Frequently commit your code to GitHub. This provides a track record of your work and will allow the teaching team to follow your footsteps as you complete your assignment. If you do not frequently commit your code, it will look suspicious.


Git Etiquette

All the take-home programming assignments will require you to make good use of Git and GitHub.

There are marks associated with Git usage. But you could stand to lose more marks if there’s evidence of tampering with your Git commit history.

Make sure you are familiar with the expectations outlined in the Git Etiquette page.


Can I use Copilot and ChatGPT for this assignment?

As you progress through the course, mastering the underlying OOP concepts is essential. Throughout this process, Generative AI tools like Copilot and ChatGPT can be beneficial. They help generate code snippets and assist with programming tasks.

We do not frown upon using these tools. In fact, part of this course includes a task specifically designed to enhance your skills in using these tools critically.

You will notice how these tools can help you write code faster and more efficiently. They boost your productivity.

While these AI tools are valuable, relying too heavily on them can impede your learning. If you depend too much on their output, you may miss out on the opportunity to develop your programming skills. Our goal is to not only acquaint you with tools such as Copilot and ChatGPT but more importantly, to solidify your understanding of core programming concepts for effective application.

This course includes invigilated and practical tests that run without the aid of AI tools (or any other resource for that matter), to ensure you can independently apply what you’ve learned. Over-dependence on AI might make these tests more difficult and stressful.

The real benefit of Generative AI tools lies in understanding the logic of the code they produce, not just in using the code. This video below illustrates the importance of comprehending AI-generated code:


As highlighted in this video, Generative AI is great at filling in the small gaps in your knowledge. Just make sure you aren’t relying on them to fill in the big gaps in your knowledge—because they won’t.


Final Submission on GitHub

In this course, all your assignments will be automatically extracted from GitHub. There will be no separate submission on Canvas.

The following instructions are very important. Make sure you double check everything, otherwise your assignment will not be marked:

  • You must use the GitHub Classroom link provided in the assignment instructions to create your GitHub repository.
  • You must have frequent commits and pushes to GitHub. This will help you to track your progress and also to ensure that you have a backup of your work. It also makes it easier for us to see that you have not been copying from someone else.
  • It is not enough that you were doing git add and git commit commands! This only tracks the changes on your local machine!
  • Unfortunately, it is not a good look for us to hack into your machine in order to take your local repo (even for the good intentions of marking it). Therefore, it is absolutely important you have (correctly) executed a git push so that all your commits and changes are sent to the remote GitHub repository.
  • To make sure you submitted your code, simply go to https://github.com and check the “commits” tab of your assignment repository. Do you see the latest changes there? If so, you are good. If no, something went wrong and you need to sort it out so that it appears in the remote repository before the deadline.
  • As an extra (strongly recommended) precaution, you should clone your GitHub remote repo to your machine (e.g., to a temporary folder), and check it works correctly by compiling it and running it all over again (in a “fresh” directory). This is to protect you if you didn’t correctly include all the changed files (in which case, the assignment runs correctly on your local repo but you didn’t push everything to the remote repo).
  • If you want to submit late, review the Late Submissions section to understand how it works with your GitHub repository.

If you don’t want zero…

It is your responsibility to make sure all your changes are correctly visible on your remote GitHub repository. Read all the submission instructions carefully. It is not enough that you did commits and they appear in your local repository. Even if you pushed them to the remote repository later on (with timestamps before the deadline), it is not enough! The changes must appear in the remote repository before the deadline to be considered for marking. No exceptions.

You must double check that you have uploaded the correct code for marking! There will be no exceptions if you accidentally submitted the wrong files, regardless of whether you can prove you did not modify them since the deadline. No exceptions. Get into the habit of downloading them again, and double-checking all is there.


Late Submissions

Late submissions are based on the GitHub server timestamp

If you intend to submit before the deadline (and not utilise the late penalty allowance), then make sure you have pushed all your commits to your remote GitHub repository before the deadline.

After the 2-day late penalty allowance, we will clone your remote repository. To determine if you have a late submission, we use the GitHub server timestamp. If the timestamp is after the deadline, then it is late.

Please note: We do NOT use the commit timestamps. This is because the commit timestamps are based on your local machine, and can be easily changed. We will therefore only use the GitHub server timestamp to determine if your submission is late or not. No exceptions. This is why it’s your responsibility to make sure you push your commits to the remote repository before the deadline.

If you would like more time and submit late (with penalties), then simply keep working on your assignment and make sure you push the latest commits to the remote repository either 24 hours late or 48 hours late. By looking at the last push timestamp, we will determine if your assignment is 24 hours late or 48 hours late.

After the 48-hour late period passes, your repository will become read-only — and you will not be able to push to it. You will get an error message when you attempt to push, that you do not have access to it. Again, it doesn’t matter if you did the commit within the 48 hours. What matters is that you do the push within the 48 hours.

Remember: your commits need to be pushed and in the remote repository within the 48 hours, not only timestamped!.

Late submissions will incur the following penalties:

  • 15% penalty for 0 minutes < t <= 24 hours late (based on GitHub server timestamp of last push).
  • 30% penalty for 24 hours < t <= 48 hours late (based on GitHub server timestamp of last push).
  • 100% penalty for t > 48 hours late (GitHub repository becomes read-only, no more pushes possible).

It is up to you if you want to risk working on your assignment up until the deadline. If you don’t successfully push to the remote repository before the above deadlines, then it will be late. Don’t risk it.

We will stick by these clearly-specified rules. We have to be fair to everyone, and we will not be able to make exceptions to these rules due to mistakes or misunderstandings. If you are unsure about anything, please ask in Ed Discussion well ahead of the deadline.