diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..f6dab30 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# See: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#about-the-dependabotyml-file +version: 2 + +updates: + # Configure check for outdated GitHub Actions actions in workflows. + # See: https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-dependabot + - package-ecosystem: github-actions + directory: / # Check the repository's workflows under /.github/workflows/ + labels: + - "topic: infrastructure" + schedule: + interval: daily diff --git a/.github/workflows/check-arduino.yml b/.github/workflows/check-arduino.yml new file mode 100644 index 0000000..500738c --- /dev/null +++ b/.github/workflows/check-arduino.yml @@ -0,0 +1,28 @@ +name: Check Arduino + +# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows +on: + push: + pull_request: + schedule: + # Run every Tuesday at 8 AM UTC to catch breakage caused by new rules added to Arduino Lint. + - cron: "0 8 * * TUE" + workflow_dispatch: + repository_dispatch: + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Arduino Lint + uses: arduino/arduino-lint-action@v1 + with: + compliance: specification + library-manager: submit + # Always use this setting for official repositories. Remove for 3rd party projects. + official: true + project-type: library diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml new file mode 100644 index 0000000..e686b80 --- /dev/null +++ b/.github/workflows/compile-examples.yml @@ -0,0 +1,103 @@ +# Source: https://github.com/per1234/.github/blob/main/workflow-templates/compile-examples-private.md +name: Compile Examples + +# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows +on: + push: + paths: + - ".github/workflows/compile-examples-private.ya?ml" + - "library.properties" + - "examples/**" + - "src/**" + pull_request: + paths: + - ".github/workflows/compile-examples-private.ya?ml" + - "library.properties" + - "examples/**" + - "src/**" + schedule: + # Run every Tuesday at 8 AM UTC to catch breakage caused by changes to external resources (libraries, platforms). + - cron: "0 8 * * TUE" + workflow_dispatch: + repository_dispatch: + +env: + SKETCHES_REPORTS_PATH: sketches-reports + SKETCHES_REPORTS_ARTIFACT_NAME: sketches-reports + +jobs: + build: + name: ${{ matrix.board.fqbn }} + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + + strategy: + fail-fast: false + + matrix: + board: + - fqbn: arduino:mbed_portenta:envie_m7 + platforms: | + - name: arduino:mbed_portenta + - fqbn: arduino:renesas_portenta:portenta_c33 + platforms: | + - name: arduino:renesas_portenta + - fqbn: arduino:mbed_opta:opta + platforms: | + - name: arduino:mbed_opta + + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Compile examples + uses: arduino/compile-sketches@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + fqbn: ${{ matrix.board.fqbn }} + platforms: ${{ matrix.board.platforms }} + libraries: | + # Install the library from the local path. + - source-path: ./ + - name: Arduino_USBHostMbed5 + - source-path: https://github.com/arduino-libraries/Arduino_POSIXStorage + # Additional library dependencies can be listed here. + # See: https://github.com/arduino/compile-sketches#libraries + sketch-paths: | + - examples + enable-deltas-report: true + sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }} + + - name: Save sketches report as workflow artifact + uses: actions/upload-artifact@v3 + with: + if-no-files-found: error + path: ${{ env.SKETCHES_REPORTS_PATH }} + name: ${{ env.SKETCHES_REPORTS_ARTIFACT_NAME }} + + report-size-deltas: + needs: build + # Run even if some compilations failed. + if: always() && github.event_name == 'pull_request' + runs-on: ubuntu-latest + permissions: + pull-requests: write + + steps: + - name: Download sketches reports artifact + id: download-artifact + continue-on-error: true # If compilation failed for all boards then there are no artifacts + uses: actions/download-artifact@v3 + with: + name: ${{ env.SKETCHES_REPORTS_ARTIFACT_NAME }} + path: ${{ env.SKETCHES_REPORTS_PATH }} + + - name: Comment size deltas report to PR + uses: arduino/report-size-deltas@v1 + # If actions/download-artifact failed, there are no artifacts to report from. + if: steps.download-artifact.outcome == 'success' + with: + sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }} \ No newline at end of file diff --git a/.github/workflows/spell-check.yml b/.github/workflows/spell-check.yml new file mode 100644 index 0000000..c50fb21 --- /dev/null +++ b/.github/workflows/spell-check.yml @@ -0,0 +1,25 @@ +# Source: https://github.com/per1234/.github/blob/main/workflow-templates/spell-check.md +name: Spell Check + +# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows +on: + push: + pull_request: + schedule: + # Run every Tuesday at 8 AM UTC to catch new misspelling detections resulting from dictionary updates. + - cron: "0 8 * * TUE" + workflow_dispatch: + repository_dispatch: + +jobs: + spellcheck: + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Spell check + uses: codespell-project/actions-codespell@v2 \ No newline at end of file diff --git a/.github/workflows/sync-labels.yml b/.github/workflows/sync-labels.yml new file mode 100644 index 0000000..a1eb627 --- /dev/null +++ b/.github/workflows/sync-labels.yml @@ -0,0 +1,144 @@ +# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/sync-labels.md +name: Sync Labels + +# See: https://docs.github.com/actions/using-workflows/events-that-trigger-workflows +on: + push: + paths: + - ".github/workflows/sync-labels.ya?ml" + - ".github/label-configuration-files/*.ya?ml" + pull_request: + paths: + - ".github/workflows/sync-labels.ya?ml" + - ".github/label-configuration-files/*.ya?ml" + schedule: + # Run daily at 8 AM UTC to sync with changes to shared label configurations. + - cron: "0 8 * * *" + workflow_dispatch: + repository_dispatch: + +env: + CONFIGURATIONS_FOLDER: .github/label-configuration-files + CONFIGURATIONS_ARTIFACT: label-configuration-files + +jobs: + check: + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Download JSON schema for labels configuration file + id: download-schema + uses: carlosperate/download-file-action@v2 + with: + file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/arduino-tooling-gh-label-configuration-schema.json + location: ${{ runner.temp }}/label-configuration-schema + + - name: Install JSON schema validator + run: | + sudo npm install \ + --global \ + ajv-cli \ + ajv-formats + + - name: Validate local labels configuration + run: | + # See: https://github.com/ajv-validator/ajv-cli#readme + ajv validate \ + --all-errors \ + -c ajv-formats \ + -s "${{ steps.download-schema.outputs.file-path }}" \ + -d "${{ env.CONFIGURATIONS_FOLDER }}/*.{yml,yaml}" + + download: + needs: check + runs-on: ubuntu-latest + permissions: {} + + strategy: + matrix: + filename: + # Filenames of the shared configurations to apply to the repository in addition to the local configuration. + # https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/sync-labels + - universal.yml + + steps: + - name: Download + uses: carlosperate/download-file-action@v2 + with: + file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/${{ matrix.filename }} + + - name: Pass configuration files to next job via workflow artifact + uses: actions/upload-artifact@v3 + with: + path: | + *.yaml + *.yml + if-no-files-found: error + name: ${{ env.CONFIGURATIONS_ARTIFACT }} + + sync: + needs: download + runs-on: ubuntu-latest + permissions: + contents: read + issues: write + + steps: + - name: Set environment variables + run: | + # See: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#setting-an-environment-variable + echo "MERGED_CONFIGURATION_PATH=${{ runner.temp }}/labels.yml" >> "$GITHUB_ENV" + + - name: Determine whether to dry run + id: dry-run + if: > + github.event_name == 'pull_request' || + ( + ( + github.event_name == 'push' || + github.event_name == 'workflow_dispatch' + ) && + github.ref != format('refs/heads/{0}', github.event.repository.default_branch) + ) + run: | + # Use of this flag in the github-label-sync command will cause it to only check the validity of the + # configuration. + echo "flag=--dry-run" >> $GITHUB_OUTPUT + + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Download configuration files artifact + uses: actions/download-artifact@v3 + with: + name: ${{ env.CONFIGURATIONS_ARTIFACT }} + path: ${{ env.CONFIGURATIONS_FOLDER }} + + - name: Remove unneeded artifact + uses: geekyeggo/delete-artifact@v2 + with: + name: ${{ env.CONFIGURATIONS_ARTIFACT }} + + - name: Merge label configuration files + run: | + # Merge all configuration files + shopt -s extglob + cat "${{ env.CONFIGURATIONS_FOLDER }}"/*.@(yml|yaml) > "${{ env.MERGED_CONFIGURATION_PATH }}" + + - name: Install github-label-sync + run: sudo npm install --global github-label-sync + + - name: Sync labels + env: + GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # See: https://github.com/Financial-Times/github-label-sync + github-label-sync \ + --labels "${{ env.MERGED_CONFIGURATION_PATH }}" \ + ${{ steps.dry-run.outputs.flag }} \ + ${{ github.repository }} \ No newline at end of file diff --git a/examples/tests/test_qspi_usb_sd/test_c33 b/examples/tests/test_qspi_usb_sd/test_c33 new file mode 100644 index 0000000..351a3d8 --- /dev/null +++ b/examples/tests/test_qspi_usb_sd/test_c33 @@ -0,0 +1,7 @@ +#!/bin/bash +<<<<<<< Updated upstream +arduino-cli compile -b arduino:renesas_portenta:portenta_c33 --library "../../Arduino_POSIXStorage" --library "/home/c.dragomir/ArduinoWorkspace/Arduino_UnifiedStorage" +======= +arduino-cli compile -b arduino:renesas_portenta:portenta_c33 --library "/home/c.dragomir/ArduinoWorkspace/Repos/POSIXStorage" --library "/home/c.dragomir/ArduinoWorkspace/Repos/Arduino_UnifiedStorage" +>>>>>>> Stashed changes +arduino-cli upload -b arduino:renesas_portenta:portenta_c33 \ No newline at end of file diff --git a/examples/tests/test_qspi_usb_sd/test_h7 b/examples/tests/test_qspi_usb_sd/test_h7 new file mode 100644 index 0000000..0448bfb --- /dev/null +++ b/examples/tests/test_qspi_usb_sd/test_h7 @@ -0,0 +1,8 @@ +#!/bin/bash +<<<<<<< Updated upstream +arduino-cli compile -b arduino:mbed_portenta:envie_m7 --library "../../Arduino_POSIXStorage" --library "/home/c.dragomir/ArduinoWorkspace/Arduino_UnifiedStorage" +arduino-cli upload -b arduino:mbed_portenta:envie_m7 +======= +arduino-cli compile -b arduino:mbed_portenta:envie_m7 --library "../../../POSIXStorage" --library "../../../Arduino_UnifiedStorage" + +>>>>>>> Stashed changes diff --git a/examples/tests/test_qspi_usb_sd/test_qspi_usb_sd.ino b/examples/tests/test_qspi_usb_sd/test_qspi_usb_sd.ino new file mode 100644 index 0000000..a579ca9 --- /dev/null +++ b/examples/tests/test_qspi_usb_sd/test_qspi_usb_sd.ino @@ -0,0 +1,582 @@ +#include +#include "Arduino_UnifiedStorage.h" + +#define HAS_USB 1 +#define HAS_SD 1 +#define HAS_QSPI 1 + +#ifdef HAS_USB +USBStorage usb = USBStorage(); +#endif + +#ifdef HAS_SD +SDStorage sd = SDStorage(); +#endif + +#ifdef HAS_QSPI +InternalStorage internal = InternalStorage(); +#endif + +void testMoveAndDelete(Arduino_UnifiedStorage* sourceStorage, Arduino_UnifiedStorage* destinationStorage, const char* storageTypeA, const char* storageTypeB) { + + + +String fileName = "/test_" + String(millis()) + ".txt"; + // Create a file in the source storage + UFile fileToMove = sourceStorage->getRootFolder().createFile(fileName, FileMode::WRITE); + fileToMove.write(reinterpret_cast("Test data"), 9); + fileToMove.close(); + + // Move the file to the destination storage + if (fileToMove.moveTo(destinationStorage->getRootFolder())) { + Serial.println("Moving from " + String(storageTypeA) + " to " + String(storageTypeB) + " successful"); + + // Delete the moved file from the destination storage + UFile movedFile; + movedFile.open(destinationStorage->getRootFolder().getPathString() + fileName, FileMode::READ); + if (movedFile.remove()) { + Serial.println("File deletion from " + String(storageTypeB) + " successful"); + } else { + Serial.println("File deletion from " + String(storageTypeB) + " failed"); + Serial.println(getErrno()); + } + } else { + Serial.println("Moving from " + String(storageTypeA) + " to " + String(storageTypeB) + " failed"); + Serial.println(getErrno()); + } + + Serial.println(); +} + + +void testCopyAndDelete(Arduino_UnifiedStorage* sourceStorage, Arduino_UnifiedStorage* destinationStorage, const char* storageTypeA, const char* storageTypeB) { + + + +String fileName = "/test_" + String(millis()) + ".txt"; + // Create a file in the source storage + UFile fileToMove = sourceStorage->getRootFolder().createFile(fileName, FileMode::WRITE); + fileToMove.write(reinterpret_cast("Test data"), 9); + fileToMove.close(); + + // Move the file to the destination storage + if (fileToMove.copyTo(destinationStorage->getRootFolder())) { + Serial.println("Copying from " + String(storageTypeA) + " to " + String(storageTypeB) + " successful"); + + // Delete the moved file from the destination storage + UFile movedFile; + movedFile.open(destinationStorage->getRootFolder().getPathString() + fileName, FileMode::READ); + if (movedFile.remove()) { + Serial.println("File deletion from " + String(storageTypeB) + " successful"); + } else { + Serial.println("File deletion from " + String(storageTypeB) + " failed"); + Serial.println(getErrno()); + } + } else { + Serial.println("Moving from " + String(storageTypeA) + " to " + String(storageTypeB) + " failed"); + Serial.println(getErrno()); + } + +fileToMove.remove(); + Serial.println(); + +} + +void printFolderContents(Folder dir, int indentation = 0) { + std::vector directories = dir.getFolders(); + std::vectorfiles = dir.getFiles(); + + // Print directories + for (Folder subdir : directories) { + for (int i = 0; i < indentation; i++) { + Serial.print(" "); + } + Serial.print("[D] "); + Serial.println(subdir.getPath()); + printFolderContents(subdir, indentation + 1); + } + + // Print files + for (UFile file : files) { + for (int i = 0; i < indentation; i++) { + Serial.print(" "); + } + Serial.print("[F] "); + Serial.println(file.getPath()); + } +} + +void runRepeatedMountTest(Arduino_UnifiedStorage * storage, String storageType, int n = 10){ + Serial.println("Running repeated mount test for " + storageType); + + for(size_t i=0;ibegin(); + + Serial.println("Mounting drive"); + if(mountResult != 1) { + Serial.println(mountResult); + Serial.println(getErrno()); + } + + Folder root = storage->getRootFolder(); + UFile file = root.createFile("file.txt", FileMode::WRITE); + file.write("writing stuff to the file"); + file.changeMode(FileMode::READ); + Serial.println(file.readAsString()); + file.close(); + file.remove(); + + int umountResult = storage->unmount(); + if(!umountResult) { + Serial.println("Unmounting drive"); + Serial.println(umountResult); + Serial.println(getErrno()); + } else { + Serial.println("Succesfully unmounted"); + } + } +} + +void setup() { + Serial.begin(9600); + while (!Serial); + + +/* UNCOMMENT THIS PART IF YOU WANT TO ENABLE FORMATTING + internal.begin(); + internal.unmount(); + + usb.begin(); + usb.unmount(); + + sd.begin(); + sd.unmount(); + + Serial.println("Formatting all attached drives..."); + Serial.println("Formatting USB drive: " + String(usb.format())); + Serial.println("Formatting SD drive: " + String(sd.format())); + Serial.println("Formatting Internal drive: " + String(internal.format())); + + */ + + runRepeatedMountTest(&usb, "USB"); + runRepeatedMountTest(&sd, "SD"); + runRepeatedMountTest(&internal, "QSPI"); + + runTests(&usb, "USB Storage"); + runTests(&internal, "Internal Storage (QSPI)"); + runTests(&sd, "SD Storage"); + + + delay(1000); + + usb.begin(); + sd.begin(); + internal.begin(); + + testMoveAndDelete(&sd, &internal, "SD", "Internal"); + testMoveAndDelete(&internal, &sd, "Internal", "SD"); + testMoveAndDelete(&usb, &sd, "USB", "SD"); + testMoveAndDelete(&sd, &usb, "SD", "USB"); + testMoveAndDelete(&usb, &internal, "USB", "Internal"); + testMoveAndDelete(&internal, &usb, "Internal", "USB"); + + + testCopyAndDelete(&sd, &internal, "SD", "Internal"); + testCopyAndDelete(&internal, &sd, "Internal", "SD"); + testCopyAndDelete(&usb, &sd, "USB", "SD"); + testCopyAndDelete(&sd, &usb, "SD", "USB"); + testCopyAndDelete(&usb, &internal, "USB", "Internal"); + testCopyAndDelete(&internal, &usb, "Internal", "USB"); + + usb.unmount(); + sd.unmount(); + internal.unmount(); + +} + +void loop() { +} + +void clearData(Folder root){ + + for(UFile f : root.getFiles()){ + f.remove(); + } + + for(Folder d: root.getFolders()){ + d.remove(); + } + +} + + + +void runTests(Arduino_UnifiedStorage * storage, String storageType) { + + + + if (storage->begin()) { + + + Folder root = storage->getRootFolder(); + // clearData(root); + + Serial.println("=== Testing " + storageType + " ==="); + + Serial.println("========= UFile Tests ========="); + + testFileCreationWithOpen(root); + testFileCreationWithCreate(root); + testWritingCharBuffer(root); + testWritingWithString(root); + testAppending(root); + testReadingAll(root); + testSeeking(root); + testAvailableData(root); + testCopyingFile(root); + testMovingFile(root); + + Serial.println("========= FS Contents after UFile Tests ========="); + printFolderContents(root); + Serial.println("=============================\n"); + + Serial.println("========= Folder Tests ========="); + + testFolderCreation(root); + testFolderRenaming(root); + testCopyingFolder(root); + testMovingFolder(root); + + Serial.println("========= FS Contents after Folder Tests ========="); + printFolderContents(root); + Serial.println("=============================\n"); + storage->unmount(); + + } else { + Serial.println(storageType + " not initialized!"); + } + +} + +bool testFileCreationWithOpen(Folder root) { + UFile file = UFile(); + String path = root.getPathString() + "/test_open.txt"; + Serial.println(path); + if (file.open(path, FileMode::WRITE)) { + Serial.println("\n--- Test creating file using file.open ---"); + Serial.println("Test creating file using file.open - Success"); + file.close(); + file.remove(); + return true; + } else { + Serial.println("Test creating file using file.open - Failed. Error: " + String(getErrno())); + return false; + } + +} + +bool testFileCreationWithCreate(Folder root) { + Serial.println("\n--- Test creating file using root.createFile ---"); + UFile file = root.createFile("test_create.txt", FileMode::WRITE); + if (file.exists()) { + Serial.println("Test creating file using root.createFile - Success"); + file.close(); + file.remove(); + return true; + } else { + Serial.println("Test creating file using root.createFile - Failed. Error: " + String(getErrno())); + return false; + } +} + +bool testWritingCharBuffer(Folder root) { + UFile file = root.createFile("test_write.txt", FileMode::WRITE); + if (file.exists()) { + Serial.println("\n--- Test writing char * buffer ---"); + size_t bytesWritten = file.write(reinterpret_cast("Hello, World!"), 13); + Serial.println("Bytes written to file: " + String(bytesWritten)); + file.close(); + file.remove(); + return bytesWritten == 13; + } else { + Serial.println("Test writing char * buffer - Failed. Error: " + String(getErrno())); + return false; + } +} + +bool testWritingWithString(Folder root) { + UFile file = root.createFile("test_write_string.txt", FileMode::WRITE); + if (file.exists()) { + Serial.println("\n--- Test writing String ---"); + String data = " This is a test with String data."; + size_t bytesWritten = file.write(data); + Serial.println("Bytes written to file (with String): " + String(bytesWritten)); + file.close(); + file.remove(); + return true; + + } else { + Serial.println("Test writing with String data type - Failed. Error: " + String(getErrno())); + return false; + } + +} + +bool testAppending(Folder root) { + UFile file = root.createFile("test_append.txt", FileMode::WRITE); + if (file.exists()) { + Serial.println("\n--- Test appending ---"); + String data = " Appending some more data."; + size_t bytesWritten = file.write(reinterpret_cast(data.c_str()), data.length()); + Serial.println("Bytes written to file (appending): " + String(bytesWritten)); + file.close(); + file.remove(); + return true; + } else { + Serial.println("Test appending to the file - Failed. Error: " + String(getErrno())); + return false; + } +} + +bool testReadingAll(Folder root) { + UFile file = root.createFile("test_read.txt", FileMode::WRITE); + if (file.exists()) { + file.write(reinterpret_cast("Hello, World!"), 13); + file.close(); + + if (file.open(root.getPathString() + "/test_read.txt", FileMode::READ)) { + char buffer[file.available()]; + size_t bytesRead = file.read(reinterpret_cast(buffer), sizeof(buffer)); + buffer[bytesRead] = '\0'; // Null-terminate the string + Serial.println("\n--- Test reading everything from the file ---"); + Serial.println("Read from file (test_read.txt): " + String(buffer)); + Serial.println("error at print? cplm "); + file.close(); + + file.remove(); + + return true; + } else { + Serial.println("Test reading everything from the file - Failed. Error: " + String(getErrno())); + return false; + } + } else { + Serial.println("Test reading everything from the file - Failed to create file. Error: " + String(getErrno())); + return false; + + } + + return false; +} + +bool testSeeking(Folder root) { + + UFile file = root.createFile("test_seek.txt", FileMode::WRITE); + if (file.exists()) { + file.write(reinterpret_cast("Hello, World!"), 13); + file.close(); + + + if (file.open(root.getPathString() + "/test_seek.txt", FileMode::READ)) { + Serial.println("\n--- Test seeking file ---"); + file.seek(7); + char buffer[20]; + size_t bytesRead = file.read(reinterpret_cast(buffer), sizeof(buffer)); + buffer[bytesRead] = '\0'; // Null-terminate the string + Serial.println("Read after seeking: " + String(buffer)); + file.close(); + file.remove(); + return true; + } else { + Serial.println("Test seeking in the file - Failed. Error: " + String(getErrno())); + return false; + } + } else { + Serial.println("Test seeking in the file - Failed to create file. Error: " + String(getErrno())); + return false; + } + +} + +bool testAvailableData(Folder root) { + UFile file = root.createFile("test_available.txt", FileMode::WRITE); + if (file.exists()) { + file.write(reinterpret_cast("Hello, World!"), 13); + file.close(); + + if (file.open(root.getPathString() + "/test_available.txt", FileMode::READ)) { + Serial.println("\n--- Test available data ---"); + int availableBytes = file.available(); + Serial.println("Available bytes in file (test_available.txt): " + String(availableBytes)); + file.close(); + file.remove(); + return true; + } else { + Serial.println("Test checking available data in the file - Failed. Error: " + String(getErrno())); + return false; + } + } else { + Serial.println("Test checking available data in the file - Failed to create file. Error: " + String(getErrno())); + return false; + } + + return false; +} + +bool testCopyingFile(Folder root) { + // Test copying a file + UFile sourceFile = root.createFile("test_source_copy.txt", FileMode::WRITE); + if (sourceFile.exists()) { + sourceFile.write(reinterpret_cast("Hello, World!"), 13); + sourceFile.close(); + + Folder destinationFolder = root.createSubfolder("test_folder_copy"); + + if (destinationFolder.exists()) { + Serial.println("\n--- Test copying a file ---"); + Serial.println("Source file name: " + String(sourceFile.getPathString())); + + if (sourceFile.copyTo(destinationFolder)) { + Serial.println("File copied successfully!"); + sourceFile.close(); + sourceFile.remove(); + destinationFolder.remove(); + return true; + } else { + Serial.println("File copying failed. Error: " + String(getErrno())); + return false; + } + } else { + Serial.println("Test copying a file - Failed. Error: " + String(getErrno())); + return false; + } + + } else { + Serial.println("Test copying a file - Failed to create destination folder. Error: " + String(getErrno())); + return false; + } +} + +bool testMovingFile(Folder root) { + UFile sourceFileMove = root.createFile("test_source_move.txt", FileMode::WRITE); + if (sourceFileMove.exists()) { + sourceFileMove.write(reinterpret_cast("Hello, World!"), 13); + sourceFileMove.close(); + + Folder destinationFolder = root.createSubfolder("test_folder_move"); + if (destinationFolder.exists()) { + UFile movedFile = sourceFileMove; + if (movedFile.exists()) { + Serial.println("\n--- Test moving a file ---"); + Serial.println("Source file name: " + String(sourceFileMove.getPathString())); + Serial.println("Destination file name: " + String(destinationFolder.getPathString()) + "/test_source_move.txt"); + if (sourceFileMove.moveTo(destinationFolder)) { + Serial.println("File moved successfully!"); + sourceFileMove.close(); + movedFile.close(); + movedFile.remove(); + destinationFolder.remove(); + sourceFileMove.remove(); + return true; + } else { + Serial.println("File moving failed. Error: " + String(getErrno())); + return false; + } + } else { + Serial.println("Test moving a file - Failed. Error: " + String(getErrno())); + return false; + } + } else { + Serial.println("Test moving a file - Failed to create destination folder. Error: " + String(getErrno())); + return false; + } + } else { + Serial.println("Test moving a file - Failed. Error: " + String(getErrno())); + return false; + } +} + +bool testFolderCreation(Folder root) { + Folder subfolder = root.createSubfolder("test_folder"); + if (subfolder.exists()) { + Serial.println("\n--- Test creating folder using root.createSubfolder ---"); + Serial.println("Test creating folder using root.createSubfolder - Success"); + subfolder.remove(); + return true; + } else { + Serial.println("Test creating folder using root.createSubfolder - Failed. Error: " + String(getErrno())); + return false; + } +} + +bool testFolderRenaming(Folder root) { + Folder sourceFolder = root.createSubfolder("source_folder"); + if (sourceFolder.exists()) { + Serial.println("\n--- Test renaming folder ---"); + Serial.println("Source folder name: " + String(sourceFolder.getPathString())); + if (sourceFolder.rename("renamed_folder")) { + Serial.println("Folder renamed to: " + String(sourceFolder.getPathString())); + sourceFolder.remove(); + return true; + } else { + Serial.println("Folder renaming failed. Error: " + String(getErrno())); + return false; + } + } else { + Serial.println("Test folder renaming - Failed. Error: " + String(getErrno())); + return false; + } +} + +bool testCopyingFolder(Folder root) { + Folder sourceFolder = root.createSubfolder("folder1"); + Folder copyDestination = root.createSubfolder("copy_destination"); + + if (sourceFolder.exists()) { + Serial.println("\n--- Test copying a folder ---"); + Serial.println("Source folder name: " + String(sourceFolder.getPathString())); + Serial.println("Destination folder name: " + String(copyDestination.getPathString())); + if (sourceFolder.copyTo(copyDestination)) { + Serial.println("Folder copied successfully!"); + sourceFolder.remove(); + copyDestination.remove(); + return true; + } else { + Serial.println("Folder copying failed. Error: " + String(getErrno())); + sourceFolder.remove(); + return false; + } + } else { + Serial.println("Test copying a folder - Failed to create source folder. Error: " + String(getErrno())); + return false; + } +} + +bool testMovingFolder(Folder root) { + + + Folder sourceFolderMove = root.createSubfolder("source_folder_move"); + Folder moveDestination = root.createSubfolder("move_destination"); + + if (sourceFolderMove.exists()) { + Serial.println("\n--- Test moving a folder ---"); + Serial.println("Source folder name: " + String(sourceFolderMove.getPathString())); + Serial.println("Destination folder name: " + String(moveDestination.getPathString())); + if (sourceFolderMove.moveTo(moveDestination)) { + Serial.println("Folder moved successfully!"); + sourceFolderMove.remove(); + moveDestination.remove(); + return true; + } else { + Serial.println("Folder moving failed. Error: " + String(getErrno())); + return false; + } + } else { + Serial.println("Test moving a folder - Failed to create source folder. Error: " + String(getErrno())); + return false; + } + + +} +