diff --git a/feladat5/UnitTest1/UnitTest1.cpp b/feladat5/UnitTest1/UnitTest1.cpp index 27ca167..55c9c7e 100644 --- a/feladat5/UnitTest1/UnitTest1.cpp +++ b/feladat5/UnitTest1/UnitTest1.cpp @@ -1,6 +1,8 @@ // Tóth Dániel Mátyás | IFPQYY | v1 #include "pch.h" #include "CppUnitTest.h" +#include +#include using namespace Microsoft::VisualStudio::CppUnitTestFramework; @@ -9,9 +11,304 @@ namespace UnitTest1 TEST_CLASS(UnitTest1) { public: - - TEST_METHOD(TestMethod1) + TEST_METHOD(EmptyTests) { + CMyString empty = CMyString(); + Assert::AreEqual(0, (int)empty.size()); + Assert::AreEqual(1, (int)empty.capacity()); + Assert::IsTrue(empty.empty()); + } + + TEST_METHOD(c_strTests) + { + try + { + char* tmp = "txt"; + CMyString str = CMyString((const char*)tmp); + Assert::IsFalse(tmp == str.c_str()); //memory addr + Assert::AreEqual(tmp, str.c_str()); //value + } + catch (...) + { + Assert::IsTrue(false); + } + } + + TEST_METHOD(StringConstructionTests) + { + + //char* constructor + char* pszargs[] = { + {nullptr}, + {""}, + {"test"}, + {"long text aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, + }; + int pszres[] = { + 0, + 0, + 4, + 48, + }; + int testcount = sizeof(pszres) / sizeof(int); + for (size_t i = 0; i < testcount; i++) + { + try + { + CMyString pszctor = CMyString(pszargs[i]); + Assert::AreEqual(pszres[i], (int)pszctor.size()); + Assert::AreEqual((pszres[i]) + 1, (int)pszctor.capacity()); + if (pszargs[i] != nullptr) + { + Assert::AreEqual(pszargs[i], pszctor.c_str()); + } + } + catch (...) + { + Assert::IsTrue(false); + } + } + + //repeat constructor + char repeatchargs[] = { + '\0', + '\0', + 'a', + 'a', + }; + int repeatcntargs[] = { + 0, + 5, + 0, + 5, + }; + int repeatres[] = { + 0, + 0, + 0, + 5, + }; + char* repeattextres[] = { + nullptr, + nullptr, + nullptr, + "aaaaa", + }; + testcount = sizeof(repeatres) / sizeof(int); + for (size_t i = 0; i < testcount; i++) + { + try + { + CMyString repeatctor = CMyString(repeatchargs[i], repeatcntargs[i]); + Assert::AreEqual(repeatres[i], (int)repeatctor.size()); + Assert::AreEqual((repeatres[i]) + 1, (int)repeatctor.capacity()); + if (repeattextres[i] != nullptr) + { + Assert::AreEqual(repeattextres[i], repeatctor.c_str()); + } + } + catch (...) + { + Assert::IsTrue(false); + } + } + + //copy constructor + CMyString strargs[] = { + CMyString(), + CMyString("test"), + CMyString('a', 10), + CMyString("really long text thats to be cleared"), + }; + strargs[3].clear(); + int strres[] = { + 0, + 4, + 10, + 0, + }; + int allocLengths[] = { + 1, + 5, + 11, + 1, + }; + char* cpytextres[] = { + "", + "test", + "aaaaaaaaaa", + "", + }; + testcount = sizeof(strres) / sizeof(int); + for (size_t i = 0; i < testcount; i++) + { + try + { + CMyString cpy = CMyString(strargs[i]); + CMyString strctor = CMyString(cpy); + Assert::AreEqual(strres[i], (int)strctor.size()); + Assert::AreEqual((allocLengths[i]), (int)strctor.capacity()); + Assert::AreEqual(cpytextres[i], strctor.c_str()); + } + catch (...) + { + Assert::IsTrue(false); + } + } + } + + TEST_METHOD(ClearTests) { + CMyString str[]{ + CMyString(), + CMyString("test"), + CMyString('a', 10), + CMyString(CMyString("to be copied then cleared")), + }; + int allocLengths[] = { + 1, + 5, + 11, + 26, + }; + int testcount = sizeof(allocLengths) / sizeof(int); + for (size_t i = 0; i < testcount; i++) + { + try + { + str[i].clear(); + Assert::IsTrue(str[i].empty()); + Assert::AreEqual(allocLengths[i], (int)str[i].capacity()); + } + catch (...) + { + Assert::IsTrue(false); + } + } + } + + TEST_METHOD(GetAtTests) { + CMyString str[]{ + CMyString(), + CMyString(), + CMyString("test"), + CMyString("test"), + CMyString("test"), + CMyString('a', 10), + CMyString(CMyString("to be copied then cleared")), + }; + int pos[] = { + 1, + 0, + 4, + -1, + 1, + 9, + 12, + }; + char character[] = { + '\0', + '\0', + '\0', + '\0', //first four are invalid + 'e', + 'a', + ' ', + }; + int testcount = sizeof(pos) / sizeof(int); + for (size_t i = 0; i < testcount; i++) + { + try + { + Assert::AreEqual(character[i], str[i].getat(pos[i])); + } + catch(const CMyStringException& e) + { + if (i < 4) + { + Assert::AreEqual(CMyStringException::ErrOutOfRange, e.what()); + } + else + { + Assert::IsTrue(false); + } + } + catch (...) + { + Assert::IsTrue(false); + } + } + } + TEST_METHOD(SetAtTests) { + CMyString str[]{ + CMyString(), + CMyString("test"), + CMyString("test"), + CMyString('a', 10), + }; + int pos[] = { + 0, + 4, + -1, + 3, + }; + char* text[] = { + '\0', + '\0', + '\0', //first three are invalid + "aaataaaaaa", + }; + int testcount = sizeof(pos) / sizeof(int); + for (size_t i = 0; i < testcount; i++) + { + try + { + str[i].setat(pos[i], 't'); + Assert::AreEqual(text[i], str[i].c_str()); + } + catch (const CMyStringException& e) + { + if (i < 3) + { + Assert::AreEqual(CMyStringException::ErrOutOfRange, e.what()); + } + else + { + Assert::IsTrue(false); + } + } + catch (...) + { + Assert::IsTrue(false); + } + } + } + + TEST_METHOD(ReserveTests) { + int allocs[] = { + 1, + 5, + 10, + 33, + }; + + int testcount = sizeof(allocs) / sizeof(int); + for (size_t i = 0; i < testcount; i++) + { + try + { + CMyString str = CMyString("test"); + str.reserve(allocs[i]); + Assert::AreEqual(allocs[i], (int)str.capacity()); + } + catch (const CMyStringException& e) + { + Assert::AreEqual(CMyStringException::ErrOutOfRange, e.what()); + } + } + } + + TEST_METHOD(EraseTests) { + //TODO } }; } diff --git a/feladat5/UnitTest1/UnitTest1.vcxproj b/feladat5/UnitTest1/UnitTest1.vcxproj index 96c458e..4b90945 100644 --- a/feladat5/UnitTest1/UnitTest1.vcxproj +++ b/feladat5/UnitTest1/UnitTest1.vcxproj @@ -144,7 +144,7 @@ Windows C:\Users\danit\Desktop\2026-27-cpp-homework\feladat5\feladat5\x64\Debug;$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories) - CMyString;%(AdditionalDependencies) + CMyString;CMyStringException;%(AdditionalDependencies) diff --git a/feladat5/feladat5/CMyString.cpp b/feladat5/feladat5/CMyString.cpp index 6de9bf9..83dc428 100644 --- a/feladat5/feladat5/CMyString.cpp +++ b/feladat5/feladat5/CMyString.cpp @@ -6,7 +6,7 @@ static int strLength(const char* str) { if (str == nullptr) { - return 0; + return -1; } int cnt = 0; while (str[cnt]) @@ -16,9 +16,10 @@ static int strLength(const char* str) { return cnt; } + static void CopyStr(char* dest, const char* src, size_t length) { if (dest == nullptr || src == nullptr) { - throw new bad_exception; + return; } size_t i; for (i = 0; i < length; i++) @@ -28,68 +29,69 @@ static void CopyStr(char* dest, const char* src, size_t length) { dest[i] = '\0'; } +static void MakeEmptyStr(size_t* datalngth, size_t* alloclngth, char** ptr) { + *datalngth = 0; + *alloclngth = 1; + *ptr = new char[1]; + (*ptr)[0] = '\0'; +} + CMyString::CMyString() { - m_nDataLength = 0; - m_nAllocLength = 1; - m_pchData = new char[m_nAllocLength]; - m_pchData[0] = '\0'; + MakeEmptyStr(&m_nDataLength, &m_nAllocLength, &m_pchData); } CMyString::CMyString(const char* psz) { - m_nDataLength = 0; if (psz == nullptr) { - m_nAllocLength = 1; + MakeEmptyStr(&m_nDataLength, &m_nAllocLength, &m_pchData); } else { + m_nDataLength = 0; while (psz[m_nDataLength]) { m_nDataLength++; } m_nAllocLength = m_nDataLength + 1; + m_pchData = new char[m_nAllocLength]; + CopyStr(m_pchData, psz, m_nDataLength); } - m_pchData = new char[m_nAllocLength]; - CopyStr(m_pchData, psz, m_nDataLength); } CMyString::CMyString(char ch, size_t repeat) { - if (ch == '\0') + if (ch == '\0' || repeat == 0) { - m_nDataLength = 0; - m_nAllocLength = 1; + MakeEmptyStr(&m_nDataLength, &m_nAllocLength, &m_pchData); } else { - m_nDataLength = repeat; + m_nDataLength = 0; m_nAllocLength = repeat + 1; + m_pchData = new char[m_nAllocLength]; + while (m_nDataLength < repeat) + { + m_pchData[m_nDataLength++] = ch; + } + m_pchData[m_nAllocLength-1] = '\0'; } - m_pchData = new char[m_nAllocLength]; - int i = 0; - while (i < m_nDataLength) - { - m_pchData[i] = ch; - i++; - } - m_pchData[i] = '\0'; } CMyString::CMyString(const CMyString& str) { if (str.empty()) { - m_nDataLength = 0; + MakeEmptyStr(&m_nDataLength, &m_nAllocLength, &m_pchData); } else { m_nDataLength = str.size(); + m_nAllocLength = m_nDataLength + 1; + m_pchData = new char[m_nAllocLength]; + int i = 0; + const char* cont = str.c_str(); + while (cont[i]) + { + m_pchData[i] = cont[i]; + i++; + } + m_pchData[m_nDataLength] = '\0'; } - m_nAllocLength = m_nDataLength + 1; - m_pchData = new char[m_nAllocLength]; - int i = 0; - const char* cont = str.c_str(); - while (cont[i]) // will never be a nullptr - { - m_pchData[i] = cont[i]; - i++; - } - m_pchData[i] = '\0'; //i will never go over nAllocLength } CMyString::~CMyString() { delete m_pchData; @@ -98,7 +100,7 @@ size_t CMyString::size() const { return m_nDataLength; } size_t CMyString::capacity() const { - return m_nDataLength; + return m_nAllocLength; } const char* CMyString::c_str() const { return m_pchData; @@ -110,35 +112,36 @@ void CMyString::clear() { char CMyString::getat(size_t index) const { if (index >= m_nDataLength) { - throw new CMyStringException(CMyStringException::ErrOutOfRange); + throw CMyStringException(CMyStringException::ErrOutOfRange); } return m_pchData[index]; } void CMyString::setat(size_t index, char ch) { if (index >= m_nDataLength) { - throw new CMyStringException(CMyStringException::ErrOutOfRange); + throw CMyStringException(CMyStringException::ErrOutOfRange); } if (ch == '\0') { - throw new CMyStringException(CMyStringException::ErrInvalidChar); + throw CMyStringException(CMyStringException::ErrInvalidChar); } m_pchData[index] = ch; } void CMyString::reserve(size_t newcapacity) { if (newcapacity < m_nAllocLength) { - throw new CMyStringException(CMyStringException::ErrUnexpected); + throw CMyStringException(CMyStringException::ErrOutOfRange); } char* tmp = m_pchData; - m_pchData = new char[newcapacity]; + m_nAllocLength = newcapacity; + m_pchData = new char[m_nAllocLength]; CopyStr(m_pchData, tmp, m_nDataLength); delete tmp; } void CMyString::erase(size_t pos, size_t count) { if (pos >= m_nDataLength) { - throw new CMyStringException(CMyStringException::ErrOutOfRange); + throw CMyStringException(CMyStringException::ErrOutOfRange); } if (pos + count > m_nDataLength) { @@ -160,17 +163,14 @@ void CMyString::display() const { } void CMyString::shrink_to_fill() { m_nAllocLength = m_nDataLength + 1; - char* tmp = m_pchData; - m_pchData = new char[m_nAllocLength]; - CopyStr(m_pchData, tmp, m_nDataLength); - delete tmp; + this->reserve(m_nAllocLength); } void CMyString::reverse() { if (!empty()) { for (size_t i = 0; i < m_nDataLength / 2; i++) { - int j = m_nDataLength - i - 1; + size_t j = m_nDataLength - i - 1; char tmp = m_pchData[i]; m_pchData[i] = m_pchData[j]; m_pchData[j] = tmp; @@ -182,25 +182,21 @@ void CMyString::append(const char* psz, unsigned offset, unsigned count) { { return; } - int len = strLength(psz); + size_t len = strLength(psz); if (count == ~0) { - count = len; + count = (int)len; } - if (len < (count - offset)) + if (len < (int)(count - offset)) { - throw new CMyStringException(CMyStringException::ErrOutOfRange); + throw CMyStringException(CMyStringException::ErrOutOfRange); } if (count + m_nDataLength > m_nAllocLength) { - char* tmp = m_pchData; - m_nAllocLength = (count + m_nDataLength) * 2; - m_pchData = new char[m_nAllocLength]; - CopyStr(m_pchData, tmp, m_nDataLength); - delete tmp; + this->reserve((m_nAllocLength + count)*2); } - int i = m_nDataLength; - int j = offset; + size_t i = m_nDataLength; + size_t j = offset; while (j < count) { m_pchData[i++] = psz[j++]; @@ -209,27 +205,20 @@ void CMyString::append(const char* psz, unsigned offset, unsigned count) { m_pchData[i] = '\0'; } CMyString& CMyString::operator=(const CMyString& str) { - if (m_pchData != str.c_str()) + if (this != &str) { if (!str.empty()) { - if (str.capacity() > m_nAllocLength) + if (str.size() >= m_nAllocLength) { - m_nAllocLength = str.capacity(); - char* cpy = m_pchData; - m_pchData = new char[m_nAllocLength]; - delete cpy; + this->reserve(str.capacity() * 2); } - CopyStr(m_pchData, str.c_str(), m_nDataLength); m_nDataLength = str.size(); + CopyStr(m_pchData, str.c_str(), m_nDataLength); } else { - m_nDataLength = 0; - m_nAllocLength = 1; - delete m_pchData; - m_pchData = new char[m_nAllocLength]; - m_pchData[0] = '\0'; + MakeEmptyStr(&m_nDataLength, &m_nAllocLength, &m_pchData); } } return *this; diff --git a/feladat5/feladat5/CMyString.h b/feladat5/feladat5/CMyString.h index 5b98f3d..c081537 100644 --- a/feladat5/feladat5/CMyString.h +++ b/feladat5/feladat5/CMyString.h @@ -1,6 +1,6 @@ // Tóth Dániel Mátyás | IFPQYY | v1 #pragma once -class CMyString { // memóriát kétszeresére növeld amikor növelni kell gyerek +class CMyString { public: CMyString(); CMyString(const char* psz); diff --git a/feladat5/feladat5/CMyStringException.cpp b/feladat5/feladat5/CMyStringException.cpp index 51fe31b..8c3bfdb 100644 --- a/feladat5/feladat5/CMyStringException.cpp +++ b/feladat5/feladat5/CMyStringException.cpp @@ -31,6 +31,6 @@ CMyStringException::CMyStringException(const char* input) { msg = unique_ptr(new char[len+1]); CopyStr(msg.get(), input, len); } -const char* CMyStringException::what() { +const char* CMyStringException::what() const { return msg.get(); } \ No newline at end of file diff --git a/feladat5/feladat5/CMyStringException.h b/feladat5/feladat5/CMyStringException.h index 166c391..362bba2 100644 --- a/feladat5/feladat5/CMyStringException.h +++ b/feladat5/feladat5/CMyStringException.h @@ -5,7 +5,7 @@ using namespace std; class CMyStringException { public: CMyStringException(const char* input); - const char* what(void); + const char* what(void) const; static constexpr const char* ErrOutOfRange = "Hiba: index hiba!"; static constexpr const char* ErrInvalidChar = "Hiba: érvénytelen karakter!"; static constexpr const char* ErrCount = "Hiba: karakterek száma 0!";