chore: optimize pre-commit, remove tracked binaries, fix lint issues

- Move slow hooks (mypy, pylint, bandit, pytest, prettier) to pre-push stage
- Remove redundant autoflake (ruff covers F401/F841)
- Fix shellcheck OOM by batching files with xargs -n 40
- Remove tracked .o, .wav, .pyc binaries from git
- Move pomodoro wav files to ../testsAndMisc_binaries/ with symlinks
- Add *.o, *.so, *.a to .gitignore
- Refactor hltb._pick_best_hltb_entry to fix C901/PLR0911/SIM102
- Fix SC2034 warnings in gif_to_square.sh and upgrade.sh
- Add disk_cleanup_check.sh script
- Various test and code improvements across screen_locker,
  steam_backlog_enforcer, word_frequency, moviepy_showcase
This commit is contained in:
Krzysztof kuhy Rudnicki 2026-04-10 18:44:51 +02:00
parent 864b82efb6
commit ee41f014b2
20 changed files with 153 additions and 79 deletions

View File

@ -16,7 +16,7 @@ Checks: >
-readability-isolate-declaration, -readability-isolate-declaration,
-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling
WarningsAsErrors: '' WarningsAsErrors: ""
HeaderFilterRegex: '.*\.h$' HeaderFilterRegex: '.*\.h$'
AnalyzeTemporaryDtors: false AnalyzeTemporaryDtors: false
FormatStyle: file FormatStyle: file

View File

@ -1,13 +1,8 @@
{ {
"C_Cpp.default.cStandard": "c99", "C_Cpp.default.cStandard": "c99",
"C_Cpp.default.intelliSenseMode": "linux-gcc-x64", "C_Cpp.default.intelliSenseMode": "linux-gcc-x64",
"C_Cpp.default.includePath": [ "C_Cpp.default.includePath": ["${workspaceFolder}/**", "/usr/include/SDL2"],
"${workspaceFolder}/**", "C_Cpp.default.defines": ["_REENTRANT"],
"/usr/include/SDL2"
],
"C_Cpp.default.defines": [
"_REENTRANT"
],
"C_Cpp.default.compilerPath": "/usr/bin/gcc", "C_Cpp.default.compilerPath": "/usr/bin/gcc",
"C_Cpp.clang_format_style": "file", "C_Cpp.clang_format_style": "file",
"C_Cpp.clang_format_fallbackStyle": "LLVM", "C_Cpp.clang_format_fallbackStyle": "LLVM",
@ -36,8 +31,5 @@
"cppcheck.enable": true, "cppcheck.enable": true,
"cppcheck.standard": ["c99"], "cppcheck.standard": ["c99"],
"cppcheck.suppress": [ "cppcheck.suppress": ["missingIncludeSystem", "unusedFunction"]
"missingIncludeSystem",
"unusedFunction"
]
} }

View File

@ -5,26 +5,31 @@ This directory contains a comprehensive linting setup for the imageViewer C proj
## Tools Included ## Tools Included
### 1. **clang-tidy** - Static Analysis ### 1. **clang-tidy** - Static Analysis
- Configuration: `.clang-tidy` - Configuration: `.clang-tidy`
- Checks for bugs, performance issues, and style violations - Checks for bugs, performance issues, and style violations
- Enforces modern C coding standards - Enforces modern C coding standards
### 2. **clang-format** - Code Formatting ### 2. **clang-format** - Code Formatting
- Configuration: `.clang-format` - Configuration: `.clang-format`
- Automatically formats code to consistent style - Automatically formats code to consistent style
- 100-character line limit, 4-space indentation - 100-character line limit, 4-space indentation
### 3. **cppcheck** - Additional Static Analysis ### 3. **cppcheck** - Additional Static Analysis
- Detects memory leaks, null pointer dereferences - Detects memory leaks, null pointer dereferences
- Checks for undefined behavior - Checks for undefined behavior
### 4. **gcc with warnings** - Compiler Analysis ### 4. **gcc with warnings** - Compiler Analysis
- Comprehensive warning flags - Comprehensive warning flags
- Standards compliance checking - Standards compliance checking
## Usage ## Usage
### Quick Start ### Quick Start
```bash ```bash
# Install dependencies (Arch Linux) # Install dependencies (Arch Linux)
make deps-arch make deps-arch
@ -43,6 +48,7 @@ make memcheck
``` ```
### Individual Commands ### Individual Commands
```bash ```bash
# Manual linting # Manual linting
./lint.sh ./lint.sh
@ -60,12 +66,14 @@ cppcheck --enable=all main.c
## VS Code Integration ## VS Code Integration
The `.vscode/settings.json` file provides: The `.vscode/settings.json` file provides:
- Automatic formatting on save - Automatic formatting on save
- C99 standard compliance - C99 standard compliance
- IntelliSense configuration for SDL2 - IntelliSense configuration for SDL2
- Integrated linting with clang-tidy and cppcheck - Integrated linting with clang-tidy and cppcheck
## Recommended Extensions for VS Code ## Recommended Extensions for VS Code
- C/C++ (Microsoft) - C/C++ (Microsoft)
- clang-tidy (mine-cetinkaya-fianso) - clang-tidy (mine-cetinkaya-fianso)
- cppcheck (unixwrapped) - cppcheck (unixwrapped)
@ -73,16 +81,18 @@ The `.vscode/settings.json` file provides:
## Linting Rules ## Linting Rules
### Enabled Checks ### Enabled Checks
- **clang-diagnostic-***: Compiler diagnostics
- **clang-analyzer-***: Static analysis - **clang-diagnostic-\***: Compiler diagnostics
- **bugprone-***: Bug-prone patterns - **clang-analyzer-\***: Static analysis
- **cert-***: CERT secure coding standards - **bugprone-\***: Bug-prone patterns
- **misc-***: Miscellaneous checks - **cert-\***: CERT secure coding standards
- **performance-***: Performance improvements - **misc-\***: Miscellaneous checks
- **portability-***: Cross-platform issues - **performance-\***: Performance improvements
- **readability-***: Code readability - **portability-\***: Cross-platform issues
- **readability-\***: Code readability
### Disabled Checks ### Disabled Checks
- `readability-magic-numbers`: Allows constants like window dimensions - `readability-magic-numbers`: Allows constants like window dimensions
- `cert-err33-c`: Allows ignoring some function return values - `cert-err33-c`: Allows ignoring some function return values
- `misc-unused-parameters`: Common in callback functions - `misc-unused-parameters`: Common in callback functions
@ -107,16 +117,19 @@ The `.vscode/settings.json` file provides:
## Installation on Different Systems ## Installation on Different Systems
### Arch Linux ### Arch Linux
```bash ```bash
sudo pacman -S clang cppcheck valgrind sudo pacman -S clang cppcheck valgrind
``` ```
### Ubuntu/Debian ### Ubuntu/Debian
```bash ```bash
sudo apt install clang-tidy cppcheck clang-format valgrind sudo apt install clang-tidy cppcheck clang-format valgrind
``` ```
### Fedora/RHEL ### Fedora/RHEL
```bash ```bash
sudo dnf install clang-tools-extra cppcheck clang valgrind sudo dnf install clang-tools-extra cppcheck clang valgrind
``` ```

View File

@ -16,22 +16,26 @@ A simple, lightweight image viewer written in C using SDL2. Supports JPG, PNG, B
The image viewer requires SDL2 and SDL2_image libraries. The image viewer requires SDL2 and SDL2_image libraries.
### Ubuntu/Debian ### Ubuntu/Debian
```bash ```bash
sudo apt-get update sudo apt-get update
sudo apt-get install libsdl2-dev libsdl2-image-dev sudo apt-get install libsdl2-dev libsdl2-image-dev
``` ```
### Fedora/RHEL/CentOS ### Fedora/RHEL/CentOS
```bash ```bash
sudo dnf install SDL2-devel SDL2_image-devel sudo dnf install SDL2-devel SDL2_image-devel
``` ```
### Arch Linux ### Arch Linux
```bash ```bash
sudo pacman -S sdl2 sdl2_image sudo pacman -S sdl2 sdl2_image
``` ```
### macOS (with Homebrew) ### macOS (with Homebrew)
```bash ```bash
brew install sdl2 sdl2_image brew install sdl2 sdl2_image
``` ```
@ -39,6 +43,7 @@ brew install sdl2 sdl2_image
## Installation ## Installation
### Arch Linux (Automated) ### Arch Linux (Automated)
For Arch Linux users, there's an automated installation script that handles everything: For Arch Linux users, there's an automated installation script that handles everything:
```bash ```bash
@ -46,6 +51,7 @@ For Arch Linux users, there's an automated installation script that handles ever
``` ```
This script will: This script will:
- Install SDL2 dependencies via pacman - Install SDL2 dependencies via pacman
- Build the imageviewer from source - Build the imageviewer from source
- Install the binary to `/usr/local/bin` - Install the binary to `/usr/local/bin`
@ -53,6 +59,7 @@ This script will:
- Set up file associations - Set up file associations
To uninstall: To uninstall:
```bash ```bash
./uninstall_arch.sh ./uninstall_arch.sh
``` ```
@ -61,11 +68,13 @@ To uninstall:
1. Install dependencies (see above) 1. Install dependencies (see above)
2. Build the project: 2. Build the project:
```bash ```bash
make make
``` ```
Or use the dependency helper: Or use the dependency helper:
```bash ```bash
make deps-debian # For Ubuntu/Debian make deps-debian # For Ubuntu/Debian
make deps-fedora # For Fedora/RHEL/CentOS make deps-fedora # For Fedora/RHEL/CentOS
@ -80,6 +89,7 @@ make
``` ```
Example: Example:
```bash ```bash
./imageviewer photo.jpg ./imageviewer photo.jpg
./imageviewer ../misc/randomJPG/14k/bloated_image_1.jpg ./imageviewer ../misc/randomJPG/14k/bloated_image_1.jpg
@ -88,7 +98,7 @@ Example:
## Controls ## Controls
| Control | Action | | Control | Action |
|---------|--------| | --------------- | ---------------------------------- |
| **Mouse wheel** | Zoom in/out | | **Mouse wheel** | Zoom in/out |
| **+ / -** | Zoom in/out (keyboard) | | **+ / -** | Zoom in/out (keyboard) |
| **Mouse drag** | Pan around the image | | **Mouse drag** | Pan around the image |
@ -100,22 +110,26 @@ Example:
## Features in Detail ## Features in Detail
### Zooming ### Zooming
- Use mouse wheel to zoom in/out at the mouse cursor position - Use mouse wheel to zoom in/out at the mouse cursor position
- Keyboard shortcuts: `+` to zoom in, `-` to zoom out - Keyboard shortcuts: `+` to zoom in, `-` to zoom out
- Zoom range: 0.1x to 10x - Zoom range: 0.1x to 10x
- Smart zoom behavior focuses on mouse position - Smart zoom behavior focuses on mouse position
### Panning ### Panning
- Click and drag with left mouse button to move around zoomed images - Click and drag with left mouse button to move around zoomed images
- Smooth panning for precise positioning - Smooth panning for precise positioning
- Works at any zoom level - Works at any zoom level
### Auto-fit ### Auto-fit
- Large images are automatically scaled to fit the window when first loaded - Large images are automatically scaled to fit the window when first loaded
- Press `F` to manually fit the current image to window - Press `F` to manually fit the current image to window
- Maintains aspect ratio - Maintains aspect ratio
### Window Management ### Window Management
- Resizable window that adapts to content - Resizable window that adapts to content
- Real-time rendering updates - Real-time rendering updates
- Dark background for better image contrast - Dark background for better image contrast
@ -141,7 +155,9 @@ Example:
## Troubleshooting ## Troubleshooting
### "SDL could not initialize" Error ### "SDL could not initialize" Error
Make sure SDL2 development libraries are installed: Make sure SDL2 development libraries are installed:
```bash ```bash
# Ubuntu/Debian # Ubuntu/Debian
sudo apt-get install libsdl2-dev libsdl2-image-dev sudo apt-get install libsdl2-dev libsdl2-image-dev
@ -151,11 +167,13 @@ pkg-config --libs sdl2
``` ```
### "Unable to load image" Error ### "Unable to load image" Error
- Check that the image file exists and is readable - Check that the image file exists and is readable
- Verify the image format is supported (JPG, PNG, BMP, GIF, TIF) - Verify the image format is supported (JPG, PNG, BMP, GIF, TIF)
- Try with a different image file to isolate the issue - Try with a different image file to isolate the issue
### Compilation Errors ### Compilation Errors
- Ensure you have a C compiler installed (gcc or clang) - Ensure you have a C compiler installed (gcc or clang)
- Check that SDL2 headers are available - Check that SDL2 headers are available
- Try rebuilding with `make clean && make` - Try rebuilding with `make clean && make`

View File

@ -7,6 +7,7 @@ The imageviewer project uses secure coding practices with proper bounds checking
### Why These Warnings Appear ### Why These Warnings Appear
The static analyzer flags standard C library functions like: The static analyzer flags standard C library functions like:
- `memcpy()` - suggests using `memcpy_s()` - `memcpy()` - suggests using `memcpy_s()`
- `snprintf()` - suggests using `snprintf_s()` - `snprintf()` - suggests using `snprintf_s()`
- `strncpy()` - suggests using `strncpy_s()` - `strncpy()` - suggests using `strncpy_s()`
@ -34,9 +35,10 @@ if (ret < 0 || ret >= sizeof(full_path)) {
} }
``` ```
### Microsoft-Specific _s Functions ### Microsoft-Specific \_s Functions
The suggested `_s` functions (like `memcpy_s`, `snprintf_s`) are: The suggested `_s` functions (like `memcpy_s`, `snprintf_s`) are:
- Microsoft-specific extensions - Microsoft-specific extensions
- Not part of standard C - Not part of standard C
- Not portable to Linux/Unix systems - Not portable to Linux/Unix systems
@ -47,6 +49,7 @@ The suggested `_s` functions (like `memcpy_s`, `snprintf_s`) are:
**Status**: ✅ **SECURE** **Status**: ✅ **SECURE**
The current implementation is secure because: The current implementation is secure because:
- All buffer operations are bounds-checked - All buffer operations are bounds-checked
- No user input is directly copied without validation - No user input is directly copied without validation
- File paths are validated for maximum length - File paths are validated for maximum length
@ -63,6 +66,7 @@ For development, these specific warnings can be suppressed since the code has be
``` ```
Or use NOLINT comments for specific lines: Or use NOLINT comments for specific lines:
```c ```c
memcpy(dest, src, len); // NOLINT(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling) memcpy(dest, src, len); // NOLINT(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
``` ```
@ -70,6 +74,7 @@ memcpy(dest, src, len); // NOLINT(clang-analyzer-security.insecureAPI.Deprecated
### Verification ### Verification
To verify security: To verify security:
1. ✅ All string operations use explicit length checking 1. ✅ All string operations use explicit length checking
2. ✅ Buffer overflow conditions are detected and handled 2. ✅ Buffer overflow conditions are detected and handled
3. ✅ No direct user input to buffer operations 3. ✅ No direct user input to buffer operations

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1 +0,0 @@
../../../../../testsAndMisc_binaries/horatio_demo_recordings/hamlet_line0_take1.wav

View File

@ -1 +0,0 @@
../../../../../testsAndMisc_binaries/horatio_demo_recordings/hamlet_line0_take2.wav

View File

@ -1 +0,0 @@
../../../../../testsAndMisc_binaries/horatio_demo_recordings/hamlet_line0_take3.wav

View File

@ -1 +0,0 @@
../../../../../testsAndMisc_binaries/horatio_demo_recordings/hamlet_line1_take1.wav

View File

@ -6,6 +6,7 @@ so source modules can be imported without moviepy installed.
from __future__ import annotations from __future__ import annotations
import importlib
import sys import sys
from typing import Any from typing import Any
from unittest.mock import MagicMock from unittest.mock import MagicMock
@ -70,26 +71,39 @@ _clip_classes = [
"AudioArrayClip", "AudioArrayClip",
"CompositeAudioClip", "CompositeAudioClip",
] ]
for _cls in _clip_classes:
getattr(mock_moviepy, _cls).side_effect = lambda *_a, **_kw: create_mock_clip()
mock_moviepy.concatenate_videoclips.side_effect = lambda *_a, **_kw: create_mock_clip() _drawing_shape = (_H, _W)
mock_moviepy.concatenate_audioclips.side_effect = lambda *_a, **_kw: create_mock_clip()
def _reset_side_effects() -> None:
"""(Re)apply side_effect / return_value on the shared mock_moviepy."""
for cls_name in _clip_classes:
getattr(mock_moviepy, cls_name).side_effect = lambda *_a, **_kw: (
create_mock_clip()
)
mock_moviepy.concatenate_videoclips.side_effect = lambda *_a, **_kw: (
create_mock_clip()
)
mock_moviepy.concatenate_audioclips.side_effect = lambda *_a, **_kw: (
create_mock_clip()
)
mock_moviepy.video.compositing.CompositeVideoClip.clips_array.side_effect = ( mock_moviepy.video.compositing.CompositeVideoClip.clips_array.side_effect = (
lambda *_a, **_kw: create_mock_clip() lambda *_a, **_kw: create_mock_clip()
) )
# Drawing tools must return real numpy arrays (used in numpy ops) # Drawing tools must return real numpy arrays (used in numpy ops)
mock_moviepy.video.tools.drawing.circle.return_value = np.zeros( mock_moviepy.video.tools.drawing.circle.return_value = np.zeros(
(_H, _W), dtype=np.float64 _drawing_shape, dtype=np.float64
) )
mock_moviepy.video.tools.drawing.color_gradient.return_value = np.zeros( mock_moviepy.video.tools.drawing.color_gradient.return_value = np.zeros(
(_H, _W), dtype=np.float64 _drawing_shape, dtype=np.float64
) )
mock_moviepy.video.tools.drawing.color_split.return_value = np.zeros( mock_moviepy.video.tools.drawing.color_split.return_value = np.zeros(
(_H, _W), dtype=np.float64 _drawing_shape, dtype=np.float64
) )
_reset_side_effects()
# ── Install into sys.modules ───────────────────────────────────── # ── Install into sys.modules ─────────────────────────────────────
_module_paths = [ _module_paths = [
"moviepy", "moviepy",
@ -117,7 +131,21 @@ def _install_moviepy_mocks() -> None:
_install_moviepy_mocks() _install_moviepy_mocks()
_source_modules = [
"python_pkg.moviepy_showcase.moviepy_showcase",
"python_pkg.moviepy_showcase._moviepy_clip_types",
"python_pkg.moviepy_showcase._moviepy_video_effects",
"python_pkg.moviepy_showcase._moviepy_audio_output",
]
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def _reinstall_moviepy_mocks() -> None: def _reinstall_moviepy_mocks() -> None:
"""Ensure our moviepy mocks are active even if another conftest overwrote.""" """Ensure our moviepy mocks are active even if another conftest overwrote."""
_install_moviepy_mocks() _install_moviepy_mocks()
_reset_side_effects()
# Re-bind cached ``from moviepy import X`` references in source modules
# that may point to stale MagicMock children from a prior sys.modules entry.
for mod_name in _source_modules:
if mod_name in sys.modules:
importlib.reload(sys.modules[mod_name])

View File

@ -325,3 +325,25 @@ class TestArgosImportReload:
importlib.reload(_helpers) importlib.reload(_helpers)
# Restore original module state # Restore original module state
importlib.reload(_helpers) importlib.reload(_helpers)
class TestTorchImportReload:
"""Test import-time torch ImportError branch via reload."""
def test_torch_import_failure_reload(self) -> None:
"""Cover lines 19-20 (except ImportError: torch = None) via reload."""
import builtins
original_import = builtins.__import__
def _block_torch(name: str, *args: object, **kwargs: object) -> object:
if name == "torch":
msg = "mocked torch unavailable"
raise ImportError(msg)
return original_import(name, *args, **kwargs)
with patch.object(builtins, "__import__", side_effect=_block_torch):
importlib.reload(_helpers)
assert _helpers.torch is None
# Restore original module state
importlib.reload(_helpers)