Inventory_Iterator

Elm20o
Inventory_iterator.zip

CPPLINT.cfg.txt

linelength=80 filter=-legal/copyright filter=-readability/namespace filter=-build/header_guard filter=-whitespace/indent filter=-whitespace/braces filter=-whitespace/blank_line filter=-build/namespaces filter=-readability/braces filter=-whitespace/newline filter=-build/include_subdir filter=-runtime/references filter=-runtime/threadsafe_fn filter=-runtime/int filter=-runtime/explicit filter=-whitespace/ending_newline filter=-runtime/string # Too many false positives filter=-build/include

Inventory.cpp

#include <utility> #include <algorithm> #include "Inventory.h" // Allow the compiler to define the remaining // comparison operators using namespace std::rel_ops; //------------------------------------------------------------------------------ Inventory::Inventory() :Inventory(10) { } //------------------------------------------------------------------------------ Inventory::Inventory(int n) { this->slots = n; // this->allItemStacks.reserve(n); // only works for std::vector } //------------------------------------------------------------------------------ Inventory::Inventory(const Inventory& src) { // @todo - implement this function } //------------------------------------------------------------------------------ Inventory::~Inventory() { // Done! Be able to explain why. } //------------------------------------------------------------------------------ int Inventory::utilizedSlots() const { return allItemStacks.size(); } //------------------------------------------------------------------------------ int Inventory::emptySlots() const { return slots - utilizedSlots(); } //------------------------------------------------------------------------------ int Inventory::totalSlots() const { return slots; } //------------------------------------------------------------------------------ bool Inventory::isFull() const { // @todo - implement this function return false; // replace this line } //------------------------------------------------------------------------------ Inventory::iterator Inventory::begin() { return allItemStacks.begin(); } //------------------------------------------------------------------------------ Inventory::iterator Inventory::end() { return allItemStacks.end(); } //------------------------------------------------------------------------------ Inventory::const_iterator Inventory::begin() const { return allItemStacks.begin(); } //------------------------------------------------------------------------------ Inventory::const_iterator Inventory::end() const { return allItemStacks.end(); } //------------------------------------------------------------------------------ void Inventory::display(std::ostream &outs) const { outs << " -Used " << utilizedSlots() << " of " << slots << " slots" << "\n"; // @todo - implement the rest of function // // 2 spaces " " before each ItemStack line } //------------------------------------------------------------------------------ Inventory::iterator Inventory::findMatchingItemStackIterator(const ItemStack& itemStack) { // @todo - implement this function return allItemStacks.end(); } //------------------------------------------------------------------------------ void Inventory::addItemStackNoCheck(ItemStack itemStack) { // @todo - implement this function. This should be one push_back-y line... } //------------------------------------------------------------------------------ Inventory& Inventory::operator=(Inventory rhs) { std::swap(*this, rhs); return *this; } //------------------------------------------------------------------------------ void swap(Inventory& lhs, Inventory& rhs) { using std::swap; swap(lhs.allItemStacks, rhs.allItemStacks); swap(lhs.slots, rhs.slots); } //------------------------------------------------------------------------------ bool operator==(const Inventory& lhs, const Inventory& rhs) { if (lhs.utilizedSlots() != rhs.utilizedSlots()) { return false; } if (lhs.emptySlots() != rhs.emptySlots()) { return false; } // The two Inventory objects have the same number of used & unused slots using const_iterator = Inventory::const_iterator; const_iterator lhsIt = lhs.begin(); const_iterator rhsIt = rhs.begin(); while (lhsIt != lhs.end() && rhsIt != rhs.end()) { if (*lhsIt != *rhsIt) { return false; } lhsIt++; rhsIt++; } // If the two Inventory objects are identical, both iterators // will have reached end positions. return lhsIt == lhs.end() && rhsIt == rhs.end(); } //------------------------------------------------------------------------------ void Inventory::mergeStacks(ItemStack& lhs, const ItemStack& rhs) { // @todo - implement this function. There is no trick here (beyond // reviewing Assignment 1). }

Inventory.h

#ifndef INVENTORY_H_INCLUDED #define INVENTORY_H_INCLUDED #include <iostream> #include <vector> #include <list> #include "ItemStack.h" /** * An Inventory is composed of n slots. Each slot may store only * one type of item--specified by *slots*. * <p> * Once all slots are filled, no additional Item types may be * stored. Individual slots may contain any number of the same * Item. */ class Inventory { public: /** * Aliases for the different possible containers * <p> * After your code is working, switch between them. * You should have identical results for all of them. */ using ItemStackCollection = std::list<ItemStack>; // using ItemStackCollection = std::vector<ItemStack>; using iterator = ItemStackCollection::iterator; using const_iterator = ItemStackCollection::const_iterator; private: /** * All `ItemStack`s in _this_ `Inventory` */ ItemStackCollection allItemStacks; int slots; ///< Capacity public: /** * Default to 10 slots */ Inventory(); /** * Create an inventory with n slots * * @pre n > 0 */ Inventory(int n); /** * Duplicate an existing Inventory */ Inventory(const Inventory& src); /** * Empty all Inventory slots. */ ~Inventory(); /** * Add one or more items to the inventory list * * @return true if *stack* was added and false otherwise */ bool addItems(ItemStack itemStack); /** * Check the number of used/utilized (i.e., non-empty). */ int utilizedSlots() const; /** * Check the number of unused (i.e., empty) slots. */ int emptySlots() const; /** * Retrieve the total size (number of slots in total). */ int totalSlots() const; /** * Check if this inventory is full * * @return (occupied < slots) // **technically a typo** */ bool isFull() const; /** * Print a Summary of the Inventory and all Items contained within */ void display(std::ostream& outs) const; // Begin Iterator Support (begin/end) iterator begin(); iterator end(); const_iterator begin() const; const_iterator end() const; // End Iterator Support /** * */ Inventory& operator=(Inventory rhs); /** * Swap the contents of two `Inventory`s * (Yes this should be spelled "ies"). However, we * need to recognize that Inventory is the type of both * `lhs` and `rhs` * <p> * I am using a friend function here and only here (under protest) * <p> * [Refer here](http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom) */ friend void swap(Inventory& lhs, Inventory& rhs); private: /** * Find Node containing and ItemStack with a matching id * * @param itemStack ItemStack for which we want a match * * @return pointer to a Node containing a matching ItemStack * or nullptr if no such Node exists */ iterator findMatchingItemStackIterator(const ItemStack& itemStack); /** * Add a new ItemStack to an empty Inventory slot. * <p> * This is simliar to the code we discussed in Review-02 * * When this method is invoked all special cases * have already been covered in `addItems`. * <p> * Abstraction and Interfaces */ void addItemStackNoCheck(ItemStack itemStack); public: /** * Merge two item stacks. * * @param lhs item stack where items need to be `add`ed * @param rhs item stack with the *number* of items to add * * @pre lhs.item == rhs.item */ static void mergeStacks(ItemStack& lhs, const ItemStack& rhs); }; //------------------------------------------------------------------------------ inline bool Inventory::addItems(ItemStack itemStack) { iterator matchingIterator = findMatchingItemStackIterator(itemStack); // A match was found if (matchingIterator != this->end()){ Inventory::mergeStacks(*matchingIterator, itemStack); return true; } // There is no space for a new type of `ItemStack` if (this->isFull()) { return false; } // This is a new type of item and there is plenty of room addItemStackNoCheck(itemStack); return true; } /** * Print the Inventory through use of the display member function */ inline std::ostream& operator<<(std::ostream& outs, const Inventory& prt) { prt.display(outs); return outs; } /** * Compare two Inventory objects, without direct access */ bool operator==(const Inventory& lhs, const Inventory& rhs); #endif

InventoryList-00.txt

# 3 - 1 10 - 2 5 - 3 2 # 6 - 4 3 - 5 27 - 6 44 - 7 55 - 8 1 - 9 4 - 4 3 # 5 - 2 5 - 9 4 - 8 1 - 5 2 - 7 5

InventoryList-01.txt

# 5 - 1 10 - 2 5 - 3 2 # 6 - 4 3 - 5 27 - 6 44 - 7 55 - 8 1 - 9 4 - 4 3 # 2 - 2 5 - 9 4 - 8 1 - 5 2 - 10 5

InventoryList-02.txt

# 2 - 1 10 - 57 1 - 57 4 # 3 - 4 3 - 13 27 - 13 44 - 17 55 - 17 1 - 19 4 - 42 3 # 2 - 41 5 - 49 4 - 49 1 - 264 2 - 33 5

InventoryList-03.txt

# 2 - 1 10 - 57 1 - 57 4 # 3 - 4 3 - 13 27 - 13 44 - 17 55 - 17 1 - 19 4 - 42 3 # 2

Item.cpp

#include <iomanip> #include "Item.h" //------------------------------------------------------------------------------ Item::Item() :Item(0, "Air") { } //------------------------------------------------------------------------------ Item::Item(int i) :Item(i, "Air") { } //------------------------------------------------------------------------------ Item::Item(int i, std::string n) :name(n) { this->id = i; } //------------------------------------------------------------------------------ void Item::display(std::ostream &outs) const { outs << std::right << std::setw(3) << id << " " << name; }

Item.h

#ifndef ITEM_H_INCLUDED #define ITEM_H_INCLUDED #include <iostream> #include <string> /** * Item represents an individual Item in an inventory. * This includes items such as potions, building materials, and food. * * Only one of each item can exist--i.e., no two items share the * same numeric id. */ class Item { private: int id; ///< Unique numeric identifier--e.g., 1 std::string name; ///< Short title--e.g., HP Potion public: /** * Default to id = 0 and name = Air */ Item(); /** * Create an Item with an id and * a blank name */ Item(int i); /** * Create an Item with a specified id and name * * @pre * - all items that share an id are of the same type * - id is strictly positive */ Item(int i, std::string n); /** * Retrieve numeric id */ int getID() const; /** * Update numeric id * * @pre i is strictly positive */ void setID(int i); /** * Retrieve name */ std::string getName() const; /** * Update name */ void setName(std::string n); /** * Check for logical equivalence--based on numeric id */ bool operator==(const Item &rhs) const; /** * Check ordering--based on numeric id */ bool operator<(const Item &rhs) const; /** * Print one Item */ void display(std::ostream &outs) const; }; /** * Print one Item by invoking display */ std::ostream& operator<<(std::ostream &outs, const Item &prt); //------------------------------------------------------------------------------ inline int Item::getID() const { return this->id; } //------------------------------------------------------------------------------ inline void Item::setID(int i) { this->id = i; } //------------------------------------------------------------------------------ inline std::string Item::getName() const { return this->name; } //------------------------------------------------------------------------------ inline void Item::setName(std::string n) { this->name = n; } //------------------------------------------------------------------------------ inline bool Item::operator==(const Item &rhs) const { return this->id == rhs.id; } //------------------------------------------------------------------------------ inline bool Item::operator<(const Item &rhs) const { return this->id < rhs.id; } //------------------------------------------------------------------------------ inline std::ostream& operator<<(std::ostream &outs, const Item &prt) { prt.display(outs); return outs; } #endif

ItemList-00.txt

0 Air 1 HP Potion 2 MP Potion 5 Iron Ore 3 Bow Tie 4 Dirt 6 Diamond Ore 7 Iron Ingot 8 Diamond 9 Diamond Block

ItemList-01.txt

0 Air 1 HP Potion 2 MP Potion 5 Iron Ore 3 Bow Tie 4 Dirt 6 Diamond Ore 7 Iron Ingot 8 Diamond 9 Diamond Block

ItemList-02.txt

0 Air 1 Stone 2 Grass 3 Dirt 4 Cobblestone 13 Gravel 14 Gold Ore 15 Iron Ore 16 Coal Ore 17 Oak Wood 19 Sponge 33 Piston 41 Gold Block 42 Iron Block 49 Obsidian 50 Torch 56 Diamond Ore 57 Diamond Block 73 Redstone Ore 264 Diamond

ItemStack.cpp

#include <iomanip> #include "ItemStack.h" //------------------------------------------------------------------------------ ItemStack::ItemStack() :item(0, "Air"), quantity(0) { } //------------------------------------------------------------------------------ ItemStack::ItemStack(const Item& item, int s) :item(item), quantity(s) { } //------------------------------------------------------------------------------ void ItemStack::addItemsFrom(const ItemStack& other) { this->quantity += other.quantity; } //------------------------------------------------------------------------------ std::ostream& operator<<(std::ostream &outs, const ItemStack& prt) { outs << std::right << "(" << std::setw(2) << prt.size() << ") " << (prt.getItem()).getName(); return outs; }

ItemStack.h

#ifndef ITEMSTACK_H_INCLUDED #define ITEMSTACK_H_INCLUDED #include <iostream> #include "Item.h" using namespace std::rel_ops; /** * A Homogeneous--i.e., uniform--stack of Items. */ class ItemStack { private: Item item; ///< Item out of which the stack is composed int quantity; ///< Number of items in the stack public: /** * Default to an empty stack composed of Air */ ItemStack(); /** * Create a stack of type *item* * * @param item Item out of which the stack is composed * @param s size of the stack * * @pre (s > 0) */ ItemStack(const Item& item, int s); /** * Retrieve the Item out of which the stack is composed */ Item getItem() const; /** * Retrieve the size of the stack */ int size() const; /** * Increase the size of the stack * * @param a number of items to add * @pre a > 0 */ void addItems(int a); /** * Increase the size of the stack * * @param other ItemStack with the items to move (i.e., steal). * * @pre *this.item == other.item */ void addItemsFrom(const ItemStack& other); /** * Consider two stacks to be the same if * they contain the same type of Item */ bool operator==(const ItemStack& rhs) const; /** * Order stacks based on Item id */ bool operator<(const ItemStack& rhs) const; }; /** * Print the ItemStack directly */ std::ostream& operator<<(std::ostream& outs, const ItemStack& prt); //------------------------------------------------------------------------------ inline Item ItemStack::getItem() const { return this->item; } //------------------------------------------------------------------------------ inline int ItemStack::size() const { return this->quantity; } //------------------------------------------------------------------------------ inline void ItemStack::addItems(int a) { this->quantity += a; } //------------------------------------------------------------------------------ inline bool ItemStack::operator==(const ItemStack& rhs) const { return this->item == rhs.item; } //------------------------------------------------------------------------------ inline bool ItemStack::operator<(const ItemStack& rhs) const { return this->item < rhs.item; } #endif

make.dep.txt

storage.o: storage.cpp Inventory.h ItemStack.h Item.h Item.o: Item.cpp Item.h ItemStack.o: ItemStack.cpp ItemStack.h Item.h Inventory.o: Inventory.cpp Inventory.h ItemStack.h Item.h

makefile.txt

AINPROG=storage CPPS= storage.cpp Item.cpp ItemStack.cpp Inventory.cpp TEST_CPPS= Item.cpp ItemStack.cpp Inventory.cpp TestInventory.cpp DIR=${PWD} ASST=$(notdir ${DIR}) ifneq (,$(findstring MinGW,$(PATH))) DISTR=MinGW EXE=.exe LFLAGS= else DISTR=Unix EXE= LFLAGS=-fsanitize=leak,address -fuse-ld=gold endif # ######################################################################## # Macro definitions for "standard" C and C++ compilations # CPPFLAGS=-g -std=c++11 -D$(DISTR) -Wall -Wextra -Wpedantic CFLAGS=-g TARGET=$(MAINPROG)$(EXE) TEST_TARGET=testInventory$(EXE) LINK=g++ $(CPPFLAGS) # CC=gcc CPP=g++ # # # In most cases, you should not change anything below this line. # # The following is "boilerplate" to set up the standard compilation # commands: # OBJS=$(CPPS:%.cpp=%.o) DEPENDENCIES = $(CPPS:%.cpp=%.d) TEST_OBJS=$(TEST_CPPS:%.cpp=%.o) %.d: %.cpp touch $@ %.o: %.cpp $(CPP) $(CPPFLAGS) -MMD -o $@ -c $*.cpp # # Targets: # all: $(TARGET) tests win: $(OBJS) $(LINK) $(FLAGS) -o $(TARGET) $(OBJS) $(TARGET): $(OBJS) $(LINK) $(FLAGS) -o $(TARGET) $(OBJS) $(LFLAGS) tests: $(TEST_OBJS) $(LINK) $(FLAGS) -o $(TEST_TARGET) $(TEST_OBJS) clean: -/bin/rm -f *.d *.o $(TARGET) $(TEST_TARGET) make.dep: $(DEPENDENCIES) -cat $(DEPENDENCIES) > $@ include make.dep

storage.cpp

#include <iostream> #include <fstream> #include <string> #include <cstdlib> #include <vector> #include <algorithm> #include <iterator> #include "Inventory.h" #include "ItemStack.h" #include "Item.h" using namespace std; /** * Trim leading and trailing whitespace from a string. * * @param str string to prune * * @pre str is nonempty */ void trim(std::string& str); /** * Read file containing the list * of all possible items */ vector<Item> parseItemList(istream& inf); /** * Read inventory file and create all Inventory * instances. * * @param items collection of valid Item entries * * @pre items is non-empty */ vector<Inventory> parseInventoryFile(istream& inf, const vector<Item>& items); /** * Generate a summary of all valid items */ void printItems(const vector<Item>& items); /** * Generate a summary of Inventory utilization */ void printInventories(const vector<Inventory>& storage); /** * Assignment 1: Item Storage * * @param argv[1] items filename * @param argv[2] inventories filename */ int main(int argc, char** argv) { vector<Item> validItems; // Listing of Valid Items vector<Inventory> storage; // Collection of Inventories // Check Command Line Arguments if (argc != 3) { cerr << "Usage: " << argv[0] << " list_file inventory_file" << "\n"; return 1; } // Open list_file ifstream infile(argv[1]); if (!infile) { cerr << "Error: " << argv[1] << " could not be opened" << "\n"; return 2; } // Read listing of possible items validItems = parseItemList(infile); // Close and reset for the next file infile.close(); infile.clear(); std::sort(validItems.begin(), validItems.end()); // Open inventory file infile.open(argv[2]); if (!infile) { cout << "Error: " << argv[2] << " could not be opened" << "\n"; return 3; } storage = parseInventoryFile(infile, validItems); infile.close(); printItems(validItems); printInventories(storage); return 0; } //------------------------------------------------------------------------------ void trim(std::string& str) { if (str.empty()) { return; } int first_nonspace = str.find_first_not_of(" \t"); int last_non_space = str.find_last_not_of(" \t"); str = str.substr(first_nonspace, last_non_space + 1); } //------------------------------------------------------------------------------ std::istream& operator>>(std::istream& ins, Item& toRead) { int i; string n; ins >> i; getline(ins, n); trim(n); toRead.setID(i); toRead.setName(n); return ins; } //------------------------------------------------------------------------------ vector<Item> parseItemList(istream& inf) { vector<Item> items; std::copy(istream_iterator<Item>(inf), istream_iterator<Item>(), back_inserter(items)); return items; } //------------------------------------------------------------------------------ vector<Inventory> parseInventoryFile(istream& inf, const vector<Item>& items) { vector<Inventory> storage; // Collection of Inventory instances Inventory* inv = nullptr; // Temporary Inventory pointer // First two values on a line char leading_char; int num_1; cout << "Processing Log:" << "\n"; while (inf >> leading_char >> num_1) { if (leading_char == '#') { if (inv != nullptr) { storage.push_back(*inv); delete inv; } inv = new Inventory(num_1); } else { int key = num_1; // Read third value int num_2; inf >> num_2; vector<Item>::const_iterator it; it = std::find_if(items.begin(), items.end(), [key](const Item& item) -> bool { return item.getID() == key; }); // Ignore any Item id not found in items if (it != items.end()) { ItemStack stack(*it, num_2); if (!(inv->addItems(stack))) { cout << " Discarded " << stack << "\n"; } else { cout << " Stored " << stack << "\n"; } } } } storage.push_back(*inv); delete inv; return storage; } //------------------------------------------------------------------------------ void printItems(const vector<Item>& items) { cout << "\n" <<"Item List:" << "\n"; for (const Item& i : items) { cout << " " << i << "\n"; } cout << "\n"; } //------------------------------------------------------------------------------ void printInventories(const vector<Inventory>& storage) { cout << "Storage Summary:" << "\n"; for (const Inventory& chest : storage) { cout << chest << "\n"; } }

TestInventory.cpp

#include <iostream> #include <fstream> #include <string> #include <cstdlib> #include <vector> #include <sstream> #include <algorithm> #include <functional> #include "Item.h" #include "ItemStack.h" #include "Inventory.h" /** * This is the Bodge-Unit-Testing... PseUdO-Framework * * Bodge - A clumsy or inelegant job, usually a temporary repair; * a patch, a repair. (From Wiktionary) */ #define bodgeAssert(expression) \ if (!(expression)) { \ std::cout << " FAILURE: "\ << __func__ << ":" << __LINE__\ << " -> (" << #expression << ")\n";\ return false;\ } // End Macro // Unit Test Pseudo-Framework //----------------------------------------------------------------------------- using UnitTestFunction = std::function<bool()>; using UnitTestPair = std::pair<UnitTestFunction, std::string>; void runTest(const UnitTestFunction& testFunction, std::string description) { std::cout << (testFunction() ? "PASSED" : "FAILED") << " -> " << description << std::endl; } //----------------------------------------------------------------------------- // Unit Tests - Support Data //----------------------------------------------------------------------------- const Inventory EMPTY_INVENTORY; const std::vector<Item> TEST_ITEMS = { {0, "Air"}, {1, "Dirt"}, {2, "Potato"}, {3, "Makefile"}, {4, "Procrastination"} }; //----------------------------------------------------------------------------- // Unit Tests - Test Functions //----------------------------------------------------------------------------- bool testDefaultConstructor() { bodgeAssert(EMPTY_INVENTORY.utilizedSlots() == 0); bodgeAssert(EMPTY_INVENTORY.emptySlots() == 10); bodgeAssert(EMPTY_INVENTORY.totalSlots() == 10); bodgeAssert(!EMPTY_INVENTORY.isFull()); // I should really check display() and/or operator<< here. However, I will // do that in a seperate `testDisplay` function return true; } //----------------------------------------------------------------------------- bool testConstructorSizeN() { Inventory invWith8Slots(8); bodgeAssert(invWith8Slots.utilizedSlots() == 0); bodgeAssert(invWith8Slots.emptySlots() == 8); bodgeAssert(invWith8Slots.totalSlots() == 8); bodgeAssert(!invWith8Slots.isFull()); // I should really check display() and/or operator<< here. However, I will // do that in a seperate `testDisplay` function return true; } //----------------------------------------------------------------------------- /** * Add ItemStacks to an Inventory without filling the Inventory or attempting * to add duplicate Items */ bool testAddItemStackNoCheck() { std::vector<ItemStack> stacksToAdd = { {TEST_ITEMS[0], 1}, {TEST_ITEMS[1], 4}, {TEST_ITEMS[2], 8} }; Inventory aBag(4); aBag.addItems(stacksToAdd[0]); aBag.addItems(stacksToAdd[1]); aBag.addItems(stacksToAdd[2]); bodgeAssert(!aBag.isFull()); bodgeAssert(aBag.utilizedSlots() == 3); bodgeAssert(aBag.emptySlots() == 1); bodgeAssert(aBag.totalSlots() == 4); // Retrieve each of the items and check that they were added Inventory::const_iterator it = aBag.begin(); bodgeAssert(*(it++) == stacksToAdd[0]); bodgeAssert(*(it++) == stacksToAdd[1]); bodgeAssert(*(it++) == stacksToAdd[2]); // Check that there are no more ItemStacks to retrieve bodgeAssert(it == aBag.end()); return true; } /** * Add ItemStacks to an Inventory without filling the Inventory or attempting * to add duplicate Items */ bool testAddItemWithDuplicateItems() { std::vector<ItemStack> stacksToAdd = { {TEST_ITEMS[0], 1}, {TEST_ITEMS[1], 4}, {TEST_ITEMS[1], 5} }; Inventory aBag(4); aBag.addItems(stacksToAdd[0]); aBag.addItems(stacksToAdd[1]); aBag.addItems(stacksToAdd[2]); bodgeAssert(!aBag.isFull()); bodgeAssert(aBag.utilizedSlots() == 2); bodgeAssert(aBag.emptySlots() == 2); bodgeAssert(aBag.totalSlots() == 4); // Retrieve each of the items and check that they were added Inventory::const_iterator it = aBag.begin(); bodgeAssert(*(it++) == stacksToAdd[0]); // Expect the merged stack to be returned. ItemStack mergedStack(TEST_ITEMS[1], 9); const ItemStack& retrieved = *it; bodgeAssert(retrieved == mergedStack); bodgeAssert(retrieved.size() == 9); it++; // Check that there are no more ItemStacks to retrieve bodgeAssert(it == aBag.end()); return true; } /** * Add ItemStacks to an Inventory and fill it. * Then try to add one more ItemStack. */ bool testAddItemAfterFull() { std::vector<ItemStack> stacksToAdd = { {TEST_ITEMS[0], 1}, {TEST_ITEMS[1], 4}, {TEST_ITEMS[4], 8} }; Inventory aBag(2); aBag.addItems(stacksToAdd[0]); aBag.addItems(stacksToAdd[1]); bodgeAssert(aBag.isFull()); bodgeAssert(aBag.utilizedSlots() == 2); bodgeAssert(aBag.emptySlots() == 0); bodgeAssert(aBag.totalSlots() == 2); // This add should fail // Procrastination is bad bodgeAssert(!(aBag.addItems(stacksToAdd[2]))); // Retrieve each of the items and check that they were added Inventory::const_iterator it = aBag.begin(); bodgeAssert(*(it++) == stacksToAdd[0]); bodgeAssert(*(it++) == stacksToAdd[1]); // Check that there are no more ItemStacks to retrieve bodgeAssert(it == aBag.end()); return true; } //----------------------------------------------------------------------------- /** * Helper function for testDisplay. * * Convert any type with an operator<< defined to a std::string */ template<class T> std::string toStr(const T& thing) { std::ostringstream outs; outs << thing; return outs.str(); } //----------------------------------------------------------------------------- bool testDisplay() { std::vector<ItemStack> stacksToAdd = { {TEST_ITEMS[0], 1}, {TEST_ITEMS[1], 4} }; // Set up the expected strings for each ItemStack std::vector<std::string> stacksAsStrings(stacksToAdd.size()); for (int i = 0; i < stacksToAdd.size(); i++) { stacksAsStrings[i] = toStr(stacksToAdd[i]); } // Set up the test Inventory Inventory aBag(2); aBag.addItems(stacksToAdd[0]); aBag.addItems(stacksToAdd[1]); // Check for the expected ItemStack lines within the larger output const std::string bagString = toStr(aBag); bodgeAssert(bagString.find(stacksAsStrings[0]) != std::string::npos); bodgeAssert(bagString.find(stacksAsStrings[1]) != std::string::npos); // Check for the Summary line const std::string expected = "-Used " + std::to_string(aBag.utilizedSlots()) + " of " + std::to_string(aBag.totalSlots()) + " slots"; bodgeAssert(toStr(aBag).find(expected) != std::string::npos); //-------------------------------------------------------------------------- // Check the entire output string. This should really be a seperate test //-------------------------------------------------------------------------- std::string expectedOverall = " " + expected + "\n" + " " + stacksAsStrings[0] + "\n" + " " + stacksAsStrings[1] + "\n"; bodgeAssert(bagString == expectedOverall); return true; } //----------------------------------------------------------------------------- bool testCopyConstructorForEmpty() { Inventory aCopy(EMPTY_INVENTORY); bodgeAssert(aCopy.utilizedSlots() == 0); bodgeAssert(aCopy.emptySlots() == 10); bodgeAssert(aCopy.totalSlots() == 10); bodgeAssert(!aCopy.isFull()); // Check that both have the same data and are distinct copies bodgeAssert(aCopy == EMPTY_INVENTORY); bodgeAssert(&aCopy != &EMPTY_INVENTORY); // bodgeAssert(aCopy.begin() != EMPTY_INVENTORY.begin()); return true; } //----------------------------------------------------------------------------- bool testCopyConstructor() { std::vector<ItemStack> stacksToAdd = { {TEST_ITEMS[0], 1}, {TEST_ITEMS[1], 4}, {TEST_ITEMS[4], 8} }; Inventory source(4); for (const ItemStack& next : stacksToAdd) { source.addItems(next); } Inventory aCopy(source); bodgeAssert(aCopy.utilizedSlots() == 3); bodgeAssert(aCopy.emptySlots() == 1); bodgeAssert(aCopy.totalSlots() == 4); bodgeAssert(!aCopy.isFull()); // Check that both have the same data and are distinct copies bodgeAssert(aCopy == source); bodgeAssert(&aCopy != &source); using ConstIterator = Inventory::const_iterator; ConstIterator it = source.begin(); for (const ItemStack& nextToCheck : aCopy) { bodgeAssert(nextToCheck == *it); // Compare ItemStacks bodgeAssert(&nextToCheck != &(*(it++))); // Compare Memory Addresses } return true; } //----------------------------------------------------------------------------- bool testAssignmentOperator() { std::vector<ItemStack> stacksToAdd = { {TEST_ITEMS[0], 1}, {TEST_ITEMS[1], 4}, {TEST_ITEMS[4], 8} }; Inventory source(4); for (const ItemStack& next : stacksToAdd) { source.addItems(next); } Inventory aCopy = source; bodgeAssert(aCopy.utilizedSlots() == 3); bodgeAssert(aCopy.emptySlots() == 1); bodgeAssert(aCopy.totalSlots() == 4); bodgeAssert(!aCopy.isFull()); // Check that both have the same data and are distinct copies bodgeAssert(aCopy == source); bodgeAssert(&aCopy != &source); using ConstIterator = Inventory::const_iterator; ConstIterator it = source.begin(); for (const ItemStack& nextToCheck : aCopy) { bodgeAssert(nextToCheck == *it); // Compare ItemStacks bodgeAssert(&nextToCheck != &(*(it++))); // Compare Memory Addresses } return true; } //----------------------------------------------------------------------------- bool testMergeStacks() { // The Inventory mergeStacks function deals only with ItemStack objects. It // is a utility function of Inventory. ItemStack stack1(TEST_ITEMS[0], 12); ItemStack stack2(TEST_ITEMS[0], 1); ItemStack stack3(TEST_ITEMS[0], 0); ItemStack stack4(TEST_ITEMS[0], 5); Inventory::mergeStacks(stack1, stack2); bodgeAssert(stack1.size() == 13); Inventory::mergeStacks(stack3, stack4); bodgeAssert(stack3.size() == 5); Inventory::mergeStacks(stack1, stack3); bodgeAssert(stack1.size() == 18); return true; } //----------------------------------------------------------------------------- int main(int argc, char** argv) { UnitTestPair tests[] = { {testDefaultConstructor, "testDefaultConstructor"}, {testConstructorSizeN, "testConstructorSizeN"}, {testAddItemStackNoCheck, "testAddItemStackNoCheck"}, {testAddItemWithDuplicateItems, "testAddItemWithDuplicateItems"}, {testAddItemAfterFull, "testAddItemAfterFull"}, {testCopyConstructorForEmpty, "testCopyConstructorForEmpty"}, {testCopyConstructor, "testCopyConstructor"}, {testAssignmentOperator, "testAssignmentOperator"}, {testDisplay, "testDisplay"}, {testMergeStacks, "testMergeStacks"} }; for (const UnitTestPair& testPair : tests) { runTest(testPair.first, testPair.second); } return 0; }