瀏覽代碼

Added File class

- added File class to do simple file operations
(reading, writing, executing omitted)
- added tests for File class
Patrick 3 年之前
父節點
當前提交
16206c7fcc
共有 8 個文件被更改,包括 435 次插入3 次删除
  1. 10 3
      CMakeLists.txt
  2. 165 0
      source/io/File.cpp
  3. 52 0
      source/io/File.hpp
  4. 32 0
      source/io/FilePathSeparator.hpp
  5. 23 0
      source/io/FilePathSeparatorMatch.hpp
  6. 152 0
      test/cases/io/FileTest.cpp
  7. 二進制
      test/resources/app.exe
  8. 1 0
      test/resources/simple.txt

+ 10 - 3
CMakeLists.txt

@@ -37,7 +37,7 @@ set(SOURCE_FILES
         ${CMAKE_CURRENT_SOURCE_DIR}/source/base/Class.cpp
         ${CMAKE_CURRENT_SOURCE_DIR}/source/boxing/Integer.cpp
         ${CMAKE_CURRENT_SOURCE_DIR}/source/boxing/IBoxing.hpp
-        ${CMAKE_CURRENT_SOURCE_DIR}/source/exception/IllegalOperationException.hpp
+        ${CMAKE_CURRENT_SOURCE_DIR}/source/exception/IllegalArithmeticOperationException.hpp
         ${CMAKE_CURRENT_SOURCE_DIR}/source/base/Types.hpp
         ${CMAKE_CURRENT_SOURCE_DIR}/source/boxing/Boolean.hpp
         ${CMAKE_CURRENT_SOURCE_DIR}/source/boxing/Boolean.cpp
@@ -49,7 +49,12 @@ set(SOURCE_FILES
         ${CMAKE_CURRENT_SOURCE_DIR}/source/boxing/String.hpp
         ${CMAKE_CURRENT_SOURCE_DIR}/source/boxing/String.cpp
         ${CMAKE_CURRENT_SOURCE_DIR}/source/time/Date.hpp
-        ${CMAKE_CURRENT_SOURCE_DIR}/source/time/Date.cpp)
+        ${CMAKE_CURRENT_SOURCE_DIR}/source/time/Date.cpp
+        ${CMAKE_CURRENT_SOURCE_DIR}/source/io/File.hpp
+        ${CMAKE_CURRENT_SOURCE_DIR}/source/io/File.cpp
+        ${CMAKE_CURRENT_SOURCE_DIR}/source/exception/FileOperationException.hpp
+        ${CMAKE_CURRENT_SOURCE_DIR}/source/io/FilePathSeparatorMatch.hpp
+        ${CMAKE_CURRENT_SOURCE_DIR}/source/io/FilePathSeparator.hpp)
 
 set(TEST_FILES
         ${CMAKE_CURRENT_SOURCE_DIR}/test/cases/boxing/IntegerTest.cpp
@@ -57,7 +62,9 @@ set(TEST_FILES
         ${CMAKE_CURRENT_SOURCE_DIR}/test/cases/boxing/FloatTest.cpp
         ${CMAKE_CURRENT_SOURCE_DIR}/test/cases/boxing/DoubleTest.cpp
         ${CMAKE_CURRENT_SOURCE_DIR}/test/cases/boxing/StringTest.cpp
-        ${CMAKE_CURRENT_SOURCE_DIR}/test/cases/time/DateTest.cpp)
+        ${CMAKE_CURRENT_SOURCE_DIR}/test/cases/time/DateTest.cpp
+        ${CMAKE_CURRENT_SOURCE_DIR}/test/cases/io/FileTest.cpp
+        ${CMAKE_CURRENT_SOURCE_DIR}/test/TestHelper.hpp)
 
 ##########################################################
 # Build

+ 165 - 0
source/io/File.cpp

@@ -0,0 +1,165 @@
+/*
+ * Author:          Patrick-Christopher Mattulat
+ * Company:         Lynar Studios
+ * E-Mail:          webmaster@lynarstudios.com
+ * Created:         2020-08-15
+ * Changed:         2020-08-15
+ *
+ * */
+
+#include "File.hpp"
+#include "../exception/FileOperationException.hpp"
+#include "FilePathSeparatorMatch.hpp"
+#include <fstream>
+#include <sys/stat.h>
+#include <algorithm>
+
+ls_std::File::File(std::string _absoluteFilePath) : Class("File"),
+absoluteFilePath(std::move(_absoluteFilePath))
+{}
+
+bool ls_std::File::operator==(File &_file)
+{
+  std::string normalizedFilePath = ls_std::File::normalizePath(this->absoluteFilePath);
+  std::string normalizedForeignFilePath = ls_std::File::normalizePath(_file.getAbsoluteFilePath());
+
+  return normalizedFilePath == normalizedForeignFilePath;
+}
+
+bool ls_std::File::operator!=(File &_file)
+{
+  std::string normalizedFilePath = ls_std::File::normalizePath(this->absoluteFilePath);
+  std::string normalizedForeignFilePath = ls_std::File::normalizePath(_file.getAbsoluteFilePath());
+
+  return normalizedFilePath != normalizedForeignFilePath;
+}
+
+bool ls_std::File::canExecute()
+{
+  bool executable {};
+  struct stat _stat {};
+
+  if(stat(this->absoluteFilePath.c_str(), &_stat) == 0) {
+    executable = (_stat.st_mode & (unsigned short) S_IEXEC) != 0;
+  }
+
+  return executable;
+}
+
+void ls_std::File::create()
+{
+  if(!this->_exists()) {
+    std::ofstream file {this->absoluteFilePath};
+    file.close();
+  } else {
+    throw ls_std::FileOperationException{this->absoluteFilePath};
+  }
+}
+
+bool ls_std::File::exists()
+{
+  return this->_exists();
+}
+
+std::string ls_std::File::getAbsoluteFilePath() {
+  return this->absoluteFilePath;
+}
+
+std::string ls_std::File::getName()
+{
+  std::string copy = this->absoluteFilePath;
+
+  // if it's a directory, remove separator from end, if it does exist
+
+  if(this->_isDirectory()) {
+    copy.erase(std::remove_if(copy.end() - 1, copy.end(), ls_std::FilePathSeparatorMatch()), copy.end());
+  }
+
+  // now get the file / directory name
+
+  auto base = std::find_if(copy.rbegin(), copy.rend(), ls_std::FilePathSeparatorMatch()).base();
+  return std::string(base, copy.end());
+}
+
+long ls_std::File::getSize()
+{
+  std::streampos fileSize {};
+
+  if(this->_exists()) {
+    std::ifstream fileHandler{this->absoluteFilePath, std::ios::in};
+    fileSize = fileHandler.tellg();
+    fileHandler.seekg(0, std::ios::end);
+    fileSize = fileHandler.tellg() - fileSize;
+    fileHandler.close();
+  }
+
+  return fileSize;
+}
+
+bool ls_std::File::isDirectory()
+{
+  return this->_isDirectory();
+}
+
+bool ls_std::File::isFile()
+{
+  return this->_isFile();
+}
+
+void ls_std::File::makeDirectory()
+{
+  if(mkdir(this->absoluteFilePath.c_str())) {
+    throw ls_std::FileOperationException {this->absoluteFilePath};
+  }
+}
+
+void ls_std::File::remove()
+{
+  if(this->_isFile()) {
+    if(std::remove(this->absoluteFilePath.c_str())) {
+      throw ls_std::FileOperationException{this->absoluteFilePath};
+    }
+  }
+
+  if(this->_isDirectory()) {
+    if(rmdir(this->absoluteFilePath.c_str())) {
+      throw ls_std::FileOperationException{this->absoluteFilePath};
+    }
+  }
+}
+
+bool ls_std::File::_exists()
+{
+  struct stat _stat {};
+  return (stat(this->absoluteFilePath.c_str(), &_stat) == 0);
+}
+
+bool ls_std::File::_isDirectory()
+{
+  bool match {};
+  struct stat _stat {};
+
+  if(stat(this->absoluteFilePath.c_str(), &_stat) == 0) {
+    match = _stat.st_mode & (unsigned short) S_IFDIR;
+  }
+
+  return match;
+}
+
+bool ls_std::File::_isFile()
+{
+  bool match {};
+  struct stat _stat {};
+
+  if(stat(this->absoluteFilePath.c_str(), &_stat) == 0) {
+    match = _stat.st_mode & (unsigned short) S_IFREG;
+  }
+
+  return match;
+}
+
+std::string ls_std::File::normalizePath(std::string path)
+{
+  std::replace(path.begin(), path.end(), '\\', '/');
+  return path;
+}

+ 52 - 0
source/io/File.hpp

@@ -0,0 +1,52 @@
+/*
+ * Author:          Patrick-Christopher Mattulat
+ * Company:         Lynar Studios
+ * E-Mail:          webmaster@lynarstudios.com
+ * Created:         2020-08-15
+ * Changed:         2020-08-15
+ *
+ * */
+
+#ifndef FILE_HPP
+#define FILE_HPP
+
+#include "../base/Class.hpp"
+#include <string>
+
+namespace ls_std {
+  class File : public Class {
+    public:
+
+      explicit File(std::string _absoluteFilePath);
+      ~File() = default;
+
+      // comparison operators
+
+      bool operator==(File& _file);
+      bool operator!=(File& _file);
+
+      // additional functionality
+
+      bool canExecute();
+      void create();
+      bool exists();
+      std::string getAbsoluteFilePath();
+      std::string getName();
+      long getSize();
+      bool isDirectory();
+      bool isFile();
+      void makeDirectory();
+      void remove();
+
+    private:
+
+      std::string absoluteFilePath {};
+
+      bool _exists();
+      bool _isDirectory();
+      bool _isFile();
+      static std::string normalizePath(std::string path);
+  };
+}
+
+#endif

+ 32 - 0
source/io/FilePathSeparator.hpp

@@ -0,0 +1,32 @@
+/*
+ * Author:          Patrick-Christopher Mattulat
+ * Company:         Lynar Studios
+ * E-Mail:          webmaster@lynarstudios.com
+ * Created:         2020-08-15
+ * Changed:         2020-08-15
+ *
+ * */
+
+#ifndef FILE_PATH_SEPARATOR_HPP
+#define FILE_PATH_SEPARATOR_HPP
+
+#include <string>
+
+namespace ls_std {
+  class FilePathSeparator {
+    public:
+
+      FilePathSeparator() = default;
+      ~FilePathSeparator() = default;
+
+      static char getLinuxFilePathSeparator() {
+        return '/';
+      }
+
+      static char getUnixFilePathSeparator() {
+        return '\\';
+      }
+  };
+}
+
+#endif

+ 23 - 0
source/io/FilePathSeparatorMatch.hpp

@@ -0,0 +1,23 @@
+/*
+ * Author:          Patrick-Christopher Mattulat
+ * Company:         Lynar Studios
+ * E-Mail:          webmaster@lynarstudios.com
+ * Created:         2020-08-15
+ * Changed:         2020-08-15
+ *
+ * */
+
+#ifndef FILE_PATH_MATCH_HPP
+#define FILE_PATH_MATCH_HPP
+
+#include "FilePathSeparator.hpp"
+
+namespace ls_std {
+  struct FilePathSeparatorMatch {
+    bool operator()(char _char) const {
+      return _char == ls_std::FilePathSeparator::getUnixFilePathSeparator() || _char == ls_std::FilePathSeparator::getLinuxFilePathSeparator();
+    }
+  };
+}
+
+#endif

+ 152 - 0
test/cases/io/FileTest.cpp

@@ -0,0 +1,152 @@
+/*
+ * Author:          Patrick-Christopher Mattulat
+ * Company:         Lynar Studios
+ * E-Mail:          webmaster@lynarstudios.com
+ * Created:         2020-08-15
+ * Changed:         2020-08-15
+ *
+ * */
+
+#include <gtest/gtest.h>
+#include "../../../source/io/File.hpp"
+#include "../../TestHelper.hpp"
+
+namespace {
+  class FileTest : public ::testing::Test {
+    protected:
+
+      FileTest() = default;
+      ~FileTest() override = default;
+
+      std::string fileLocation = TestHelper::getResourcesFolderLocation() + "simple.txt";
+
+      void SetUp() override {}
+      void TearDown() override {}
+  };
+
+  // comparison operators
+
+  TEST_F(FileTest, operatorEqual)
+  {
+    ls_std::File file {this->fileLocation};
+    ls_std::File file2 {this->fileLocation};
+    ls_std::File file3 {"/home/bla/text.txt"};
+    ls_std::File file4 {"\\home/bla\\text.txt"};
+
+    ASSERT_TRUE(file == file2);
+    ASSERT_TRUE(file2 == file);
+    ASSERT_TRUE(file3 == file4);
+    ASSERT_TRUE(file4 == file3);
+  }
+
+  TEST_F(FileTest, operatorNotEqual)
+  {
+    ls_std::File file {this->fileLocation};
+    ls_std::File file2 {TestHelper::getResourcesFolderLocation() + "app.exe"};
+
+    ASSERT_TRUE(file != file2);
+    ASSERT_TRUE(file2 != file);
+  }
+
+  // additional functionality
+
+  TEST_F(FileTest, canExecute)
+  {
+    ls_std::File executableFile {TestHelper::getResourcesFolderLocation() + "app.exe"};
+    ASSERT_TRUE(executableFile.canExecute());
+  }
+
+  TEST_F(FileTest, canExecuteNegative)
+  {
+    ls_std::File file {this->fileLocation};
+    ASSERT_FALSE(file.canExecute());
+  }
+
+  TEST_F(FileTest, createAndRemove)
+  {
+    ls_std::File file {TestHelper::getResourcesFolderLocation() + "tmp.txt"};
+    ASSERT_FALSE(file.exists());
+
+    file.create();
+    ASSERT_TRUE(file.exists());
+
+    file.remove();
+    ASSERT_FALSE(file.exists());
+  }
+
+  TEST_F(FileTest, exists)
+  {
+    ls_std::File file {this->fileLocation};
+    ls_std::File directory {TestHelper::getResourcesFolderLocation()};
+
+    ASSERT_TRUE(file.exists());
+    ASSERT_TRUE(directory.exists());
+  }
+
+  TEST_F(FileTest, existsNegative)
+  {
+    ls_std::File file {TestHelper::getResourcesFolderLocation() + "bla.txt"};
+    ASSERT_FALSE(file.exists());
+  }
+
+  TEST_F(FileTest, getAbsoluteFilePath)
+  {
+    ls_std::File file {this->fileLocation};
+    ASSERT_STREQ(fileLocation.c_str(), file.getAbsoluteFilePath().c_str());
+  }
+
+  TEST_F(FileTest, getName)
+  {
+    ls_std::File file {this->fileLocation};
+    ls_std::File executableFile {TestHelper::getResourcesFolderLocation() + "app.exe"};
+    ls_std::File anotherFile {"bla.txt"};
+    ls_std::File directory {TestHelper::getResourcesFolderLocation()};
+
+    ASSERT_STREQ("simple.txt", file.getName().c_str());
+    ASSERT_STREQ("app.exe", executableFile.getName().c_str());
+    ASSERT_STREQ("bla.txt", anotherFile.getName().c_str());
+    ASSERT_STREQ("resources", directory.getName().c_str());
+  }
+
+  TEST_F(FileTest, getSize)
+  {
+    ls_std::File file {this->fileLocation};
+    ASSERT_EQ(8, file.getSize());
+  }
+
+  TEST_F(FileTest, isDirectory)
+  {
+    ls_std::File directory {TestHelper::getResourcesFolderLocation()};
+    ASSERT_TRUE(directory.isDirectory());
+  }
+
+  TEST_F(FileTest, isDirectoryNegative)
+  {
+    ls_std::File file {this->fileLocation};
+    ASSERT_FALSE(file.isDirectory());
+  }
+
+  TEST_F(FileTest, isFile)
+  {
+    ls_std::File file {this->fileLocation};
+    ASSERT_TRUE(file.isFile());
+  }
+
+  TEST_F(FileTest, isFileNegative)
+  {
+    ls_std::File directory {TestHelper::getResourcesFolderLocation()};
+    ASSERT_FALSE(directory.isFile());
+  }
+
+  TEST_F(FileTest, makeDirectory)
+  {
+    ls_std::File directory {TestHelper::getResourcesFolderLocation() + "testDir"};
+    ASSERT_FALSE(directory.exists());
+
+    directory.makeDirectory();
+    ASSERT_TRUE(directory.exists());
+
+    directory.remove();
+    ASSERT_FALSE(directory.exists());
+  }
+}

二進制
test/resources/app.exe


+ 1 - 0
test/resources/simple.txt

@@ -0,0 +1 @@
+Hello!