p4-web
EECS 280 Project 4: Web
Due 8:00pm Thursday November 10, 2022. You may work alone or with a partner (partnership guidelines).
Fall 2022 release.
Fall 2022
For this term, the driver portion of the project that implements the web API (api.cpp
) is OPTIONAL and is NOT GRADED on the autograder.
The List.h
and List_tests.cpp
files are all that is required.
You are still welcome to do the whole project if you like, or to return to it on your own after the course has finished.
Introduction
Build a web server for an office hours queue.
The learning goals of this project include Container ADTs, Dynamic Memory, The Big Three, Linked Lists, and Iterators. You will gain experience with new
and delete
, constructors and destructors, and the list
data structure.
When you’re done, you’ll have a working web application accessible through your browser.
Web app background
When you browse to a web site like our EECS 280 office hours queue http://eecsoh.org, your computer makes a request and a server returns a response.
Simple web pages
Your web browser makes a request when you visit a page. First, it connects to the eecsoh.org
server, then requests the /index.html
page (“no filename” is a shortcut for index.html
).
GET / HTTP/1.1
The eecsoh.org
server responds with plain text in HTML format. Your browser renders the HTML, adding colors, formatting and images.
HTTP/1.1 200 OK
<html>
<body>
EECS Office Hours
...
</body>
</html>
HTTP
HTTP is the protocol that describes what requests and responses should look like. Both are plain text sent from one computer to another computer through the internet. Let’s take a second look at the previous example in more detail.
The request contains an action (GET
), a path (/eecsoh/
), a version (HTTP/1.1
) and some headers (Host: localhost
). Headers are key/value pairs separated by a colon.
GET /eecsoh/ HTTP/1.1
Host: localhost
The response contains a version (HTTP/1.1
), a status code (200
), status description (OK
), some headers (Content-Type ...
and Content-Length ...
), and a body (<html> ... </html>
).
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 3316
<html>
<body>
EECS Office Hours
...
</body>
</html>
Web 2.0 applications
Web 2.0 applications like the EECS 280 office hours queue interact with the user. Let’s take a look at what happens when you click the “Sign Up” button.
First, the client’s web browser sends an HTTP request to the server. The request might look like this. Notice that the request includes a body with the information entered by the client. The information is in a machine-readable format called JSON.
POST /api/queue/tail/ HTTP/1.1
Host: localhost
Content-Type: application/json; charset=utf-8
Content-Length: 59
{
"uniqname": "awdeorio",
"location": "2705 BBB"
}
Next, the server receives the request sent by the client. The server acts on the request.
- Deserialize the JSON data, converting it into a data structure
- Modify an internal data structure, possibly a list
- Create a response data structure
- Serialize the response data structure, converting it to JSON
- Send the response to the client
The response to the client might look like this.
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
Content-Length: 78
{
"location": "2705 BBB",
"position": 1,
"uniqname": "awdeorio"
}
Finally, the client receives the response and updates the web page, showing the up-to-date queue in this example.
A server that responds to requests with data instead of HTML is called a REST API (REpresentational State Transfer). REST APIs return data in a machine-readable format like JSON.
Our tutorial Working with JSON provides many more details about the JSON format.
Setup
We’ll remind you which parts of the EECS 280 Setup Mega Tutorial you need to look back at to get started on this project.
Group registration
Please register your partnership (or working alone) on the Autograder.
Project folder
Create a folder for this project (instructions). Your folder location might be different.
$ pwd
/Users/awdeorio/src/eecs280/p4-web
Version control
Set up version control using the Version control tutorial. If you’ve used version control before on your computer, you’ll probably want to start with the Create a local repository section.
Be sure to check out the Version control for a team tutorial.
After you’re done, you should have a local repository with a “clean” status and your local repository should be connected to a remote GitLab repository.
$ pwd
/Users/awdeorio/src/eecs280/p4-web
$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
nothing to commit, working tree clean
$ git remote -v
origin https://gitlab.eecs.umich.edu/awdeorio/p4-web.git (fetch)
origin https://gitlab.eecs.umich.edu/awdeorio/p4-web.git (push)
You should have a .gitignore
file (instructions).
$ pwd
/Users/awdeorio/src/eecs280/p4-web
$ head .gitignore
# This is a sample .gitignore file that's useful for C++ projects.
...
Starter files
Download the starter files and unpack them. These instructions are adapted from the Setup Tutorial Starter files section.
$ pwd
/Users/awdeorio/src/eecs280/p4-web
$ wget https://eecs280staff.github.io/p4-web/starter-files.tar.gz
$ tar -xvzf starter-files.tar.gz
$ ls
starter-files starter-files.tar.gz
Move the starter files from starter-files/
to your present working directory (.
) and clean up the old directory and tarball.
$ mv starter-files/* .
$ rm -rf starter-files/ starter-files.tar.gz
$ ls
List.h.starter public_error01.in test03.in
List_compile_check.cpp public_error01.out.correct test03.out.correct
List_public_test.cpp server.py test04.in
List_tests.cpp test01.in test04.out.correct
Makefile test01.out.correct test05.in
index.html test02.in test05.out.correct
json.hpp test02.out.correct unit_test_framework.h
Rename each .cpp.starter
file to a .cpp
file.
$ mv List.h.starter List.h
Create these new files.
$ touch api.cpp
Your project directory should look like this.
$ ls
List.h public_error01.in test03.in
List_compile_check.cpp public_error01.out.correct test03.out.correct
List_public_test.cpp server.py test04.in
List_tests.cpp test01.in test04.out.correct
Makefile test01.out.correct test05.in
index.html test02.in test05.out.correct
json.hpp test02.out.correct unit_test_framework.h
Here’s a short description of each starter file.
File(s) | Description |
---|---|
List.h.starter |
Skeleton List class template header file without function implementations. Rename this file to List.h and then add your function implementations. |
List_tests.cpp |
Add your List unit tests to this file. |
List_compile_check.cpp |
A “does my code compile” test for List.h |
List_public_test.cpp |
A very small test case for List.h . |
test01.in test01.out.correct test02.in test02.out.correct test03.in test03.out.correct test04.in test04.out.correct test05.in test05.out.correct |
Simple test cases for the server program. |
Makefile |
A Makefile that has targets for compiling the published test cases and your own tests. Use$ make test to compile and run all tests. |
json.hpp |
The library you must use to work with JSON. See Working with JSON for details. |
unit_test_framework.h |
The unit test framework you must use to write your test cases. |
server.py |
Python wrapper script for running the office hours queue server. |
index.html |
HTML for the office hours queue. |
Create a project in your IDE
Create a project in your IDE (visual debugger). Later, we’ll compile and debug.
VS Code
If you’ve already used VS Code on your computer before, all you need to do is start VS Code from your project directory. Otherwise, start the tutorial at the beginning. Stop after you’ve completed the Install the C/C++ extension section.
$ pwd
/Users/awdeorio/src/eecs280/p4-web
$ code .
Visual studio
If you’ve already used Visual Studio on your computer before, start the tutorial at the Create a project section, otherwise start at the beginning. Stop after you’ve completed the Add existing files section.
Xcode
If you’ve already used Xcode on your computer before, start the tutorial at the Create a project section, otherwise start at the beginning. Stop after you’ve completed the Add existing files section.
Compile
Next, we’ll get all our code to compile by adding function stubs.
List
Edit List.h
, adding a function stub for every function prototype at the top of List.h
. Recall the example of function stubs in Project 1’s stats.cpp
.
Pro-tip: Start by copy-pasting each function prototype from the class declaration at the top of List.h
to the bottom of the same file.
Here is an example of a function stub to get you started.
template<typename T>
bool List<T>::empty() const {
assert(false);
}
Now you should be able to compile and run the List unit tests. The public tests will fail until you implement the functions. The test you write (List_tests.cpp
) will pass because the starter file only contains ASSERT_TRUE(true)
.
$ make List_public_test.exe
c++ -Wall -Werror -pedantic --std=c++11 -g List_public_test.cpp -o List_public_test.exe
$ ./List_public_test.exe
Running test: test_list_default_ctor
Assertion failed: (false), function empty, file ./List.h, line 136.
$ make List_tests.exe
c++ -Wall -Werror -pedantic --std=c++11 -g List_tests.cpp -o List_tests.exe
$ ./List_tests.exe
Running test: test_stub
PASS
*** Results ***
** Test case "test_stub": PASS
*** Summary ***
Out of 1 tests run:
0 failure(s), 0 error(s)
At this point, we haven’t written the List Iterator, so List_compile_check.exe
won’t compile. You’ll need to take a look at the lecture about iterators and write your own tests. After you do, use the provided compile check like this:
$ make List_compile_check.exe
API
Edit api.cpp
to print a message, similar to Project 1’s main.cpp
.
Make sure that the Project UID is in the comments at the top.
// Project UID c1f28c309e55405daf00c565d57ff9ad
You should be able to compile and run your main function.
$ make api.exe
c++ -Wall -Werror -pedantic --std=c++11 -g api.cpp -o api.exe
$ ./api.exe
hello from main!
Everything
You can check if everything compiles all at once by running make -j
, which compiles everything in parallel. The tests will fail until you’ve implemented the functions. Also, List_compile_check.exe
won’t compile until you write the List Iterator.
$ make clean
rm -vrf *.o *.exe *.gch *.dSYM *.stackdump *.out
$ make -j
Commit and submit
Now that your code compiles with function stubs, it’s a great time to make a Git commit and make your first autograder submission.
Submit the code you have to the autograder. It’s best to find out early if there’s a mismatch between the autograder and your local development environment.
Make a git commit.
$ git status
$ git add .
$ git commit -m "Starter files with function stubs"
$ git push
Debug
Configure your visual debugger to compile and run the api.exe
with the test01.in
system test.
Here’s how to run test01
from the command line. We see that the actual output (test01.out
) says “hello from main!”, but the correct output provided with the starter files (test01.out.correct
) says “HTTP/1.1 …”.
$ make api.exe
c++ -Wall -Werror -pedantic --std=c++11 -g api.cpp -o api.exe
$ ./api.exe < test01.in > test01.out
$ diff test01.out test01.out.correct
1c1,9
< hello from main!
---
> HTTP/1.1 200 OK
> Content-Type: application/json; charset=utf-8
> Content-Length: 160
>
> {
> "queue_head_url": "http://localhost/queue/head/",
> "queue_list_url": "http://localhost/queue/",
> "queue_tail_url": "http://localhost/queue/tail/"
> }
VS Code
Follow the VS Code Run instructions and configure it to run api.exe
. Don’t forget to change stats_tests.exe
to api.exe
in launch.json
.
Edit the setting for input redirection so that test01.in
is the input file.
Finally, follow the Debug instructions to run your program with a breakpoint.
Visual Studio
First, make sure the correct files are included in the build. You can figure out the right files by compiling at the command line. In this example, you can see that we’ll need only api.cpp
. All other files should be excluded from the build.
$ make api.exe
c++ -Wall -Werror -pedantic --std=c++11 -g api.cpp -o api.exe
Edit the setting for input redirection so that test01.in
is the input file.
Now you should be able to run your main program in api.cpp
from inside Visual Studio (instructions).
Finally, follow the Debug instructions to run your program with a breakpoint.
Xcode
First, make sure the correct files are included in the Xcode compile sources. You can figure out the right files by compiling at the command line. In this example, you can see that we’ll need only api.cpp
. All other files should be excluded from the build.
$ make api.exe
c++ -Wall -Werror -pedantic --std=c++11 -g api.cpp -o api.exe
Next, change the settings for running your program (instructions).
Follow the instructions for input redirection so that test01.in
is the input file.
Finally, follow the Debug instructions to run your program with a breakpoint.
Configure Address Sanitizer
The Address Sanitizer is very good at finding memory errors, including going off the end of an array or vector or making a mistake with a pointer. Use the Address Sanitizer Quick Start.
Queue REST API
The top-level application is an office hours queue REST API that reads requests from stdin (cin
) and writes responses to stdout (cout
). Requests and responses are formatted using a simplified subset of real HTTP.
Write the program in api.cpp
. Run it with one of our provided input files.
$ make api.exe
$ ./api.exe < test01.in
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 160
{
"queue_head_url": "http://localhost/queue/head/",
"queue_list_url": "http://localhost/queue/",
"queue_tail_url": "http://localhost/queue/tail/"
}
Libraries
A queue contains items stored in first-in-first-out order: the first item to be added is also the first one to be removed. Queues are commonly implemented using a linked list. A linked list allows insertion and removal at both ends, allowing items to be added at one end and removed at the other. This is in contrast to a vector, which only allows insertion and removal at one end.
Use the standard library list
so you can get started on this project right away. Later, you’ll implement your own linked list that works just like the STL.
The REST API will implement the requests summarized in this table. The following sections provide more detail.
Request | Description |
---|---|
GET /api/ |
Read routes |
GET /api/queue/ |
Read all queue positions |
GET /api/queue/head/ |
Read first queue position |
POST /api/queue/tail/ |
Create last queue position |
DELETE /api/queue/head/ |
Delete first queue position |
Design
Use a linked list
containing a struct
or class
to store your queue. Don’t use json
objects to store your queue or the data in your queue.
Here’s an outline of how to structure your solution.
- Read a request with
cin
- To read data, create a temporary
json
object and usecin
(Reading JSON from a stream)
- To read data, create a temporary
- Read or write the
list
data structure - Write a response with
cout
- To write data, create a temporary
json
object and usecout
(Writing JSON to a stream)
- To write data, create a temporary
Your code should be structured in such a way that your program will return 0
if it fails to read the beginning of a request from cin (i.e. it fails to read one of “GET /api/”, “POST /api/queue/tail/”, etc. because of some error, including end of file). NOTE: Your code should not return
from main if it encounters an error as described in Error handling.
Pro-tip: Here’s how the instructors started their solution.
#include <list>
class OHQueue {
public:
private:
struct Student {
};
std::list<Student> queue;
};
Sample browser session
The following is an example of a browser session that adds three people to an empty queue and then retrieves the full queue.
The browser starts by sending a POST
request to the /api/queue/tail
path to add a student. The request body includes the student’s uniqname and location.
POST /api/queue/tail/ HTTP/1.1
Host: localhost
Content-Type: application/json; charset=utf-8
Content-Length: 58
{
"uniqname": "awdeorio",
"location": "Table 3"
}
The server returns the following response, indicating success:
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
Content-Length: 77
{
"location": "Table 3",
"position": 1,
"uniqname": "awdeorio"
}
The browser sends a second POST
request to add another student:
POST /api/queue/tail/ HTTP/1.1
Host: localhost
Content-Type: application/json; charset=utf-8
Content-Length: 57
{
"uniqname": "akamil",
"location": "Table 15"
}
The server responds:
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
Content-Length: 76
{
"location": "Table 15",
"position": 2,
"uniqname": "akamil"
}
The browser adds one more student to the queue:
POST /api/queue/tail/ HTTP/1.1
Host: localhost
Content-Type: application/json; charset=utf-8
Content-Length: 75
{
"uniqname": "jklooste",
"location": "Desks behind bookshelves"
}
The server response:
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
Content-Length: 94
{
"location": "Desks behind bookshelves",
"position": 3,
"uniqname": "jklooste"
}
The browser now sends a GET
request to the /api/queue/
path to obtain the entire queue:
GET /api/queue/ HTTP/1.1
Host: localhost
Content-Type: application/json; charset=utf-8
Content-Length: 0
The server responds with the contents of the queue in order:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 412
{
"count": 3,
"results": [
{
"location": "Table 3",
"position": 1,
"uniqname": "awdeorio"
},
{
"location": "Table 15",
"position": 2,
"uniqname": "akamil"
},
{
"location": "Desks behind bookshelves",
"position": 3,
"uniqname": "jklooste"
}
]
}
The requests for this example are in the file test02.in
, and the responses are in test02.out.correct
.
Request format
Every request has the same format. The only parts that change are the method (GET
in this example), the path (/api/
in this example), the content length (0
here) and the body (empty here).
The content length in a request is the number of bytes in the body. Two newlines between the headers and the body are not included in the content length. Each body is followed a newline, which is included in the content length.
In this example, the two newlines separating the headers and the body are present, but the body is empty. That is why you see a blank line at the end and Content-Length: 0
.
GET /api/ HTTP/1.1
Host: localhost
Content-Type: application/json; charset=utf-8
Content-Length: 0
Response format
Every response has the same format. The only parts that change are the response code (200
in this example), the content length (160
) and the body. The body is everything inside the curly braces { ... }
followed by a trailing newline.
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 160
{
"queue_head_url": "http://localhost/queue/head/",
"queue_list_url": "http://localhost/queue/",
"queue_tail_url": "http://localhost/queue/tail/"
}
Your implementation must order key-value pairs alphabetically by key. Use the process in Writing JSON to a stream to ensure that the ordering is correct.
The content length in a response is the number of bytes in the body. Two newlines between the headers and the body are not included in the content length. Each body is followed a newline, which is included in the content length.
Error handling
Your implementation may assume that requests are properly formatted, and that the HTTP method is one of GET
, DELETE
, or POST
. However, you must handle the following errors:
- HTTP path is not valid. The path must exactly match one of
/api/
,/api/queue/
,/api/queue/head/
, or/api/queue/tail/
, including the slashes. - HTTP method is not appropriate for the path. For example,
POST /api/
.
If one of the errors above occurs, read the remainder of the request, including any headers or body. Then, return the following response after reading the entire request. Note that there is a blank line after Content-Length: 0
.
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Content-Length: 0
The Content-Length
in the HTTP header tells you whether or not there is a body. If the length is nonzero, a body follows. You may assume that the Content-Length
of a request is correct.
GET /api/
The /api/
route accepts a GET
request and returns a list of URLs supported by this REST API. It always returns the same data. See the examples in Request format and Response format for the input and output for this path.
Run the unit test.
$ make api.exe
$ ./api.exe < test01.in > test01.out
$ diff test01.out test01.out.correct
Pro-tip: Debug output differences using sdiff -B
, which shows differences side-by-side and ignores whitespace. We’ll use the less
pager so we can scroll through the long terminal output. Press q
to quit.
$ ./api.exe < test01.in > test01.out
$ sdiff -B test01.out test01.out.correct | less # q to quit
POST /api/queue/tail/
The /api/queue/tail/
route accepts a POST
request and creates one new person on the queue. As a simplification, we do not check if a person is already on the queue, thus the same uniqname may appear multiple times.
Example request
POST /api/queue/tail/ HTTP/1.1
Host: localhost
Content-Type: application/json; charset=utf-8
Content-Length: 58
{
"uniqname": "jackgood",
"location": "Table 5"
}
Example response
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
Content-Length: 77
{
"location": "Table 5",
"position": 1,
"uniqname": "jackgood"
}
Run the unit test.
$ make api.exe
$ ./api.exe < test04.in > test04.out
$ diff test04.out test04.out.correct
GET /api/queue/head/
The /api/queue/head
route accepts a GET
request and returns the person at the head of the queue. Fields are in the order shown by the example, and the person at the head of the queue always has position 1. If the queue is empty, return a 400
error.
Example request
GET /api/queue/head/ HTTP/1.1
Host: localhost
Content-Type: application/json; charset=utf-8
Content-Length: 0
Example response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 77
{
"location": "Table 3",
"position": 1,
"uniqname": "awdeorio"
}
Run the unit test.
$ make api.exe
$ ./api.exe < test03.in > test03.out
$ diff test03.out test03.out.correct
GET /api/queue/
The /api/queue/
route accepts a GET
request and returns a list of everyone on the queue, including location
, position
and uniqname
in that order. The list is ordered by position, which always starts with 1 for the person currently at the head of the queue.
Example request
GET /api/queue/ HTTP/1.1
Host: localhost
Content-Type: application/json; charset=utf-8
Content-Length: 0
Example response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 412
{
"count": 3,
"results": [
{
"location": "Table 3",
"position": 1,
"uniqname": "awdeorio"
},
{
"location": "Table 15",
"position": 2,
"uniqname": "akamil"
},
{
"location": "Desks behind bookshelves",
"position": 3,
"uniqname": "jklooste"
}
]
}
If the queue is empty, the response should be:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 40
{
"count": 0,
"results": null
}
Run the unit test.
$ make api.exe
$ ./api.exe < test02.in > test02.out
$ diff test02.out test02.out.correct
DELETE /api/queue/head/
The /api/queue/head/
route accepts a DELETE
request and removes the person at the head of the queue.
Example request
DELETE /api/queue/head/ HTTP/1.1
Host: localhost
Content-Type: application/json; charset=utf-8
Content-Length: 0
Example response
HTTP/1.1 204 No Content
Content-Type: application/json; charset=utf-8
Content-Length: 0
If the queue is empty, return a 400
error.
Run the unit test.
$ make api.exe
$ ./api.exe < test05.in > test05.out
$ diff test05.out test05.out.correct
Real web server (Optional)
Once you have a working solution for the office hours queue API as specified, you have a working back-end for a real office hours queue web server!
First, make sure your API passes all the unit tests.
$ make test-api
Build and start the server. You might need to install Python 3 with brew install python3
(macOS) or apt-get install python3
(WSL or Linux).
$ make api.exe
$ python3 server.py
Starting server on localhost:8000
In a web browser, navigate to http://localhost:8000/index.html. You should see a web page. A shortcut is http://localhost:8000.
Now try http://localhost:8000/api/. You should see JSON data.
Your browser is sending a GET request over the network. Let’s try it using the command line using a second terminal.
$ curl localhost:8000/api/
{
"queue_head_url": "http://localhost/queue/head/",
"queue_list_url": "http://localhost/queue/",
"queue_tail_url": "http://localhost/queue/tail/"
}
The server.py
script listens for incoming network requests. If the client request path starts with /api
, it copies the request to the stdin of api.exe
and copies the stdout of api.exe
back to the client. Otherwise, server.py
copies a file to the client over the network (e.g., index.html
).
Visual Studio Note: If you are working on Windows and use Visual Studio (not to be confused with Visual Studio Code), compile api.exe
from the Ubuntu (WSL) terminal (make api.exe
), just for this demo. This avoids a problem with Windows vs. Linux line endings when running server.py
.
Submit
Run all the API tests.
$ make test-api
Submit api.cpp
to the autograder.
Linked list
Implement your doubly linked list in List.h
. List.h.starter
provides prototypes for each function. Because List
is a templated container, function implementations go in List.h
. There is no List.cpp
.
While the List
from lecture was singly linked, this List
is doubly linked.
This List
also contains an iterator interface.
Do not modify the public interface of the List
class. Implement a doubly-linked list. No arrays or vectors, etc. Manage memory allocation so that there are no memory leaks.
Compile and run the provided compile check and List
tests.
$ make List_compile_check.exe
$ make List_public_test.exe
$ ./List_public_test.exe
Write tests for List
in List_tests.cpp
using the Unit Test Framework. You’ll submit these tests to the autograder. See the Unit Test Grading section.
$ make List_tests.exe
$ ./List_tests.exe
Pro-tip: Getting an error about typename
? Take a look at our reference on Typename.
Submission and grading
Submit these files to the autograder.
List.h
List_tests.cpp
api.cpp
This project will be autograded for correctness, comprehensiveness of your test cases, and programming style. See the style checking tutorial for the criteria and how to check your style automatically on CAEN.
Testing
Run all the unit tests and system tests. This includes the public tests we provided and the unit tests that you wrote.
$ make test
Unit Test Grading
We will autograde your List
unit tests.
Your unit tests must use the unit test framework.
A test suite must complete less than 5 seconds and contain 50 or fewer TEST()
items. One test suite is one _test.cpp
file.
To grade your unit tests, we use a set of intentionally buggy instructor solutions. You get points for catching the bugs.
- We compile and run your unit tests with a correct solution.
- Tests that pass are valid.
- Tests that fail are invalid, they falsely report a bug.
- We compile and run all of your valid tests against each buggy solution.
- If any of your tests fail, you caught the bug.
- You earn points for each bug that you catch.
Requirements and restrictions
It is our goal for you to gain practice with good C++ code, classes, and dynamic memory.
DO | DO NOT |
---|---|
Modify .cpp files and List.h |
Modify other .h files |
For List , make helper member functions private |
Modify the public interface of List |
Use these libraries: <iostream> , <string> , <cassert> , <sstream> , <utility> |
Use other libraries |
Use <list> (and optionally <algorithm> ) in api.cpp |
Use <algorithm> , <list> , or other containers in List.h |
#include a library to use its functions |
Assume that the compiler will find the library for you (some do, some don’t) |
Use C++ strings | Use C-strings |
Send all output to standard out (AKA stdout) by using cout |
Send any output to standard error (AKA stderr) by using cerr |
Pass large structs or classes by reference | Pass large structs or classes by value |
Pass by const reference when appropriate | “I don’t think I’ll modify it …” |
Use the Address Sanitizer to check for memory errors | “It’s probably fine…” |