Skip to content

Commit

Permalink
Finished readme
Browse files Browse the repository at this point in the history
  • Loading branch information
rowanG077 committed Nov 12, 2018
1 parent 87f5ab7 commit 0f6b6c8
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 51 deletions.
64 changes: 58 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ Given a set of boxes where each box has a height, length and depth between 0.5m

# Usage
```
usage: box_nesting [options]
usage: BoxNesting [options]
basic user options:
-h --help show this message
-v --version show version
-h --help show this message
-v --version show version
when no options are specified program waits for input of boxes on stdin in the following format:
Expand Down Expand Up @@ -51,7 +51,7 @@ Now the executable will be available in `build/src/BoxNesting`
## Test
The project uses the catch2 testing framework. The build is tested with version 2.4.2 but it should work with any version >= 2.0.0

To enable testing the `-DTEST:BOOL=ON` has to be passed to cmake. Subsequentally the `test` target is available on the resulting make file and the test executable will be build when building the code.
To enable testing the `-DTEST:BOOL=ON` has to be passed to cmake. Subsequentally the `test` target is available on the resulting make file and the test executable will be build when building the code. Running `make test` will run all test cases and print the results.

Example usage:

Expand Down Expand Up @@ -88,14 +88,66 @@ Example usage:
## Flawfinder
Flawfinder is a static checked which is also used to ensure a higher code quality, tested with version 2.0.7. There is a specific target for this checked since it's not ran while building the code.

Example usage:

```
> mkdir build && cd build
> cmake ../ -DFLAWFINDER=ON
> make
> make flawfinder
```

## Sanitizer

When using gcc there is support for running the undefined behaviour sanitizer(ubsan) and the adress sanitizer(asan) which can detect certain issues with the program at runtime. To enable the sanitizers to be included in the code the `-DSANITISE:BOOL=ON` flag can be passed to cmake. Then the resulting executables(code and test) will be instrumented with the sanitizers. Please note that enabling these sanitizers can NOT be enabled at the same time as code coverage instrumentation since they are not compatible with eachother.

Example usage:

```
> mkdir build && cd build
> cmake ../ -DSANITISE:BOOL=ON
> make
```

## Code coverage
When using gcc there is support for instrumenting the code with coverage counters and generating a html report(dependency on gcov >= 7.3 and lcov >= 1.13 other version might work or they might not). This will allow you to get insight on what lines are hit in your code and how many times. Note that these flags cannot be enabled at the same time as the Sanitizer flags since they are incompatible. To enable the code coverage counters the `-DSANITISE:BOOL=ON` flag can be passed to cmake. Now when running the program or the tests coverage counter files will be generated. These can be converted to a html page by running `make coverage_report`. Since multiple runs of the code can poison the counters to no longer make much sense another target is available `make coverage_reset` which will reset the counters.

Example usage:

```
> mkdir build && cd build
> cmake ../ -DCOVERAGE:BOOL=ON -DTEST:BOOL=ON
> make
> make test
> make coverage_report
> make coverage_reset
```

## Doxygen
Doxygen documentation html pages can be build by passing `-DDOXYGEN:BOOL=ON` to cmake and then building it with `make doxygen`. This has a dependency on doxygen >= 1.8.13 and graphviz >= 2.40. Other version might work but they might not.

```
> mkdir build && cd build
> cmake ../ -DDOXYGEN:BOOL=ON
> make doxygen
```

## Warnings as errors
By default any target will not fail if it somehow emits warnings. If `-DWERROR:BOOL=ON` is passed to cmake any warnings will turn into errors and building will be stopped when any error is encountered.

Example usage:

```
> mkdir build && cd build
> cmake ../ -DWERROR:BOOL=ON
> make
```

## Release and debug builds
By default a release build is made. To make an unoptimized debug build pass `-DCMAKE_BUILD_TYPE:STRING=Debug` to cmake.

Example usage:

```
> mkdir build && cd build
> cmake ../ -DCMAKE_BUILD_TYPE:STRING=Debug
> make
```
12 changes: 7 additions & 5 deletions include/BoxNesting/Box.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class Box
* @param sideLengths The length of the sides of the box in each dimensions
* @return A new Box object
*/
explicit Box(const std::array<double, 3>& sideLengths);
explicit Box(const std::array<float, 3>& sideLengths);

/**
* @brief Check if this box can nest inside other box
Expand All @@ -71,19 +71,21 @@ class Box
*
* @return array containing the side lengths ordered from smallest to largest
*/
[[nodiscard]] const std::array<double, 3>& getSideLengths() const { return this->sideLengths; }
[[nodiscard]] const std::array<float, 3>& getSideLengths() const {
return this->sideLengths;
}

/**
* @brief The minimum length that a side of a box may have
* Is non-inclusive so the length x > minLength
*/
static constexpr double minLength = 0.5;
static constexpr float minLength = 0.5;

/**
* @brief The maximum length that a side of a box may have
* Is non-inclusive so the length x < maxLength
*/
static constexpr double maxLength = 1.0;
static constexpr float maxLength = 1.0;

/**
* @brief Static assert on the assumption any box can only contain a single box nested inside
Expand All @@ -96,6 +98,6 @@ class Box
/**
* @brief The lengths of each side ordered from smallest to longest
*/
std::array<double, 3> sideLengths;
std::array<float, 3> sideLengths;
};
}
2 changes: 1 addition & 1 deletion src/Box.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace BoxNesting
{
Box::Box(const std::array<double, 3>& sideLengths) : sideLengths(sideLengths)
Box::Box(const std::array<float, 3>& sideLengths) : sideLengths(sideLengths)
{
std::sort(this->sideLengths.begin(), this->sideLengths.end());

Expand Down
14 changes: 7 additions & 7 deletions src/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,17 @@ Box Parser::parseBoxSpecification(std::istream& inputStream)
throw ParserError(ss.str());
}

double x = 0;
double y = 0;
double z = 0;
float x = 0;
float y = 0;
float z = 0;

try {
x = std::stod(match[1].str());
y = std::stod(match[2].str());
z = std::stod(match[3].str());
x = std::stof(match[1].str());
y = std::stof(match[2].str());
z = std::stof(match[3].str());
} catch (const std::out_of_range& e) {
std::stringstream ss;
ss << "x, y or z length of box is out of range of doubles range, got x: " << match[1].str()
ss << "x, y or z length of box is out of range of floats range, got x: " << match[1].str()
<< ", y: " << match[2].str() << ", z: " << match[3].str();
throw ParserError(ss.str(), e);
}
Expand Down
6 changes: 3 additions & 3 deletions test/Algorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ SCENARIO("Running the 'graph creation from a set of boxes' function")
{
std::vector<BoxNesting::Box> boxes;

boxes.emplace_back(BoxNesting::Box({0.6, 0.6, 0.6}));
boxes.emplace_back(BoxNesting::Box({0.7, 0.7, 0.7}));
boxes.emplace_back(BoxNesting::Box({0.8, 0.8, 0.8}));
boxes.emplace_back(BoxNesting::Box({0.6f, 0.6f, 0.6f}));
boxes.emplace_back(BoxNesting::Box({0.7f, 0.7f, 0.7f}));
boxes.emplace_back(BoxNesting::Box({0.8f, 0.8f, 0.8f}));

BoxNesting::Algorithm boxNestingAlgorithm;

Expand Down
36 changes: 18 additions & 18 deletions test/Box.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ SCENARIO("Box construction and valid side lengths")
THEN("std::invalid_argument is thrown")
{
REQUIRE_THROWS_AS(
BoxNesting::Box({minLength, minLength + 0.01, minLength + 0.01}), std::invalid_argument);
BoxNesting::Box({minLength, minLength + 0.01f, minLength + 0.01f}), std::invalid_argument);
REQUIRE_THROWS_AS(
BoxNesting::Box({minLength + 0.01, minLength, minLength + 0.01}), std::invalid_argument);
BoxNesting::Box({minLength + 0.01f, minLength, minLength + 0.01f}), std::invalid_argument);
REQUIRE_THROWS_AS(
BoxNesting::Box({minLength + 0.01, minLength + 0.01, minLength}), std::invalid_argument);
BoxNesting::Box({minLength + 0.01f, minLength + 0.01f, minLength}), std::invalid_argument);
REQUIRE_THROWS_AS(BoxNesting::Box({minLength, minLength, minLength}), std::invalid_argument);
}
}
Expand All @@ -27,18 +27,18 @@ SCENARIO("Box construction and valid side lengths")
{
THEN("box is constructed")
{
REQUIRE_NOTHROW(BoxNesting::Box({maxLength - 0.01, maxLength - 0.01, maxLength - 0.01}));
REQUIRE_NOTHROW(BoxNesting::Box({maxLength - 0.01f, maxLength - 0.01f, maxLength - 0.01f}));
REQUIRE_NOTHROW(BoxNesting::Box({validLength, validLength, validLength}));
REQUIRE_NOTHROW(BoxNesting::Box({validLength, validLength, minLength + 0.01}));
REQUIRE_NOTHROW(BoxNesting::Box({validLength, minLength + 0.01, validLength}));
REQUIRE_NOTHROW(BoxNesting::Box({minLength + 0.01, minLength + 0.01, minLength + 0.01}));
REQUIRE_NOTHROW(BoxNesting::Box({validLength, validLength, minLength + 0.01f}));
REQUIRE_NOTHROW(BoxNesting::Box({validLength, minLength + 0.01f, validLength}));
REQUIRE_NOTHROW(BoxNesting::Box({minLength + 0.01f, minLength + 0.01f, minLength + 0.01f}));
}

THEN("box lengths are ordered from small to large")
{
const auto l1 = minLength + 0.01;
const auto l2 = minLength + 0.02;
const auto l3 = minLength + 0.03;
const auto l1 = minLength + 0.01f;
const auto l2 = minLength + 0.02f;
const auto l3 = minLength + 0.03f;

const BoxNesting::Box a({l1, l2, l3});
const BoxNesting::Box b({l2, l3, l1});
Expand All @@ -58,11 +58,11 @@ SCENARIO("Box construction and valid side lengths")
THEN("std::invalid_argument is thrown")
{
REQUIRE_THROWS_AS(
BoxNesting::Box({maxLength, maxLength - 0.01, maxLength - 0.01}), std::invalid_argument);
BoxNesting::Box({maxLength, maxLength - 0.01f, maxLength - 0.01f}), std::invalid_argument);
REQUIRE_THROWS_AS(
BoxNesting::Box({maxLength - 0.01, maxLength, maxLength - 0.01}), std::invalid_argument);
BoxNesting::Box({maxLength - 0.01f, maxLength, maxLength - 0.01f}), std::invalid_argument);
REQUIRE_THROWS_AS(
BoxNesting::Box({maxLength - 0.01, maxLength - 0.01, maxLength}), std::invalid_argument);
BoxNesting::Box({maxLength - 0.01f, maxLength - 0.01f, maxLength}), std::invalid_argument);
REQUIRE_THROWS_AS(BoxNesting::Box({maxLength, maxLength, maxLength}), std::invalid_argument);
}
}
Expand All @@ -78,11 +78,11 @@ SCENARIO("Boxes can nest inside another if their dimensions allow it", "[Box]")
GIVEN("a set of boxes")
{
BoxNesting::Box a({validLength, validLength, validLength});
BoxNesting::Box b({validLength, validLength, minLength + 0.01});
BoxNesting::Box c({validLength, minLength + 0.01, validLength});
BoxNesting::Box d({validLength - 0.01, validLength, validLength});
BoxNesting::Box e({validLength - 0.01, validLength - 0.01, validLength - 0.01});
BoxNesting::Box f({minLength + 0.01, minLength + 0.01, minLength + 0.01});
BoxNesting::Box b({validLength, validLength, minLength + 0.01f});
BoxNesting::Box c({validLength, minLength + 0.01f, validLength});
BoxNesting::Box d({validLength - 0.01f, validLength, validLength});
BoxNesting::Box e({validLength - 0.01f, validLength - 0.01f, validLength - 0.01f});
BoxNesting::Box f({minLength + 0.01f, minLength + 0.01f, minLength + 0.01f});

THEN("they can nest inside eachother if their dimensions allow it")
{
Expand Down
6 changes: 3 additions & 3 deletions test/Graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ SCENARIO("A graph of boxes add edged and check if no vertex has an edge to itsse
{
Graph::Graph<BoxNesting::Box> graph;

auto a = Graph::Vertex(BoxNesting::Box({0.6, 0.6, 0.61}));
auto b = Graph::Vertex(BoxNesting::Box({0.6, 0.6, 0.51}));
auto c = Graph::Vertex(BoxNesting::Box({0.6, 0.51, 0.6}));
auto a = Graph::Vertex(BoxNesting::Box({0.6f, 0.6f, 0.61f}));
auto b = Graph::Vertex(BoxNesting::Box({0.6f, 0.6f, 0.51f}));
auto c = Graph::Vertex(BoxNesting::Box({0.6f, 0.51f, 0.6f}));

graph.addVertex(a);
graph.addVertex(b);
Expand Down
16 changes: 8 additions & 8 deletions test/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ SCENARIO("Parsing box specifcations from inputStream")
REQUIRE(boxes.size() == 5);
for (std::size_t i = 0; i < boxes.size(); ++i) {
const auto& l = boxes.at(i).getSideLengths();
auto offset = static_cast<double>(i) * 0.03;
REQUIRE(l.at(0) == Approx(minLength + offset + 0.01));
REQUIRE(l.at(1) == Approx(minLength + offset + 0.02));
REQUIRE(l.at(2) == Approx(minLength + offset + 0.03));
auto offset = static_cast<float>(i) * 0.03f;
REQUIRE(l.at(0) == Approx(minLength + offset + 0.01f));
REQUIRE(l.at(1) == Approx(minLength + offset + 0.02f));
REQUIRE(l.at(2) == Approx(minLength + offset + 0.03f));
}
}
}
Expand All @@ -48,10 +48,10 @@ SCENARIO("Parsing box specifcations from inputStream")
}
}

WHEN("parsing the first line and a very very large number is present")
WHEN("parsing the first line and a large number is present")
{
std::stringstream stream;
stream << "9" << std::numeric_limits<std::uint64_t>::max() << std::endl;
stream << "9" << std::numeric_limits<std::uint16_t>::max() << std::endl;
THEN("a ParserError is thrown")
{
REQUIRE_THROWS_AS(BoxNesting::Parser::getBoxes(stream), BoxNesting::ParserError);
Expand All @@ -68,11 +68,11 @@ SCENARIO("Parsing box specifcations from inputStream")
}
}

WHEN("parsing a specification which is outside of the range of a double")
WHEN("parsing a specification which is outside of the range of a float")
{
std::stringstream stream;
stream << "1" << std::endl
<< std::fixed << "9" << std::numeric_limits<double>::max() << " " << validLength << " "
<< std::fixed << "9" << std::numeric_limits<float>::max() << " " << validLength << " "
<< validLength << std::endl;

THEN("a ParserError is thrown")
Expand Down

0 comments on commit 0f6b6c8

Please sign in to comment.