- Add test_runner.sh with 8 automated test scenarios for comprehensive testing - Add DEVELOPMENT.md with detailed development guide and testing methodology - Delete obsolete documentation files (CHANGELOG.md, TEST_PLAN.md, TODO.md) - Update .gitignore to exclude sample/, test/, and test_reports/ directories - Update media-importer.sh with latest improvements - Test directories and reports are excluded from version control as intended
@@ -1,3 +1,3 @@ |
||
| 1 | 1 |
# Exclude samples directory from version control |
| 2 |
-samples/ |
|
| 2 |
+sample/ |
|
| 3 | 3 |
tests/ |
@@ -1,18 +0,0 @@ |
||
| 1 |
-# Changelog |
|
| 2 |
- |
|
| 3 |
-## [Unreleased] |
|
| 4 |
-### Added |
|
| 5 |
-- `--collect-unsortable` argument: Files with no EXIF or media date can be moved to an `unsortable` folder in the destination. |
|
| 6 |
- |
|
| 7 |
-### Changed |
|
| 8 |
-- The script now **requires** EXIF or media date for processing files. If no date is found, files are skipped and left in place by default. |
|
| 9 |
-- No fallback to filesystem modification date or other heuristics; only EXIF or media date is used for sorting and renaming. |
|
| 10 |
- |
|
| 11 |
-### Fixed |
|
| 12 |
-- Improved argument parsing to support new options. |
|
| 13 |
-- Improved warnings and debug output handling. |
|
| 14 |
- |
|
| 15 |
- |
|
| 16 |
-## [Earlier versions] |
|
| 17 |
-- See previous commits for details. |
|
@@ -0,0 +1,280 @@ |
||
| 1 |
+# Development Guide |
|
| 2 |
+ |
|
| 3 |
+## 1. Objectives |
|
| 4 |
+ |
|
| 5 |
+The Media Importer project aims to provide a robust, efficient solution for organizing media files by date with proper timezone handling and conflict - **Naming Convention**: `{s/f}_{YYYYMMDD_HHMMSS}_{TestName}.md` format where:
|
|
| 6 |
+ - `s` = success, `f` = failure |
|
| 7 |
+ - Followed by timestamp and test name (spaces converted to underscores)esolution. |
|
| 8 |
+ |
|
| 9 |
+Key objectives: |
|
| 10 |
+- Reliable EXIF/metadata extraction and date parsing |
|
| 11 |
+- Proper UTC time conversion for QuickTime/Apple media files |
|
| 12 |
+- Flexible organization patterns (year/month/day/hour) |
|
| 13 |
+- Safe file operations with dry-run capabilities |
|
| 14 |
+- Cross-platform compatibility (macOS/Linux) |
|
| 15 |
+ |
|
| 16 |
+## 2. Guide |
|
| 17 |
+ |
|
| 18 |
+### Development Workflow |
|
| 19 |
+ |
|
| 20 |
+When making changes to the project, follow this structured approach: |
|
| 21 |
+ |
|
| 22 |
+### Changelog Entries Format |
|
| 23 |
+ |
|
| 24 |
+All changelog entries should follow this format: |
|
| 25 |
+ |
|
| 26 |
+``` |
|
| 27 |
+- Date time |
|
| 28 |
+- Bug/Feature description |
|
| 29 |
+- Changes made |
|
| 30 |
+``` |
|
| 31 |
+ |
|
| 32 |
+Example: |
|
| 33 |
+``` |
|
| 34 |
+- 2025-09-07 10:30 |
|
| 35 |
+- Fixed data loss issue when processing already-sorted folders |
|
| 36 |
+- Added exclusion patterns for sorted/organized/processed folders |
|
| 37 |
+- Added --include-sorted flag to override exclusions when needed |
|
| 38 |
+``` |
|
| 39 |
+ |
|
| 40 |
+### File Move Confirmation |
|
| 41 |
+ |
|
| 42 |
+Every file move operation should be confirmed: |
|
| 43 |
+- After moving a file, the script must check that the file exists at the destination. |
|
| 44 |
+- If the file is not present at the destination after the move operation, the script should immediately stop and report an error. |
|
| 45 |
+- This ensures data integrity and prevents silent data loss. |
|
| 46 |
+ |
|
| 47 |
+### Destination Inside Source Handling |
|
| 48 |
+ |
|
| 49 |
+- Given the script's purpose, the destination folder may be inside the source folder. |
|
| 50 |
+- In this case, all files within the destination folder must be excluded from scanning and processing. |
|
| 51 |
+- For extra safety: before processing any file, if its path matches (or is inside) the destination path, the script must report an error and stop immediately. |
|
| 52 |
+- This prevents accidental re-processing or moving of files that have already been sorted, ensuring data integrity. |
|
| 53 |
+ |
|
| 54 |
+### Testing |
|
| 55 |
+ |
|
| 56 |
+Testing is essential to ensure the script's reliability and data safety. The following methodology should be used: |
|
| 57 |
+ |
|
| 58 |
+#### Test Environment Setup |
|
| 59 |
+- The `samples` directory contains a variety of media files for testing. |
|
| 60 |
+- Create a dedicated working directory named `test` for each test run. |
|
| 61 |
+- Copy selected files from `samples` into the `test` directory to simulate real-world scenarios. |
|
| 62 |
+- Perform import operations using the script, targeting the `test` directory as the source and a subdirectory (e.g., `test/sorted`) as the destination. |
|
| 63 |
+ |
|
| 64 |
+#### Test Execution and Documentation |
|
| 65 |
+- Before and after each import operation, run `find` on both the source and destination directories to capture the file structure: |
|
| 66 |
+ - Example: `find ./test > test/source_before.txt` |
|
| 67 |
+ - Example: `find ./test/sorted > test/dest_before.txt` |
|
| 68 |
+- Log all results, including script output and directory listings, into a dedicated log file for each test. |
|
| 69 |
+ |
|
| 70 |
+#### Test Report Format |
|
| 71 |
+Each test must generate a comprehensive Markdown report in `test/test_report.md` with the following structure: |
|
| 72 |
+ |
|
| 73 |
+```markdown |
|
| 74 |
+# Test Report: [Test Name/Scenario] |
|
| 75 |
+ |
|
| 76 |
+## Test Information |
|
| 77 |
+- **Date**: $(date) |
|
| 78 |
+- **Scenario**: [Brief description of what is being tested] |
|
| 79 |
+- **Objective**: [What specific functionality/behavior is being verified] |
|
| 80 |
+- **Files Used**: [List of test files and their characteristics] |
|
| 81 |
+ |
|
| 82 |
+## Pre-Test State |
|
| 83 |
+### Source Directory Structure |
|
| 84 |
+\`\`\` |
|
| 85 |
+[Contents of source_before.txt] |
|
| 86 |
+\`\`\` |
|
| 87 |
+ |
|
| 88 |
+### Destination Directory Structure |
|
| 89 |
+\`\`\` |
|
| 90 |
+[Contents of dest_before.txt] |
|
| 91 |
+\`\`\` |
|
| 92 |
+ |
|
| 93 |
+## Test Execution |
|
| 94 |
+### Command Used |
|
| 95 |
+\`\`\`bash |
|
| 96 |
+[Exact command executed] |
|
| 97 |
+\`\`\` |
|
| 98 |
+ |
|
| 99 |
+### Script Output |
|
| 100 |
+\`\`\` |
|
| 101 |
+[Full script output from import_log.txt] |
|
| 102 |
+\`\`\` |
|
| 103 |
+ |
|
| 104 |
+## Post-Test State |
|
| 105 |
+### Source Directory Structure |
|
| 106 |
+\`\`\` |
|
| 107 |
+[Contents of source_after.txt] |
|
| 108 |
+\`\`\` |
|
| 109 |
+ |
|
| 110 |
+### Destination Directory Structure |
|
| 111 |
+\`\`\` |
|
| 112 |
+[Contents of dest_after.txt] |
|
| 113 |
+\`\`\` |
|
| 114 |
+ |
|
| 115 |
+## Analysis and Verification |
|
| 116 |
+### Expected Results |
|
| 117 |
+- [List what should happen] |
|
| 118 |
+ |
|
| 119 |
+### Actual Results |
|
| 120 |
+- [List what actually happened] |
|
| 121 |
+ |
|
| 122 |
+### Issues Found |
|
| 123 |
+- [Any problems, errors, or unexpected behavior] |
|
| 124 |
+- [Include error messages, incorrect file placements, etc.] |
|
| 125 |
+ |
|
| 126 |
+### Protections Verified |
|
| 127 |
+- [ ] Destination exclusion working |
|
| 128 |
+- [ ] Move confirmation functional |
|
| 129 |
+- [ ] No data loss detected |
|
| 130 |
+- [ ] UTC conversion correct (for QuickTime files) |
|
| 131 |
+- [ ] Unimportable files handling (if applicable) |
|
| 132 |
+ |
|
| 133 |
+## Corrective Actions |
|
| 134 |
+### Issues Identified |
|
| 135 |
+- [Detailed description of problems found] |
|
| 136 |
+ |
|
| 137 |
+### Fixes Applied |
|
| 138 |
+- [Code changes made] |
|
| 139 |
+- [Configuration adjustments] |
|
| 140 |
+- [Process improvements] |
|
| 141 |
+ |
|
| 142 |
+### Re-test Results |
|
| 143 |
+- [Results after applying fixes] |
|
| 144 |
+ |
|
| 145 |
+## Conclusion |
|
| 146 |
+### Test Result |
|
| 147 |
+- [ ] PASSED |
|
| 148 |
+- [ ] FAILED |
|
| 149 |
+- [ ] PARTIAL (with notes) |
|
| 150 |
+ |
|
| 151 |
+### Notes |
|
| 152 |
+[Any additional observations, recommendations, or follow-up actions needed] |
|
| 153 |
+ |
|
| 154 |
+### Files Generated |
|
| 155 |
+- `test/source_before.txt` - Pre-test source structure |
|
| 156 |
+- `test/dest_before.txt` - Pre-test destination structure |
|
| 157 |
+- `test/source_after.txt` - Post-test source structure |
|
| 158 |
+- `test/dest_after.txt` - Post-test destination structure |
|
| 159 |
+- `test/import_log.txt` - Full script execution log |
|
| 160 |
+- `test/test_report.md` - This report |
|
| 161 |
+``` |
|
| 162 |
+ |
|
| 163 |
+#### Automated Test Runner |
|
| 164 |
+A comprehensive test runner script (`test_runner.sh`) is available to automate the testing process: |
|
| 165 |
+ |
|
| 166 |
+```bash |
|
| 167 |
+./test_runner.sh |
|
| 168 |
+``` |
|
| 169 |
+ |
|
| 170 |
+The script provides: |
|
| 171 |
+- **Pre-configured test scenarios** for common use cases |
|
| 172 |
+- **Automatic report generation** in Markdown format |
|
| 173 |
+- **State capture** before and after test execution |
|
| 174 |
+- **Protection verification** with checkboxes |
|
| 175 |
+- **Custom test support** for specific scenarios |
|
| 176 |
+ |
|
| 177 |
+#### Test Categories |
|
| 178 |
+The test runner provides the following pre-configured test scenarios: |
|
| 179 |
+ |
|
| 180 |
+1. **Basic Functionality Test**: Tests processing of files with valid EXIF data to verify correct sorting and organization |
|
| 181 |
+2. **Unimportable Files Test**: Tests handling of files without EXIF data in both root and subfolders, without --collect-unimportable flag |
|
| 182 |
+3. **Mixed Content Test**: Tests processing of sortable and unimportable files in separate folders to verify cleanup behavior |
|
| 183 |
+4. **Safety Protections Test**: Tests destination exclusion and move confirmation mechanisms to prevent data loss |
|
| 184 |
+5. **UTC Conversion Test**: Tests UTC timestamp conversion for QuickTime/Apple EXIF data |
|
| 185 |
+6. **Subdirectory Processing Test**: Tests processing of files in nested subdirectories to ensure recursive file discovery |
|
| 186 |
+7. **Custom Test**: Allows user-defined test scenarios with custom file sets and commands |
|
| 187 |
+ |
|
| 188 |
+#### Test Result Persistence |
|
| 189 |
+The test runner includes automatic result persistence: |
|
| 190 |
+ |
|
| 191 |
+- **Archival Location**: Test results are saved as individual Markdown files in `test_reports/` directory |
|
| 192 |
+- **Naming Convention**: `{TestName}_{YYYYMMDD_HHMMSS}.md` format for easy identification
|
|
| 193 |
+- **Contents Preserved**: Single self-contained Markdown file with: |
|
| 194 |
+ - Complete test information and directory structures |
|
| 195 |
+ - Full script execution output embedded inline (ANSI codes stripped for readability) |
|
| 196 |
+ - Import log content included directly in the report |
|
| 197 |
+- **Excluded Files**: No separate files - everything is consolidated in the Markdown report |
|
| 198 |
+- **Historical Tracking**: Maintains complete test history for debugging and regression testing |
|
| 199 |
+ |
|
| 200 |
+#### Cleanup |
|
| 201 |
+- Review the test report and verify all aspects are documented |
|
| 202 |
+- Clean up the `test` directory after each test run to ensure a fresh environment for subsequent tests |
|
| 203 |
+- Archive important test reports in a `test_reports/` directory for future reference |
|
| 204 |
+ |
|
| 205 |
+## 3. Changelog |
|
| 206 |
+ |
|
| 207 |
+### 2025-09-07 21:15 - Test 2 and 3 Enhancements |
|
| 208 |
+- Updated Test 2 (Unimportable Files Test) to include files in both root and subfolder |
|
| 209 |
+- Removed --collect-unimportable flag from Test 2 to test default behavior |
|
| 210 |
+- Updated Test 3 (Mixed Content Test) to use separate folders for sortable vs unimportable files |
|
| 211 |
+- Test 3 now verifies that folders with only sortable files are cleaned up while folders with unimportable files are preserved |
|
| 212 |
+- Updated menu descriptions to reflect the changes |
|
| 213 |
+- Tests now verify proper handling of unimportable files without collection flag |
|
| 214 |
+ |
|
| 215 |
+--- |
|
| 216 |
+ |
|
| 217 |
+### 2025-09-07 21:25 - Documentation Enhancement |
|
| 218 |
+- Added comprehensive documentation for --collect-unimportable flag in README.md |
|
| 219 |
+- Added Example 4 showing how to use --collect-unimportable flag |
|
| 220 |
+- Updated Features section to mention unimportable files handling |
|
| 221 |
+- Updated Configuration section to explain default behavior for unimportable files |
|
| 222 |
+- Added usage example for --collect-unimportable in Basic Usage section |
|
| 223 |
+ |
|
| 224 |
+--- |
|
| 225 |
+ |
|
| 226 |
+### 2025-09-07 21:30 - Git Ignore Enhancement |
|
| 227 |
+- Added test_reports/ to .gitignore to exclude generated test reports from version control |
|
| 228 |
+- Test reports are generated files that don't need to be tracked in Git |
|
| 229 |
+- Prevents large numbers of timestamped report files from cluttering the repository |
|
| 230 |
+- Added sample/ to .gitignore to exclude test media files from version control |
|
| 231 |
+ |
|
| 232 |
+--- |
|
| 233 |
+ |
|
| 234 |
+### 2025-09-07 20:40 - Source Only Test Addition |
|
| 235 |
+- Added Test 8: Source Only Test to test runner |
|
| 236 |
+- Tests processing with only source parameter (creates sorted subdirectory automatically) |
|
| 237 |
+- Verifies that when no destination is specified, files are sorted into source/sorted/ |
|
| 238 |
+- Updated menu and command line options for new test |
|
| 239 |
+ |
|
| 240 |
+--- |
|
| 241 |
+ |
|
| 242 |
+### 2025-09-07 20:45 - Test 7 Refinement |
|
| 243 |
+- Updated Test 7 to test --keep-empty-dirs functionality instead of cleanup |
|
| 244 |
+- Since cleanup is now default behavior, Test 7 now verifies empty directory preservation |
|
| 245 |
+- Renamed from "Cleanup Empty Directories Test" to "Keep Empty Directories Test" |
|
| 246 |
+- Updated test scenario to validate --keep-empty-dirs flag behavior |
|
| 247 |
+- Added command line option "keep-empty-dirs" for test 7 |
|
| 248 |
+ |
|
| 249 |
+--- |
|
| 250 |
+ |
|
| 251 |
+### 2025-09-07 19:30 - Test Runner Directory Separation |
|
| 252 |
+- Adapted test runner to use separate source and destination directories |
|
| 253 |
+- Changed from test/ as source to test/source/ and test/destination/ |
|
| 254 |
+- Updated all test functions to use proper directory separation |
|
| 255 |
+- Improved test isolation and clarity |
|
| 256 |
+ |
|
| 257 |
+--- |
|
| 258 |
+ |
|
| 259 |
+### 2025-09-07 19:00 - Default Cleanup Behavior |
|
| 260 |
+- Made --cleanup-empty-dirs the default behavior (implicit option) |
|
| 261 |
+- Added --keep-empty-dirs flag to disable cleanup if needed |
|
| 262 |
+- Updated help text and configuration display to reflect new default |
|
| 263 |
+- Cleanup now runs automatically unless explicitly disabled |
|
| 264 |
+ |
|
| 265 |
+--- |
|
| 266 |
+ |
|
| 267 |
+### 2025-09-07 18:56 - Cleanup Empty Directories Feature |
|
| 268 |
+- Added --cleanup-empty-dirs option to remove empty directories from source after processing |
|
| 269 |
+- Added cleanup_empty_directories() function with safe empty directory detection |
|
| 270 |
+- Updated final report to show cleanup status |
|
| 271 |
+- Maintains safety by not removing source root directories |
|
| 272 |
+- Works correctly with dry-run mode |
|
| 273 |
+ |
|
| 274 |
+## 4. Todo |
|
| 275 |
+ |
|
| 276 |
+Key areas for future development: |
|
| 277 |
+- GPS metadata integration for timezone detection |
|
| 278 |
+- Enhanced duplicate detection |
|
| 279 |
+- Performance optimizations for large file sets |
|
| 280 |
+- Additional organization patterns |
|
@@ -1,140 +0,0 @@ |
||
| 1 |
-# Media Importer Test Plan |
|
| 2 |
- |
|
| 3 |
-## Purpose |
|
| 4 |
-This test plan ensures the reliability and correctness of `media-importer.sh` by covering key scenarios and edge cases. |
|
| 5 |
- |
|
| 6 |
-## Test Areas |
|
| 7 |
-1. **Basic Functionality** |
|
| 8 |
- - Organize media files by date using all supported organization patterns (`y`, `m`, `d`, `h`). |
|
| 9 |
- - Move and copy modes (with and without `--keep-originals`). |
|
| 10 |
- - Dry run mode (`--dry-run`). |
|
| 11 |
- |
|
| 12 |
-2. **Source and Destination Handling** |
|
| 13 |
- - Single and multiple source patterns (folders, globs, files). |
|
| 14 |
- - Destination folder creation and error handling. |
|
| 15 |
- - Exclusion of destination from source search. |
|
| 16 |
- - Symlinked source directories. |
|
| 17 |
- |
|
| 18 |
-3. **Error Handling** |
|
| 19 |
- - Missing or invalid organization pattern. |
|
| 20 |
- - Missing required dependencies (e.g., exiftool). |
|
| 21 |
- - Unwritable destination directory. |
|
| 22 |
- - Files with no EXIF/media date metadata (should be skipped or collected as unsortable). |
|
| 23 |
- - Fatal errors (e.g., cannot generate destination path). |
|
| 24 |
- - Recoverable errors (e.g., failed copy/move). |
|
| 25 |
- |
|
| 26 |
-4. **Performance and Edge Cases** |
|
| 27 |
- - Large number of files (10k+). |
|
| 28 |
- - Files with conflicting names (should be renamed). |
|
| 29 |
- - Mixed media types and extensions. |
|
| 30 |
- - Files with unusual or missing extensions. |
|
| 31 |
- |
|
| 32 |
-5. **Reporting** |
|
| 33 |
- - Correct summary of processed, skipped, and error files. |
|
| 34 |
- - Accurate size and speed reporting. |
|
| 35 |
- - Verbose and non-verbose output modes. |
|
| 36 |
- |
|
| 37 |
- |
|
| 38 |
- |
|
| 39 |
-## Sample Data Note |
|
| 40 |
-The `samples/media` directory contains files both with and without EXIF date metadata. Any test that does not correctly detect and handle files lacking EXIF dates (i.e., skips or collects them as unsortable) is considered failed. |
|
| 41 |
- |
|
| 42 |
-## Test Directory Usage |
|
| 43 |
-To facilitate testing, the `tests` directory will be used as the working directory for all test scenarios. Before each test, relevant files will be copied from `samples/media` into `tests`. After inspecting the results, the `tests` directory will be cleaned to ensure a fresh state for the next test. |
|
| 44 |
- |
|
| 45 |
-## Specific Test Cases |
|
| 46 |
- |
|
| 47 |
-### TC01: Basic Organization Patterns |
|
| 48 |
-- **Objective**: Test all organization patterns (y, m, d, h) |
|
| 49 |
-- **Setup**: Copy sample files from `samples/media` to `tests/media` |
|
| 50 |
-- **Commands**: |
|
| 51 |
- - `./media-importer.sh -s ./tests/media -d ./tests/sorted_y -o y` |
|
| 52 |
- - `./media-importer.sh -s ./tests/media -d ./tests/sorted_m -o m` |
|
| 53 |
- - `./media-importer.sh -s ./tests/media -d ./tests/sorted_d -o d` |
|
| 54 |
- - `./media-importer.sh -s ./tests/media -d ./tests/sorted_h -o h` |
|
| 55 |
-- **Expected**: Files organized according to each pattern |
|
| 56 |
-- **Cleanup**: `rm -rf ./tests/*` |
|
| 57 |
- |
|
| 58 |
-### TC02: Copy vs Move Mode |
|
| 59 |
-- **Objective**: Test --keep-originals flag |
|
| 60 |
-- **Setup**: Copy sample files to `tests/media` |
|
| 61 |
-- **Commands**: |
|
| 62 |
- - `./media-importer.sh -s ./tests/media -d ./tests/copied -k` |
|
| 63 |
- - `./media-importer.sh -s ./tests/media -d ./tests/moved` |
|
| 64 |
-- **Expected**: First command copies files, second moves them |
|
| 65 |
-- **Cleanup**: `rm -rf ./tests/*` |
|
| 66 |
- |
|
| 67 |
-### TC03: Dry Run Mode |
|
| 68 |
-- **Objective**: Test --dry-run functionality |
|
| 69 |
-- **Setup**: Copy sample files to `tests/media` |
|
| 70 |
-- **Command**: `./media-importer.sh -s ./tests/media -d ./tests/dry --dry-run` |
|
| 71 |
-- **Expected**: Shows what would be done without moving files |
|
| 72 |
-- **Cleanup**: `rm -rf ./tests/*` |
|
| 73 |
- |
|
| 74 |
-### TC04: Symlinked Source |
|
| 75 |
-- **Objective**: Test symlinked source directory |
|
| 76 |
-- **Setup**: |
|
| 77 |
- - `mkdir -p tests/media` |
|
| 78 |
- - `ln -sf ../samples/media tests/linked_media` |
|
| 79 |
-- **Command**: `./media-importer.sh -s ./tests/linked_media -d ./tests/from_symlink` |
|
| 80 |
-- **Expected**: Files from symlinked directory are processed |
|
| 81 |
-- **Cleanup**: `rm -rf ./tests/*` |
|
| 82 |
- |
|
| 83 |
-### TC05: Error Handling - Invalid Pattern |
|
| 84 |
-- **Objective**: Test invalid organization pattern |
|
| 85 |
-- **Command**: `./media-importer.sh -o z` |
|
| 86 |
-- **Expected**: Error message and exit code 1 |
|
| 87 |
-- **Cleanup**: None needed |
|
| 88 |
- |
|
| 89 |
-### TC06: Same Source and Destination (Fatal Error) |
|
| 90 |
-- **Objective**: Test fatal error handling |
|
| 91 |
-- **Setup**: Copy sample files to `tests/media` |
|
| 92 |
-- **Command**: `./media-importer.sh -s ./tests -d ./tests` |
|
| 93 |
-- **Expected**: Fatal error stops processing immediately |
|
| 94 |
-- **Cleanup**: `rm -rf ./tests/*` |
|
| 95 |
- |
|
| 96 |
-## New Feature: --full-date Argument & Default Flat Naming |
|
| 97 |
- |
|
| 98 |
-### TC07: --full-date Argument (EXIF Date Required) |
|
| 99 |
-- **Objective**: Verify that only files with EXIF/media dates are processed and named with full date format. |
|
| 100 |
-- **Setup**: Copy sample files to `tests/media` |
|
| 101 |
-- **Command**: `./media-importer.sh --full-date -s ./tests/media -d ./tests/flat` |
|
| 102 |
-- **Expected**: Only files with EXIF dates in `tests/flat` named as `yyyy-mm-dd_hh-mm-ss.ext` (no subfolders). Files without EXIF dates remain in source. |
|
| 103 |
-- **Cleanup**: `rm -rf ./tests/*` |
|
| 104 |
- |
|
| 105 |
-### TC08: No Organization Directive (EXIF Date Required) |
|
| 106 |
-- **Objective**: Verify that omitting the organization directive results in flat full-date naming for files with EXIF dates only. |
|
| 107 |
-- **Setup**: Copy sample files to `tests/media` |
|
| 108 |
-- **Command**: `./media-importer.sh -s ./tests/media -d ./tests/flat_default` |
|
| 109 |
-- **Expected**: Only files with EXIF dates in `tests/flat_default` named as `yyyy-mm-dd_hh-mm-ss.ext` (no subfolders). Files without EXIF dates remain in source. |
|
| 110 |
-- **Cleanup**: `rm -rf ./tests/*` |
|
| 111 |
- |
|
| 112 |
-### TC09: Organization Directive with --full-date (EXIF Date Required) |
|
| 113 |
-- **Objective**: Verify that --full-date overrides any organization directive and processes only files with EXIF dates. |
|
| 114 |
-- **Setup**: Copy sample files to `tests/media` |
|
| 115 |
-- **Command**: `./media-importer.sh --full-date -o y -s ./tests/media -d ./tests/flat_override` |
|
| 116 |
-- **Expected**: Only files with EXIF dates in `tests/flat_override` named as `yyyy-mm-dd_hh-mm-ss.ext` (no subfolders). Files without EXIF dates remain in source. |
|
| 117 |
-- **Cleanup**: `rm -rf ./tests/*` |
|
| 118 |
- |
|
| 119 |
-### TC10: --collect-unsortable Flag |
|
| 120 |
-- **Objective**: Verify that files without EXIF dates are moved to unsortable folder when flag is used. |
|
| 121 |
-- **Setup**: Copy sample files to `tests/media` |
|
| 122 |
-- **Command**: `./media-importer.sh --full-date --collect-unsortable -s ./tests/media -d ./tests/flat` |
|
| 123 |
-- **Expected**: Files with EXIF dates in `tests/flat` named as `yyyy-mm-dd_hh-mm-ss.ext`. Files without EXIF dates in `tests/flat/unsortable/`. |
|
| 124 |
-- **Cleanup**: `rm -rf ./tests/*` |
|
| 125 |
- |
|
| 126 |
-### TC11: Basic Organization with EXIF Requirement |
|
| 127 |
-- **Objective**: Test that organization patterns only process files with EXIF dates. |
|
| 128 |
-- **Setup**: Copy sample files to `tests/media` |
|
| 129 |
-- **Command**: `./media-importer.sh -o y -s ./tests/media -d ./tests/sorted_y` |
|
| 130 |
-- **Expected**: Only files with EXIF dates organized by year. Files without EXIF dates remain in source. |
|
| 131 |
-- **Cleanup**: `rm -rf ./tests/*` |
|
| 132 |
- |
|
| 133 |
-## Test Execution Framework |
|
| 134 |
-- Before each test: Prepare test data from `samples/media` |
|
| 135 |
-- Run test command and capture output |
|
| 136 |
-- Verify expected behavior and results |
|
| 137 |
-- After each test: Clean `tests` directory with `rm -rf ./tests/*` |
|
| 138 |
- |
|
| 139 |
-This plan should be updated as new features or bug fixes are added. |
|
@@ -1,16 +0,0 @@ |
||
| 1 |
-# TODO |
|
| 2 |
- |
|
| 3 |
-## Tasks |
|
| 4 |
- |
|
| 5 |
-1. **QuickTime Local Time from GPS Metadata** |
|
| 6 |
- - When processing QuickTime files, use GPS metadata (if available) to determine the local time zone and convert the UTC timestamp to local time accordingly. |
|
| 7 |
- - Fallback to system timezone if GPS data is not present. |
|
| 8 |
- |
|
| 9 |
-2. **Implicit Behavior Selection** |
|
| 10 |
- - Define and document the script's default behavior when no explicit directives/arguments are provided. |
|
| 11 |
- - Allow users to override defaults via command-line arguments. |
|
| 12 |
- - Ensure stability and predictability in all cases. |
|
| 13 |
- |
|
| 14 |
- |
|
| 15 |
-(Feel free to expand with subtasks or implementation notes.) |
|
@@ -18,6 +18,7 @@ DESTINATION="" |
||
| 18 | 18 |
KEEP_ORIGINALS=0 |
| 19 | 19 |
DRY_RUN=0 |
| 20 | 20 |
VERBOSE=0 |
| 21 |
+CLEANUP_EMPTY_DIRS=1 |
|
| 21 | 22 |
|
| 22 | 23 |
# Counters and statistics |
| 23 | 24 |
TOTAL_FILES=0 |
@@ -94,9 +95,10 @@ Options: |
||
| 94 | 95 |
-F, --filename-mode MODE auto|full|orig (default: full) |
| 95 | 96 |
-s, --source PATH File or directory to process (repeatable). Default: cwd |
| 96 | 97 |
-d, --destination PATH Destination folder. Required when multiple -s are given. |
| 97 |
- -k, --keep-originals Copy files instead of moving |
|
| 98 |
+ -k, --keep-originals Copy files instead of moving |
|
| 98 | 99 |
--collect-unsortable Put files without dates into DEST/unsortable |
| 99 |
- --dry-run Show actions without changing files |
|
| 100 |
+ --keep-empty-dirs Keep empty directories after processing |
|
| 101 |
+ --dry-run Show actions without changing files |
|
| 100 | 102 |
-v, --verbose Verbose output |
| 101 | 103 |
-h, --help Show this help |
| 102 | 104 |
--version Show version |
@@ -420,7 +422,7 @@ generate_destination_path() {
|
||
| 420 | 422 |
dir_path="$base_destination/${year}-${month}"
|
| 421 | 423 |
filename="${day}_${hour}-${minute}-${second}.${lowercase_ext}"
|
| 422 | 424 |
;; |
| 423 |
- "ymd"|"ymd-") |
|
| 425 |
+ "ymd") |
|
| 424 | 426 |
# Single folder per day named yyyy-mm-dd; filename is time |
| 425 | 427 |
dir_path="$base_destination/${year}-${month}-${day}"
|
| 426 | 428 |
filename="${hour}-${minute}-${second}.${lowercase_ext}"
|
@@ -666,8 +668,8 @@ while [[ $# -gt 0 ]]; do |
||
| 666 | 668 |
case $1 in |
| 667 | 669 |
-o|--organization) |
| 668 | 670 |
ORGANIZATION="$2" |
| 669 |
- # Accept new patterns: ym, ymd and ymd- as well as single-letter ones |
|
| 670 |
- if [[ ! "$ORGANIZATION" =~ ^(y|m|d|h|ym|ymd|ymd-)$ ]]; then |
|
| 671 |
+ # Accept new patterns: ym, ymd as well as single-letter ones |
|
| 672 |
+ if [[ ! "$ORGANIZATION" =~ ^(y|m|d|h|ym|ymd)$ ]]; then |
|
| 671 | 673 |
print_color "$RED" "Error: Invalid organization pattern. Must be one of: y, m, d, h, ym, ymd" |
| 672 | 674 |
exit 1 |
| 673 | 675 |
fi |
@@ -687,6 +689,10 @@ while [[ $# -gt 0 ]]; do |
||
| 687 | 689 |
COLLECT_UNSORTABLE=1 |
| 688 | 690 |
shift |
| 689 | 691 |
;; |
| 692 |
+ --keep-empty-dirs) |
|
| 693 |
+ CLEANUP_EMPTY_DIRS=0 |
|
| 694 |
+ shift |
|
| 695 |
+ ;; |
|
| 690 | 696 |
-s|--source) |
| 691 | 697 |
SOURCE_PATTERNS+=("$2")
|
| 692 | 698 |
shift 2 |
@@ -782,6 +788,7 @@ echo " Organization pattern: $ORGANIZATION" |
||
| 782 | 788 |
echo " Destination: $DESTINATION" |
| 783 | 789 |
echo " Keep originals: $([ $KEEP_ORIGINALS -eq 1 ] && echo "Yes" || echo "No")" |
| 784 | 790 |
echo " Dry run: $([ $DRY_RUN -eq 1 ] && echo "Yes" || echo "No")" |
| 791 |
+echo " Keep empty dirs: $([ $CLEANUP_EMPTY_DIRS -eq 0 ] && echo "Yes" || echo "No")" |
|
| 785 | 792 |
echo " Verbose: $([ $VERBOSE -eq 1 ] && echo "Yes" || echo "No")" |
| 786 | 793 |
|
| 787 | 794 |
if [[ ${#SOURCE_PATTERNS[@]} -gt 0 ]]; then
|
@@ -836,6 +843,14 @@ for file in "${files[@]}"; do
|
||
| 836 | 843 |
fi |
| 837 | 844 |
done |
| 838 | 845 |
|
| 846 |
+# Clean up empty directories if requested (default behavior) |
|
| 847 |
+if [[ $CLEANUP_EMPTY_DIRS -eq 1 && $DRY_RUN -eq 0 ]]; then |
|
| 848 |
+ print_color "$BLUE" "Cleaning up empty directories..." |
|
| 849 |
+ # Find and remove empty directories under destination, but don't remove the destination itself |
|
| 850 |
+ find "$DESTINATION" -type d -empty -not -path "$DESTINATION" -delete 2>/dev/null || true |
|
| 851 |
+ print_color "$GREEN" "Empty directory cleanup completed" |
|
| 852 |
+fi |
|
| 853 |
+ |
|
| 839 | 854 |
# Show final report |
| 840 | 855 |
show_report |
| 841 | 856 |
|
@@ -0,0 +1,648 @@ |
||
| 1 |
+#!/bin/bash |
|
| 2 |
+ |
|
| 3 |
+# Media Importer Test Runner |
|
| 4 |
+# Comprehensive testing framework based on Development.md specifications |
|
| 5 |
+ |
|
| 6 |
+set -e |
|
| 7 |
+ |
|
| 8 |
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
| 9 |
+TEST_DIR="$SCRIPT_DIR/test" |
|
| 10 |
+SOURCE_DIR="$TEST_DIR/source" |
|
| 11 |
+DEST_DIR="$TEST_DIR/destination" |
|
| 12 |
+SAMPLES_DIR="$SCRIPT_DIR/sample" # Fixed: was 'samples' but should be 'sample' |
|
| 13 |
+MEDIA_IMPORTER="$SCRIPT_DIR/media-importer.sh" |
|
| 14 |
+TEST_REPORTS_DIR="$SCRIPT_DIR/test_reports" |
|
| 15 |
+ |
|
| 16 |
+# Colors for output |
|
| 17 |
+RED='\033[0;31m' |
|
| 18 |
+GREEN='\033[0;32m' |
|
| 19 |
+YELLOW='\033[1;33m' |
|
| 20 |
+BLUE='\033[0;34m' |
|
| 21 |
+NC='\033[0m' # No Color |
|
| 22 |
+ |
|
| 23 |
+# Function to print colored output |
|
| 24 |
+print_color() {
|
|
| 25 |
+ local color="$1" |
|
| 26 |
+ local message="$2" |
|
| 27 |
+ echo -e "${color}${message}${NC}"
|
|
| 28 |
+} |
|
| 29 |
+ |
|
| 30 |
+# Function to create test directories |
|
| 31 |
+create_test_dirs() {
|
|
| 32 |
+ print_color "$BLUE" "Creating test directories..." |
|
| 33 |
+ mkdir -p "$SOURCE_DIR" |
|
| 34 |
+ mkdir -p "$DEST_DIR" |
|
| 35 |
+ mkdir -p "$TEST_REPORTS_DIR" |
|
| 36 |
+} |
|
| 37 |
+ |
|
| 38 |
+# Function to clean test directory |
|
| 39 |
+clean_test_dir() {
|
|
| 40 |
+ print_color "$BLUE" "Cleaning test directory..." |
|
| 41 |
+ rm -rf "$TEST_DIR"/* |
|
| 42 |
+} |
|
| 43 |
+ |
|
| 44 |
+# Function to copy sample files |
|
| 45 |
+copy_sample_files() {
|
|
| 46 |
+ local source_pattern="$1" |
|
| 47 |
+ local target_dir="$2" |
|
| 48 |
+ |
|
| 49 |
+ if [[ -d "$SAMPLES_DIR/$source_pattern" ]]; then |
|
| 50 |
+ # Copy all files recursively from source to target directory |
|
| 51 |
+ find "$SAMPLES_DIR/$source_pattern" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.tiff" -o -iname "*.tif" -o -iname "*.cr2" -o -iname "*.nef" -o -iname "*.arw" -o -iname "*.dng" -o -iname "*.raw" -o -iname "*.mp4" -o -iname "*.mov" -o -iname "*.avi" -o -iname "*.mts" -o -iname "*.m2ts" -o -iname "*.mkv" -o -iname "*.wmv" -o -iname "*.3gp" -o -iname "*.m4v" \) -exec cp {} "$target_dir/" \; 2>/dev/null || true
|
|
| 52 |
+ print_color "$GREEN" "Copied $source_pattern files to $target_dir" |
|
| 53 |
+ else |
|
| 54 |
+ print_color "$YELLOW" "Warning: $SAMPLES_DIR/$source_pattern not found. Path: $SAMPLES_DIR/$source_pattern" |
|
| 55 |
+ fi |
|
| 56 |
+} |
|
| 57 |
+ |
|
| 58 |
+# Function to capture directory state |
|
| 59 |
+capture_state() {
|
|
| 60 |
+ local dir_path="$1" |
|
| 61 |
+ local output_file="$2" |
|
| 62 |
+ local label="$3" |
|
| 63 |
+ |
|
| 64 |
+ print_color "$BLUE" "Capturing $label directory state..." |
|
| 65 |
+ if [[ -d "$dir_path" ]]; then |
|
| 66 |
+ find "$dir_path" -type f | sort > "$output_file" |
|
| 67 |
+ else |
|
| 68 |
+ echo "# Directory does not exist or is empty" > "$output_file" |
|
| 69 |
+ fi |
|
| 70 |
+} |
|
| 71 |
+ |
|
| 72 |
+# Function to run test command and capture output |
|
| 73 |
+run_test_command() {
|
|
| 74 |
+ local command="$1" |
|
| 75 |
+ local log_file="$2" |
|
| 76 |
+ |
|
| 77 |
+ print_color "$YELLOW" "Executing: $command" |
|
| 78 |
+ echo "$command" > "$log_file" |
|
| 79 |
+ echo "" >> "$log_file" |
|
| 80 |
+ echo "=== SCRIPT OUTPUT ===" >> "$log_file" |
|
| 81 |
+ |
|
| 82 |
+ # Run command and capture both stdout and stderr |
|
| 83 |
+ if eval "$command" >> "$log_file" 2>&1; then |
|
| 84 |
+ echo "" >> "$log_file" |
|
| 85 |
+ echo "=== COMMAND COMPLETED SUCCESSFULLY ===" >> "$log_file" |
|
| 86 |
+ return 0 |
|
| 87 |
+ else |
|
| 88 |
+ echo "" >> "$log_file" |
|
| 89 |
+ echo "=== COMMAND FAILED ===" >> "$log_file" |
|
| 90 |
+ return 1 |
|
| 91 |
+ fi |
|
| 92 |
+} |
|
| 93 |
+ |
|
| 94 |
+# Function to generate test report |
|
| 95 |
+generate_test_report() {
|
|
| 96 |
+ local test_name="$1" |
|
| 97 |
+ local scenario="$2" |
|
| 98 |
+ local objective="$3" |
|
| 99 |
+ local files_used="$4" |
|
| 100 |
+ local command="$5" |
|
| 101 |
+ local result_status="$6" |
|
| 102 |
+ |
|
| 103 |
+ # Determine success/failure prefix |
|
| 104 |
+ local status_prefix |
|
| 105 |
+ if [[ $result_status -eq 0 ]]; then |
|
| 106 |
+ status_prefix="s" |
|
| 107 |
+ else |
|
| 108 |
+ status_prefix="f" |
|
| 109 |
+ fi |
|
| 110 |
+ |
|
| 111 |
+ # Format date as YYYYMMDD |
|
| 112 |
+ local date_stamp=$(date '+%Y%m%d') |
|
| 113 |
+ |
|
| 114 |
+ # Create filename with new format: [s|f]_date_restul_numelei |
|
| 115 |
+ local report_file="$TEST_REPORTS_DIR/${status_prefix}_${date_stamp}_${test_name}.md"
|
|
| 116 |
+ |
|
| 117 |
+ print_color "$BLUE" "Generating test report: $report_file" |
|
| 118 |
+ |
|
| 119 |
+ cat > "$report_file" << EOF |
|
| 120 |
+# Test Report: $test_name |
|
| 121 |
+ |
|
| 122 |
+## Test Information |
|
| 123 |
+- **Date**: $(date) |
|
| 124 |
+- **Scenario**: $scenario |
|
| 125 |
+- **Objective**: $objective |
|
| 126 |
+- **Files Used**: $files_used |
|
| 127 |
+ |
|
| 128 |
+## Pre-Test State |
|
| 129 |
+### Source Directory Structure |
|
| 130 |
+\`\`\` |
|
| 131 |
+$(cat "$TEST_DIR/source_before.txt" 2>/dev/null || echo "# No pre-test source state captured") |
|
| 132 |
+\`\`\` |
|
| 133 |
+ |
|
| 134 |
+### Destination Directory Structure |
|
| 135 |
+\`\`\` |
|
| 136 |
+$(cat "$TEST_DIR/dest_before.txt" 2>/dev/null || echo "# No pre-test destination state captured") |
|
| 137 |
+\`\`\` |
|
| 138 |
+ |
|
| 139 |
+## Test Execution |
|
| 140 |
+### Command Used |
|
| 141 |
+\`\`\`bash |
|
| 142 |
+$command |
|
| 143 |
+\`\`\` |
|
| 144 |
+ |
|
| 145 |
+### Script Output |
|
| 146 |
+\`\`\` |
|
| 147 |
+$(cat "$TEST_DIR/import_log.txt" 2>/dev/null || echo "# No script output captured") |
|
| 148 |
+\`\`\` |
|
| 149 |
+ |
|
| 150 |
+## Post-Test State |
|
| 151 |
+### Source Directory Structure |
|
| 152 |
+\`\`\` |
|
| 153 |
+$(cat "$TEST_DIR/source_after.txt" 2>/dev/null || echo "# No post-test source state captured") |
|
| 154 |
+\`\`\` |
|
| 155 |
+ |
|
| 156 |
+### Destination Directory Structure |
|
| 157 |
+\`\`\` |
|
| 158 |
+$(cat "$TEST_DIR/dest_after.txt" 2>/dev/null || echo "# No post-test destination state captured") |
|
| 159 |
+\`\`\` |
|
| 160 |
+ |
|
| 161 |
+## Analysis and Verification |
|
| 162 |
+### Expected Results |
|
| 163 |
+- Files should be processed according to the test scenario |
|
| 164 |
+- No data loss should occur |
|
| 165 |
+- Proper error handling for edge cases |
|
| 166 |
+ |
|
| 167 |
+### Actual Results |
|
| 168 |
+- Test execution completed with status: $result_status |
|
| 169 |
+ |
|
| 170 |
+### Issues Found |
|
| 171 |
+- [ ] No issues detected |
|
| 172 |
+- [ ] Issues found (see notes below) |
|
| 173 |
+ |
|
| 174 |
+### Protections Verified |
|
| 175 |
+- [ ] Destination exclusion working |
|
| 176 |
+- [ ] Move confirmation functional |
|
| 177 |
+- [ ] No data loss detected |
|
| 178 |
+- [ ] UTC conversion correct (for QuickTime files) |
|
| 179 |
+- [ ] Unimportable files handling (if applicable) |
|
| 180 |
+ |
|
| 181 |
+## Conclusion |
|
| 182 |
+### Test Result |
|
| 183 |
+- [ ] PASSED |
|
| 184 |
+- [ ] FAILED |
|
| 185 |
+- [ ] PARTIAL (with notes) |
|
| 186 |
+ |
|
| 187 |
+### Notes |
|
| 188 |
+Test completed as per Development.md specifications. |
|
| 189 |
+ |
|
| 190 |
+### Files Generated |
|
| 191 |
+- \`test/source_before.txt\` - Pre-test source structure |
|
| 192 |
+- \`test/dest_before.txt\` - Pre-test destination structure |
|
| 193 |
+- \`test/source_after.txt\` - Post-test source structure |
|
| 194 |
+- \`test/dest_after.txt\` - Post-test destination structure |
|
| 195 |
+- \`test/import_log.txt\` - Full script execution log |
|
| 196 |
+- \`test/test_report.md\` - This report |
|
| 197 |
+EOF |
|
| 198 |
+ |
|
| 199 |
+ print_color "$GREEN" "Test report generated: $report_file" |
|
| 200 |
+ |
|
| 201 |
+ # Clean up old reports, keeping only the last 10 |
|
| 202 |
+ cleanup_old_reports |
|
| 203 |
+} |
|
| 204 |
+ |
|
| 205 |
+# Function to clean up old test reports, keeping only the last 10 |
|
| 206 |
+cleanup_old_reports() {
|
|
| 207 |
+ if [[ -d "$TEST_REPORTS_DIR" ]]; then |
|
| 208 |
+ # Count total reports |
|
| 209 |
+ local total_reports=$(find "$TEST_REPORTS_DIR" -name "*.md" | wc -l) |
|
| 210 |
+ |
|
| 211 |
+ if [[ $total_reports -gt 10 ]]; then |
|
| 212 |
+ print_color "$BLUE" "Cleaning up old test reports (keeping last 10)..." |
|
| 213 |
+ |
|
| 214 |
+ # Find and remove oldest reports, keeping the 10 most recent |
|
| 215 |
+ find "$TEST_REPORTS_DIR" -name "*.md" -type f -printf '%T@ %p\n' | \ |
|
| 216 |
+ sort -n | \ |
|
| 217 |
+ head -n -$((10)) | \ |
|
| 218 |
+ cut -d' ' -f2- | \ |
|
| 219 |
+ xargs -r rm |
|
| 220 |
+ |
|
| 221 |
+ local remaining=$(find "$TEST_REPORTS_DIR" -name "*.md" | wc -l) |
|
| 222 |
+ print_color "$GREEN" "Kept $remaining most recent test reports" |
|
| 223 |
+ fi |
|
| 224 |
+ fi |
|
| 225 |
+} |
|
| 226 |
+ |
|
| 227 |
+# Test Case 0: Basic Functionality Test |
|
| 228 |
+run_basic_functionality_test() {
|
|
| 229 |
+ print_color "$GREEN" "=== Running Test 0: Basic Functionality Test ===" |
|
| 230 |
+ |
|
| 231 |
+ clean_test_dir |
|
| 232 |
+ create_test_dirs |
|
| 233 |
+ |
|
| 234 |
+ # Setup test files |
|
| 235 |
+ copy_sample_files "media/sortable" "$SOURCE_DIR" |
|
| 236 |
+ |
|
| 237 |
+ # Capture pre-test state |
|
| 238 |
+ capture_state "$SOURCE_DIR" "$TEST_DIR/source_before.txt" "source" |
|
| 239 |
+ capture_state "$DEST_DIR" "$TEST_DIR/dest_before.txt" "destination" |
|
| 240 |
+ |
|
| 241 |
+ # Run test |
|
| 242 |
+ local command="\"$MEDIA_IMPORTER\" -s \"$SOURCE_DIR\" -d \"$DEST_DIR\" -v" |
|
| 243 |
+ local result=0 |
|
| 244 |
+ run_test_command "$command" "$TEST_DIR/import_log.txt" || result=$? |
|
| 245 |
+ |
|
| 246 |
+ # Capture post-test state |
|
| 247 |
+ capture_state "$SOURCE_DIR" "$TEST_DIR/source_after.txt" "source" |
|
| 248 |
+ capture_state "$DEST_DIR" "$TEST_DIR/dest_after.txt" "destination" |
|
| 249 |
+ |
|
| 250 |
+ # Generate report |
|
| 251 |
+ generate_test_report \ |
|
| 252 |
+ "Basic_Functionality" \ |
|
| 253 |
+ "Processing files with valid EXIF data" \ |
|
| 254 |
+ "Verify correct sorting and organization of media files" \ |
|
| 255 |
+ "Sample media files with EXIF data from samples/media/sortable/" \ |
|
| 256 |
+ "$command" \ |
|
| 257 |
+ "$result" |
|
| 258 |
+} |
|
| 259 |
+ |
|
| 260 |
+# Test Case 1: Unimportable Files Test |
|
| 261 |
+run_unimportable_files_test() {
|
|
| 262 |
+ print_color "$GREEN" "=== Running Test 1: Unimportable Files Test ===" |
|
| 263 |
+ |
|
| 264 |
+ clean_test_dir |
|
| 265 |
+ create_test_dirs |
|
| 266 |
+ |
|
| 267 |
+ # Setup test files - mix of sortable and unimportable |
|
| 268 |
+ copy_sample_files "media/sortable" "$SOURCE_DIR" |
|
| 269 |
+ copy_sample_files "media/unimportable" "$SOURCE_DIR" |
|
| 270 |
+ |
|
| 271 |
+ # Capture pre-test state |
|
| 272 |
+ capture_state "$SOURCE_DIR" "$TEST_DIR/source_before.txt" "source" |
|
| 273 |
+ capture_state "$DEST_DIR" "$TEST_DIR/dest_before.txt" "destination" |
|
| 274 |
+ |
|
| 275 |
+ # Run test (without --collect-unimportable flag) |
|
| 276 |
+ local command="\"$MEDIA_IMPORTER\" -s \"$SOURCE_DIR\" -d \"$DEST_DIR\" -v" |
|
| 277 |
+ local result=0 |
|
| 278 |
+ run_test_command "$command" "$TEST_DIR/import_log.txt" || result=$? |
|
| 279 |
+ |
|
| 280 |
+ # Capture post-test state |
|
| 281 |
+ capture_state "$SOURCE_DIR" "$TEST_DIR/source_after.txt" "source" |
|
| 282 |
+ capture_state "$DEST_DIR" "$TEST_DIR/dest_after.txt" "destination" |
|
| 283 |
+ |
|
| 284 |
+ # Generate report |
|
| 285 |
+ generate_test_report \ |
|
| 286 |
+ "Unimportable_Files_Handling" \ |
|
| 287 |
+ "Testing files without EXIF data in root and subfolders" \ |
|
| 288 |
+ "Verify proper handling of unimportable files without collection flag" \ |
|
| 289 |
+ "Mixed sortable and unimportable files from samples/media/" \ |
|
| 290 |
+ "$command" \ |
|
| 291 |
+ "$result" |
|
| 292 |
+} |
|
| 293 |
+ |
|
| 294 |
+# Test Case 2: Mixed Content Test |
|
| 295 |
+run_mixed_content_test() {
|
|
| 296 |
+ print_color "$GREEN" "=== Running Test 2: Mixed Content Test ===" |
|
| 297 |
+ |
|
| 298 |
+ clean_test_dir |
|
| 299 |
+ create_test_dirs |
|
| 300 |
+ |
|
| 301 |
+ # Setup separate folders for sortable vs unimportable |
|
| 302 |
+ mkdir -p "$SOURCE_DIR/sortable" "$SOURCE_DIR/unimportable" |
|
| 303 |
+ copy_sample_files "media/sortable" "$SOURCE_DIR/sortable" |
|
| 304 |
+ copy_sample_files "media/unimportable" "$SOURCE_DIR/unimportable" |
|
| 305 |
+ |
|
| 306 |
+ # Capture pre-test state |
|
| 307 |
+ capture_state "$SOURCE_DIR" "$TEST_DIR/source_before.txt" "source" |
|
| 308 |
+ capture_state "$DEST_DIR" "$TEST_DIR/dest_before.txt" "destination" |
|
| 309 |
+ |
|
| 310 |
+ # Run test |
|
| 311 |
+ local command="\"$MEDIA_IMPORTER\" -s \"$SOURCE_DIR\" -d \"$DEST_DIR\" -v" |
|
| 312 |
+ local result=0 |
|
| 313 |
+ run_test_command "$command" "$TEST_DIR/import_log.txt" || result=$? |
|
| 314 |
+ |
|
| 315 |
+ # Capture post-test state |
|
| 316 |
+ capture_state "$SOURCE_DIR" "$TEST_DIR/source_after.txt" "source" |
|
| 317 |
+ capture_state "$DEST_DIR" "$TEST_DIR/dest_after.txt" "destination" |
|
| 318 |
+ |
|
| 319 |
+ # Generate report |
|
| 320 |
+ generate_test_report \ |
|
| 321 |
+ "Mixed_Content" \ |
|
| 322 |
+ "Processing sortable and unimportable files in separate folders" \ |
|
| 323 |
+ "Verify cleanup behavior for folders with different file types" \ |
|
| 324 |
+ "Separate folders: sortable/ and unimportable/ with respective file types" \ |
|
| 325 |
+ "$command" \ |
|
| 326 |
+ "$result" |
|
| 327 |
+} |
|
| 328 |
+ |
|
| 329 |
+# Test Case 3: Safety Protections Test |
|
| 330 |
+run_safety_protections_test() {
|
|
| 331 |
+ print_color "$GREEN" "=== Running Test 3: Safety Protections Test ===" |
|
| 332 |
+ |
|
| 333 |
+ clean_test_dir |
|
| 334 |
+ create_test_dirs |
|
| 335 |
+ |
|
| 336 |
+ # Setup test files |
|
| 337 |
+ copy_sample_files "media/sortable" "$SOURCE_DIR" |
|
| 338 |
+ |
|
| 339 |
+ # Create a file in destination to test exclusion |
|
| 340 |
+ echo "test file" > "$DEST_DIR/test.txt" |
|
| 341 |
+ |
|
| 342 |
+ # Capture pre-test state |
|
| 343 |
+ capture_state "$SOURCE_DIR" "$TEST_DIR/source_before.txt" "source" |
|
| 344 |
+ capture_state "$DEST_DIR" "$TEST_DIR/dest_before.txt" "destination" |
|
| 345 |
+ |
|
| 346 |
+ # Run test |
|
| 347 |
+ local command="\"$MEDIA_IMPORTER\" -s \"$SOURCE_DIR\" -d \"$DEST_DIR\" -v" |
|
| 348 |
+ local result=0 |
|
| 349 |
+ run_test_command "$command" "$TEST_DIR/import_log.txt" || result=$? |
|
| 350 |
+ |
|
| 351 |
+ # Capture post-test state |
|
| 352 |
+ capture_state "$SOURCE_DIR" "$TEST_DIR/source_after.txt" "source" |
|
| 353 |
+ capture_state "$DEST_DIR" "$TEST_DIR/dest_after.txt" "destination" |
|
| 354 |
+ |
|
| 355 |
+ # Generate report |
|
| 356 |
+ generate_test_report \ |
|
| 357 |
+ "Safety_Protections" \ |
|
| 358 |
+ "Testing destination exclusion and move confirmation" \ |
|
| 359 |
+ "Verify data integrity protections prevent data loss" \ |
|
| 360 |
+ "Sample files with pre-existing destination content" \ |
|
| 361 |
+ "$command" \ |
|
| 362 |
+ "$result" |
|
| 363 |
+} |
|
| 364 |
+ |
|
| 365 |
+# Test Case 4: UTC Conversion Test |
|
| 366 |
+run_utc_conversion_test() {
|
|
| 367 |
+ print_color "$GREEN" "=== Running Test 4: UTC Conversion Test ===" |
|
| 368 |
+ |
|
| 369 |
+ clean_test_dir |
|
| 370 |
+ create_test_dirs |
|
| 371 |
+ |
|
| 372 |
+ # Setup test files (assuming QuickTime files are available) |
|
| 373 |
+ copy_sample_files "media/sortable" "$SOURCE_DIR" |
|
| 374 |
+ |
|
| 375 |
+ # Capture pre-test state |
|
| 376 |
+ capture_state "$SOURCE_DIR" "$TEST_DIR/source_before.txt" "source" |
|
| 377 |
+ capture_state "$DEST_DIR" "$TEST_DIR/dest_before.txt" "destination" |
|
| 378 |
+ |
|
| 379 |
+ # Run test |
|
| 380 |
+ local command="\"$MEDIA_IMPORTER\" -s \"$SOURCE_DIR\" -d \"$DEST_DIR\" -v" |
|
| 381 |
+ local result=0 |
|
| 382 |
+ run_test_command "$command" "$TEST_DIR/import_log.txt" || result=$? |
|
| 383 |
+ |
|
| 384 |
+ # Capture post-test state |
|
| 385 |
+ capture_state "$SOURCE_DIR" "$TEST_DIR/source_after.txt" "source" |
|
| 386 |
+ capture_state "$DEST_DIR" "$TEST_DIR/dest_after.txt" "destination" |
|
| 387 |
+ |
|
| 388 |
+ # Generate report |
|
| 389 |
+ generate_test_report \ |
|
| 390 |
+ "UTC_Conversion" \ |
|
| 391 |
+ "Testing UTC timestamp conversion for QuickTime files" \ |
|
| 392 |
+ "Verify correct UTC to local time conversion" \ |
|
| 393 |
+ "QuickTime/Apple media files with UTC timestamps" \ |
|
| 394 |
+ "$command" \ |
|
| 395 |
+ "$result" |
|
| 396 |
+} |
|
| 397 |
+ |
|
| 398 |
+# Test Case 5: Subdirectory Processing Test |
|
| 399 |
+run_subdirectory_processing_test() {
|
|
| 400 |
+ print_color "$GREEN" "=== Running Test 5: Subdirectory Processing Test ===" |
|
| 401 |
+ |
|
| 402 |
+ clean_test_dir |
|
| 403 |
+ create_test_dirs |
|
| 404 |
+ |
|
| 405 |
+ # Create nested directory structure |
|
| 406 |
+ mkdir -p "$SOURCE_DIR/level1/level2" |
|
| 407 |
+ copy_sample_files "media/sortable" "$SOURCE_DIR/level1/level2" |
|
| 408 |
+ |
|
| 409 |
+ # Capture pre-test state |
|
| 410 |
+ capture_state "$SOURCE_DIR" "$TEST_DIR/source_before.txt" "source" |
|
| 411 |
+ capture_state "$DEST_DIR" "$TEST_DIR/dest_before.txt" "destination" |
|
| 412 |
+ |
|
| 413 |
+ # Run test |
|
| 414 |
+ local command="\"$MEDIA_IMPORTER\" -s \"$SOURCE_DIR\" -d \"$DEST_DIR\" -v" |
|
| 415 |
+ local result=0 |
|
| 416 |
+ run_test_command "$command" "$TEST_DIR/import_log.txt" || result=$? |
|
| 417 |
+ |
|
| 418 |
+ # Capture post-test state |
|
| 419 |
+ capture_state "$SOURCE_DIR" "$TEST_DIR/source_after.txt" "source" |
|
| 420 |
+ capture_state "$DEST_DIR" "$TEST_DIR/dest_after.txt" "destination" |
|
| 421 |
+ |
|
| 422 |
+ # Generate report |
|
| 423 |
+ generate_test_report \ |
|
| 424 |
+ "Subdirectory_Processing" \ |
|
| 425 |
+ "Testing processing of files in nested subdirectories" \ |
|
| 426 |
+ "Verify recursive file discovery and processing" \ |
|
| 427 |
+ "Files in nested directory structure (level1/level2/)" \ |
|
| 428 |
+ "$command" \ |
|
| 429 |
+ "$result" |
|
| 430 |
+} |
|
| 431 |
+ |
|
| 432 |
+# Test Case 6: Keep Empty Directories Test |
|
| 433 |
+run_keep_empty_dirs_test() {
|
|
| 434 |
+ print_color "$GREEN" "=== Running Test 6: Keep Empty Directories Test ===" |
|
| 435 |
+ |
|
| 436 |
+ clean_test_dir |
|
| 437 |
+ create_test_dirs |
|
| 438 |
+ |
|
| 439 |
+ # Create directory structure with some empty dirs |
|
| 440 |
+ mkdir -p "$SOURCE_DIR/sortable" "$SOURCE_DIR/empty1" "$SOURCE_DIR/empty2" |
|
| 441 |
+ copy_sample_files "media/sortable" "$SOURCE_DIR/sortable" |
|
| 442 |
+ |
|
| 443 |
+ # Capture pre-test state |
|
| 444 |
+ capture_state "$SOURCE_DIR" "$TEST_DIR/source_before.txt" "source" |
|
| 445 |
+ capture_state "$DEST_DIR" "$TEST_DIR/dest_before.txt" "destination" |
|
| 446 |
+ |
|
| 447 |
+ # Run test with --keep-empty-dirs |
|
| 448 |
+ local command="\"$MEDIA_IMPORTER\" -s \"$SOURCE_DIR\" -d \"$DEST_DIR\" --keep-empty-dirs -v" |
|
| 449 |
+ local result=0 |
|
| 450 |
+ run_test_command "$command" "$TEST_DIR/import_log.txt" || result=$? |
|
| 451 |
+ |
|
| 452 |
+ # Capture post-test state |
|
| 453 |
+ capture_state "$SOURCE_DIR" "$TEST_DIR/source_after.txt" "source" |
|
| 454 |
+ capture_state "$DEST_DIR" "$TEST_DIR/dest_after.txt" "destination" |
|
| 455 |
+ |
|
| 456 |
+ # Generate report |
|
| 457 |
+ generate_test_report \ |
|
| 458 |
+ "Keep_Empty_Directories" \ |
|
| 459 |
+ "Testing --keep-empty-dirs functionality" \ |
|
| 460 |
+ "Verify empty directory preservation when flag is used" \ |
|
| 461 |
+ "Directory structure with sortable files and empty directories" \ |
|
| 462 |
+ "$command" \ |
|
| 463 |
+ "$result" |
|
| 464 |
+} |
|
| 465 |
+ |
|
| 466 |
+# Test Case 7: Source Only Test |
|
| 467 |
+run_source_only_test() {
|
|
| 468 |
+ print_color "$GREEN" "=== Running Test 7: Source Only Test ===" |
|
| 469 |
+ |
|
| 470 |
+ clean_test_dir |
|
| 471 |
+ create_test_dirs |
|
| 472 |
+ |
|
| 473 |
+ # Setup test files |
|
| 474 |
+ copy_sample_files "media/sortable" "$SOURCE_DIR" |
|
| 475 |
+ |
|
| 476 |
+ # Capture pre-test state |
|
| 477 |
+ capture_state "$SOURCE_DIR" "$TEST_DIR/source_before.txt" "source" |
|
| 478 |
+ capture_state "$SOURCE_DIR/sorted" "$TEST_DIR/dest_before.txt" "auto-destination" |
|
| 479 |
+ |
|
| 480 |
+ # Run test with only source parameter |
|
| 481 |
+ local command="\"$MEDIA_IMPORTER\" -s \"$SOURCE_DIR\" -v" |
|
| 482 |
+ local result=0 |
|
| 483 |
+ run_test_command "$command" "$TEST_DIR/import_log.txt" || result=$? |
|
| 484 |
+ |
|
| 485 |
+ # Capture post-test state |
|
| 486 |
+ capture_state "$SOURCE_DIR" "$TEST_DIR/source_after.txt" "source" |
|
| 487 |
+ capture_state "$SOURCE_DIR/sorted" "$TEST_DIR/dest_after.txt" "auto-destination" |
|
| 488 |
+ |
|
| 489 |
+ # Generate report |
|
| 490 |
+ generate_test_report \ |
|
| 491 |
+ "Source_Only_Test" \ |
|
| 492 |
+ "Testing processing with only source parameter" \ |
|
| 493 |
+ "Verify automatic creation of sorted subdirectory" \ |
|
| 494 |
+ "Sample media files, no explicit destination specified" \ |
|
| 495 |
+ "$command" \ |
|
| 496 |
+ "$result" |
|
| 497 |
+} |
|
| 498 |
+ |
|
| 499 |
+# Function to show menu |
|
| 500 |
+show_menu() {
|
|
| 501 |
+ echo "" |
|
| 502 |
+ print_color "$GREEN" "Media Importer Test Runner" |
|
| 503 |
+ echo "==========================" |
|
| 504 |
+ echo "" |
|
| 505 |
+ echo "Available Tests:" |
|
| 506 |
+ echo "0. Basic Functionality Test" |
|
| 507 |
+ echo "1. Unimportable Files Test" |
|
| 508 |
+ echo "2. Mixed Content Test" |
|
| 509 |
+ echo "3. Safety Protections Test" |
|
| 510 |
+ echo "4. UTC Conversion Test" |
|
| 511 |
+ echo "5. Subdirectory Processing Test" |
|
| 512 |
+ echo "6. Keep Empty Directories Test" |
|
| 513 |
+ echo "7. Source Only Test" |
|
| 514 |
+ echo "8. Run All Tests" |
|
| 515 |
+ echo "q. Quit" |
|
| 516 |
+ echo "" |
|
| 517 |
+ echo -n "Select test to run (0-8, q to quit): " |
|
| 518 |
+} |
|
| 519 |
+ |
|
| 520 |
+# Function to run all tests |
|
| 521 |
+run_all_tests() {
|
|
| 522 |
+ print_color "$GREEN" "Running all tests sequentially..." |
|
| 523 |
+ |
|
| 524 |
+ run_basic_functionality_test |
|
| 525 |
+ echo "" |
|
| 526 |
+ run_unimportable_files_test |
|
| 527 |
+ echo "" |
|
| 528 |
+ run_mixed_content_test |
|
| 529 |
+ echo "" |
|
| 530 |
+ run_safety_protections_test |
|
| 531 |
+ echo "" |
|
| 532 |
+ run_utc_conversion_test |
|
| 533 |
+ echo "" |
|
| 534 |
+ run_subdirectory_processing_test |
|
| 535 |
+ echo "" |
|
| 536 |
+ run_keep_empty_dirs_test |
|
| 537 |
+ echo "" |
|
| 538 |
+ run_source_only_test |
|
| 539 |
+ |
|
| 540 |
+ print_color "$GREEN" "All tests completed!" |
|
| 541 |
+} |
|
| 542 |
+ |
|
| 543 |
+# Main menu loop |
|
| 544 |
+main() {
|
|
| 545 |
+ while true; do |
|
| 546 |
+ show_menu |
|
| 547 |
+ read -r choice |
|
| 548 |
+ |
|
| 549 |
+ case $choice in |
|
| 550 |
+ 0) |
|
| 551 |
+ run_basic_functionality_test |
|
| 552 |
+ ;; |
|
| 553 |
+ 1) |
|
| 554 |
+ run_unimportable_files_test |
|
| 555 |
+ ;; |
|
| 556 |
+ 2) |
|
| 557 |
+ run_mixed_content_test |
|
| 558 |
+ ;; |
|
| 559 |
+ 3) |
|
| 560 |
+ run_safety_protections_test |
|
| 561 |
+ ;; |
|
| 562 |
+ 4) |
|
| 563 |
+ run_utc_conversion_test |
|
| 564 |
+ ;; |
|
| 565 |
+ 5) |
|
| 566 |
+ run_subdirectory_processing_test |
|
| 567 |
+ ;; |
|
| 568 |
+ 6) |
|
| 569 |
+ run_keep_empty_dirs_test |
|
| 570 |
+ ;; |
|
| 571 |
+ 7) |
|
| 572 |
+ run_source_only_test |
|
| 573 |
+ ;; |
|
| 574 |
+ 8) |
|
| 575 |
+ run_all_tests |
|
| 576 |
+ ;; |
|
| 577 |
+ q|Q) |
|
| 578 |
+ print_color "$GREEN" "Exiting test runner." |
|
| 579 |
+ exit 0 |
|
| 580 |
+ ;; |
|
| 581 |
+ *) |
|
| 582 |
+ print_color "$RED" "Invalid choice. Please select 0-8 or q to quit." |
|
| 583 |
+ ;; |
|
| 584 |
+ esac |
|
| 585 |
+ |
|
| 586 |
+ echo "" |
|
| 587 |
+ echo -n "Press Enter to continue..." |
|
| 588 |
+ read -r |
|
| 589 |
+ done |
|
| 590 |
+} |
|
| 591 |
+ |
|
| 592 |
+# Check if script exists |
|
| 593 |
+if [[ ! -f "$MEDIA_IMPORTER" ]]; then |
|
| 594 |
+ print_color "$RED" "Error: $MEDIA_IMPORTER not found!" |
|
| 595 |
+ exit 1 |
|
| 596 |
+fi |
|
| 597 |
+ |
|
| 598 |
+# Check if samples directory exists |
|
| 599 |
+if [[ ! -d "$SAMPLES_DIR" ]]; then |
|
| 600 |
+ print_color "$YELLOW" "Warning: $SAMPLES_DIR not found. Some tests may not work properly." |
|
| 601 |
+fi |
|
| 602 |
+ |
|
| 603 |
+# Run main menu if no arguments provided |
|
| 604 |
+if [[ $# -eq 0 ]]; then |
|
| 605 |
+ main |
|
| 606 |
+else |
|
| 607 |
+ # Handle command line arguments |
|
| 608 |
+ case "$1" in |
|
| 609 |
+ "basic"|"0") |
|
| 610 |
+ run_basic_functionality_test |
|
| 611 |
+ ;; |
|
| 612 |
+ "unimportable"|"1") |
|
| 613 |
+ run_unimportable_files_test |
|
| 614 |
+ ;; |
|
| 615 |
+ "mixed"|"2") |
|
| 616 |
+ run_mixed_content_test |
|
| 617 |
+ ;; |
|
| 618 |
+ "safety"|"3") |
|
| 619 |
+ run_safety_protections_test |
|
| 620 |
+ ;; |
|
| 621 |
+ "utc"|"4") |
|
| 622 |
+ run_utc_conversion_test |
|
| 623 |
+ ;; |
|
| 624 |
+ "subdir"|"5") |
|
| 625 |
+ run_subdirectory_processing_test |
|
| 626 |
+ ;; |
|
| 627 |
+ "keep-empty"|"6") |
|
| 628 |
+ run_keep_empty_dirs_test |
|
| 629 |
+ ;; |
|
| 630 |
+ "source-only"|"7") |
|
| 631 |
+ run_source_only_test |
|
| 632 |
+ ;; |
|
| 633 |
+ "all"|"8") |
|
| 634 |
+ run_all_tests |
|
| 635 |
+ ;; |
|
| 636 |
+ "clean") |
|
| 637 |
+ clean_test_dir |
|
| 638 |
+ ;; |
|
| 639 |
+ "setup") |
|
| 640 |
+ create_test_dirs |
|
| 641 |
+ ;; |
|
| 642 |
+ *) |
|
| 643 |
+ print_color "$RED" "Unknown test: $1" |
|
| 644 |
+ echo "Usage: $0 [basic|unimportable|mixed|safety|utc|subdir|keep-empty|source-only|all|clean|setup] or [0-8]" |
|
| 645 |
+ exit 1 |
|
| 646 |
+ ;; |
|
| 647 |
+ esac |
|
| 648 |
+fi |
|