Add unit tests instead of main; more implementations

This commit is contained in:
karl 2021-03-05 15:25:09 +01:00
parent 2efd3407ac
commit d313d0ce63
7 changed files with 20691 additions and 53 deletions

2
.vscode/launch.json vendored
View File

@ -5,7 +5,7 @@
"version": "0.2.0",
"configurations": [
{
"name": "Debug",
"name": "Test",
"type": "gdb",
"request": "launch",
"target": "./vector.out",

View File

@ -6,4 +6,7 @@ Run `scons` in the root directory.
## Developing
The `scons` command also generates a `compile_commands.json` which can be used by the VSCodium extension `clangd` for autocompletion, debugging, etc.
Build and run scripts for VSCodium are provided as well.
Build and run scripts for VSCodium are provided as well.
## Credits
Catch2 for unit tests: https://github.com/catchorg/Catch2

View File

@ -9,7 +9,6 @@ class Vector {
// Constructor
Vector(unsigned int capacity = 10)
: capacity(capacity), element_count(0), data(new T[capacity]) {
std::cout << "Vector created" << std::endl;
}
// Copy Constructor
@ -30,6 +29,9 @@ class Vector {
// Copy Assignment Operator using the copy-and-swap-idiom
// Since this takes a value rather than a const reference due to
// copy-and-swap, this is also the Move Assignment Operator
// This works because we pass-by-value, causing the copy constructor (which
// does the actual copying) to be called, and then we swap the resulting
// temporary into `this`.
Vector &operator=(Vector other) {
swap(*this, other);
@ -39,8 +41,6 @@ class Vector {
// Destructor
~Vector() {
delete[] data;
std::cout << "Vector deleted" << std::endl;
}
// Bracket Operator
@ -48,6 +48,19 @@ class Vector {
return at(position);
}
// Equals Operator
bool operator==(const Vector &other) {
if (size() != other.size()) return false;
for (unsigned int i = 0; i < size(); i++) {
if (at(i) != other[i]) {
return false;
}
}
return true;
}
// Swap function for the copy-and-swap idiom.
// See also:
// https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom
@ -93,9 +106,31 @@ class Vector {
return data[position];
}
void reserve(unsigned int);
// Expand the capacity (length) of the vector by the given addition
void reserve(unsigned int addition) {
// TODO: Actual reserve
capacity += addition;
}
void resize(unsigned int);
// Resize the size of the vector to the given new_size
// If this decreases the size, some elements are deleted
// If this increases the size, some default-constructed elements are added
void resize(unsigned int new_size) {
// TODO: Reserve if needed
int difference = new_size - size();
if (difference > 0) {
for (int i = 0; i < difference; i++) {
data[element_count + i] = T();
}
} else if (difference < 0) {
for (int i = -1; i > difference; i--) {
data[element_count + i].~T();
}
}
element_count += difference;
}
private:
T *data;

9430
catch_amalgamated.cpp Normal file

File diff suppressed because it is too large Load Diff

10987
catch_amalgamated.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,46 +0,0 @@
#include "Vector.h"
#include <iostream>
void print_float_vector(const Vector<float> &v) {
for (int i = 0; i < v.size(); i++) {
std::cout << v[i] << ", ";
}
std::cout << std::endl;
}
int main() {
Vector<float> vector1;
vector1.push_back(0.5);
vector1.push_back(0.7);
vector1.push_back(1.2);
vector1.push_back(2.0);
vector1.push_back(3.0);
std::cout << "Before erase at 2" << std::endl;
print_float_vector(vector1);
vector1.erase(2);
std::cout << "After erase at 2" << std::endl;
print_float_vector(vector1);
Vector<float> vector2 = std::move(vector1);
std::cout << "After std::move" << std::endl;
print_float_vector(vector2);
Vector<float> vector3 = vector2;
std::cout << "After copy construction" << std::endl;
print_float_vector(vector2);
print_float_vector(vector3);
Vector<float> vector4;
vector4.push_back(7353.0);
vector4 = vector3;
std::cout << "After copy assignment" << std::endl;
print_float_vector(vector3);
print_float_vector(vector4);
}

229
test.cpp Normal file
View File

@ -0,0 +1,229 @@
#include "Vector.h"
#include <iostream>
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this
// in one cpp file
#include "catch_amalgamated.hpp"
SCENARIO("Vector size and length are correct", "[vector]") {
Vector<int> v(20);
v.push_back(1);
REQUIRE(v.size() == 1);
REQUIRE(v.length() == 20);
}
SCENARIO("The bracket operator returns the correct element", "[vector]") {
Vector<int> v(20);
v.push_back(1);
v.push_back(2);
v.push_back(3);
REQUIRE(v[1] == 2);
}
SCENARIO("Equality is returned correctly", "[vector]") {
GIVEN("Two vectors with the same items") {
Vector<int> v1;
Vector<int> v2;
v1.push_back(1);
v2.push_back(1);
v1.push_back(5);
v2.push_back(5);
REQUIRE(v1.size() == 2);
REQUIRE(v2.size() == 2);
WHEN("Comparing them") {
bool equals = v1 == v2;
THEN("The result should be true") {
REQUIRE(equals);
}
}
}
GIVEN("Two vectors with different items") {
Vector<int> v1;
Vector<int> v2;
v1.push_back(1);
v2.push_back(2);
v1.push_back(5);
v2.push_back(5);
REQUIRE(v1.size() == 2);
REQUIRE(v2.size() == 2);
WHEN("Comparing them") {
bool equals = v1 == v2;
THEN("The result should be false") {
REQUIRE_FALSE(equals);
}
}
}
}
SCENARIO("Erasing an item removes it and moves the following ones forward",
"[vector]") {
GIVEN("Two vectors with almost identical items") {
Vector<int> v1;
Vector<int> v2;
v1.push_back(1);
v2.push_back(1);
v1.push_back(2);
v2.push_back(5);
v1.push_back(5);
v1.push_back(10);
v2.push_back(10);
REQUIRE(v1.size() == 4);
REQUIRE(v2.size() == 3);
WHEN("Comparing them") {
bool equals = v1 == v2;
THEN("The result should be false") {
REQUIRE_FALSE(equals);
}
}
WHEN("Erasing the different item") {
v1.erase(1);
bool equals = v1 == v2;
THEN("The result should be true") {
REQUIRE(equals);
}
}
}
}
SCENARIO("Copy Assignment", "[vector]") {
GIVEN("Two vectors with identical items") {
Vector<int> v1;
Vector<int> v2;
v1.push_back(1);
v2.push_back(1);
v1.push_back(5);
v2.push_back(5);
REQUIRE(v1.size() == 2);
REQUIRE(v2.size() == 2);
WHEN("Copy assigning the second vector to a third vector") {
Vector<int> v3;
v3 = v2;
THEN("All vectors should be identical") {
bool equals = v1 == v2 && v2 == v3 && v1 == v3;
REQUIRE(equals);
}
}
}
}
SCENARIO("Move Assignment", "[vector]") {
GIVEN("Two vectors with identical items") {
Vector<int> v1;
Vector<int> v2;
v1.push_back(1);
v2.push_back(1);
v1.push_back(5);
v2.push_back(5);
REQUIRE(v1.size() == 2);
REQUIRE(v2.size() == 2);
WHEN("Move assigning the second vector to a third vector") {
Vector<int> v3;
v3 = std::move(v2);
THEN("The first and third vector should be identical") {
bool equals = v1 == v3;
REQUIRE(equals);
}
}
}
}
SCENARIO("Reserve additional space", "[vector]") {
GIVEN("A vector with a given capacity") {
Vector<int> v(5);
REQUIRE(v.length() == 5);
WHEN("Reserving additional space") {
v.reserve(10);
THEN("The capacity has increased accordingly") {
REQUIRE(v.length() == 15);
}
}
}
}
SCENARIO("Resizing a vector", "[vector]") {
GIVEN("A vector with 3 items") {
Vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
Vector<int> target;
target.push_back(1);
target.push_back(2);
target.push_back(3);
target.push_back(0);
target.push_back(0);
WHEN("Resizing to 5") {
v.resize(5);
THEN("The size should be 5") {
REQUIRE(v.size() == 5);
}
THEN("2 new default items should've been added") {
bool equals = v == target;
REQUIRE(equals);
}
}
WHEN("Resizing to 1") {
v.resize(1);
THEN("The size should be 1") {
REQUIRE(v.size() == 1);
}
THEN("The remaining element should be correct") {
REQUIRE(v[0] == 1);
}
THEN("Adding the elements again produces the same result again") {
v.push_back(2);
v.push_back(3);
v.push_back(0);
v.push_back(0);
bool equals = v == target;
REQUIRE(equals);
}
}
}
}