diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f78ad5..4c101e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ endif() option(CLANG_TIDY "Check code with clang-tidy." OFF) option(CODE "Build primary libraries and executables." ON) option(COVERAGE "Instrument code with coverage flags." OFF) +option(DOXYGEN "Add \"doxygen\" target which builds doxygen HTML output from the sources." OFF) option(FORMAT "Add \"format\" target which runs clang-format." OFF) option(FLAWFINDER "Add \"flawfinder\" target which checks code." OFF) option(SANITISE "Add -fsanitize=address and -fsanitize=undefined flags." OFF) @@ -65,3 +66,7 @@ endif() if(${FLAWFINDER} OR ${FORMAT}) include(check) endif() + +if(${DOXYGEN}) + add_subdirectory(doxygen) +endif() \ No newline at end of file diff --git a/doxygen/CMakeLists.txt b/doxygen/CMakeLists.txt new file mode 100644 index 0000000..ccc2d3a --- /dev/null +++ b/doxygen/CMakeLists.txt @@ -0,0 +1,24 @@ +find_package(Doxygen REQUIRED COMPONENTS dot) + +get_target_property(DOXY_DOT_PATH Doxygen::dot IMPORTED_LOCATION) +get_filename_component(DOXY_DOT_PATH "${DOXY_DOT_PATH}" DIRECTORY) +file(TO_NATIVE_PATH "${DOXY_DOT_PATH}" DOXY_DOT_PATH) + +set(DOXY_BUILD_HTML "YES") +set(DOXY_BUILD_XML "NO") +set(DOXY_OUTPUT_DIR "${PROJECT_BINARY_DIR}/doxygen") +set(DOXY_FILE "${PROJECT_BINARY_DIR}/doxygen/doxyfile") + +configure_file( + "${PROJECT_SOURCE_DIR}/doxygen/doxyfile.in" + DOXY_FILE + @ONLY) + +add_custom_target(doxygen + COMMAND Doxygen::doxygen DOXY_FILE + COMMENT "Generating HTML API documentation with Doxygen") + +add_custom_command(TARGET doxygen POST_BUILD + COMMAND ; + COMMENT "Output at ${DOXY_OUTPUT_DIR}/html/index.html") + diff --git a/doxygen/doxyfile.in b/doxygen/doxyfile.in new file mode 100644 index 0000000..c197688 --- /dev/null +++ b/doxygen/doxyfile.in @@ -0,0 +1,22 @@ +DOT_MULTI_TARGETS = YES +DOT_PATH = "@DOXY_DOT_PATH@" +ENABLE_PREPROCESSING = YES +EXPAND_ONLY_PREDEF = YES +EXTRACT_LOCAL_CLASSES = NO +GENERATE_HTML = @DOXY_BUILD_HTML@ +GENERATE_LATEX = @DOXY_BUILD_LATEX@ +GENERATE_XML = @DOXY_BUILD_XML@ +HAVE_DOT = YES +INPUT = "@PROJECT_SOURCE_DIR@/include" +JAVADOC_AUTOBRIEF = YES +MACRO_EXPANSION = YES +OUTPUT_DIRECTORY = "@DOXY_OUTPUT_DIR@" +PREDEFINED = restrict= +PROJECT_NAME = "@PROJECT_NAME@" +PROJECT_NUMBER = @PROJECT_VERSION@ +QT_AUTOBRIEF = YES +QUIET = YES +RECURSIVE = YES +STRIP_FROM_PATH = "@PROJECT_SOURCE_DIR@" +WARN_AS_ERROR = @DOXY_WARN_AS_ERR@ +WARN_NO_PARAMDOC = YES diff --git a/include/box_nesting/Box.hpp b/include/box_nesting/Box.hpp index f1ee3e7..6cd69fd 100644 --- a/include/box_nesting/Box.hpp +++ b/include/box_nesting/Box.hpp @@ -20,31 +20,31 @@ class Box Box() = delete; /** - * Default virtual destructor. + * Default virtual destructor */ virtual ~Box() = default; /** - * Default copy constructor. + * Default copy constructor * \param b */ Box(const Box& b) = default; /** - * Default move constructor. + * Default move constructor * \param b */ Box(Box&& b) = default; /** - * Default copy assignment operator. + * Default copy assignment operator * \param b * \return */ Box& operator=(const Box& b) = default; /** - * Default move assignment operator. + * Default move assignment operator * \param b * \return */ @@ -61,15 +61,15 @@ class Box /** * @brief Check if this box can nest inside other box * - * @param b The box to check if this box can nest inside. - * @return True if this box can nest inside the passed box. False otherwise + * @param b The box to check if this box can nest inside + * @return True if this box can nest inside the passed box, False otherwise */ [[nodiscard]] bool isNestable(const Box& b) const; /** - * @brief Get the side lengths of the box. + * @brief Get the side lengths of the box * - * @return array containing the side lengths ordered from smallest to largest. + * @return array containing the side lengths ordered from smallest to largest */ [[nodiscard]] const std::array& getSideLengths() const { @@ -77,19 +77,19 @@ class Box } /** - * @brief The minimum length that a side of a box may have. + * @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; /** - * @brief The maximum length that a side of a box may have. + * @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; /** - * @brief Static assert on the assumption any box can only contain a single box nested inside. + * @brief Static assert on the assumption any box can only contain a single box nested inside */ static_assert(minLength * 2 >= maxLength, "More then 1 box can be fit inside a larger box. " diff --git a/include/box_nesting/Parser.hpp b/include/box_nesting/Parser.hpp index f5ae448..01a3c85 100644 --- a/include/box_nesting/Parser.hpp +++ b/include/box_nesting/Parser.hpp @@ -12,7 +12,7 @@ namespace BoxNesting { /** - * @brief Parser class that handles reading from input to obtain boxes. + * @brief Parser class that handles reading from input to obtain boxes */ class Parser { @@ -23,50 +23,54 @@ class Parser Parser() = delete; /** - * @brief Delete virtual destructor. + * @brief Delete virtual destructor */ virtual ~Parser() = delete; /** - * @brief Delete copy constructor. + * @brief Delete copy constructor * \param b */ Parser(const Parser& b) = delete; /** - * @brief Delete move constructor. + * @brief Delete move constructor * \param b */ Parser(Parser&& b) = delete; /** - * @brief Delete copy assignment operator. + * @brief Delete copy assignment operator * \param b * \return */ Parser& operator=(const Parser& b) = delete; /** - * @brief Delete move assignment operator. + * @brief Delete move assignment operator * \param b * \return */ Parser& operator=(Parser&& b) = delete; /** - * @brief Get boxes from stdin, if parser fails a ParserException is thrown - * If specification are not acceptable a std::invalid_argument is thrown. + * @brief Get boxes from stdin. * + * @throw ParserError Parsing failed due to malformed input + * @throw std::invalid_argument Parsing succeeded but the box specification is not valid + * + * @param inputStream The inputStream to read from * @return A set of boxes */ [[nodiscard]] static std::vector getBoxes(std::istream& inputStream); private: /** - * @brief Wait for box specification from inputStream and return a box object from it. - * If parser fails a ParserException is thrown. If specification are not acceptable - * a std::invalid_argument is thrown. - * + * @brief Wait for box specification from inputStream and return a box object from it + + * @throw ParserError Parsing failed due to malformed input + * @throw std::invalid_argument Parsing succeeded but the box specification is not valid + * * @param inputStream The inputStream to read from * @return Instantiated box object */ diff --git a/test/Parser.cpp b/test/Parser.cpp index 5fd3bd6..eb779a9 100644 --- a/test/Parser.cpp +++ b/test/Parser.cpp @@ -1,6 +1,8 @@ #include #include +#include +#include #include SCENARIO("Parsing box specifcations from inputStream") @@ -49,7 +51,29 @@ SCENARIO("Parsing box specifcations from inputStream") WHEN("parsing the first line and a very very large number is present") { std::stringstream stream; - stream << "99999999999999999999999999999999999999" << std::endl; + stream << "9" << std::numeric_limits::max() << std::endl; + THEN("a ParserError is thrown") + { + REQUIRE_THROWS_AS(BoxNesting::Parser::getBoxes(stream), BoxNesting::ParserError); + } + } + + WHEN("parsing the first line and no number is present") + { + std::stringstream stream; + stream << "foobar" << std::endl; + THEN("a ParserError is thrown") + { + REQUIRE_THROWS_AS(BoxNesting::Parser::getBoxes(stream), BoxNesting::ParserError); + } + } + + WHEN("parsing a specification which is outside of the range of a double") + { + std::stringstream stream; + stream << "1" << std::endl << std::fixed << "9" << std::numeric_limits::max() << " " + << validLength << " " << validLength << std::endl; + THEN("a ParserError is thrown") { REQUIRE_THROWS_AS(BoxNesting::Parser::getBoxes(stream), BoxNesting::ParserError);