diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..a33cfed --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,80 @@ +name: build + +on: + push: + branches: [main, master] + tags: ['v*'] + pull_request: + branches: [main, master] + +permissions: + contents: read + +jobs: + build-3ds: + name: Build .3dsx (devkitARM) + runs-on: ubuntu-latest + permissions: + contents: read + container: + image: devkitpro/devkitarm:latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Build + shell: bash + run: | + make + ls -la *.3dsx *.smdh + + - name: Upload .3dsx artifact + uses: actions/upload-artifact@v4 + with: + name: 3ds-zip-extractor-3dsx + path: | + *.3dsx + *.smdh + if-no-files-found: error + + host-tests: + name: Host unit tests (ASAN/UBSAN) + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install build deps + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends build-essential + + - name: Run host tests with sanitizers + run: make -C tests -f Makefile.host test-asan + + release: + name: Publish GitHub Release + needs: [build-3ds, host-tests] + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download build artifact + uses: actions/download-artifact@v4 + with: + name: 3ds-zip-extractor-3dsx + path: dist/ + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + files: | + dist/*.3dsx + dist/*.smdh + generate_release_notes: true diff --git a/.gitignore b/.gitignore index c214363..3e2d194 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,14 @@ # Build directories +build/ build/*.o build/*.d build/*.map build/*.lst *.elf -# *.smdh - REMOVED: We need to commit the SMDH file for the build to work + +# Build artifacts (published as Release assets, not tracked in git) +*.3dsx +*.smdh # Editor files *.swp @@ -30,3 +34,16 @@ lib/ # Nested duplicated directories _codeql_detected_source_root/ + +# Host test artifacts +tests/test_gdrive +tests/test_config +tests/test_archive_detect +tests/test_sha256 +tests/*.gcda +tests/*.gcno +tests/coverage/ +tests/fixtures/tiny.* +tests/fixtures/empty.bin +tests/fixtures/three_bytes.bin +tests/fixtures/not_an_archive.bin diff --git a/3ds-zip-extractor.3dsx b/3ds-zip-extractor.3dsx deleted file mode 100644 index ccd1483..0000000 Binary files a/3ds-zip-extractor.3dsx and /dev/null differ diff --git a/3ds-zip-extractor.smdh b/3ds-zip-extractor.smdh deleted file mode 100644 index d763264..0000000 Binary files a/3ds-zip-extractor.smdh and /dev/null differ diff --git a/CHANGELOG.md b/CHANGELOG.md index 43bacbe..4bd08c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,61 @@ # Changelog +## [Unreleased] + +### Added +- **Modular source layout.** `source/main.c` has been split into focused + modules with public headers in `include/`: + `led`, `gdrive`, `config`, `download`, `file_browser`, `queue`, + `integrity`, plus a pure `archive_extractor_detect` module that's + reusable on the host. +- **Optional integrity check.** A URL line in `config.txt` may now end with + ` sha256:<64-hex>` to verify the downloaded file. Mismatches mark the + item as failed without extracting. +- **Configurable runtime limits.** New optional config keys + `max_urls`, `download_buffer_kb`, `connect_timeout_s` (defaults: 100, + 128, 30). Values out of range are clamped, never rejected. +- **Per-run unique temp paths.** Downloads now land in + `sdmc:/3ds/zip-extractor/tmp/run__.part` instead of a single + shared `temp_download.tmp`. Orphan `.part` files are cleaned up at + startup and shutdown. +- **Honest stubs.** `umask` / `getpwnam` / `getgrnam` / `LZ4_*` now log a + one-shot warning to `stderr` the first time they're hit so unexpected + use is visible. +- **Off-target unit tests.** A new `tests/` directory builds with a plain + host C compiler (no devkitARM, no 3DS) and exercises the pure modules + with vendored Unity. Run with `make -C tests -f Makefile.host test` + (or `test-asan` for ASan/UBSan, or `coverage` for an `lcov` HTML + report). +- **CI**. New `.github/workflows/build.yml` builds the `.3dsx` in the + `devkitpro/devkitarm:latest` image, runs the host test suite under + ASan/UBSan, uploads `.3dsx`/`.smdh` as build artifacts, and publishes + a GitHub Release on `v*` tags. + +### Changed +- **Hardened extraction.** libarchive is now configured with + `ARCHIVE_EXTRACT_SECURE_NODOTDOT | + ARCHIVE_EXTRACT_SECURE_SYMLINKS | + ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS` to mitigate zip-slip and + symlink-based attacks on top of the previous protections. +- **Resume hardening.** The HTTP resume path now detects servers that + reply with `200 OK` instead of `206 Partial Content` and restarts the + download from zero rather than appending to a stale prefix. +- **Config parser.** Lines longer than `MAX_URL_LENGTH` are now drained + to the next `\n` and recorded as a single (truncated, NUL-terminated) + entry instead of splitting into bogus extra "URLs". UTF-8 BOMs on the + first line are skipped. +- **Build artifacts no longer tracked.** `.3dsx` and `.smdh` are now + ignored by git and produced fresh by every build; releases ship them + as Release assets. + +### Removed +- The hand-rolled ZIP/zlib path (`extract_zip_file`, `mkdir_recursive`, + `ZIP_LOCAL_SIGNATURE`, manual `inflate`) is gone from `main.c`. All + archive types — ZIP included — now go through the libarchive + extractor. + +--- + ## [1.0] - 2026-02-05 ### First Stable Release diff --git a/CLAUDE.md b/CLAUDE.md index e6856ee..65d3f2b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,8 +1,8 @@ -> **Stato attuale (2026-04-30):** questo documento descrive lo stato **target** del -> repository dopo il refactor pianificato (vedi prompt di lavoro nelle issue/PR). -> Alcuni moduli marcati `[post-refactor]` non esistono ancora nel codice: -> al momento `source/main.c` è monolitico e contiene tutta la logica. -> Aggiornare questo file mano a mano che il refactor procede. +> **Stato attuale (2026-04-30):** il refactor modulare è stato completato. +> Tutti i moduli elencati nella sezione 3 esistono in `source/` e in +> `include/`, la build con `make` è verde su `devkitpro/devkitarm:latest` +> e la suite host test in `tests/` passa con ASan/UBSan. Aggiornare questo +> file quando si introducono nuovi moduli o si cambiano comandi di build. > > # CLAUDE.md @@ -48,14 +48,16 @@ L'applicazione viene distribuita come `.3dsx` da lanciare dall'**Homebrew Launch . ├── source/ # Codice C target 3DS │ ├── main.c # Entry point + state machine principale -│ ├── archive_extractor.c # Wrapper libarchive (multi-formato) +│ ├── archive_extractor.c # Driver libarchive (estrazione multi-formato) +│ ├── archive_extractor_detect.c # Magic-byte sniffing (puro, host-testabile) │ ├── gui.c # Rendering citro2d (top + bottom screen) -│ ├── config.c # Parser config.txt [post-refactor] -│ ├── download.c # libcurl + retry [post-refactor] -│ ├── gdrive.c # Conversione URL Google Drive [post-refactor] -│ ├── file_browser.c # File browser SD card [post-refactor] -│ ├── led.c # Notifiche LED MCU [post-refactor] -│ └── queue.c # Gestione coda download [post-refactor] +│ ├── config.c # Parser config.txt (puro, host-testabile) +│ ├── download.c # libcurl + retry + resume +│ ├── gdrive.c # Conversione URL Google Drive (puro) +│ ├── integrity.c # SHA-256 + verify_integrity (mbedtls/host) +│ ├── file_browser.c # File browser SD card +│ ├── led.c # Notifiche LED MCU +│ └── queue.c # Rendering coda di download ├── include/ # Header pubblici corrispondenti a source/ ├── tests/ # Unit test off-target (host build) │ ├── Makefile.host diff --git a/Makefile b/Makefile index 2798a62..3eb1cfc 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,7 @@ GRAPHICS := gfx APP_TITLE := 3DS Zip Extractor APP_DESCRIPTION := Download and extract archives APP_AUTHOR := Marcogn +ICON := icon.png #--------------------------------------------------------------------------------- # options for code generation diff --git a/README.md b/README.md index a6b4c12..10d67c5 100644 --- a/README.md +++ b/README.md @@ -50,19 +50,31 @@ extract_path=sdmc:/extracted/ auto_retry=true max_retries=3 +# Optional limits (defaults shown) +# max_urls=100 +# download_buffer_kb=128 +# connect_timeout_s=30 + # Add URLs below https://example.com/file.zip + +# Optional: integrity check — append " sha256:<64-hex>" to a URL +https://example.com/strict.zip sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 ``` +The format is **backwards-compatible with v1.0** config files. + --- ## Controls | Button | Action | |--------|--------| -| A | Start/Confirm | +| A | Start / Confirm | | B | Cancel | | X | View queue | +| Y | (in queue view) Mark failed items as skipped | +| L / R | (in queue view) Page through URLs | | SELECT | File browser | | START | Exit | | D-Pad | Navigate | @@ -71,11 +83,36 @@ https://example.com/file.zip ## Building +### Native (devkitPRO) + ```bash -# Requires devkitPRO +# Requires devkitPRO + devkitARM + portlibs 3DS make ``` +### Docker (no local devkitPRO needed) + +```bash +docker run --rm -v "$PWD":/src -w /src devkitpro/devkitarm:latest make +``` + +This is the same image used by CI; useful for reproducible builds. + +### Host unit tests + +The pure modules (`config`, `gdrive`, `integrity`, archive detection) +have an off-target unit-test suite that runs on a normal Linux/macOS +PC — no devkitARM, no 3DS: + +```bash +make -C tests -f Makefile.host test # plain build +make -C tests -f Makefile.host test-asan # with AddressSanitizer + UBSan +make -C tests -f Makefile.host coverage # gcov/lcov HTML report +``` + +The CI pipeline runs both `build-3ds` (Docker) and `host-tests` +(ASan/UBSan); both must be green for a PR to be merged. + --- ## License @@ -87,4 +124,5 @@ MIT License - see [LICENSE](LICENSE) ## Links - [Changelog](CHANGELOG.md) +- [Architecture](docs/ARCHITECTURE.md) - [Contributing](CONTRIBUTING.md) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..d8fdf7a --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,93 @@ +# Architecture + +> Snapshot of the post-refactor layout. Use this as the high-level map +> when adding a feature or tracking down a bug. + +## 1. Module map + +``` + ┌────────────────────────────────┐ + │ source/main.c │ + │ state machine, app lifecycle │ + └───────────────┬────────────────┘ + │ + ┌───────────┬───────────────┼───────────────┬─────────────┐ + ▼ ▼ ▼ ▼ ▼ + ┌─────────┐ ┌────────┐ ┌──────────────┐ ┌────────────┐ ┌─────────┐ + │ config │ │ gdrive │ │ download │ │ archive_* │ │ queue │ + │ (pure) │ │ (pure) │ │ (libcurl) │ │ extractor │ │ (UI) │ + └────┬────┘ └────────┘ └──────┬───────┘ └────┬───────┘ └─────────┘ + │ │ │ + │ ▼ ▼ + │ ┌────────────┐ ┌────────────────┐ + │ │ libcurl │ │ libarchive │ + │ │ + mbedtls │ │ + zlib/bz2/ │ + │ └────────────┘ │ xz/zstd │ + │ └────────────────┘ + ▼ + ┌──────────┐ ┌────────┐ ┌──────────────┐ ┌──────┐ + │integrity │ │ led │ │file_browser │ │ gui │ + │(mbedtls/ │ │ (MCU │ │ (sdmc files) │ │(C2D) │ + │ pure) │ │ hook) │ └──────────────┘ └──────┘ + └──────────┘ └────────┘ +``` + +## 2. Module responsibilities + +| Module | File(s) | Pure? | Responsibility | +| --- | --- | --- | --- | +| `config` | `source/config.c`, `include/config.h` | ✅ | Parse `config.txt`, apply defaults, expose `AppConfig` (settings + URL list). Backwards compatible with v1.0. | +| `gdrive` | `source/gdrive.c`, `include/gdrive.h` | ✅ | Convert Google Drive sharing URLs into direct-download URLs. Pass-through for everything else. | +| `integrity` | `source/integrity.c`, `include/integrity.h` | ✅ | SHA-256 of buffers/files, optional integrity check. Uses mbedtls on target, a vendored pure-C implementation on host. | +| `archive_extractor_detect` | `source/archive_extractor_detect.c`, `include/archive_extractor.h` | ✅ | Magic-byte sniffing for ZIP/TAR/GZIP/BZIP2/XZ/ZSTD/7Z/RAR. No libarchive dependency, host-testable. | +| `archive_extractor` | `source/archive_extractor.c` | ❌ (libarchive) | Driver around `libarchive` for extraction. Ships honest stubs for `umask`/`getpwnam`/`getgrnam`/LZ4 missing on devkitARM. | +| `download` | `source/download.c`, `include/download.h` | ❌ (libcurl) | Run a `curl` transfer to a unique `*.part` file under `sdmc:/3ds/zip-extractor/tmp/`. Implements resume (Range/206) with 200 fallback, configurable buffer + connect timeout. | +| `led` | `source/led.c`, `include/led.h` | ❌ (libctru) | Thin wrapper for the MCUHWC LED notifications. | +| `file_browser` | `source/file_browser.c`, `include/file_browser.h` | ❌ (citro2d) | SD card directory browser (used to choose extraction path). | +| `queue` | `source/queue.c`, `include/queue.h` | ❌ (citro2d) | Renders the download/queue status screen on the top screen. `DownloadQueue` is just an alias for `AppConfig`. | +| `gui` | `source/gui.c`, `include/gui.h` | ❌ (citro2d/3d) | Common rendering helpers (status, menu, progress, error). Owns the dark-blue theme constants. | +| `main` | `source/main.c` | ❌ | App lifecycle: init/shutdown, state machine `MENU → BROWSER/QUEUE/RUNNING → SUMMARY → MENU/EXIT`, single-thread cooperative loop. | + +## 3. Build pipeline + +- Target: `make` invokes the devkitARM rules from `$DEVKITARM/3ds_rules`. + All `source/*.c` are compiled and linked against + `libcitro2d`, `libcitro3d`, `libcurl`, `libmbedtls`, `libarchive`, + `liblzma`, `libbz2`, `libzstd`, `libz`, `libctru`. Output: + `3ds-zip-extractor.{elf,3dsx,smdh}`. +- Host tests: `make -C tests -f Makefile.host` compiles only the *pure* + modules (`config`, `gdrive`, `integrity`, `archive_extractor_detect`) + plus vendored Unity, with `-DHOST_BUILD=1`. No 3DS dependency. + +## 4. Data flow for a single URL + +``` +config.txt ──► read_config_file ──► AppConfig.items[i] + │ (url, sha256_hex, state) + ▼ + download_make_temp_path + │ + ▼ + convert_gdrive_url ─► download_file ──► curl + │ (resume / 200 fallback) + ▼ + verify_integrity (if hash present) + │ + ▼ + detect_archive_type + │ + ▼ + extract_archive_libarchive + │ + ▼ + led_notification_green +``` + +## 5. Threading model + +The application is intentionally **single-thread cooperative**. +`aptMainLoop()` drives the main loop; long operations (`curl_easy_perform`, +`extract_archive_libarchive`) yield only inside their own libraries. +The progress/cancel callbacks call `hidScanInput` once per chunk to +keep the UI responsive. Adding threads would require careful work +around APT/HID/citro2d ownership and is explicitly out of scope. diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..38ce84d --- /dev/null +++ b/include/config.h @@ -0,0 +1,75 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#include +#include + +// Hard limits used to size the in-memory configuration. +// `max_urls` in `AppConfig` may further reduce the number of URLs accepted +// at runtime (clamped to MAX_URLS). +#define MAX_URLS 100 +#define MAX_URL_LENGTH 512 +#define MAX_PATH_LENGTH 256 +#define SHA256_HEX_LEN 64 // 32 bytes hex-encoded + +// Per-URL download state (used by the queue/UI; lives in the config to +// keep struct size in one place). +typedef enum { + DOWNLOAD_PENDING = 0, + DOWNLOAD_IN_PROGRESS, + DOWNLOAD_COMPLETED, + DOWNLOAD_FAILED, + DOWNLOAD_SKIPPED +} DownloadState; + +// One queued download plus optional integrity hash. +typedef struct { + char url[MAX_URL_LENGTH]; + DownloadState state; + char error_msg[128]; + // SHA256 hex digest, lowercase, NUL-terminated. Empty string if not provided. + char sha256_hex[SHA256_HEX_LEN + 1]; +} DownloadItem; + +// Application configuration (settings + URL list). +// +// Format of the config file is line-oriented: +// - lines starting with `#` are comments +// - blank lines are ignored +// - `key=value` for known settings (unknown keys are ignored with no error) +// - any other line is treated as a URL, optionally followed by +// ` sha256:` for integrity checking +// +// Backwards compatible with the v1.0 format (extract_path/auto_retry/max_retries +// + bare URLs). +typedef struct { + DownloadItem items[MAX_URLS]; + int count; + + // Settings + char extract_path[MAX_PATH_LENGTH]; + bool auto_retry; + int max_retries; + + // Phase 2.10 — configurable limits, with safe defaults. + int max_urls; // default 100 (= MAX_URLS) + int download_buffer_kb; // default 128 + int connect_timeout_s; // default 30 +} AppConfig; + +// Read a configuration file into `cfg`. Defaults are applied first so an +// empty/missing file still yields a usable config. +// +// Returns the number of URLs read on success, or -1 if the file does not +// exist (or cannot be opened). The defaults are still applied to `cfg` +// in that case. +int read_config_file(const char* file_path, AppConfig* cfg); + +// Apply defaults to `cfg`, leaving `count == 0` and no URLs. +void config_apply_defaults(AppConfig* cfg); + +// Write a commented example configuration to `file_path`. Returns true on +// success. +bool create_example_config(const char* file_path); + +#endif // CONFIG_H diff --git a/include/download.h b/include/download.h new file mode 100644 index 0000000..8460663 --- /dev/null +++ b/include/download.h @@ -0,0 +1,28 @@ +#ifndef DOWNLOAD_H +#define DOWNLOAD_H + +#include <3ds.h> +#include + +#include "config.h" + +// Download `url` to `output_path`, with optional resume and progress callback. +// +// `*cancelled` is set to true if the user pressed B during download. +// `current` and `total` are the queue position passed through to the GUI. +// Buffer size and connect timeout come from `cfg`. +// +// Returns 0 on success, -1 on hard failure, -2 on user cancel. +Result download_file(const AppConfig* cfg, + const char* url, const char* output_path, + bool* cancelled, int current, int total); + +// Build the per-run unique temporary download path under +// `sdmc:/3ds/zip-extractor/tmp/`. The directory is created if missing. +// `out` will receive a NUL-terminated path; `out_size` must be >= 96. +void download_make_temp_path(char* out, size_t out_size); + +// Remove orphaned `.part` files from previous runs in the temp directory. +void download_cleanup_orphans(void); + +#endif // DOWNLOAD_H diff --git a/include/file_browser.h b/include/file_browser.h new file mode 100644 index 0000000..ac21483 --- /dev/null +++ b/include/file_browser.h @@ -0,0 +1,35 @@ +#ifndef FILE_BROWSER_H +#define FILE_BROWSER_H + +#include + +#include "config.h" // MAX_PATH_LENGTH + +#define MAX_DIR_ENTRIES 100 + +typedef struct { + char name[256]; + bool is_directory; +} DirEntry; + +typedef struct { + DirEntry entries[MAX_DIR_ENTRIES]; + int count; + int selected; + char current_path[MAX_PATH_LENGTH]; +} FileBrowser; + +// Initialise the browser at the given starting path. +void init_file_browser(FileBrowser* browser, const char* start_path); + +// Load the contents of `browser->current_path`. Returns the entry count, +// or -1 if the directory cannot be opened. Entries are sorted with +// directories first, then alphabetically. +int load_directory(FileBrowser* browser); + +// Render the browser screen. citro2d-only; not built on host. +#ifndef HOST_BUILD +void display_file_browser(FileBrowser* browser, int scroll_offset); +#endif + +#endif // FILE_BROWSER_H diff --git a/include/gdrive.h b/include/gdrive.h new file mode 100644 index 0000000..f965182 --- /dev/null +++ b/include/gdrive.h @@ -0,0 +1,22 @@ +#ifndef GDRIVE_H +#define GDRIVE_H + +#include + +// Convert a Google Drive sharing URL into a direct-download URL. +// +// Supported input formats: +// - https://drive.google.com/file/d//view +// - https://drive.google.com/open?id= +// - https://drive.google.com/uc?id=&export=download (idempotent) +// +// Folder URLs (https://drive.google.com/drive/folders/...) are NOT +// converted; the original URL is copied through unchanged. +// +// Non-Google-Drive URLs are copied through unchanged. +// +// `output_url` is always NUL-terminated as long as `output_size > 0`. +// Safe against NULL inputs (no-op). +void convert_gdrive_url(const char* input_url, char* output_url, size_t output_size); + +#endif // GDRIVE_H diff --git a/include/integrity.h b/include/integrity.h new file mode 100644 index 0000000..1a05ee1 --- /dev/null +++ b/include/integrity.h @@ -0,0 +1,27 @@ +#ifndef INTEGRITY_H +#define INTEGRITY_H + +#include +#include +#include + +#define SHA256_DIGEST_BYTES 32 + +// Compute SHA-256 of `data`/`len` and write the lowercase hex digest +// (64 chars + NUL) to `out_hex`. `out_hex` must have room for at least +// 65 bytes. +// +// On the 3DS target this uses mbedtls (already in portlibs); on host +// builds it uses the same vendored constants in pure C so the unit +// tests don't need any extra dependency. +void sha256_hex(const void* data, size_t len, char* out_hex); + +// Compute SHA-256 of an open file (read in chunks). Returns true on +// success; on failure `out_hex[0]` is set to NUL. +bool sha256_hex_file(const char* path, char* out_hex); + +// Verify the SHA-256 of `path` against `expected_hex` (64 lowercase hex +// chars). Returns true on match. +bool verify_integrity(const char* path, const char* expected_hex); + +#endif // INTEGRITY_H diff --git a/include/led.h b/include/led.h new file mode 100644 index 0000000..b72249a --- /dev/null +++ b/include/led.h @@ -0,0 +1,20 @@ +#ifndef LED_H +#define LED_H + +#ifndef HOST_BUILD +#include <3ds.h> +#endif + +// LED notification helpers. +// +// On real 3DS hardware these will eventually drive the MCUHWC LED. The +// current implementation is a thin abstraction matching the historical +// behaviour: the pattern argument selects a colour family (1=green, +// 2=pink/red, 0=off). Centralising the calls here keeps the rest of +// the codebase free from MCU-specific details and makes it easy to +// plug in a real implementation later. +void led_notification_green(void); +void led_notification_pink(void); +void led_notification_off(void); + +#endif // LED_H diff --git a/include/queue.h b/include/queue.h new file mode 100644 index 0000000..ac24bb9 --- /dev/null +++ b/include/queue.h @@ -0,0 +1,19 @@ +#ifndef QUEUE_H +#define QUEUE_H + +#include "config.h" + +// `DownloadQueue` is an alias for `AppConfig`. The two concepts are tightly +// coupled (settings + the URL list with per-item state) so we keep a single +// underlying type. The alias preserves the original naming used throughout +// the codebase. +typedef AppConfig DownloadQueue; + +// Render the queue/status screen for `current_page` (paged 12 items per +// page). Implementation lives in queue.c (uses citro2d). On host builds +// this is unavailable. +#ifndef HOST_BUILD +void display_queue_status(DownloadQueue* queue, int current_page); +#endif + +#endif // QUEUE_H diff --git a/source/archive_extractor.c b/source/archive_extractor.c index 8a578be..2b6a860 100644 --- a/source/archive_extractor.c +++ b/source/archive_extractor.c @@ -1,4 +1,5 @@ #include "archive_extractor.h" +#include #include #include #include @@ -10,30 +11,60 @@ #include #include <3ds.h> -// Stub implementations for missing functions on 3DS -// umask is declared but not implemented in devkitARM +// Stub implementations for symbols missing on devkitARM. Each one logs a +// one-shot warning to stderr the first time it's called so that unexpected +// usage surfaces during testing instead of failing silently. +// +// These stubs are intentionally honest: they don't simulate the real +// behaviour, they just keep the link step happy and tell us when libarchive +// (or any other dependency) actually reaches for them. + +static void warn_once(bool* warned, const char* name) { + if (!*warned) { + *warned = true; + fprintf(stderr, + "[3ds-zip-extractor] stub: %s called (no-op on 3DS)\n", + name); + } +} + mode_t umask(mode_t mask) { - return 0022; // Return default umask + static bool warned = false; + warn_once(&warned, "umask"); + (void)mask; + return 0022; // Return default umask. } -// getpwnam is declared but not implemented in devkitARM struct passwd *getpwnam(const char *name) { + static bool warned = false; + warn_once(&warned, "getpwnam"); + (void)name; return NULL; } -// getgrnam is declared but not implemented in devkitARM struct group *getgrnam(const char *name) { + static bool warned = false; + warn_once(&warned, "getgrnam"); + (void)name; return NULL; } -// LZ4 functions are not available in 3DS portlibs +// LZ4 is not available in 3DS portlibs. The stubs return error so libarchive +// will refuse LZ4-compressed archives with a clear status code. int LZ4_decompress_safe(const char* src, char* dst, int compressedSize, int dstCapacity) { - return -1; // Not supported + static bool warned = false; + warn_once(&warned, "LZ4_decompress_safe"); + (void)src; (void)dst; (void)compressedSize; (void)dstCapacity; + return -1; } int LZ4_decompress_safe_usingDict(const char* src, char* dst, int srcSize, int dstCapacity, const char* dictStart, int dictSize) { - return -1; // Not supported + static bool warned = false; + warn_once(&warned, "LZ4_decompress_safe_usingDict"); + (void)src; (void)dst; (void)srcSize; (void)dstCapacity; + (void)dictStart; (void)dictSize; + return -1; } #define BUFFER_SIZE (128 * 1024) // 128KB buffer for extraction @@ -59,91 +90,8 @@ static int mkdir_recursive(const char* path) { return mkdir(tmp, 0777); } -// Detect archive type by file signature (magic bytes) -ArchiveType detect_archive_type(const char* file_path) { - FILE* f = fopen(file_path, "rb"); - if (!f) { - return ARCHIVE_UNKNOWN; - } - - unsigned char sig[16] = {0}; - size_t read = fread(sig, 1, sizeof(sig), f); - fclose(f); - - if (read < 4) { - return ARCHIVE_UNKNOWN; - } - - // ZIP: PK\x03\x04 or PK\x05\x06 (empty zip) - if (sig[0] == 'P' && sig[1] == 'K' && (sig[2] == 0x03 || sig[2] == 0x05)) { - return ARCHIVE_ZIP; - } - - // GZIP: 0x1f 0x8b - if (sig[0] == 0x1f && sig[1] == 0x8b) { - return ARCHIVE_GZIP; - } - - // BZIP2: BZ - if (sig[0] == 'B' && sig[1] == 'Z') { - return ARCHIVE_BZIP2; - } - - // XZ: 0xFD 0x37 0x7A 0x58 0x5A 0x00 - if (sig[0] == 0xFD && sig[1] == 0x37 && sig[2] == 0x7A && - sig[3] == 0x58 && sig[4] == 0x5A && sig[5] == 0x00) { - return ARCHIVE_XZ; - } - - // 7z: 37 7A BC AF 27 1C - if (sig[0] == 0x37 && sig[1] == 0x7A && sig[2] == 0xBC && - sig[3] == 0xAF && sig[4] == 0x27 && sig[5] == 0x1C) { - return ARCHIVE_7Z; - } - - // RAR: Rar!\x1a\x07 (RAR 4.x) or Rar!\x1a\x07\x01\x00 (RAR 5.x) - if (sig[0] == 'R' && sig[1] == 'a' && sig[2] == 'r' && sig[3] == '!' && - sig[4] == 0x1a && sig[5] == 0x07) { - return ARCHIVE_RAR; - } - - // TAR (ustar format): "ustar" at offset 257 - // Need to read more data for TAR detection - f = fopen(file_path, "rb"); - if (f) { - char ustar[6] = {0}; - fseek(f, 257, SEEK_SET); - if (fread(ustar, 1, 5, f) == 5) { - if (strncmp(ustar, "ustar", 5) == 0) { - fclose(f); - return ARCHIVE_TAR; - } - } - fclose(f); - } - - // ZSTD: 0x28 0xB5 0x2F 0xFD - if (sig[0] == 0x28 && sig[1] == 0xB5 && sig[2] == 0x2F && sig[3] == 0xFD) { - return ARCHIVE_ZSTD; - } - - return ARCHIVE_UNKNOWN; -} - -// Get archive type name -const char* get_archive_type_name(ArchiveType type) { - switch (type) { - case ARCHIVE_ZIP: return "ZIP"; - case ARCHIVE_TAR: return "TAR"; - case ARCHIVE_GZIP: return "GZIP/TAR.GZ"; - case ARCHIVE_BZIP2: return "BZIP2/TAR.BZ2"; - case ARCHIVE_XZ: return "XZ/TAR.XZ"; - case ARCHIVE_7Z: return "7-Zip"; - case ARCHIVE_RAR: return "RAR"; - case ARCHIVE_ZSTD: return "ZSTD/TAR.ZSTD"; - default: return "Unknown"; - } -} +// Detect / type-name / is_supported_archive moved to archive_extractor_detect.c +// (kept pure to allow host-side unit tests). // Extract archive using libarchive (supports multiple formats) int extract_archive_libarchive(const char* archive_path, const char* output_dir, @@ -185,10 +133,13 @@ int extract_archive_libarchive(const char* archive_path, const char* output_dir, return -3; } - // Use minimal options to avoid POSIX functions not available on 3DS + // Hardening: prevent zip-slip, symlink attacks, and absolute-path writes. + // ARCHIVE_EXTRACT_TIME is preserved so timestamps are restored. archive_write_disk_set_options(ext, ARCHIVE_EXTRACT_TIME | - ARCHIVE_EXTRACT_SECURE_NODOTDOT); + ARCHIVE_EXTRACT_SECURE_NODOTDOT | + ARCHIVE_EXTRACT_SECURE_SYMLINKS | + ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS); // Don't use standard lookup - causes issues with getpwnam/getgrnam on 3DS // archive_write_disk_set_standard_lookup(ext); @@ -264,9 +215,3 @@ int extract_archive_libarchive(const char* archive_path, const char* output_dir, return cancelled ? -4 : file_count; } - -// Check if file is a supported archive -bool is_supported_archive(const char* file_path) { - ArchiveType type = detect_archive_type(file_path); - return type != ARCHIVE_UNKNOWN; -} diff --git a/source/archive_extractor_detect.c b/source/archive_extractor_detect.c new file mode 100644 index 0000000..c4b4a59 --- /dev/null +++ b/source/archive_extractor_detect.c @@ -0,0 +1,98 @@ +// Pure archive detection (magic-byte sniffing). No libarchive, no 3ds.h +// dependency — host-testable. + +#include "archive_extractor.h" + +#include +#include + +ArchiveType detect_archive_type(const char* file_path) { + if (file_path == NULL) { + return ARCHIVE_UNKNOWN; + } + + FILE* f = fopen(file_path, "rb"); + if (!f) { + return ARCHIVE_UNKNOWN; + } + + unsigned char sig[16] = {0}; + size_t got = fread(sig, 1, sizeof(sig), f); + + if (got < 4) { + fclose(f); + return ARCHIVE_UNKNOWN; + } + + // ZIP: PK\x03\x04 or PK\x05\x06 (empty zip). + if (sig[0] == 'P' && sig[1] == 'K' && (sig[2] == 0x03 || sig[2] == 0x05)) { + fclose(f); + return ARCHIVE_ZIP; + } + // GZIP. + if (sig[0] == 0x1f && sig[1] == 0x8b) { + fclose(f); + return ARCHIVE_GZIP; + } + // BZIP2. + if (sig[0] == 'B' && sig[1] == 'Z') { + fclose(f); + return ARCHIVE_BZIP2; + } + // XZ. + if (got >= 6 && + sig[0] == 0xFD && sig[1] == 0x37 && sig[2] == 0x7A && + sig[3] == 0x58 && sig[4] == 0x5A && sig[5] == 0x00) { + fclose(f); + return ARCHIVE_XZ; + } + // 7z. + if (got >= 6 && + sig[0] == 0x37 && sig[1] == 0x7A && sig[2] == 0xBC && + sig[3] == 0xAF && sig[4] == 0x27 && sig[5] == 0x1C) { + fclose(f); + return ARCHIVE_7Z; + } + // RAR (4.x and 5.x both share the first 6 bytes). + if (got >= 6 && + sig[0] == 'R' && sig[1] == 'a' && sig[2] == 'r' && sig[3] == '!' && + sig[4] == 0x1a && sig[5] == 0x07) { + fclose(f); + return ARCHIVE_RAR; + } + // ZSTD. + if (sig[0] == 0x28 && sig[1] == 0xB5 && sig[2] == 0x2F && sig[3] == 0xFD) { + fclose(f); + return ARCHIVE_ZSTD; + } + + // TAR (ustar magic at offset 257). Reuse the open file handle. + char ustar[6] = {0}; + if (fseek(f, 257, SEEK_SET) == 0 && + fread(ustar, 1, 5, f) == 5 && + strncmp(ustar, "ustar", 5) == 0) { + fclose(f); + return ARCHIVE_TAR; + } + fclose(f); + + return ARCHIVE_UNKNOWN; +} + +const char* get_archive_type_name(ArchiveType type) { + switch (type) { + case ARCHIVE_ZIP: return "ZIP"; + case ARCHIVE_TAR: return "TAR"; + case ARCHIVE_GZIP: return "GZIP/TAR.GZ"; + case ARCHIVE_BZIP2: return "BZIP2/TAR.BZ2"; + case ARCHIVE_XZ: return "XZ/TAR.XZ"; + case ARCHIVE_7Z: return "7-Zip"; + case ARCHIVE_RAR: return "RAR"; + case ARCHIVE_ZSTD: return "ZSTD/TAR.ZSTD"; + default: return "Unknown"; + } +} + +bool is_supported_archive(const char* file_path) { + return detect_archive_type(file_path) != ARCHIVE_UNKNOWN; +} diff --git a/source/config.c b/source/config.c new file mode 100644 index 0000000..5de3258 --- /dev/null +++ b/source/config.c @@ -0,0 +1,254 @@ +#include "config.h" + +#include +#include +#include +#include +#include // strncasecmp (POSIX) + +#define DEFAULT_EXTRACT_PATH "sdmc:/extracted/" + +// --- Internal helpers ------------------------------------------------------ + +// Trim trailing CR/LF in place. +static void strip_eol(char* s, size_t* len_inout) { + size_t len = *len_inout; + while (len > 0 && (s[len - 1] == '\n' || s[len - 1] == '\r')) { + s[--len] = '\0'; + } + *len_inout = len; +} + +// Trim trailing ASCII whitespace in place. +static void rtrim(char* s) { + size_t len = strlen(s); + while (len > 0) { + unsigned char c = (unsigned char)s[len - 1]; + if (c == ' ' || c == '\t') { + s[--len] = '\0'; + } else { + break; + } + } +} + +// Skip a single UTF-8 BOM (EF BB BF) at the start of `s` if present. +static char* skip_bom(char* s) { + if ((unsigned char)s[0] == 0xEF && + (unsigned char)s[1] == 0xBB && + (unsigned char)s[2] == 0xBF) { + return s + 3; + } + return s; +} + +// Match `prefix` at the start of `s`. Returns pointer to value after the +// prefix, or NULL if not a match. +static const char* match_prefix(const char* s, const char* prefix) { + size_t pl = strlen(prefix); + if (strncmp(s, prefix, pl) == 0) { + return s + pl; + } + return NULL; +} + +// Parse a "true"/"false"/"1"/"0" boolean. Unknown values default to `dflt`. +static bool parse_bool(const char* v, bool dflt) { + if (v == NULL) return dflt; + if (strcmp(v, "true") == 0 || strcmp(v, "1") == 0) return true; + if (strcmp(v, "false") == 0 || strcmp(v, "0") == 0) return false; + return dflt; +} + +// Clamp helper. +static int clamp_int(int v, int lo, int hi) { + if (v < lo) return lo; + if (v > hi) return hi; + return v; +} + +// Split a URL line into URL and optional sha256 hex digest. +// Recognises the trailing ` sha256:<64hex>` token (case-insensitive prefix, +// hex digits required to be exactly 64). On match, the URL portion is +// truncated in `line` and `out_hash` is populated (lowercase). If no valid +// hash is found, `out_hash[0]` is left as NUL. +static void extract_sha256(char* line, char* out_hash) { + out_hash[0] = '\0'; + + // Find the last whitespace-separated token starting with sha256: + // We scan for " sha256:" (case-insensitive) so the URL itself can + // contain "sha256" without issue. + char* p = line; + char* match = NULL; + while (*p) { + if ((*p == ' ' || *p == '\t') && + (strncasecmp(p + 1, "sha256:", 7) == 0)) { + match = p; + } + p++; + } + if (match == NULL) { + return; + } + + const char* hex = match + 1 + 7; // skip the space and "sha256:" + // Validate that the remainder is exactly 64 hex chars (allow trailing ws). + size_t hex_len = 0; + while (hex[hex_len] != '\0' && hex[hex_len] != ' ' && hex[hex_len] != '\t') { + if (!isxdigit((unsigned char)hex[hex_len])) { + return; // not a clean hex token — leave URL untouched + } + hex_len++; + } + if (hex_len != SHA256_HEX_LEN) { + return; + } + + // Copy lowercase digest. + for (size_t i = 0; i < SHA256_HEX_LEN; i++) { + out_hash[i] = (char)tolower((unsigned char)hex[i]); + } + out_hash[SHA256_HEX_LEN] = '\0'; + + // Truncate the line at the match (drop trailing spaces too). + *match = '\0'; + rtrim(line); +} + +// --- Public API ------------------------------------------------------------ + +void config_apply_defaults(AppConfig* cfg) { + if (cfg == NULL) return; + memset(cfg, 0, sizeof(*cfg)); + strncpy(cfg->extract_path, DEFAULT_EXTRACT_PATH, MAX_PATH_LENGTH - 1); + cfg->extract_path[MAX_PATH_LENGTH - 1] = '\0'; + cfg->auto_retry = false; + cfg->max_retries = 3; + cfg->max_urls = MAX_URLS; + cfg->download_buffer_kb = 128; + cfg->connect_timeout_s = 30; + cfg->count = 0; +} + +int read_config_file(const char* file_path, AppConfig* cfg) { + if (cfg == NULL) return -1; + config_apply_defaults(cfg); + + FILE* file = fopen(file_path, "r"); + if (!file) { + return -1; + } + + char line[MAX_URL_LENGTH]; + bool first_line = true; + + while (fgets(line, sizeof(line), file) != NULL) { + // Strip CR/LF. + size_t len = strlen(line); + bool line_was_truncated = (len == sizeof(line) - 1 && line[len - 1] != '\n'); + strip_eol(line, &len); + + // If the line exceeded MAX_URL_LENGTH, drain the rest of it so + // subsequent fgets calls start at the next real line. We then keep + // the truncated content as the URL/setting (it will be too long to + // be useful, but won't overflow buffers). + if (line_was_truncated) { + int c; + while ((c = fgetc(file)) != EOF && c != '\n') { + /* drop */ + } + } + + // Strip a leading BOM on the first line only. + char* p = line; + if (first_line) { + p = skip_bom(p); + first_line = false; + } + + // Skip blank lines and comments. + if (*p == '\0' || *p == '#') { + continue; + } + + // Settings (key=value) — order independent. + const char* v; + if ((v = match_prefix(p, "extract_path=")) != NULL) { + strncpy(cfg->extract_path, v, MAX_PATH_LENGTH - 1); + cfg->extract_path[MAX_PATH_LENGTH - 1] = '\0'; + continue; + } + if ((v = match_prefix(p, "auto_retry=")) != NULL) { + cfg->auto_retry = parse_bool(v, false); + continue; + } + if ((v = match_prefix(p, "max_retries=")) != NULL) { + cfg->max_retries = clamp_int(atoi(v), 0, 10); + continue; + } + if ((v = match_prefix(p, "max_urls=")) != NULL) { + cfg->max_urls = clamp_int(atoi(v), 1, MAX_URLS); + continue; + } + if ((v = match_prefix(p, "download_buffer_kb=")) != NULL) { + cfg->download_buffer_kb = clamp_int(atoi(v), 4, 4096); + continue; + } + if ((v = match_prefix(p, "connect_timeout_s=")) != NULL) { + cfg->connect_timeout_s = clamp_int(atoi(v), 1, 600); + continue; + } + + // Otherwise it's a URL, possibly with ` sha256:HEX` suffix. + if (cfg->count < cfg->max_urls && cfg->count < MAX_URLS) { + DownloadItem* it = &cfg->items[cfg->count]; + extract_sha256(p, it->sha256_hex); + // Defensive copy (truncate, no overflow). + strncpy(it->url, p, MAX_URL_LENGTH - 1); + it->url[MAX_URL_LENGTH - 1] = '\0'; + it->state = DOWNLOAD_PENDING; + it->error_msg[0] = '\0'; + cfg->count++; + } + // Else: silently drop excess URLs (clamped by max_urls). + } + + fclose(file); + return cfg->count; +} + +bool create_example_config(const char* file_path) { + FILE* file = fopen(file_path, "w"); + if (!file) { + return false; + } + + fprintf(file, "# 3DS Archive Extractor - Configuration File\n"); + fprintf(file, "# Lines starting with # are comments\n"); + fprintf(file, "#\n"); + fprintf(file, "# Settings:\n"); + fprintf(file, "extract_path=sdmc:/extracted/\n"); + fprintf(file, "auto_retry=true\n"); + fprintf(file, "max_retries=3\n"); + fprintf(file, "#\n"); + fprintf(file, "# Optional limits (defaults shown):\n"); + fprintf(file, "# max_urls=100\n"); + fprintf(file, "# download_buffer_kb=128\n"); + fprintf(file, "# connect_timeout_s=30\n"); + fprintf(file, "#\n"); + fprintf(file, "# Add your URLs below (one per line):\n"); + fprintf(file, "# Example:\n"); + fprintf(file, "# https://example.com/file.zip\n"); + fprintf(file, "# https://example.com/file.zip sha256:<64-hex-digits>\n"); + fprintf(file, "# https://drive.google.com/file/d/FILE_ID/view\n"); + fprintf(file, "#\n"); + fprintf(file, "# Supported formats:\n"); + fprintf(file, "# ZIP, TAR, TAR.GZ, TAR.BZ2, TAR.XZ, TAR.ZSTD\n"); + fprintf(file, "# 7Z, RAR, GZIP, BZIP2, XZ, ZSTD\n"); + fprintf(file, "#\n"); + fprintf(file, "# Add your URLs here:\n"); + fprintf(file, "\n"); + + fclose(file); + return true; +} diff --git a/source/download.c b/source/download.c new file mode 100644 index 0000000..69ff56f --- /dev/null +++ b/source/download.c @@ -0,0 +1,184 @@ +#include "download.h" + +#include +#include +#include +#include +#include +#include +#include <3ds.h> +#include + +#include "gdrive.h" +#include "gui.h" + +#define TEMP_DIR "sdmc:/3ds/zip-extractor/tmp" + +typedef struct { + FILE* file; + u64 downloaded; + u64 total; + bool resume; + // For server-200-when-resuming detection + bool first_chunk; +} DownloadData; + +// curl write callback. If we asked to resume but the server replied with +// 200 (full content), reset the file before writing the first chunk. +static size_t write_callback(void* contents, size_t size, size_t nmemb, void* userp) { + size_t realsize = size * nmemb; + DownloadData* data = (DownloadData*)userp; + + if (data->first_chunk && data->resume) { + // Will be reset elsewhere if needed; here we just record we've started. + data->first_chunk = false; + } + + size_t written = fwrite(contents, 1, realsize, data->file); + data->downloaded += written; + return written; +} + +// Progress + cancel-detection callback. +static int progress_callback(void* clientp, curl_off_t dltotal, curl_off_t dlnow, + curl_off_t ultotal, curl_off_t ulnow) { + (void)dlnow; (void)ultotal; (void)ulnow; + DownloadData* data = (DownloadData*)clientp; + if (dltotal > 0) { + data->total = dltotal; + } + + hidScanInput(); + if (hidKeysDown() & KEY_B) { + return 1; // abort + } + return 0; +} + +void download_make_temp_path(char* out, size_t out_size) { + if (out == NULL || out_size == 0) return; + mkdir("sdmc:/3ds", 0777); + mkdir("sdmc:/3ds/zip-extractor", 0777); + mkdir(TEMP_DIR, 0777); + + u64 ts = osGetTime(); + // libctru does not expose a real PID; use a counter + osGetTime to create + // a path that is unique per-run. + static unsigned int counter = 0; + counter++; + snprintf(out, out_size, "%s/run_%llu_%u.part", + TEMP_DIR, (unsigned long long)ts, counter); +} + +void download_cleanup_orphans(void) { + DIR* d = opendir(TEMP_DIR); + if (!d) return; + struct dirent* e; + char path[512]; + while ((e = readdir(d)) != NULL) { + // Remove any file ending in ".part" left from previous runs. + size_t n = strlen(e->d_name); + if (n > 5 && strcmp(e->d_name + n - 5, ".part") == 0) { + snprintf(path, sizeof(path), "%s/%s", TEMP_DIR, e->d_name); + remove(path); + } + } + closedir(d); +} + +Result download_file(const AppConfig* cfg, + const char* url, const char* output_path, + bool* cancelled, int current, int total) { + CURL* curl; + CURLcode res; + DownloadData data = {0}; + *cancelled = false; + data.first_chunk = true; + + long buffer_size = (long)(cfg ? cfg->download_buffer_kb : 128) * 1024L; + long connect_timeout = (long)(cfg ? cfg->connect_timeout_s : 30); + if (buffer_size < 4096) buffer_size = 4096; + + // Check if a partial file exists (for resume). + FILE* check_file = fopen(output_path, "rb"); + if (check_file) { + fseek(check_file, 0, SEEK_END); + long sz = ftell(check_file); + fclose(check_file); + if (sz > 0) { + data.downloaded = (u64)sz; + data.resume = true; + } + } + + data.file = fopen(output_path, data.resume ? "ab" : "wb"); + if (!data.file) { + return -1; + } + + curl = curl_easy_init(); + if (!curl) { + fclose(data.file); + return -1; + } + + char converted_url[512]; + convert_gdrive_url(url, converted_url, sizeof(converted_url)); + + curl_easy_setopt(curl, CURLOPT_URL, converted_url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback); + curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &data); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, buffer_size); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, connect_timeout); + // SSL verification disabled because the 3DS lacks a modern certificate + // store. Documented trade-off (see SECURITY.md). + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(curl, CURLOPT_USERAGENT, "3DS-Zip-Extractor/1.0"); + + if (data.resume && data.downloaded > 0) { + curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, (curl_off_t)data.downloaded); + } + + gui_draw_download(current, total, converted_url, data.downloaded, data.total); + res = curl_easy_perform(curl); + + // If we asked to resume but got 200 (full content), restart from scratch. + if (res == CURLE_OK && data.resume) { + long http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + if (http_code == 200) { + // Server ignored Range; close, truncate, retry. + fclose(data.file); + data.file = fopen(output_path, "wb"); + data.downloaded = 0; + data.resume = false; + if (!data.file) { + curl_easy_cleanup(curl); + return -1; + } + curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, (curl_off_t)0); + res = curl_easy_perform(curl); + } + } + + if (res == CURLE_OK) { + gui_draw_download(current, total, converted_url, data.downloaded, data.total); + } + + curl_easy_cleanup(curl); + fclose(data.file); + + if (res == CURLE_ABORTED_BY_CALLBACK) { + *cancelled = true; + return -2; + } + if (res != CURLE_OK) { + return -1; + } + return 0; +} diff --git a/source/file_browser.c b/source/file_browser.c new file mode 100644 index 0000000..8373e8b --- /dev/null +++ b/source/file_browser.c @@ -0,0 +1,133 @@ +#include "file_browser.h" + +#include +#include +#include +#include <3ds.h> +#include + +#include "gui.h" + +void init_file_browser(FileBrowser* browser, const char* start_path) { + strncpy(browser->current_path, start_path, MAX_PATH_LENGTH - 1); + browser->current_path[MAX_PATH_LENGTH - 1] = '\0'; + browser->count = 0; + browser->selected = 0; +} + +int load_directory(FileBrowser* browser) { + DIR* dir = opendir(browser->current_path); + if (!dir) { + return -1; + } + + browser->count = 0; + + // Add parent directory entry if not at root + if (strcmp(browser->current_path, "sdmc:/") != 0) { + strncpy(browser->entries[browser->count].name, "..", sizeof(browser->entries[0].name) - 1); + browser->entries[browser->count].name[sizeof(browser->entries[0].name) - 1] = '\0'; + browser->entries[browser->count].is_directory = true; + browser->count++; + } + + struct dirent* entry; + while ((entry = readdir(dir)) != NULL && browser->count < MAX_DIR_ENTRIES) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { + continue; + } + strncpy(browser->entries[browser->count].name, entry->d_name, + sizeof(browser->entries[0].name) - 1); + browser->entries[browser->count].name[sizeof(browser->entries[0].name) - 1] = '\0'; + browser->entries[browser->count].is_directory = (entry->d_type == DT_DIR); + browser->count++; + } + closedir(dir); + + // Sort: directories first, then alphabetically. + for (int i = 0; i < browser->count - 1; i++) { + for (int j = i + 1; j < browser->count; j++) { + bool swap = false; + if (browser->entries[i].is_directory && !browser->entries[j].is_directory) { + continue; + } + if (!browser->entries[i].is_directory && browser->entries[j].is_directory) { + swap = true; + } else if (strcmp(browser->entries[i].name, browser->entries[j].name) > 0) { + swap = true; + } + if (swap) { + DirEntry tmp = browser->entries[i]; + browser->entries[i] = browser->entries[j]; + browser->entries[j] = tmp; + } + } + } + + browser->selected = 0; + return browser->count; +} + +void display_file_browser(FileBrowser* browser, int scroll_offset) { + C3D_FrameBegin(C3D_FRAME_SYNCDRAW); + + C2D_TargetClear(g_top, COLOR_BG); + C2D_SceneBegin(g_top); + + C2D_TextBufClear(g_textBuf); + C2D_Text text; + float y = 5.0f; + + C2D_DrawRectSolid(0, 0, 0.5f, 400, 22, COLOR_ACCENT); + C2D_TextParse(&text, g_textBuf, " File Browser - Select Path"); + C2D_TextOptimize(&text); + C2D_DrawText(&text, C2D_WithColor, 5.0f, 3.0f, 0.5f, 0.5f, 0.5f, C2D_Color32(0, 0, 0, 255)); + y = 25.0f; + + char pathBuf[64]; + snprintf(pathBuf, sizeof(pathBuf), "%.50s", browser->current_path); + C2D_TextParse(&text, g_textBuf, pathBuf); + C2D_TextOptimize(&text); + C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.35f, 0.35f, COLOR_PENDING); + y += 15.0f; + + C2D_DrawRectSolid(10, y, 0.5f, 380, 1, COLOR_ACCENT); + y += 5.0f; + + int visible_lines = 10; + int start = scroll_offset; + int end = start + visible_lines; + if (end > browser->count) end = browser->count; + + for (int i = start; i < end; i++) { + char lineBuf[64]; + const char* type_marker = browser->entries[i].is_directory ? "/" : ""; + snprintf(lineBuf, sizeof(lineBuf), "%.45s%s", browser->entries[i].name, type_marker); + + if (i == browser->selected) { + C2D_DrawRectSolid(10, y - 1, 0.5f, 380, 14, COLOR_ACCENT); + C2D_TextParse(&text, g_textBuf, lineBuf); + C2D_TextOptimize(&text); + C2D_DrawText(&text, C2D_WithColor, 15.0f, y, 0.5f, 0.38f, 0.38f, C2D_Color32(0, 0, 0, 255)); + } else { + C2D_TextParse(&text, g_textBuf, lineBuf); + C2D_TextOptimize(&text); + C2D_DrawText(&text, C2D_WithColor, 15.0f, y, 0.5f, 0.38f, 0.38f, COLOR_TEXT); + } + y += 14.0f; + } + + y = 200.0f; + C2D_TextParse(&text, g_textBuf, "D-Pad: Navigate A: Enter Y: Select"); + C2D_TextOptimize(&text); + C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.35f, 0.35f, COLOR_PROGRESS); + y += 12.0f; + C2D_TextParse(&text, g_textBuf, "B: Cancel X: New Folder"); + C2D_TextOptimize(&text); + C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.35f, 0.35f, COLOR_TEXT); + + C2D_TargetClear(g_bottom, COLOR_BG); + C2D_SceneBegin(g_bottom); + + C3D_FrameEnd(0); +} diff --git a/source/gdrive.c b/source/gdrive.c new file mode 100644 index 0000000..33ded15 --- /dev/null +++ b/source/gdrive.c @@ -0,0 +1,73 @@ +#include "gdrive.h" + +#include +#include + +// Maximum size of a Google Drive file ID buffer used internally. +#define GDRIVE_MAX_ID_LEN 256 + +void convert_gdrive_url(const char* input_url, char* output_url, size_t output_size) { + if (output_url == NULL || output_size == 0) { + return; + } + output_url[0] = '\0'; + if (input_url == NULL) { + return; + } + + // Pass-through if not a Google Drive URL. + if (strstr(input_url, "drive.google.com") == NULL) { + strncpy(output_url, input_url, output_size - 1); + output_url[output_size - 1] = '\0'; + return; + } + + // Folder URLs are not downloadable as a single file. + if (strstr(input_url, "/folders/") != NULL) { + // Pass through unchanged; caller may emit a warning. + strncpy(output_url, input_url, output_size - 1); + output_url[output_size - 1] = '\0'; + return; + } + + char file_id[GDRIVE_MAX_ID_LEN]; + file_id[0] = '\0'; + + // Format: https://drive.google.com/file/d/FILE_ID/view + const char* id_start = strstr(input_url, "/file/d/"); + if (id_start != NULL) { + id_start += 8; // skip "/file/d/" + const char* id_end = strchr(id_start, '/'); + size_t id_len = id_end ? (size_t)(id_end - id_start) : strlen(id_start); + if (id_len > 0 && id_len < sizeof(file_id)) { + memcpy(file_id, id_start, id_len); + file_id[id_len] = '\0'; + } + } + + // Format: ...?id=FILE_ID&... or ...?id=FILE_ID at end + if (file_id[0] == '\0') { + id_start = strstr(input_url, "id="); + if (id_start != NULL) { + id_start += 3; // skip "id=" + const char* id_end = strpbrk(id_start, "&/ \t\n\r"); + size_t id_len = id_end ? (size_t)(id_end - id_start) : strlen(id_start); + if (id_len > 0 && id_len < sizeof(file_id)) { + memcpy(file_id, id_start, id_len); + file_id[id_len] = '\0'; + } + } + } + + if (file_id[0] != '\0') { + // confirm=t bypasses the virus-scan warning for files >100MB. + snprintf(output_url, output_size, + "https://drive.google.com/uc?export=download&id=%s&confirm=t", + file_id); + return; + } + + // Couldn't parse — fall back to the original URL. + strncpy(output_url, input_url, output_size - 1); + output_url[output_size - 1] = '\0'; +} diff --git a/source/integrity.c b/source/integrity.c new file mode 100644 index 0000000..e324c82 --- /dev/null +++ b/source/integrity.c @@ -0,0 +1,209 @@ +#include "integrity.h" + +#include +#include +#include + +// We support two backends: +// - 3DS / target build: mbedtls (already in portlibs) +// - host build: small public-domain SHA-256 implementation, used only by +// the unit tests so they don't need an extra dependency. +// +// The mbedtls path is preferred whenever available because it's the same +// implementation that ships with the 3DS firmware and curl on-device. + +#if defined(HOST_BUILD) || !defined(__3DS__) + +// ---- Pure-C SHA-256 (host) ----------------------------------------------- +// Compact reference implementation. Not constant-time, but integrity +// verification of downloaded archives is not a side-channel scenario. + +#include + +typedef struct { + uint32_t state[8]; + uint64_t bitcount; + uint8_t buffer[64]; +} sha256_ctx; + +static const uint32_t K256[64] = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +#define ROTR(x,n) (((x) >> (n)) | ((x) << (32-(n)))) + +static void sha256_transform(sha256_ctx* c, const uint8_t* d) { + uint32_t w[64], a, b, ce, dd, e, f, g, h, t1, t2; + for (int i = 0; i < 16; i++) { + w[i] = ((uint32_t)d[i*4] << 24) | ((uint32_t)d[i*4+1] << 16) | + ((uint32_t)d[i*4+2] << 8) | (uint32_t)d[i*4+3]; + } + for (int i = 16; i < 64; i++) { + uint32_t s0 = ROTR(w[i-15],7) ^ ROTR(w[i-15],18) ^ (w[i-15] >> 3); + uint32_t s1 = ROTR(w[i-2],17) ^ ROTR(w[i-2],19) ^ (w[i-2] >> 10); + w[i] = w[i-16] + s0 + w[i-7] + s1; + } + a = c->state[0]; b = c->state[1]; ce = c->state[2]; dd = c->state[3]; + e = c->state[4]; f = c->state[5]; g = c->state[6]; h = c->state[7]; + for (int i = 0; i < 64; i++) { + uint32_t S1 = ROTR(e,6) ^ ROTR(e,11) ^ ROTR(e,25); + uint32_t ch = (e & f) ^ (~e & g); + t1 = h + S1 + ch + K256[i] + w[i]; + uint32_t S0 = ROTR(a,2) ^ ROTR(a,13) ^ ROTR(a,22); + uint32_t mj = (a & b) ^ (a & ce) ^ (b & ce); + t2 = S0 + mj; + h = g; g = f; f = e; e = dd + t1; + dd = ce; ce = b; b = a; a = t1 + t2; + } + c->state[0] += a; c->state[1] += b; c->state[2] += ce; c->state[3] += dd; + c->state[4] += e; c->state[5] += f; c->state[6] += g; c->state[7] += h; +} + +static void sha256_init(sha256_ctx* c) { + c->state[0] = 0x6a09e667; c->state[1] = 0xbb67ae85; + c->state[2] = 0x3c6ef372; c->state[3] = 0xa54ff53a; + c->state[4] = 0x510e527f; c->state[5] = 0x9b05688c; + c->state[6] = 0x1f83d9ab; c->state[7] = 0x5be0cd19; + c->bitcount = 0; +} + +static void sha256_update(sha256_ctx* c, const uint8_t* data, size_t len) { + size_t buf_used = (size_t)((c->bitcount >> 3) & 63); + c->bitcount += (uint64_t)len * 8; + if (buf_used) { + size_t need = 64 - buf_used; + if (len < need) { + memcpy(c->buffer + buf_used, data, len); + return; + } + memcpy(c->buffer + buf_used, data, need); + sha256_transform(c, c->buffer); + data += need; len -= need; + } + while (len >= 64) { + sha256_transform(c, data); + data += 64; len -= 64; + } + if (len) memcpy(c->buffer, data, len); +} + +static void sha256_final(sha256_ctx* c, uint8_t out[32]) { + size_t buf_used = (size_t)((c->bitcount >> 3) & 63); + c->buffer[buf_used++] = 0x80; + if (buf_used > 56) { + memset(c->buffer + buf_used, 0, 64 - buf_used); + sha256_transform(c, c->buffer); + buf_used = 0; + } + memset(c->buffer + buf_used, 0, 56 - buf_used); + uint64_t bc = c->bitcount; + for (int i = 0; i < 8; i++) { + c->buffer[63 - i] = (uint8_t)(bc & 0xff); + bc >>= 8; + } + sha256_transform(c, c->buffer); + for (int i = 0; i < 8; i++) { + out[i*4] = (uint8_t)(c->state[i] >> 24); + out[i*4+1] = (uint8_t)(c->state[i] >> 16); + out[i*4+2] = (uint8_t)(c->state[i] >> 8); + out[i*4+3] = (uint8_t)(c->state[i]); + } +} + +static void compute_sha256(const void* data, size_t len, uint8_t out[32]) { + sha256_ctx c; + sha256_init(&c); + sha256_update(&c, (const uint8_t*)data, len); + sha256_final(&c, out); +} + +#else +// ---- mbedtls (target) ---------------------------------------------------- +#include + +static void compute_sha256(const void* data, size_t len, unsigned char out[32]) { + mbedtls_sha256_context ctx; + mbedtls_sha256_init(&ctx); + // 3rd arg: 0 = SHA-256, 1 = SHA-224. Compatible across mbedtls 2.x/3.x. + mbedtls_sha256_starts_ret(&ctx, 0); + mbedtls_sha256_update_ret(&ctx, (const unsigned char*)data, len); + mbedtls_sha256_finish_ret(&ctx, out); + mbedtls_sha256_free(&ctx); +} +#endif + +static void to_hex(const unsigned char* digest, char* out_hex) { + static const char* hex = "0123456789abcdef"; + for (int i = 0; i < SHA256_DIGEST_BYTES; i++) { + out_hex[i*2] = hex[digest[i] >> 4]; + out_hex[i*2 + 1] = hex[digest[i] & 0x0f]; + } + out_hex[SHA256_DIGEST_BYTES * 2] = '\0'; +} + +void sha256_hex(const void* data, size_t len, char* out_hex) { + if (out_hex == NULL) return; + unsigned char digest[SHA256_DIGEST_BYTES]; + compute_sha256(data ? data : "", data ? len : 0, digest); + to_hex(digest, out_hex); +} + +bool sha256_hex_file(const char* path, char* out_hex) { + if (out_hex == NULL) return false; + out_hex[0] = '\0'; + if (path == NULL) return false; + + FILE* f = fopen(path, "rb"); + if (!f) return false; + +#if defined(HOST_BUILD) || !defined(__3DS__) + sha256_ctx ctx; + sha256_init(&ctx); + unsigned char buf[8192]; + size_t n; + while ((n = fread(buf, 1, sizeof(buf), f)) > 0) { + sha256_update(&ctx, buf, n); + } + fclose(f); + unsigned char digest[SHA256_DIGEST_BYTES]; + sha256_final(&ctx, digest); +#else + mbedtls_sha256_context ctx; + mbedtls_sha256_init(&ctx); + mbedtls_sha256_starts_ret(&ctx, 0); + unsigned char buf[8192]; + size_t n; + while ((n = fread(buf, 1, sizeof(buf), f)) > 0) { + mbedtls_sha256_update_ret(&ctx, buf, n); + } + fclose(f); + unsigned char digest[SHA256_DIGEST_BYTES]; + mbedtls_sha256_finish_ret(&ctx, digest); + mbedtls_sha256_free(&ctx); +#endif + to_hex(digest, out_hex); + return true; +} + +bool verify_integrity(const char* path, const char* expected_hex) { + if (path == NULL || expected_hex == NULL || expected_hex[0] == '\0') { + return false; + } + char actual[SHA256_DIGEST_BYTES * 2 + 1]; + if (!sha256_hex_file(path, actual)) { + return false; + } + // Case-insensitive compare against the expected digest. + for (int i = 0; i < SHA256_DIGEST_BYTES * 2; i++) { + char e = (char)tolower((unsigned char)expected_hex[i]); + if (actual[i] != e) return false; + } + return expected_hex[SHA256_DIGEST_BYTES * 2] == '\0'; +} diff --git a/source/led.c b/source/led.c new file mode 100644 index 0000000..ec92d5b --- /dev/null +++ b/source/led.c @@ -0,0 +1,25 @@ +#include "led.h" + +// Internal: select an LED notification pattern. +// 0 = off, 1 = green (download + extraction completed), +// 2 = pink/red (download completed, before extraction). +// +// NOTE: actual MCUHWC LED control is not yet wired up here; this preserves +// the historical behaviour from main.c (the previous implementation also +// did not drive the MCU directly). The function signature is kept stable +// so a real implementation can drop in without further refactoring. +static void set_led_notification(unsigned char pattern) { + (void)pattern; +} + +void led_notification_green(void) { + set_led_notification(1); +} + +void led_notification_pink(void) { + set_led_notification(2); +} + +void led_notification_off(void) { + set_led_notification(0); +} diff --git a/source/main.c b/source/main.c index 77111c5..d096f73 100644 --- a/source/main.c +++ b/source/main.c @@ -2,849 +2,74 @@ #include #include #include -#include #include #include <3ds.h> #include #include #include -#include -#include "gui.h" + #include "archive_extractor.h" +#include "config.h" +#include "download.h" +#include "file_browser.h" +#include "gui.h" +#include "integrity.h" +#include "led.h" +#include "queue.h" -#define DOWNLOAD_BUFFER_SIZE (128 * 1024) // 128KB buffer -#define DEFAULT_EXTRACT_PATH "sdmc:/extracted/" -#define TEMP_DOWNLOAD_PATH "sdmc:/temp_download.tmp" #define CONFIG_FILE_PATH "sdmc:/3ds/zip-extractor/config.txt" -#define MAX_URLS 50 -#define MAX_URL_LENGTH 512 -#define MAX_PATH_LENGTH 256 -#define MAX_DIR_ENTRIES 100 -// Global GUI context for hybrid rendering +// Global GUI context for hybrid rendering. static GUI g_gui = {0}; static bool g_use_gui = false; -// Sleep mode handling -static bool enable_sleep_mode() { - // Disable sleep mode to continue downloading in background - APT_SetAppCpuTimeLimit(30); // 30% CPU limit for background - return true; -} - -static void restore_sleep_mode() { - APT_SetAppCpuTimeLimit(0); // Restore normal CPU usage -} - -// LED notification functions -static void set_led_notification(u8 pattern) { - // Use MCUHWC for LED control - // Pattern: 0 = off, 1-7 = various blink patterns - u8 led_state = 0; - - if (pattern == 1) { - // Green notification pattern - led_state = 1; // Blink pattern - } else if (pattern == 2) { - // Pink/Red notification pattern - led_state = 2; // Different blink pattern - } - - // Note: Actual LED control requires mcuHwcInit() and specific API calls - // This is a simplified version -} -static void led_notification_green() { - // Green LED: Download + Extraction completed - set_led_notification(1); -} - -static void led_notification_pink() { - // Pink/Red LED: Download completed (before extraction) - set_led_notification(2); -} - -static void led_notification_off() { - // Turn off LED notification - set_led_notification(0); -} - - -// Download states for queue management -typedef enum { - DOWNLOAD_PENDING, - DOWNLOAD_IN_PROGRESS, - DOWNLOAD_COMPLETED, - DOWNLOAD_FAILED, - DOWNLOAD_SKIPPED -} DownloadState; - -// Directory entry for file browser -typedef struct { - char name[256]; - bool is_directory; -} DirEntry; - -typedef struct { - DirEntry entries[MAX_DIR_ENTRIES]; - int count; - int selected; - char current_path[MAX_PATH_LENGTH]; -} FileBrowser; - -typedef struct { - FILE* file; - u64 downloaded; - u64 total; - bool resume; -} DownloadData; - +// Tracks the currently-extracting archive for the GUI callback. typedef struct { u64 extracted_files; - u64 current_size; char current_file[256]; } ExtractData; - -typedef struct { - char url[MAX_URL_LENGTH]; - DownloadState state; - char error_msg[128]; -} DownloadItem; - -typedef struct { - DownloadItem items[MAX_URLS]; - int count; - char extract_path[MAX_PATH_LENGTH]; - bool auto_retry; - int max_retries; -} DownloadQueue; - static ExtractData extract_data = {0}; -// Initialize file browser -static void init_file_browser(FileBrowser* browser, const char* start_path) { - strncpy(browser->current_path, start_path, MAX_PATH_LENGTH - 1); - browser->current_path[MAX_PATH_LENGTH - 1] = '\0'; - browser->count = 0; - browser->selected = 0; -} - -// Load directory contents into browser -static int load_directory(FileBrowser* browser) { - DIR* dir = opendir(browser->current_path); - if (!dir) { - return -1; - } - - browser->count = 0; - - // Add parent directory entry if not at root - if (strcmp(browser->current_path, "sdmc:/") != 0) { - strncpy(browser->entries[browser->count].name, "..", sizeof(browser->entries[0].name) - 1); - browser->entries[browser->count].is_directory = true; - browser->count++; - } - - struct dirent* entry; - while ((entry = readdir(dir)) != NULL && browser->count < MAX_DIR_ENTRIES) { - // Skip . and .. - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { - continue; - } - - strncpy(browser->entries[browser->count].name, entry->d_name, sizeof(browser->entries[0].name) - 1); - browser->entries[browser->count].name[sizeof(browser->entries[0].name) - 1] = '\0'; - browser->entries[browser->count].is_directory = (entry->d_type == DT_DIR); - browser->count++; - } - - closedir(dir); - - // Sort: directories first, then alphabetically - for (int i = 0; i < browser->count - 1; i++) { - for (int j = i + 1; j < browser->count; j++) { - bool swap = false; - - // Directories before files - if (browser->entries[i].is_directory && !browser->entries[j].is_directory) { - continue; - } - if (!browser->entries[i].is_directory && browser->entries[j].is_directory) { - swap = true; - } - // Alphabetical within same type - else if (strcmp(browser->entries[i].name, browser->entries[j].name) > 0) { - swap = true; - } - - if (swap) { - DirEntry temp = browser->entries[i]; - browser->entries[i] = browser->entries[j]; - browser->entries[j] = temp; - } - } - } - - browser->selected = 0; - return browser->count; -} - -// Display file browser using GUI -static void display_file_browser(FileBrowser* browser, int scroll_offset) { - C3D_FrameBegin(C3D_FRAME_SYNCDRAW); - - C2D_TargetClear(g_top, COLOR_BG); - C2D_SceneBegin(g_top); - - C2D_TextBufClear(g_textBuf); - C2D_Text text; - float y = 5.0f; - - // Title bar - C2D_DrawRectSolid(0, 0, 0.5f, 400, 22, COLOR_ACCENT); - C2D_TextParse(&text, g_textBuf, " File Browser - Select Path"); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 5.0f, 3.0f, 0.5f, 0.5f, 0.5f, C2D_Color32(0, 0, 0, 255)); - y = 25.0f; - - // Current path - char pathBuf[64]; - snprintf(pathBuf, sizeof(pathBuf), "%.50s", browser->current_path); - C2D_TextParse(&text, g_textBuf, pathBuf); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.35f, 0.35f, COLOR_PENDING); - y += 15.0f; - - C2D_DrawRectSolid(10, y, 0.5f, 380, 1, COLOR_ACCENT); - y += 5.0f; - - // File list - int visible_lines = 10; - int start = scroll_offset; - int end = start + visible_lines; - if (end > browser->count) end = browser->count; - - for (int i = start; i < end; i++) { - char lineBuf[64]; - const char* type_marker = browser->entries[i].is_directory ? "/" : ""; - snprintf(lineBuf, sizeof(lineBuf), "%.45s%s", browser->entries[i].name, type_marker); - - if (i == browser->selected) { - C2D_DrawRectSolid(10, y - 1, 0.5f, 380, 14, COLOR_ACCENT); - C2D_TextParse(&text, g_textBuf, lineBuf); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 15.0f, y, 0.5f, 0.38f, 0.38f, C2D_Color32(0, 0, 0, 255)); - } else { - C2D_TextParse(&text, g_textBuf, lineBuf); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 15.0f, y, 0.5f, 0.38f, 0.38f, COLOR_TEXT); - } - y += 14.0f; - } - - // Controls - y = 200.0f; - C2D_TextParse(&text, g_textBuf, "D-Pad: Navigate A: Enter Y: Select"); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.35f, 0.35f, COLOR_PROGRESS); - y += 12.0f; - C2D_TextParse(&text, g_textBuf, "B: Cancel X: New Folder"); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.35f, 0.35f, COLOR_TEXT); - - C2D_TargetClear(g_bottom, COLOR_BG); - C2D_SceneBegin(g_bottom); - - C3D_FrameEnd(0); -} - -// Forward declaration -static void convert_gdrive_url(const char* input_url, char* output_url, size_t output_size); - -/* -// Handle Google Drive large file confirmation -// NOTE: This function is currently not used but kept for future reference -static bool handle_gdrive_confirmation(const char* url, char* final_url, size_t final_url_size) { - // Check if URL is already a direct download link - if (strstr(url, "drive.google.com/uc") != NULL) { - strncpy(final_url, url, final_url_size - 1); - final_url[final_url_size - 1] = '\0'; - return true; - } - - // For large files, Google Drive requires a confirmation token - // We need to make a request and check for the confirmation page - CURL* curl = curl_easy_init(); - if (!curl) { - return false; - } - - // First, try the normal conversion - char converted[512]; - convert_gdrive_url(url, converted, sizeof(converted)); - - // For files >100MB, we need to extract the confirm token - // This is a simplified approach - in reality, you'd need to: - // 1. Make initial request - // 2. Parse HTML for confirm token - // 3. Make second request with token - - // For now, we'll just add a warning parameter that helps with some cases - if (strstr(converted, "?") != NULL) { - snprintf(final_url, final_url_size, "%s&confirm=t", converted); - } else { - snprintf(final_url, final_url_size, "%s?confirm=t", converted); - } - - curl_easy_cleanup(curl); - return true; -} -*/ - -// Function to read configuration file with settings and URLs -static int read_config_file(const char* file_path, DownloadQueue* queue) { - FILE* file = fopen(file_path, "r"); - if (!file) { - return -1; - } - - // Set defaults - strncpy(queue->extract_path, DEFAULT_EXTRACT_PATH, MAX_PATH_LENGTH - 1); - queue->extract_path[MAX_PATH_LENGTH - 1] = '\0'; - queue->auto_retry = false; - queue->max_retries = 3; - queue->count = 0; - - char line[MAX_URL_LENGTH]; - - while (fgets(line, sizeof(line), file) != NULL) { - // Remove trailing newline and carriage return - size_t len = strlen(line); - while (len > 0 && (line[len-1] == '\n' || line[len-1] == '\r')) { - line[len-1] = '\0'; - len--; - } - - // Skip empty lines and comments - if (len == 0 || line[0] == '#') { - continue; - } - - // Check for settings (format: setting=value) - if (strstr(line, "extract_path=") == line) { - strncpy(queue->extract_path, line + 13, MAX_PATH_LENGTH - 1); - queue->extract_path[MAX_PATH_LENGTH - 1] = '\0'; - continue; - } - - if (strstr(line, "auto_retry=") == line) { - queue->auto_retry = (strcmp(line + 11, "true") == 0 || strcmp(line + 11, "1") == 0); - continue; - } - - if (strstr(line, "max_retries=") == line) { - queue->max_retries = atoi(line + 12); - if (queue->max_retries < 0) queue->max_retries = 0; - if (queue->max_retries > 10) queue->max_retries = 10; - continue; - } - - // Otherwise, treat as URL - if (queue->count < MAX_URLS) { - strncpy(queue->items[queue->count].url, line, MAX_URL_LENGTH - 1); - queue->items[queue->count].url[MAX_URL_LENGTH - 1] = '\0'; - queue->items[queue->count].state = DOWNLOAD_PENDING; - queue->items[queue->count].error_msg[0] = '\0'; - queue->count++; - } - } - - fclose(file); - return queue->count; -} - -// Create example config file if it doesn't exist -static bool create_example_config(const char* file_path) { - FILE* file = fopen(file_path, "w"); - if (!file) { - return false; - } +// --- Sleep mode ----------------------------------------------------------- - // Write example configuration - fprintf(file, "# 3DS Archive Extractor - Configuration File\n"); - fprintf(file, "# Lines starting with # are comments\n"); - fprintf(file, "#\n"); - fprintf(file, "# Settings:\n"); - fprintf(file, "extract_path=sdmc:/extracted/\n"); - fprintf(file, "auto_retry=true\n"); - fprintf(file, "max_retries=3\n"); - fprintf(file, "#\n"); - fprintf(file, "# Add your URLs below (one per line):\n"); - fprintf(file, "# Example:\n"); - fprintf(file, "# https://example.com/file.zip\n"); - fprintf(file, "# https://drive.google.com/file/d/FILE_ID/view\n"); - fprintf(file, "#\n"); - fprintf(file, "# Supported formats:\n"); - fprintf(file, "# ZIP, TAR, TAR.GZ, TAR.BZ2, TAR.XZ, TAR.ZSTD\n"); - fprintf(file, "# 7Z, RAR, GZIP, BZIP2, XZ, ZSTD\n"); - fprintf(file, "#\n"); - fprintf(file, "# Add your URLs here:\n"); - fprintf(file, "\n"); - - fclose(file); - return true; +static void enable_sleep_mode(void) { + APT_SetAppCpuTimeLimit(30); // 30% CPU for background activity. } -// Display queue status using GUI -static void display_queue_status(DownloadQueue* queue, int current_page) { - C3D_FrameBegin(C3D_FRAME_SYNCDRAW); - - C2D_TargetClear(g_top, COLOR_BG); - C2D_SceneBegin(g_top); - - C2D_TextBufClear(g_textBuf); - C2D_Text text; - float y = 5.0f; - - // Title bar - C2D_DrawRectSolid(0, 0, 0.5f, 400, 22, COLOR_ACCENT); - C2D_TextParse(&text, g_textBuf, " Queue Status"); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 5.0f, 3.0f, 0.5f, 0.5f, 0.5f, C2D_Color32(0, 0, 0, 255)); - y = 25.0f; - - int items_per_page = 10; - int start = current_page * items_per_page; - int end = start + items_per_page; - if (end > queue->count) end = queue->count; - - char buf[64]; - snprintf(buf, sizeof(buf), "Showing %d-%d of %d", start + 1, end, queue->count); - C2D_TextParse(&text, g_textBuf, buf); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.35f, 0.35f, COLOR_PENDING); - y += 15.0f; - - for (int i = start; i < end; i++) { - const char* state_str = "?"; - u32 state_color = COLOR_TEXT; - - switch (queue->items[i].state) { - case DOWNLOAD_PENDING: state_str = "[ ]"; state_color = COLOR_PENDING; break; - case DOWNLOAD_IN_PROGRESS: state_str = "[>]"; state_color = COLOR_PROGRESS; break; - case DOWNLOAD_COMPLETED: state_str = "[OK]"; state_color = COLOR_SUCCESS; break; - case DOWNLOAD_FAILED: state_str = "[X]"; state_color = COLOR_ERROR; break; - case DOWNLOAD_SKIPPED: state_str = "[-]"; state_color = COLOR_PENDING; break; - } - - snprintf(buf, sizeof(buf), "%s %.42s", state_str, queue->items[i].url); - C2D_TextParse(&text, g_textBuf, buf); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.33f, 0.33f, state_color); - y += 13.0f; - } - - int total_pages = (queue->count + items_per_page - 1) / items_per_page; - if (total_pages == 0) total_pages = 1; - - y = 195.0f; - snprintf(buf, sizeof(buf), "Page %d/%d", current_page + 1, total_pages); - C2D_TextParse(&text, g_textBuf, buf); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.38f, 0.38f, COLOR_TEXT); - y += 14.0f; - - C2D_TextParse(&text, g_textBuf, "L/R: Page Y: Skip failed B: Back"); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.35f, 0.35f, COLOR_PROGRESS); - - C2D_TargetClear(g_bottom, COLOR_BG); - C2D_SceneBegin(g_bottom); - - C3D_FrameEnd(0); +static void restore_sleep_mode(void) { + APT_SetAppCpuTimeLimit(0); } -// Function to convert Google Drive URLs to direct download links -static void convert_gdrive_url(const char* input_url, char* output_url, size_t output_size) { - // Check if it's a Google Drive URL - if (strstr(input_url, "drive.google.com") != NULL) { - // Extract file ID from various Google Drive URL formats - char* id_start = NULL; - - // Format: https://drive.google.com/file/d/FILE_ID/view - if ((id_start = strstr(input_url, "/file/d/")) != NULL) { - id_start += 8; // Skip "/file/d/" - char* id_end = strchr(id_start, '/'); - if (id_end) { - size_t id_len = id_end - id_start; - char file_id_buf[256]; - strncpy(file_id_buf, id_start, id_len); - file_id_buf[id_len] = '\0'; - // Use confirm parameter for large files (>100MB) to bypass virus scan warning - snprintf(output_url, output_size, - "https://drive.google.com/uc?export=download&id=%s&confirm=t", - file_id_buf); - return; - } - } - - // Format: https://drive.google.com/open?id=FILE_ID - // Format: https://drive.google.com/uc?id=FILE_ID - if ((id_start = strstr(input_url, "id=")) != NULL) { - id_start += 3; // Skip "id=" - char* id_end = strpbrk(id_start, "&/ \t\n\r"); - if (id_end) { - size_t id_len = id_end - id_start; - char file_id_buf[256]; - if (id_len > 0 && id_len < sizeof(file_id_buf)) { - strncpy(file_id_buf, id_start, id_len); - file_id_buf[id_len] = '\0'; - snprintf(output_url, output_size, - "https://drive.google.com/uc?export=download&id=%s&confirm=t", - file_id_buf); - return; - } - } else { - // ID is at the end of URL - snprintf(output_url, output_size, - "https://drive.google.com/uc?export=download&id=%s&confirm=t", - id_start); - return; - } - } - - // Format: https://drive.google.com/drive/folders/... (not supported for download) - if (strstr(input_url, "/folders/") != NULL) { - printf("Warning: Folder URLs are not supported, only direct file links\n"); - } - } - - // Not a Google Drive URL or couldn't parse, use original - strncpy(output_url, input_url, output_size - 1); - output_url[output_size - 1] = '\0'; -} - -// Callback for writing downloaded data -static size_t write_callback(void* contents, size_t size, size_t nmemb, void* userp) { - size_t realsize = size * nmemb; - DownloadData* data = (DownloadData*)userp; - - size_t written = fwrite(contents, 1, realsize, data->file); - data->downloaded += written; - - return written; -} - -// Callback for download progress -static int progress_callback(void* clientp, curl_off_t dltotal, curl_off_t dlnow, - curl_off_t ultotal, curl_off_t ulnow) { - DownloadData* data = (DownloadData*)clientp; - - if (dltotal > 0) { - data->total = dltotal; - } - - // Check if user wants to cancel - hidScanInput(); - u32 kDown = hidKeysDown(); - if (kDown & KEY_B) { - return 1; // Abort download - } - - return 0; -} +// --- Extraction adapter --------------------------------------------------- -// Update download progress display using GUI (like fast-uninstall) -static void update_download_display(int current, int total, DownloadData* data, const char* url) { - gui_draw_download(current, total, url, data->downloaded, data->total); -} - -// Download file with resume support -static Result download_file(const char* url, const char* output_path, bool* cancelled, int current, int total) { - CURL* curl; - CURLcode res; - DownloadData data = {0}; - *cancelled = false; - - // Check if partial file exists - FILE* check_file = fopen(output_path, "rb"); - if (check_file) { - fseek(check_file, 0, SEEK_END); - data.downloaded = ftell(check_file); - fclose(check_file); - data.resume = true; - } - - // Open file for appending or writing - data.file = fopen(output_path, data.resume ? "ab" : "wb"); - if (!data.file) { - printf("Failed to open output file\n"); - return -1; - } - - curl = curl_easy_init(); - if (!curl) { - fclose(data.file); - return -1; - } - - // Convert Google Drive URLs if needed - char converted_url[512]; - convert_gdrive_url(url, converted_url, sizeof(converted_url)); - - curl_easy_setopt(curl, CURLOPT_URL, converted_url); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data); - curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); - curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback); - curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &data); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, DOWNLOAD_BUFFER_SIZE); - // Note: SSL verification is disabled due to certificate store limitations on 3DS - // This is a known trade-off for 3DS homebrew applications - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); - curl_easy_setopt(curl, CURLOPT_USERAGENT, "3DS-Zip-Extractor/1.0"); - - // Resume support - if (data.resume && data.downloaded > 0) { - curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, (curl_off_t)data.downloaded); - } - - // Initial display update - update_download_display(current, total, &data, converted_url); - - // Perform download with periodic display updates - res = curl_easy_perform(curl); - - // Final display update - if (res == CURLE_OK) { - update_download_display(current, total, &data, converted_url); - } - - curl_easy_cleanup(curl); - fclose(data.file); - - if (res == CURLE_ABORTED_BY_CALLBACK) { - *cancelled = true; - return -2; - } - - if (res != CURLE_OK) { - printf("Download failed: %s\n", curl_easy_strerror(res)); - return -1; - } - - return 0; -} - -// Simple ZIP structures (minimal implementation) -#pragma pack(1) -typedef struct { - u32 signature; // 0x04034b50 - u16 version; - u16 flags; - u16 compression; // 0=store, 8=deflate - u16 mod_time; - u16 mod_date; - u32 crc32; - u32 compressed_size; - u32 uncompressed_size; - u16 filename_len; - u16 extra_len; -} ZipLocalHeader; - -typedef struct { - u32 signature; // 0x02014b50 - u16 version_made; - u16 version_needed; - u16 flags; - u16 compression; - u16 mod_time; - u16 mod_date; - u32 crc32; - u32 compressed_size; - u32 uncompressed_size; - u16 filename_len; - u16 extra_len; - u16 comment_len; - u16 disk_start; - u16 internal_attr; - u32 external_attr; - u32 local_header_offset; -} ZipCentralHeader; -#pragma pack() - -#define ZIP_LOCAL_SIGNATURE 0x04034b50 -#define ZIP_CENTRAL_SIGNATURE 0x02014b50 -#define ZIP_END_SIGNATURE 0x06054b50 - -// Create directory recursively -static int mkdir_recursive(const char* path) { - char tmp[512]; - char* p = NULL; - size_t len; - - snprintf(tmp, sizeof(tmp), "%s", path); - len = strlen(tmp); - if (tmp[len - 1] == '/') - tmp[len - 1] = 0; - - for (p = tmp + 1; *p; p++) { - if (*p == '/') { - *p = 0; - mkdir(tmp, 0777); - *p = '/'; - } - } - return mkdir(tmp, 0777); -} - -// Extract single file from ZIP -static int extract_zip_file(FILE* zip, ZipLocalHeader* header, const char* output_dir) { - char filename[512]; - char fullpath[1024]; - - // Read filename - if (header->filename_len >= sizeof(filename)) { - printf("Filename too long\n"); - fseek(zip, header->filename_len + header->extra_len, SEEK_CUR); - return -1; - } - - fread(filename, 1, header->filename_len, zip); - filename[header->filename_len] = '\0'; - - // Skip extra field - fseek(zip, header->extra_len, SEEK_CUR); - - // Build full output path - snprintf(fullpath, sizeof(fullpath), "%s%s", output_dir, filename); - - // Check if it's a directory - if (filename[header->filename_len - 1] == '/') { - mkdir_recursive(fullpath); - fseek(zip, header->compressed_size, SEEK_CUR); - return 0; - } - - // Create parent directories - char dirpath[1024]; - snprintf(dirpath, sizeof(dirpath), "%s", fullpath); - char* last_slash = strrchr(dirpath, '/'); - if (last_slash) { - *last_slash = '\0'; - mkdir_recursive(dirpath); - } - - // Open output file - FILE* out = fopen(fullpath, "wb"); - if (!out) { - printf("Cannot create: %s\n", fullpath); - fseek(zip, header->compressed_size, SEEK_CUR); - return -1; - } - - // Extract based on compression method - if (header->compression == 0) { - // Stored (no compression) - char buffer[8192]; - u32 remaining = header->uncompressed_size; - while (remaining > 0) { - size_t to_read = (remaining < sizeof(buffer)) ? remaining : sizeof(buffer); - size_t read = fread(buffer, 1, to_read, zip); - if (read == 0) break; - fwrite(buffer, 1, read, out); - remaining -= read; - } - } else if (header->compression == 8) { - // Deflate compression - z_stream stream = {0}; - if (inflateInit2(&stream, -MAX_WBITS) != Z_OK) { - printf("inflateInit2 failed\n"); - fclose(out); - return -1; - } - - unsigned char in_buffer[8192]; - unsigned char out_buffer[8192]; - u32 remaining = header->compressed_size; - - while (remaining > 0) { - size_t to_read = (remaining < sizeof(in_buffer)) ? remaining : sizeof(in_buffer); - stream.avail_in = fread(in_buffer, 1, to_read, zip); - if (stream.avail_in == 0) break; - - stream.next_in = in_buffer; - remaining -= stream.avail_in; - - do { - stream.avail_out = sizeof(out_buffer); - stream.next_out = out_buffer; - - int ret = inflate(&stream, Z_NO_FLUSH); - if (ret == Z_STREAM_ERROR || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) { - printf("inflate error: %d\n", ret); - inflateEnd(&stream); - fclose(out); - return -1; - } - - size_t have = sizeof(out_buffer) - stream.avail_out; - fwrite(out_buffer, 1, have, out); - - } while (stream.avail_out == 0); - } - - inflateEnd(&stream); - } else { - printf("Unsupported compression: %d\n", header->compression); - fclose(out); - fseek(zip, header->compressed_size, SEEK_CUR); - return -1; - } - - fclose(out); - return 0; -} - -// Callback for extraction progress static bool extraction_progress_callback(int file_count, const char* current_file, void* user_data) { - int* params = (int*)user_data; - int current = params[0]; - int total = params[1]; - + (void)user_data; extract_data.extracted_files = file_count; strncpy(extract_data.current_file, current_file, sizeof(extract_data.current_file) - 1); extract_data.current_file[sizeof(extract_data.current_file) - 1] = '\0'; - // Update display using GUI gui_draw_extraction(current_file, file_count); - // Check for cancel hidScanInput(); if (hidKeysDown() & KEY_B) { - return true; // Cancel extraction + return true; // cancel } - - return false; // Continue extraction + return false; } -// Extract archive with progress tracking (multi-format support) -static Result extract_archive(const char* archive_path, const char* output_dir, int current, int total) { +// Extract `archive_path` into `output_dir`. Returns 0 on success, -1 on +// hard error, -2 if cancelled by user. +static Result extract_archive(const char* archive_path, const char* output_dir) { extract_data.extracted_files = 0; - extract_data.current_size = 0; extract_data.current_file[0] = '\0'; - // Detect archive type ArchiveType type = detect_archive_type(archive_path); const char* type_name = get_archive_type_name(type); - // Show extraction starting char msg[64]; snprintf(msg, sizeof(msg), "Extracting %s archive...", type_name); gui_draw_status("Archive Extractor for 3DS", msg); - // Check if format is supported if (type == ARCHIVE_UNKNOWN) { gui_draw_error("Unsupported Format", "ZIP, TAR, 7Z, RAR supported"); while (aptMainLoop()) { @@ -855,16 +80,11 @@ static Result extract_archive(const char* archive_path, const char* output_dir, return -1; } - // Extract using libarchive - int params[2] = {current, total}; int file_count = extract_archive_libarchive(archive_path, output_dir, - extraction_progress_callback, params); - - // Remove temp archive file + extraction_progress_callback, NULL); remove(archive_path); if (file_count == -4) { - // Cancelled by user gui_draw_status("Archive Extractor for 3DS", "Extraction cancelled!"); while (aptMainLoop()) { hidScanInput(); @@ -873,12 +93,10 @@ static Result extract_archive(const char* archive_path, const char* output_dir, } return -2; } - if (file_count < 0) { - // Error during extraction - char errMsg[64]; - snprintf(errMsg, sizeof(errMsg), "Extraction error: %d", file_count); - gui_draw_error("Extraction Failed", errMsg); + char err_msg[64]; + snprintf(err_msg, sizeof(err_msg), "Extraction error: %d", file_count); + gui_draw_error("Extraction Failed", err_msg); while (aptMainLoop()) { hidScanInput(); if (hidKeysDown() & KEY_A) break; @@ -887,44 +105,32 @@ static Result extract_archive(const char* archive_path, const char* output_dir, return -1; } - // Success - Trigger green LED notification led_notification_green(); - gui_draw_status("Extraction Complete!", "Press A to continue"); while (aptMainLoop()) { hidScanInput(); if (hidKeysDown() & KEY_A) break; } - return 0; } +// --- Main ----------------------------------------------------------------- + int main(int argc, char** argv) { - // Initialize graphics (like fast-uninstall) - gfxInitDefault(); + (void)argc; (void)argv; - // Initialize GUI with citro2d + gfxInitDefault(); g_use_gui = gui_init(&g_gui); - if (!g_use_gui) { - // Cannot continue without GUI gfxExit(); return 1; } - // Show initializing screen gui_draw_status("Archive Extractor for 3DS", "Initializing..."); - - // Initialize PTMU for LED notifications ptmuInit(); - - // Enable sleep mode support (continue downloads in background) enable_sleep_mode(); gui_draw_status("Archive Extractor for 3DS", "Initializing network..."); - - // Initialize networking - Result ret = 0; u32* socMemory = (u32*)memalign(0x1000, 0x100000); if (!socMemory) { gui_draw_error("Error", "Failed to allocate socket memory!"); @@ -937,9 +143,8 @@ int main(int argc, char** argv) { gfxExit(); return 1; } - - ret = socInit(socMemory, 0x100000); - if (ret != 0) { + + if (socInit(socMemory, 0x100000) != 0) { gui_draw_error("Network Error", "Failed to initialize network!"); while (aptMainLoop()) { hidScanInput(); @@ -951,17 +156,11 @@ int main(int argc, char** argv) { gfxExit(); return 1; } - - gui_draw_status("Archive Extractor for 3DS", "Initializing downloads..."); - // Initialize curl + gui_draw_status("Archive Extractor for 3DS", "Initializing downloads..."); curl_global_init(CURL_GLOBAL_ALL); - - const char* extract_path = DEFAULT_EXTRACT_PATH; - gui_draw_status("Archive Extractor for 3DS", "Initializing..."); - - // Allocate queue on heap to avoid stack overflow (structure is very large) + // Heap-allocated to keep large structures off the small 3DS stack. DownloadQueue* queue = (DownloadQueue*)calloc(1, sizeof(DownloadQueue)); if (!queue) { gui_draw_error("Memory Error", "Failed to allocate queue!"); @@ -979,106 +178,38 @@ int main(int argc, char** argv) { } gui_draw_status("Archive Extractor for 3DS", "Loading..."); - - // Create config directory if it doesn't exist mkdir("sdmc:/3ds", 0777); mkdir("sdmc:/3ds/zip-extractor", 0777); - // Ignore errors - directories may already exist - // Try to read configuration file - int url_count = read_config_file(CONFIG_FILE_PATH, queue); + // Sweep up any orphaned `.part` files from previous runs. + download_cleanup_orphans(); + int url_count = read_config_file(CONFIG_FILE_PATH, queue); - // If config doesn't exist, create an example one and EXIT + // First-run experience: create an example config and ask user to edit. if (url_count < 0) { gui_draw_status("Archive Extractor for 3DS", "Config not found! Creating..."); - - // Small delay so user sees the message for (int i = 0; i < 30; i++) gspWaitForVBlank(); if (create_example_config(CONFIG_FILE_PATH)) { - // Config created successfully - show message and force exit while (aptMainLoop()) { hidScanInput(); if (hidKeysDown() & KEY_START) break; - - // Show clear instructions - C3D_FrameBegin(C3D_FRAME_SYNCDRAW); - C2D_TargetClear(g_top, COLOR_BG); - C2D_SceneBegin(g_top); - C2D_TextBufClear(g_textBuf); - C2D_Text text; - float y = 10.0f; - - C2D_TextParse(&text, g_textBuf, "Config File Created!"); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.6f, 0.6f, COLOR_SUCCESS); - y += 30; - - C2D_DrawRectSolid(10, y, 0.5f, 380, 2, COLOR_ACCENT); - y += 15; - - C2D_TextParse(&text, g_textBuf, "Location:"); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.4f, 0.4f, COLOR_TEXT); - y += 16; - - C2D_TextParse(&text, g_textBuf, " sdmc:/3ds/zip-extractor/config.txt"); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.35f, 0.35f, COLOR_PENDING); - y += 25; - - C2D_TextParse(&text, g_textBuf, "What to do:"); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.4f, 0.4f, COLOR_TEXT); - y += 16; - - C2D_TextParse(&text, g_textBuf, " 1. Close this app (START)"); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.35f, 0.35f, COLOR_PENDING); - y += 14; - - C2D_TextParse(&text, g_textBuf, " 2. Edit config.txt on your SD card"); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.35f, 0.35f, COLOR_PENDING); - y += 14; - - C2D_TextParse(&text, g_textBuf, " 3. Add your download URLs"); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.35f, 0.35f, COLOR_PENDING); - y += 14; - - C2D_TextParse(&text, g_textBuf, " 4. Restart the app"); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.35f, 0.35f, COLOR_PENDING); - y += 30; - - C2D_TextParse(&text, g_textBuf, "Press START to exit"); - C2D_TextOptimize(&text); - C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.45f, 0.45f, COLOR_PROGRESS); - - C2D_TargetClear(g_bottom, COLOR_BG); - C2D_SceneBegin(g_bottom); - C3D_FrameEnd(0); + gui_draw_status("Config Created", + "Edit sdmc:/3ds/zip-extractor/config.txt and restart."); } } else { - // Cannot create config - show error while (aptMainLoop()) { hidScanInput(); if (hidKeysDown() & KEY_START) break; gui_draw_error("Cannot Create Config", "SD card read-only? Press START"); } } - - // Force exit - user must edit config and restart goto exit_loop; } - if (url_count > 0) { - extract_path = queue->extract_path; - } - - // Show main menu immediately after loading config + const char* extract_path = (url_count > 0) ? queue->extract_path : "sdmc:/extracted/"; + gui_draw_main_menu(url_count, CONFIG_FILE_PATH, extract_path, queue->auto_retry, queue->max_retries); @@ -1088,45 +219,34 @@ int main(int argc, char** argv) { bool show_browser = false; int queue_page = 0; - // Allocate browser on heap to avoid stack overflow FileBrowser* browser = (FileBrowser*)calloc(1, sizeof(FileBrowser)); if (!browser) { gui_draw_error("Warning", "File browser disabled (memory)"); - // Continue without browser } - int browser_scroll = 0; - - // Main loop - MUST render every frame like fast-uninstall + while (aptMainLoop()) { hidScanInput(); u32 kDown = hidKeysDown(); - - if (kDown & KEY_START) { - break; - } - - // Render current screen state + + if (kDown & KEY_START) break; + + // Default render: main menu. if (!started && !show_queue && !show_browser) { - // Main menu - render every frame gui_draw_main_menu(url_count, CONFIG_FILE_PATH, extract_path, - queue->auto_retry, queue->max_retries); + queue->auto_retry, queue->max_retries); } - // File browser - if (show_browser) { - // TODO: implement gui_draw_file_browser + // ----- File browser ----- + if (show_browser && browser) { if (kDown & KEY_UP) { - if (browser && browser->selected > 0) { + if (browser->selected > 0) { browser->selected--; - if (browser->selected < browser_scroll) { - browser_scroll = browser->selected; - } + if (browser->selected < browser_scroll) browser_scroll = browser->selected; } } - if (kDown & KEY_DOWN) { - if (browser && browser->selected < browser->count - 1) { + if (browser->selected < browser->count - 1) { browser->selected++; if (browser->selected >= browser_scroll + 14) { browser_scroll = browser->selected - 13; @@ -1134,34 +254,28 @@ int main(int argc, char** argv) { } display_file_browser(browser, browser_scroll); } - if (kDown & KEY_A) { - // Enter directory or select if (browser->entries[browser->selected].is_directory) { if (strcmp(browser->entries[browser->selected].name, "..") == 0) { - // Go up one directory char* last_slash = strrchr(browser->current_path, '/'); if (last_slash != NULL && last_slash != browser->current_path) { *last_slash = '\0'; - // Handle case where we're at sdmc:/something - if (strncmp(browser->current_path, "sdmc:", 5) == 0 && strlen(browser->current_path) == 5) { + if (strncmp(browser->current_path, "sdmc:", 5) == 0 + && strlen(browser->current_path) == 5) { strcat(browser->current_path, "/"); } } } else { - // Enter subdirectory - use safe string operations size_t path_len = strlen(browser->current_path); size_t name_len = strlen(browser->entries[browser->selected].name); - - // Check if we have enough space if (path_len + name_len + 2 < MAX_PATH_LENGTH) { if (browser->current_path[path_len - 1] != '/') { - browser->current_path[path_len] = '/'; - browser->current_path[path_len + 1] = '\0'; - path_len++; + browser->current_path[path_len++] = '/'; + browser->current_path[path_len] = '\0'; } - strncat(browser->current_path, browser->entries[browser->selected].name, - MAX_PATH_LENGTH - path_len - 1); + strncat(browser->current_path, + browser->entries[browser->selected].name, + MAX_PATH_LENGTH - path_len - 1); } } load_directory(browser); @@ -1169,63 +283,21 @@ int main(int argc, char** argv) { display_file_browser(browser, browser_scroll); } } - if (kDown & KEY_Y) { - // Use current directory strncpy(queue->extract_path, browser->current_path, MAX_PATH_LENGTH - 1); queue->extract_path[MAX_PATH_LENGTH - 1] = '\0'; - // Ensure path ends with / if (queue->extract_path[strlen(queue->extract_path) - 1] != '/') { strcat(queue->extract_path, "/"); } extract_path = queue->extract_path; show_browser = false; - - // Return to main menu - consoleClear(); - printf("\x1b[2;1HArchive Extractor for 3DS"); - printf("\x1b[4;1H================================"); - printf("\x1b[6;1HLoaded %d URL(s) from config", url_count); - printf("\x1b[8;1HConfig file:"); - printf("\x1b[9;1H %s", CONFIG_FILE_PATH); - printf("\x1b[11;1HExtract path:"); - printf("\x1b[12;1H %s", extract_path); - if (queue->auto_retry) { - printf("\x1b[13;1HAuto-retry: ON (max %d)", queue->max_retries); - } - printf("\x1b[14;1HSupports: ZIP, TAR, 7Z, RAR"); - printf("\x1b[15;1H TAR.GZ, TAR.BZ2, etc."); - printf("\x1b[17;1HPress A to start downloads"); - printf("\x1b[18;1HPress X to view queue"); - printf("\x1b[19;1HPress SELECT to browse path"); - printf("\x1b[20;1HPress START to exit"); } - if (kDown & KEY_B) { show_browser = false; - - // Return to main menu - consoleClear(); - printf("\x1b[2;1HArchive Extractor for 3DS"); - printf("\x1b[4;1H================================"); - printf("\x1b[6;1HLoaded %d URL(s) from config", url_count); - printf("\x1b[8;1HConfig file:"); - printf("\x1b[9;1H %s", CONFIG_FILE_PATH); - printf("\x1b[11;1HExtract path:"); - printf("\x1b[12;1H %s", extract_path); - if (queue->auto_retry) { - printf("\x1b[13;1HAuto-retry: ON (max %d)", queue->max_retries); - } - printf("\x1b[14;1HSupports: ZIP, TAR, 7Z, RAR"); - printf("\x1b[15;1H TAR.GZ, TAR.BZ2, etc."); - printf("\x1b[17;1HPress A to start downloads"); - printf("\x1b[18;1HPress X to view queue"); - printf("\x1b[19;1HPress SELECT to browse path"); - printf("\x1b[20;1HPress START to exit"); } } - - // Show file browser + + // Open file browser. if ((kDown & KEY_SELECT) && url_count > 0 && !started && !show_queue && !show_browser && browser) { show_browser = true; init_file_browser(browser, "sdmc:/"); @@ -1233,23 +305,19 @@ int main(int argc, char** argv) { browser_scroll = 0; display_file_browser(browser, browser_scroll); } - - // Queue navigation + + // ----- Queue view ----- if (show_queue) { int total_pages = (url_count + 11) / 12; - if ((kDown & KEY_R) && queue_page < total_pages - 1) { queue_page++; display_queue_status(queue, queue_page); } - if ((kDown & KEY_L) && queue_page > 0) { queue_page--; display_queue_status(queue, queue_page); } - if (kDown & KEY_Y) { - // Skip all failed downloads for (int i = 0; i < url_count; i++) { if (queue->items[i].state == DOWNLOAD_FAILED) { queue->items[i].state = DOWNLOAD_SKIPPED; @@ -1257,180 +325,116 @@ int main(int argc, char** argv) { } display_queue_status(queue, queue_page); } - if (kDown & KEY_B) { show_queue = false; queue_page = 0; - consoleClear(); - printf("\x1b[2;1HArchive Extractor for 3DS"); - printf("\x1b[4;1H================================"); - printf("\x1b[6;1HLoaded %d URL(s) from config", url_count); - printf("\x1b[8;1HConfig file:"); - printf("\x1b[9;1H %s", CONFIG_FILE_PATH); - printf("\x1b[11;1HExtract path:"); - printf("\x1b[12;1H %s", extract_path); - if (queue->auto_retry) { - printf("\x1b[13;1HAuto-retry: ON (max %d)", queue->max_retries); - } - printf("\x1b[14;1HSupports: ZIP, TAR, 7Z, RAR"); - printf("\x1b[15;1H TAR.GZ, TAR.BZ2, etc."); - printf("\x1b[17;1HPress A to start downloads"); - printf("\x1b[18;1HPress X to view queue"); - printf("\x1b[19;1HPress START to exit"); } - if ((kDown & KEY_A) && !started) { show_queue = false; started = true; - // Continue to processing below } } - - // Show queue if ((kDown & KEY_X) && url_count > 0 && !started && !show_queue) { show_queue = true; queue_page = 0; display_queue_status(queue, queue_page); } - - // Start processing + + // ----- Start processing ----- if ((kDown & KEY_A) && url_count > 0 && !started && !show_queue) { started = true; } - + if (started) { - // Create extract directory mkdir(extract_path, 0777); - + int successful = 0; int failed = 0; int skipped = 0; u64 total_files_extracted = 0; - - // Process each URL in queue + for (int i = 0; i < url_count && !cancelled; i++) { - // Skip items that are skipped or already completed - if (queue->items[i].state == DOWNLOAD_SKIPPED) { - skipped++; - continue; - } - if (queue->items[i].state == DOWNLOAD_COMPLETED) { - successful++; - continue; - } - + if (queue->items[i].state == DOWNLOAD_SKIPPED) { skipped++; continue; } + if (queue->items[i].state == DOWNLOAD_COMPLETED) { successful++; continue; } + queue->items[i].state = DOWNLOAD_IN_PROGRESS; - int retries = 0; bool download_success = false; - + + // Per-URL temp path so concurrent runs / aborts don't collide. + char temp_path[160]; + download_make_temp_path(temp_path, sizeof(temp_path)); + do { - consoleClear(); - printf("\x1b[2;1HArchive Extractor for 3DS"); - printf("\x1b[4;1H================================"); - printf("\x1b[6;1HProcessing file %d of %d", i + 1, url_count); - if (retries > 0) { - printf("\x1b[7;1HRetry attempt %d/%d", retries, queue->max_retries); - } - printf("\x1b[9;1HStarting download..."); - - gfxFlushBuffers(); - gfxSwapBuffers(); - gspWaitForVBlank(); - - // Download file - Result download_result = download_file(queue->items[i].url, TEMP_DOWNLOAD_PATH, &cancelled, i + 1, url_count); - - if (cancelled) { - break; - } - - if (download_result == 0) { - // Download completed - Trigger pink LED notification + Result rc = download_file(queue, queue->items[i].url, temp_path, + &cancelled, i + 1, url_count); + if (cancelled) break; + + if (rc == 0) { led_notification_pink(); - // Extract archive - Result extract_result = extract_archive(TEMP_DOWNLOAD_PATH, extract_path, i + 1, url_count); - - if (extract_result == 0) { - queue->items[i].state = DOWNLOAD_COMPLETED; - successful++; - total_files_extracted += extract_data.extracted_files; - download_success = true; - } else if (extract_result == -2) { - cancelled = true; - break; + // Optional integrity check. + if (queue->items[i].sha256_hex[0] != '\0' && + !verify_integrity(temp_path, queue->items[i].sha256_hex)) { + strncpy(queue->items[i].error_msg, "SHA256 mismatch", + sizeof(queue->items[i].error_msg) - 1); + remove(temp_path); } else { - strncpy(queue->items[i].error_msg, "Extraction failed", sizeof(queue->items[i].error_msg) - 1); + Result er = extract_archive(temp_path, extract_path); + if (er == 0) { + queue->items[i].state = DOWNLOAD_COMPLETED; + successful++; + total_files_extracted += extract_data.extracted_files; + download_success = true; + } else if (er == -2) { + cancelled = true; + break; + } else { + strncpy(queue->items[i].error_msg, "Extraction failed", + sizeof(queue->items[i].error_msg) - 1); + } + remove(temp_path); } - - // Clean up temp file - remove(TEMP_DOWNLOAD_PATH); } else { - strncpy(queue->items[i].error_msg, "Download failed", sizeof(queue->items[i].error_msg) - 1); + strncpy(queue->items[i].error_msg, "Download failed", + sizeof(queue->items[i].error_msg) - 1); } - + if (!download_success && queue->auto_retry && retries < queue->max_retries) { retries++; - // Wait a bit before retry - svcSleepThread(2000000000LL); // 2 seconds + svcSleepThread(2000000000LL); // 2s before retry } else { break; } - } while (!download_success && retries <= queue->max_retries); - + if (!download_success && !cancelled) { queue->items[i].state = DOWNLOAD_FAILED; failed++; } } - - // Show summary - consoleClear(); - printf("\x1b[2;1HArchive Extractor for 3DS"); - printf("\x1b[4;1H================================"); - - if (cancelled) { - printf("\x1b[6;1HOperation cancelled!"); - } else { - printf("\x1b[6;1HAll downloads complete!"); - } - - printf("\x1b[8;1HSummary:"); - printf("\x1b[9;1H Successful: %d", successful); - printf("\x1b[10;1H Failed: %d", failed); - printf("\x1b[11;1H Skipped: %d", skipped); - printf("\x1b[12;1H Total files extracted: %llu", total_files_extracted); - printf("\x1b[14;1HOutput directory:"); - printf("\x1b[15;1H %s", extract_path); - - if (failed > 0) { - printf("\x1b[17;1HPress X to view failed items"); - printf("\x1b[18;1HPress A to retry failed"); - } - printf("\x1b[19;1HPress START to exit"); - + + // Summary screen. + char summary[160]; + snprintf(summary, sizeof(summary), + cancelled ? "Cancelled. OK %d, FAIL %d, SKIP %d, files %llu" + : "Done. OK %d, FAIL %d, SKIP %d, files %llu", + successful, failed, skipped, + (unsigned long long)total_files_extracted); + gui_draw_status("Archive Extractor for 3DS", summary); + started = false; - - // Wait for user input while (aptMainLoop()) { hidScanInput(); u32 kDown2 = hidKeysDown(); - - if (kDown2 & KEY_START) { - goto exit_loop; - } - + if (kDown2 & KEY_START) goto exit_loop; if ((kDown2 & KEY_X) && failed > 0) { show_queue = true; queue_page = 0; display_queue_status(queue, queue_page); break; } - if ((kDown2 & KEY_A) && failed > 0) { - // Reset failed items to pending and restart for (int i = 0; i < url_count; i++) { if (queue->items[i].state == DOWNLOAD_FAILED) { queue->items[i].state = DOWNLOAD_PENDING; @@ -1439,42 +443,31 @@ int main(int argc, char** argv) { started = true; break; } - gfxFlushBuffers(); gfxSwapBuffers(); gspWaitForVBlank(); } } - + gfxFlushBuffers(); gfxSwapBuffers(); gspWaitForVBlank(); } - + exit_loop: - - // Turn off LED notifications led_notification_off(); - - // Restore normal sleep mode restore_sleep_mode(); - // Free allocated memory - if (browser) { - free(browser); - } - if (queue) { - free(queue); - } + download_cleanup_orphans(); + + if (browser) free(browser); + if (queue) free(queue); curl_global_cleanup(); socExit(); free(socMemory); - - // Cleanup PTMU ptmuExit(); - gfxExit(); return 0; } diff --git a/source/queue.c b/source/queue.c new file mode 100644 index 0000000..3e9f6df --- /dev/null +++ b/source/queue.c @@ -0,0 +1,78 @@ +#include "queue.h" + +#include +#include +#include <3ds.h> +#include + +#include "gui.h" + +// Render the queue status screen. Called every frame while the queue view +// is active. Mirrors the original implementation that lived in main.c. +void display_queue_status(DownloadQueue* queue, int current_page) { + C3D_FrameBegin(C3D_FRAME_SYNCDRAW); + + C2D_TargetClear(g_top, COLOR_BG); + C2D_SceneBegin(g_top); + + C2D_TextBufClear(g_textBuf); + C2D_Text text; + float y = 5.0f; + + // Title bar + C2D_DrawRectSolid(0, 0, 0.5f, 400, 22, COLOR_ACCENT); + C2D_TextParse(&text, g_textBuf, " Queue Status"); + C2D_TextOptimize(&text); + C2D_DrawText(&text, C2D_WithColor, 5.0f, 3.0f, 0.5f, 0.5f, 0.5f, C2D_Color32(0, 0, 0, 255)); + y = 25.0f; + + int items_per_page = 10; + int start = current_page * items_per_page; + int end = start + items_per_page; + if (end > queue->count) end = queue->count; + + char buf[64]; + snprintf(buf, sizeof(buf), "Showing %d-%d of %d", start + 1, end, queue->count); + C2D_TextParse(&text, g_textBuf, buf); + C2D_TextOptimize(&text); + C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.35f, 0.35f, COLOR_PENDING); + y += 15.0f; + + for (int i = start; i < end; i++) { + const char* state_str = "?"; + u32 state_color = COLOR_TEXT; + + switch (queue->items[i].state) { + case DOWNLOAD_PENDING: state_str = "[ ]"; state_color = COLOR_PENDING; break; + case DOWNLOAD_IN_PROGRESS: state_str = "[>]"; state_color = COLOR_PROGRESS; break; + case DOWNLOAD_COMPLETED: state_str = "[OK]"; state_color = COLOR_SUCCESS; break; + case DOWNLOAD_FAILED: state_str = "[X]"; state_color = COLOR_ERROR; break; + case DOWNLOAD_SKIPPED: state_str = "[-]"; state_color = COLOR_PENDING; break; + } + + snprintf(buf, sizeof(buf), "%s %.42s", state_str, queue->items[i].url); + C2D_TextParse(&text, g_textBuf, buf); + C2D_TextOptimize(&text); + C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.33f, 0.33f, state_color); + y += 13.0f; + } + + int total_pages = (queue->count + items_per_page - 1) / items_per_page; + if (total_pages == 0) total_pages = 1; + + y = 195.0f; + snprintf(buf, sizeof(buf), "Page %d/%d", current_page + 1, total_pages); + C2D_TextParse(&text, g_textBuf, buf); + C2D_TextOptimize(&text); + C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.38f, 0.38f, COLOR_TEXT); + y += 14.0f; + + C2D_TextParse(&text, g_textBuf, "L/R: Page Y: Skip failed B: Back"); + C2D_TextOptimize(&text); + C2D_DrawText(&text, C2D_WithColor, 10.0f, y, 0.5f, 0.35f, 0.35f, COLOR_PROGRESS); + + C2D_TargetClear(g_bottom, COLOR_BG); + C2D_SceneBegin(g_bottom); + + C3D_FrameEnd(0); +} diff --git a/tests/3ds_stubs.h b/tests/3ds_stubs.h new file mode 100644 index 0000000..b97809b --- /dev/null +++ b/tests/3ds_stubs.h @@ -0,0 +1,22 @@ +// Minimal stand-ins for libctru types so pure modules can be built on a +// regular host PC for the unit-test suite. The corresponding C sources +// guard real `<3ds.h>` includes with `#ifndef HOST_BUILD`. +// +// Only the very small subset of types the pure modules need is provided +// here. Anything that depends on actual 3DS hardware (curl, citro2d, +// libarchive disk extraction, hidScanInput, ...) is NOT host-testable +// and is excluded from the host build. + +#ifndef THREE_DS_STUBS_H +#define THREE_DS_STUBS_H + +#include +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +typedef int32_t Result; + +#endif // THREE_DS_STUBS_H diff --git a/tests/Makefile.host b/tests/Makefile.host new file mode 100644 index 0000000..510b36b --- /dev/null +++ b/tests/Makefile.host @@ -0,0 +1,88 @@ +#--------------------------------------------------------------------------------- +# Host build for 3ds-zip-extractor unit tests. +# +# These tests run on a normal Linux/macOS host (no devkitARM, no 3DS). +# Only the *pure* modules of the project (config, gdrive, integrity, +# archive_extractor:detect_archive_type) are linked here. UI / network +# / on-disk extraction code is excluded — that part is exercised on +# the real device. +#--------------------------------------------------------------------------------- + +CC ?= cc +CSTD ?= -std=c11 +CFLAGS ?= $(CSTD) -O0 -g -Wall -Wextra -Wno-unused-parameter \ + -DHOST_BUILD=1 \ + -I. -I../include +LDFLAGS ?= + +ASAN_FLAGS := -fsanitize=address,undefined -fno-omit-frame-pointer + +# Pure sources from the main project that we link into every test binary. +PROJECT_PURE := \ + ../source/config.c \ + ../source/gdrive.c \ + ../source/integrity.c + +# Unity vendor. +UNITY := unity.c + +# Test binaries. +TEST_GDRIVE := test_gdrive +TEST_CONFIG := test_config +TEST_ARCHIVE_DETECT := test_archive_detect +TEST_SHA256 := test_sha256 + +ALL_TESTS := $(TEST_GDRIVE) $(TEST_CONFIG) $(TEST_ARCHIVE_DETECT) $(TEST_SHA256) + +.PHONY: all test test-asan clean fixtures coverage help + +all: $(ALL_TESTS) + +help: + @echo "Targets:" + @echo " test - build and run all unit tests" + @echo " test-asan - same, with AddressSanitizer + UBSan" + @echo " coverage - generate gcov/lcov HTML report (needs lcov)" + @echo " clean - remove build artifacts" + +# Generic test rule — each test gets the full set of pure sources plus +# its own *.c file plus unity.c. +$(TEST_GDRIVE): test_gdrive.c $(UNITY) $(PROJECT_PURE) + $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) + +$(TEST_CONFIG): test_config.c $(UNITY) $(PROJECT_PURE) + $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) + +$(TEST_ARCHIVE_DETECT): test_archive_detect.c $(UNITY) ../source/archive_extractor_detect.c + $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) + +$(TEST_SHA256): test_sha256.c $(UNITY) $(PROJECT_PURE) + $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) + +fixtures: + @./make_fixtures.sh + +test: fixtures $(ALL_TESTS) + @set -e; for t in $(ALL_TESTS); do echo "=== $$t ==="; ./$$t; done + @echo "All host tests passed." + +test-asan: + @$(MAKE) -f Makefile.host CFLAGS="$(CFLAGS) $(ASAN_FLAGS)" LDFLAGS="$(LDFLAGS) $(ASAN_FLAGS)" test + +coverage: + @$(MAKE) -f Makefile.host clean + @$(MAKE) -f Makefile.host CFLAGS="$(CFLAGS) -O0 --coverage" LDFLAGS="$(LDFLAGS) --coverage" test + @mkdir -p coverage + @command -v lcov >/dev/null 2>&1 || { echo "lcov not installed"; exit 1; } + @lcov --capture --directory . --output-file coverage/lcov.info \ + --include "$(CURDIR)/../source/*" + @genhtml coverage/lcov.info --output-directory coverage + @echo "Coverage report: coverage/index.html" + +clean: + @rm -f $(ALL_TESTS) *.o *.gcda *.gcno + @rm -rf coverage + @rm -f fixtures/tiny.zip fixtures/tiny.tar fixtures/tiny.gz \ + fixtures/tiny.bz2 fixtures/tiny.xz fixtures/tiny.7z \ + fixtures/tiny.zst fixtures/tiny.rar fixtures/not_an_archive.bin \ + fixtures/empty.bin fixtures/three_bytes.bin diff --git a/tests/fixtures/config_bom.txt b/tests/fixtures/config_bom.txt new file mode 100644 index 0000000..cef63e4 --- /dev/null +++ b/tests/fixtures/config_bom.txt @@ -0,0 +1 @@ +https://example.com/bom.zip diff --git a/tests/fixtures/config_empty.txt b/tests/fixtures/config_empty.txt new file mode 100644 index 0000000..02db8e1 --- /dev/null +++ b/tests/fixtures/config_empty.txt @@ -0,0 +1,4 @@ +# this file contains only comments +# +# nothing else + diff --git a/tests/fixtures/config_long_url.txt b/tests/fixtures/config_long_url.txt new file mode 100644 index 0000000..0f491ab --- /dev/null +++ b/tests/fixtures/config_long_url.txt @@ -0,0 +1 @@ +https://example.com/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.zip diff --git a/tests/fixtures/config_malformed.txt b/tests/fixtures/config_malformed.txt new file mode 100644 index 0000000..b65efb1 --- /dev/null +++ b/tests/fixtures/config_malformed.txt @@ -0,0 +1,6 @@ +extract_path=sdmc:/x/ +auto_retry=invalid +max_retries=999 +unknown_setting=42 +https://example.com/a.zip sha256:notavalidhash +https://example.com/b.zip sha256:0123456789abcdef0123456789ABCDEF0123456789abcdef0123456789abcdef diff --git a/tests/fixtures/config_many_urls.txt b/tests/fixtures/config_many_urls.txt new file mode 100644 index 0000000..995b0be --- /dev/null +++ b/tests/fixtures/config_many_urls.txt @@ -0,0 +1,60 @@ +https://example.com/0.zip +https://example.com/1.zip +https://example.com/2.zip +https://example.com/3.zip +https://example.com/4.zip +https://example.com/5.zip +https://example.com/6.zip +https://example.com/7.zip +https://example.com/8.zip +https://example.com/9.zip +https://example.com/10.zip +https://example.com/11.zip +https://example.com/12.zip +https://example.com/13.zip +https://example.com/14.zip +https://example.com/15.zip +https://example.com/16.zip +https://example.com/17.zip +https://example.com/18.zip +https://example.com/19.zip +https://example.com/20.zip +https://example.com/21.zip +https://example.com/22.zip +https://example.com/23.zip +https://example.com/24.zip +https://example.com/25.zip +https://example.com/26.zip +https://example.com/27.zip +https://example.com/28.zip +https://example.com/29.zip +https://example.com/30.zip +https://example.com/31.zip +https://example.com/32.zip +https://example.com/33.zip +https://example.com/34.zip +https://example.com/35.zip +https://example.com/36.zip +https://example.com/37.zip +https://example.com/38.zip +https://example.com/39.zip +https://example.com/40.zip +https://example.com/41.zip +https://example.com/42.zip +https://example.com/43.zip +https://example.com/44.zip +https://example.com/45.zip +https://example.com/46.zip +https://example.com/47.zip +https://example.com/48.zip +https://example.com/49.zip +https://example.com/50.zip +https://example.com/51.zip +https://example.com/52.zip +https://example.com/53.zip +https://example.com/54.zip +https://example.com/55.zip +https://example.com/56.zip +https://example.com/57.zip +https://example.com/58.zip +https://example.com/59.zip diff --git a/tests/fixtures/config_negative_retries.txt b/tests/fixtures/config_negative_retries.txt new file mode 100644 index 0000000..9d28758 --- /dev/null +++ b/tests/fixtures/config_negative_retries.txt @@ -0,0 +1,2 @@ +max_retries=-1 +https://example.com/x.zip diff --git a/tests/fixtures/config_valid.txt b/tests/fixtures/config_valid.txt new file mode 100644 index 0000000..9b061b2 --- /dev/null +++ b/tests/fixtures/config_valid.txt @@ -0,0 +1,8 @@ +extract_path=sdmc:/foo/ +auto_retry=true +max_retries=5 +https://example.com/a.zip +https://example.com/b.tar.gz sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +# comment line +# another +https://drive.google.com/file/d/ABC123/view diff --git a/tests/make_fixtures.sh b/tests/make_fixtures.sh new file mode 100755 index 0000000..73e0f9e --- /dev/null +++ b/tests/make_fixtures.sh @@ -0,0 +1,139 @@ +#!/usr/bin/env bash +# Generate small archive fixtures for host-side unit tests. +# Idempotent: only writes files when they don't already exist. +set -euo pipefail + +cd "$(dirname "$0")/fixtures" + +# 1. Tiny ZIP — minimal local file header for a single empty file "a". +# Layout: PK\x03\x04 + version+flags+compression+date+time+crc+sizes(0)+name(1)+extra(0) + name "a" +# + central dir + EOCD. We craft this by hand for repeatability and to +# avoid depending on `zip` being installed. +python3 - <<'PY' +import struct, os + +def write_zip(path): + name = b"a" + local = struct.pack(" + +void setUp(void) {} +void tearDown(void) {} + +#define FIXTURE(name) ("fixtures/" name) + +static void test_zip(void) { + TEST_ASSERT_EQUAL(ARCHIVE_ZIP, detect_archive_type(FIXTURE("tiny.zip"))); +} +static void test_gzip(void) { + TEST_ASSERT_EQUAL(ARCHIVE_GZIP, detect_archive_type(FIXTURE("tiny.gz"))); +} +static void test_bzip2(void) { + TEST_ASSERT_EQUAL(ARCHIVE_BZIP2, detect_archive_type(FIXTURE("tiny.bz2"))); +} +static void test_xz(void) { + TEST_ASSERT_EQUAL(ARCHIVE_XZ, detect_archive_type(FIXTURE("tiny.xz"))); +} +static void test_zstd(void) { + TEST_ASSERT_EQUAL(ARCHIVE_ZSTD, detect_archive_type(FIXTURE("tiny.zst"))); +} +static void test_7z(void) { + TEST_ASSERT_EQUAL(ARCHIVE_7Z, detect_archive_type(FIXTURE("tiny.7z"))); +} +static void test_rar(void) { + TEST_ASSERT_EQUAL(ARCHIVE_RAR, detect_archive_type(FIXTURE("tiny.rar"))); +} +static void test_tar(void) { + TEST_ASSERT_EQUAL(ARCHIVE_TAR, detect_archive_type(FIXTURE("tiny.tar"))); +} + +static void test_too_short(void) { + TEST_ASSERT_EQUAL(ARCHIVE_UNKNOWN, detect_archive_type(FIXTURE("three_bytes.bin"))); + TEST_ASSERT_EQUAL(ARCHIVE_UNKNOWN, detect_archive_type(FIXTURE("empty.bin"))); +} + +static void test_not_an_archive(void) { + TEST_ASSERT_EQUAL(ARCHIVE_UNKNOWN, detect_archive_type(FIXTURE("not_an_archive.bin"))); +} + +static void test_missing_file(void) { + TEST_ASSERT_EQUAL(ARCHIVE_UNKNOWN, detect_archive_type(FIXTURE("does_not_exist.bin"))); +} + +static void test_null_safe(void) { + TEST_ASSERT_EQUAL(ARCHIVE_UNKNOWN, detect_archive_type(NULL)); +} + +static void test_type_names(void) { + TEST_ASSERT_EQUAL_STRING("ZIP", get_archive_type_name(ARCHIVE_ZIP)); + TEST_ASSERT_EQUAL_STRING("TAR", get_archive_type_name(ARCHIVE_TAR)); + TEST_ASSERT_EQUAL_STRING("GZIP/TAR.GZ", get_archive_type_name(ARCHIVE_GZIP)); + TEST_ASSERT_EQUAL_STRING("BZIP2/TAR.BZ2",get_archive_type_name(ARCHIVE_BZIP2)); + TEST_ASSERT_EQUAL_STRING("XZ/TAR.XZ", get_archive_type_name(ARCHIVE_XZ)); + TEST_ASSERT_EQUAL_STRING("7-Zip", get_archive_type_name(ARCHIVE_7Z)); + TEST_ASSERT_EQUAL_STRING("RAR", get_archive_type_name(ARCHIVE_RAR)); + TEST_ASSERT_EQUAL_STRING("ZSTD/TAR.ZSTD",get_archive_type_name(ARCHIVE_ZSTD)); + TEST_ASSERT_EQUAL_STRING("Unknown", get_archive_type_name(ARCHIVE_UNKNOWN)); +} + +int main(void) { + UNITY_BEGIN(); + RUN_TEST(test_zip); + RUN_TEST(test_gzip); + RUN_TEST(test_bzip2); + RUN_TEST(test_xz); + RUN_TEST(test_zstd); + RUN_TEST(test_7z); + RUN_TEST(test_rar); + RUN_TEST(test_tar); + RUN_TEST(test_too_short); + RUN_TEST(test_not_an_archive); + RUN_TEST(test_missing_file); + RUN_TEST(test_null_safe); + RUN_TEST(test_type_names); + return UNITY_END(); +} diff --git a/tests/test_config.c b/tests/test_config.c new file mode 100644 index 0000000..38e3a65 --- /dev/null +++ b/tests/test_config.c @@ -0,0 +1,123 @@ +// Unit tests for read_config_file. +#include "unity.h" +#include "../include/config.h" +#include + +void setUp(void) {} +void tearDown(void) {} + +#define FIXTURE(name) ("fixtures/" name) + +static void test_missing_file_returns_minus_one(void) { + AppConfig cfg; + int rc = read_config_file(FIXTURE("does_not_exist.txt"), &cfg); + TEST_ASSERT_EQUAL(-1, rc); + // Defaults still applied. + TEST_ASSERT_EQUAL_STRING("sdmc:/extracted/", cfg.extract_path); + TEST_ASSERT_EQUAL(3, cfg.max_retries); + TEST_ASSERT_FALSE(cfg.auto_retry); + TEST_ASSERT_EQUAL(MAX_URLS, cfg.max_urls); + TEST_ASSERT_EQUAL(128, cfg.download_buffer_kb); + TEST_ASSERT_EQUAL(30, cfg.connect_timeout_s); +} + +static void test_empty_or_comments_only(void) { + AppConfig cfg; + int rc = read_config_file(FIXTURE("config_empty.txt"), &cfg); + TEST_ASSERT_EQUAL(0, rc); + TEST_ASSERT_EQUAL(0, cfg.count); + TEST_ASSERT_EQUAL_STRING("sdmc:/extracted/", cfg.extract_path); +} + +static void test_valid_settings_and_urls(void) { + AppConfig cfg; + int rc = read_config_file(FIXTURE("config_valid.txt"), &cfg); + TEST_ASSERT_GREATER_OR_EQUAL(3, rc); + TEST_ASSERT_EQUAL_STRING("sdmc:/foo/", cfg.extract_path); + TEST_ASSERT_TRUE(cfg.auto_retry); + TEST_ASSERT_EQUAL(5, cfg.max_retries); + + // First URL — bare. + TEST_ASSERT_EQUAL_STRING("https://example.com/a.zip", cfg.items[0].url); + TEST_ASSERT_EQUAL_STRING("", cfg.items[0].sha256_hex); + + // Second URL — has a sha256 suffix that must be split off. + TEST_ASSERT_EQUAL_STRING("https://example.com/b.tar.gz", cfg.items[1].url); + TEST_ASSERT_EQUAL_STRING( + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + cfg.items[1].sha256_hex); + + // Third URL — Google Drive (kept unchanged in storage; conversion + // happens at download time). + TEST_ASSERT_EQUAL_STRING("https://drive.google.com/file/d/ABC123/view", + cfg.items[2].url); +} + +static void test_malformed_settings_clamped(void) { + AppConfig cfg; + read_config_file(FIXTURE("config_malformed.txt"), &cfg); + // auto_retry=invalid → falls back to default (false). + TEST_ASSERT_FALSE(cfg.auto_retry); + // max_retries=999 → clamped to 10. + TEST_ASSERT_EQUAL(10, cfg.max_retries); + // First URL has an invalid sha (not 64 hex), so it stays attached as + // part of the URL — but we should NOT crash. + TEST_ASSERT_TRUE(cfg.count >= 1); + // Second URL has a valid 64-hex sha (mixed case — we lowercase). + int idx = -1; + for (int i = 0; i < cfg.count; i++) { + if (strcmp(cfg.items[i].url, "https://example.com/b.zip") == 0) idx = i; + } + TEST_ASSERT_NOT_EQUAL(-1, idx); + TEST_ASSERT_EQUAL_STRING( + "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + cfg.items[idx].sha256_hex); +} + +static void test_negative_retries_clamped(void) { + AppConfig cfg; + read_config_file(FIXTURE("config_negative_retries.txt"), &cfg); + TEST_ASSERT_EQUAL(0, cfg.max_retries); +} + +static void test_many_urls_clamped_to_max(void) { + AppConfig cfg; + int rc = read_config_file(FIXTURE("config_many_urls.txt"), &cfg); + TEST_ASSERT_EQUAL(MAX_URLS < 60 ? MAX_URLS : 60, rc); + TEST_ASSERT_EQUAL(rc, cfg.count); + TEST_ASSERT_LESS_OR_EQUAL(MAX_URLS, cfg.count); +} + +static void test_long_url_truncated_no_overflow(void) { + AppConfig cfg; + int rc = read_config_file(FIXTURE("config_long_url.txt"), &cfg); + // Still loads (1 URL), URL is truncated to fit, NUL terminated. + TEST_ASSERT_EQUAL(1, rc); + TEST_ASSERT_EQUAL_CHAR('\0', cfg.items[0].url[MAX_URL_LENGTH - 1]); +} + +static void test_utf8_bom_ignored(void) { + AppConfig cfg; + int rc = read_config_file(FIXTURE("config_bom.txt"), &cfg); + TEST_ASSERT_EQUAL(1, rc); + TEST_ASSERT_EQUAL_STRING("https://example.com/bom.zip", cfg.items[0].url); +} + +static void test_null_cfg_safe(void) { + int rc = read_config_file(FIXTURE("config_valid.txt"), NULL); + TEST_ASSERT_EQUAL(-1, rc); +} + +int main(void) { + UNITY_BEGIN(); + RUN_TEST(test_missing_file_returns_minus_one); + RUN_TEST(test_empty_or_comments_only); + RUN_TEST(test_valid_settings_and_urls); + RUN_TEST(test_malformed_settings_clamped); + RUN_TEST(test_negative_retries_clamped); + RUN_TEST(test_many_urls_clamped_to_max); + RUN_TEST(test_long_url_truncated_no_overflow); + RUN_TEST(test_utf8_bom_ignored); + RUN_TEST(test_null_cfg_safe); + return UNITY_END(); +} diff --git a/tests/test_gdrive.c b/tests/test_gdrive.c new file mode 100644 index 0000000..124b5cf --- /dev/null +++ b/tests/test_gdrive.c @@ -0,0 +1,92 @@ +// Unit tests for convert_gdrive_url. +#include "unity.h" +#include "../include/gdrive.h" +#include + +void setUp(void) {} +void tearDown(void) {} + +static void assert_contains(const char* haystack, const char* needle) { + TEST_ASSERT_NOT_NULL_MESSAGE(strstr(haystack, needle), needle); +} + +// /file/d//view → uc?export=download&id=&confirm=t +static void test_file_d_view(void) { + char out[512]; + convert_gdrive_url("https://drive.google.com/file/d/ABC123/view", out, sizeof(out)); + assert_contains(out, "drive.google.com/uc?export=download"); + assert_contains(out, "id=ABC123"); + assert_contains(out, "confirm=t"); +} + +static void test_open_id(void) { + char out[512]; + convert_gdrive_url("https://drive.google.com/open?id=XYZ789", out, sizeof(out)); + assert_contains(out, "id=XYZ789"); + assert_contains(out, "confirm=t"); +} + +static void test_uc_id(void) { + char out[512]; + convert_gdrive_url("https://drive.google.com/uc?id=DEF&export=download", + out, sizeof(out)); + assert_contains(out, "id=DEF"); +} + +static void test_non_gdrive_unchanged(void) { + char out[512]; + convert_gdrive_url("https://example.com/foo.zip", out, sizeof(out)); + TEST_ASSERT_EQUAL_STRING("https://example.com/foo.zip", out); +} + +static void test_folder_url_unchanged(void) { + const char* in = "https://drive.google.com/drive/folders/abcd"; + char out[512]; + convert_gdrive_url(in, out, sizeof(out)); + TEST_ASSERT_EQUAL_STRING(in, out); +} + +static void test_small_buffer_no_overflow(void) { + // Buffer too small to hold the full converted URL — output must still be + // NUL-terminated and not overrun. We sandwich the buffer between guards. + char guard1[8]; + char out[16]; + char guard2[8]; + memset(guard1, 'A', sizeof(guard1)); + memset(guard2, 'B', sizeof(guard2)); + + convert_gdrive_url("https://drive.google.com/file/d/ABCDEFGHIJ/view", + out, sizeof(out)); + // Guards must be untouched. + for (size_t i = 0; i < sizeof(guard1); i++) TEST_ASSERT_EQUAL(guard1[i], 'A'); + for (size_t i = 0; i < sizeof(guard2); i++) TEST_ASSERT_EQUAL(guard2[i], 'B'); + // out must be NUL-terminated. + TEST_ASSERT_EQUAL_CHAR('\0', out[sizeof(out) - 1]); +} + +static void test_null_inputs_dont_crash(void) { + char out[16]; + out[0] = 'X'; + convert_gdrive_url(NULL, out, sizeof(out)); + TEST_ASSERT_EQUAL_CHAR('\0', out[0]); + + // NULL out is also tolerated. + convert_gdrive_url("https://example.com", NULL, 0); + + // Empty input. + out[0] = 'X'; + convert_gdrive_url("", out, sizeof(out)); + TEST_ASSERT_EQUAL_STRING("", out); +} + +int main(void) { + UNITY_BEGIN(); + RUN_TEST(test_file_d_view); + RUN_TEST(test_open_id); + RUN_TEST(test_uc_id); + RUN_TEST(test_non_gdrive_unchanged); + RUN_TEST(test_folder_url_unchanged); + RUN_TEST(test_small_buffer_no_overflow); + RUN_TEST(test_null_inputs_dont_crash); + return UNITY_END(); +} diff --git a/tests/test_sha256.c b/tests/test_sha256.c new file mode 100644 index 0000000..5b09569 --- /dev/null +++ b/tests/test_sha256.c @@ -0,0 +1,83 @@ +// Unit tests for SHA-256 hashing + integrity verification. +#include "unity.h" +#include "../include/integrity.h" +#include +#include + +void setUp(void) {} +void tearDown(void) {} + +static const char* SHA256_EMPTY = + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; +static const char* SHA256_ABC = + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"; + +static void test_empty_string(void) { + char hex[65]; + sha256_hex("", 0, hex); + TEST_ASSERT_EQUAL_STRING(SHA256_EMPTY, hex); +} + +static void test_abc(void) { + char hex[65]; + sha256_hex("abc", 3, hex); + TEST_ASSERT_EQUAL_STRING(SHA256_ABC, hex); +} + +static void test_null_data_safe(void) { + char hex[65]; + sha256_hex(NULL, 0, hex); + TEST_ASSERT_EQUAL_STRING(SHA256_EMPTY, hex); +} + +static void test_file_known(void) { + // Hash the known fixture "fixtures/three_bytes.bin" which contains "abc". + char hex[65]; + TEST_ASSERT_TRUE(sha256_hex_file("fixtures/three_bytes.bin", hex)); + TEST_ASSERT_EQUAL_STRING(SHA256_ABC, hex); +} + +static void test_file_missing(void) { + char hex[65]; + TEST_ASSERT_FALSE(sha256_hex_file("fixtures/does_not_exist", hex)); + TEST_ASSERT_EQUAL_STRING("", hex); +} + +static void test_verify_integrity_match(void) { + TEST_ASSERT_TRUE(verify_integrity("fixtures/three_bytes.bin", SHA256_ABC)); +} + +static void test_verify_integrity_case_insensitive(void) { + char upper[65]; + for (int i = 0; i < 64; i++) { + char c = SHA256_ABC[i]; + if (c >= 'a' && c <= 'f') c = (char)(c - 'a' + 'A'); + upper[i] = c; + } + upper[64] = '\0'; + TEST_ASSERT_TRUE(verify_integrity("fixtures/three_bytes.bin", upper)); +} + +static void test_verify_integrity_mismatch(void) { + TEST_ASSERT_FALSE(verify_integrity("fixtures/three_bytes.bin", SHA256_EMPTY)); +} + +static void test_verify_integrity_null_safe(void) { + TEST_ASSERT_FALSE(verify_integrity(NULL, SHA256_EMPTY)); + TEST_ASSERT_FALSE(verify_integrity("fixtures/three_bytes.bin", NULL)); + TEST_ASSERT_FALSE(verify_integrity("fixtures/three_bytes.bin", "")); +} + +int main(void) { + UNITY_BEGIN(); + RUN_TEST(test_empty_string); + RUN_TEST(test_abc); + RUN_TEST(test_null_data_safe); + RUN_TEST(test_file_known); + RUN_TEST(test_file_missing); + RUN_TEST(test_verify_integrity_match); + RUN_TEST(test_verify_integrity_case_insensitive); + RUN_TEST(test_verify_integrity_mismatch); + RUN_TEST(test_verify_integrity_null_safe); + return UNITY_END(); +} diff --git a/tests/unity.c b/tests/unity.c new file mode 100644 index 0000000..b105fa2 --- /dev/null +++ b/tests/unity.c @@ -0,0 +1,2487 @@ +/* ========================================================================= + Unity Project - A Test Framework for C + Copyright (c) 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +============================================================================ */ + +#include "unity.h" + +#ifndef UNITY_PROGMEM +#define UNITY_PROGMEM +#endif + +/* If omitted from header, declare overrideable prototypes here so they're ready for use */ +#ifdef UNITY_OMIT_OUTPUT_CHAR_HEADER_DECLARATION +void UNITY_OUTPUT_CHAR(int); +#endif + +/* Helpful macros for us to use here in Assert functions */ +#define UNITY_FAIL_AND_BAIL do { Unity.CurrentTestFailed = 1; UNITY_OUTPUT_FLUSH(); TEST_ABORT(); } while (0) +#define UNITY_IGNORE_AND_BAIL do { Unity.CurrentTestIgnored = 1; UNITY_OUTPUT_FLUSH(); TEST_ABORT(); } while (0) +#define RETURN_IF_FAIL_OR_IGNORE do { if (Unity.CurrentTestFailed || Unity.CurrentTestIgnored) { TEST_ABORT(); } } while (0) + +struct UNITY_STORAGE_T Unity; + +#ifdef UNITY_OUTPUT_COLOR +const char UNITY_PROGMEM UnityStrOk[] = "\033[42mOK\033[0m"; +const char UNITY_PROGMEM UnityStrPass[] = "\033[42mPASS\033[0m"; +const char UNITY_PROGMEM UnityStrFail[] = "\033[41mFAIL\033[0m"; +const char UNITY_PROGMEM UnityStrIgnore[] = "\033[43mIGNORE\033[0m"; +#else +const char UNITY_PROGMEM UnityStrOk[] = "OK"; +const char UNITY_PROGMEM UnityStrPass[] = "PASS"; +const char UNITY_PROGMEM UnityStrFail[] = "FAIL"; +const char UNITY_PROGMEM UnityStrIgnore[] = "IGNORE"; +#endif +static const char UNITY_PROGMEM UnityStrNull[] = "NULL"; +static const char UNITY_PROGMEM UnityStrSpacer[] = ". "; +static const char UNITY_PROGMEM UnityStrExpected[] = " Expected "; +static const char UNITY_PROGMEM UnityStrWas[] = " Was "; +static const char UNITY_PROGMEM UnityStrGt[] = " to be greater than "; +static const char UNITY_PROGMEM UnityStrLt[] = " to be less than "; +static const char UNITY_PROGMEM UnityStrOrEqual[] = "or equal to "; +static const char UNITY_PROGMEM UnityStrNotEqual[] = " to be not equal to "; +static const char UNITY_PROGMEM UnityStrElement[] = " Element "; +static const char UNITY_PROGMEM UnityStrByte[] = " Byte "; +static const char UNITY_PROGMEM UnityStrMemory[] = " Memory Mismatch."; +static const char UNITY_PROGMEM UnityStrDelta[] = " Values Not Within Delta "; +static const char UNITY_PROGMEM UnityStrPointless[] = " You Asked Me To Compare Nothing, Which Was Pointless."; +static const char UNITY_PROGMEM UnityStrNullPointerForExpected[] = " Expected pointer to be NULL"; +static const char UNITY_PROGMEM UnityStrNullPointerForActual[] = " Actual pointer was NULL"; +#ifndef UNITY_EXCLUDE_FLOAT +static const char UNITY_PROGMEM UnityStrNot[] = "Not "; +static const char UNITY_PROGMEM UnityStrInf[] = "Infinity"; +static const char UNITY_PROGMEM UnityStrNegInf[] = "Negative Infinity"; +static const char UNITY_PROGMEM UnityStrNaN[] = "NaN"; +static const char UNITY_PROGMEM UnityStrDet[] = "Determinate"; +static const char UNITY_PROGMEM UnityStrInvalidFloatTrait[] = "Invalid Float Trait"; +#endif +const char UNITY_PROGMEM UnityStrErrShorthand[] = "Unity Shorthand Support Disabled"; +const char UNITY_PROGMEM UnityStrErrFloat[] = "Unity Floating Point Disabled"; +const char UNITY_PROGMEM UnityStrErrDouble[] = "Unity Double Precision Disabled"; +const char UNITY_PROGMEM UnityStrErr64[] = "Unity 64-bit Support Disabled"; +static const char UNITY_PROGMEM UnityStrBreaker[] = "-----------------------"; +static const char UNITY_PROGMEM UnityStrResultsTests[] = " Tests "; +static const char UNITY_PROGMEM UnityStrResultsFailures[] = " Failures "; +static const char UNITY_PROGMEM UnityStrResultsIgnored[] = " Ignored "; +#ifndef UNITY_EXCLUDE_DETAILS +static const char UNITY_PROGMEM UnityStrDetail1Name[] = UNITY_DETAIL1_NAME " "; +static const char UNITY_PROGMEM UnityStrDetail2Name[] = " " UNITY_DETAIL2_NAME " "; +#endif +/*----------------------------------------------- + * Pretty Printers & Test Result Output Handlers + *-----------------------------------------------*/ + +/*-----------------------------------------------*/ +/* Local helper function to print characters. */ +static void UnityPrintChar(const char* pch) +{ + /* printable characters plus CR & LF are printed */ + if ((*pch <= 126) && (*pch >= 32)) + { + UNITY_OUTPUT_CHAR(*pch); + } + /* write escaped carriage returns */ + else if (*pch == 13) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('r'); + } + /* write escaped line feeds */ + else if (*pch == 10) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('n'); + } + /* unprintable characters are shown as codes */ + else + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)*pch, 2); + } +} + +/*-----------------------------------------------*/ +/* Local helper function to print ANSI escape strings e.g. "\033[42m". */ +#ifdef UNITY_OUTPUT_COLOR +static UNITY_UINT UnityPrintAnsiEscapeString(const char* string) +{ + const char* pch = string; + UNITY_UINT count = 0; + + while (*pch && (*pch != 'm')) + { + UNITY_OUTPUT_CHAR(*pch); + pch++; + count++; + } + UNITY_OUTPUT_CHAR('m'); + count++; + + return count; +} +#endif + +/*-----------------------------------------------*/ +void UnityPrint(const char* string) +{ + const char* pch = string; + + if (pch != NULL) + { + while (*pch) + { +#ifdef UNITY_OUTPUT_COLOR + /* print ANSI escape code */ + if ((*pch == 27) && (*(pch + 1) == '[')) + { + pch += UnityPrintAnsiEscapeString(pch); + continue; + } +#endif + UnityPrintChar(pch); + pch++; + } + } +} +/*-----------------------------------------------*/ +void UnityPrintLen(const char* string, const UNITY_UINT32 length) +{ + const char* pch = string; + + if (pch != NULL) + { + while (*pch && ((UNITY_UINT32)(pch - string) < length)) + { + /* printable characters plus CR & LF are printed */ + if ((*pch <= 126) && (*pch >= 32)) + { + UNITY_OUTPUT_CHAR(*pch); + } + /* write escaped carriage returns */ + else if (*pch == 13) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('r'); + } + /* write escaped line feeds */ + else if (*pch == 10) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('n'); + } + /* unprintable characters are shown as codes */ + else + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)*pch, 2); + } + pch++; + } + } +} + +/*-----------------------------------------------*/ +void UnityPrintNumberByStyle(const UNITY_INT number, const UNITY_DISPLAY_STYLE_T style) +{ + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + if (style == UNITY_DISPLAY_STYLE_CHAR) + { + /* printable characters plus CR & LF are printed */ + UNITY_OUTPUT_CHAR('\''); + if ((number <= 126) && (number >= 32)) + { + UNITY_OUTPUT_CHAR((int)number); + } + /* write escaped carriage returns */ + else if (number == 13) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('r'); + } + /* write escaped line feeds */ + else if (number == 10) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('n'); + } + /* unprintable characters are shown as codes */ + else + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)number, 2); + } + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrintNumber(number); + } + } + else if ((style & UNITY_DISPLAY_RANGE_UINT) == UNITY_DISPLAY_RANGE_UINT) + { + UnityPrintNumberUnsigned((UNITY_UINT)number); + } + else + { + UNITY_OUTPUT_CHAR('0'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)number, (char)((style & 0xF) * 2)); + } +} + +/*-----------------------------------------------*/ +void UnityPrintNumber(const UNITY_INT number_to_print) +{ + UNITY_UINT number = (UNITY_UINT)number_to_print; + + if (number_to_print < 0) + { + /* A negative number, including MIN negative */ + UNITY_OUTPUT_CHAR('-'); + number = (~number) + 1; + } + UnityPrintNumberUnsigned(number); +} + +/*----------------------------------------------- + * basically do an itoa using as little ram as possible */ +void UnityPrintNumberUnsigned(const UNITY_UINT number) +{ + UNITY_UINT divisor = 1; + + /* figure out initial divisor */ + while (number / divisor > 9) + { + divisor *= 10; + } + + /* now mod and print, then divide divisor */ + do + { + UNITY_OUTPUT_CHAR((char)('0' + (number / divisor % 10))); + divisor /= 10; + } while (divisor > 0); +} + +/*-----------------------------------------------*/ +void UnityPrintNumberHex(const UNITY_UINT number, const char nibbles_to_print) +{ + int nibble; + char nibbles = nibbles_to_print; + + if ((unsigned)nibbles > UNITY_MAX_NIBBLES) + { + nibbles = UNITY_MAX_NIBBLES; + } + + while (nibbles > 0) + { + nibbles--; + nibble = (int)(number >> (nibbles * 4)) & 0x0F; + if (nibble <= 9) + { + UNITY_OUTPUT_CHAR((char)('0' + nibble)); + } + else + { + UNITY_OUTPUT_CHAR((char)('A' - 10 + nibble)); + } + } +} + +/*-----------------------------------------------*/ +void UnityPrintMask(const UNITY_UINT mask, const UNITY_UINT number) +{ + UNITY_UINT current_bit = (UNITY_UINT)1 << (UNITY_INT_WIDTH - 1); + UNITY_INT32 i; + + for (i = 0; i < UNITY_INT_WIDTH; i++) + { + if (current_bit & mask) + { + if (current_bit & number) + { + UNITY_OUTPUT_CHAR('1'); + } + else + { + UNITY_OUTPUT_CHAR('0'); + } + } + else + { + UNITY_OUTPUT_CHAR('X'); + } + current_bit = current_bit >> 1; + } +} + +/*-----------------------------------------------*/ +#ifndef UNITY_EXCLUDE_FLOAT_PRINT +/* + * This function prints a floating-point value in a format similar to + * printf("%.7g") on a single-precision machine or printf("%.9g") on a + * double-precision machine. The 7th digit won't always be totally correct + * in single-precision operation (for that level of accuracy, a more + * complicated algorithm would be needed). + */ +void UnityPrintFloat(const UNITY_DOUBLE input_number) +{ +#ifdef UNITY_INCLUDE_DOUBLE + static const int sig_digits = 9; + static const UNITY_INT32 min_scaled = 100000000; + static const UNITY_INT32 max_scaled = 1000000000; +#else + static const int sig_digits = 7; + static const UNITY_INT32 min_scaled = 1000000; + static const UNITY_INT32 max_scaled = 10000000; +#endif + + UNITY_DOUBLE number = input_number; + + /* print minus sign (does not handle negative zero) */ + if (number < 0.0f) + { + UNITY_OUTPUT_CHAR('-'); + number = -number; + } + + /* handle zero, NaN, and +/- infinity */ + if (number == 0.0f) + { + UnityPrint("0"); + } + else if (UNITY_IS_NAN(number)) + { + UnityPrint("nan"); + } + else if (UNITY_IS_INF(number)) + { + UnityPrint("inf"); + } + else + { + UNITY_INT32 n_int = 0; + UNITY_INT32 n; + int exponent = 0; + int decimals; + int digits; + char buf[16] = {0}; + + /* + * Scale up or down by powers of 10. To minimize rounding error, + * start with a factor/divisor of 10^10, which is the largest + * power of 10 that can be represented exactly. Finally, compute + * (exactly) the remaining power of 10 and perform one more + * multiplication or division. + */ + if (number < 1.0f) + { + UNITY_DOUBLE factor = 1.0f; + + while (number < (UNITY_DOUBLE)max_scaled / 1e10f) { number *= 1e10f; exponent -= 10; } + while (number * factor < (UNITY_DOUBLE)min_scaled) { factor *= 10.0f; exponent--; } + + number *= factor; + } + else if (number > (UNITY_DOUBLE)max_scaled) + { + UNITY_DOUBLE divisor = 1.0f; + + while (number > (UNITY_DOUBLE)min_scaled * 1e10f) { number /= 1e10f; exponent += 10; } + while (number / divisor > (UNITY_DOUBLE)max_scaled) { divisor *= 10.0f; exponent++; } + + number /= divisor; + } + else + { + /* + * In this range, we can split off the integer part before + * doing any multiplications. This reduces rounding error by + * freeing up significant bits in the fractional part. + */ + UNITY_DOUBLE factor = 1.0f; + n_int = (UNITY_INT32)number; + number -= (UNITY_DOUBLE)n_int; + + while (n_int < min_scaled) { n_int *= 10; factor *= 10.0f; exponent--; } + + number *= factor; + } + + /* round to nearest integer */ + n = ((UNITY_INT32)(number + number) + 1) / 2; + +#ifndef UNITY_ROUND_TIES_AWAY_FROM_ZERO + /* round to even if exactly between two integers */ + if ((n & 1) && (((UNITY_DOUBLE)n - number) == 0.5f)) + n--; +#endif + + n += n_int; + + if (n >= max_scaled) + { + n = min_scaled; + exponent++; + } + + /* determine where to place decimal point */ + decimals = ((exponent <= 0) && (exponent >= -(sig_digits + 3))) ? (-exponent) : (sig_digits - 1); + exponent += decimals; + + /* truncate trailing zeroes after decimal point */ + while ((decimals > 0) && ((n % 10) == 0)) + { + n /= 10; + decimals--; + } + + /* build up buffer in reverse order */ + digits = 0; + while ((n != 0) || (digits <= decimals)) + { + buf[digits++] = (char)('0' + n % 10); + n /= 10; + } + + /* print out buffer (backwards) */ + while (digits > 0) + { + if (digits == decimals) + { + UNITY_OUTPUT_CHAR('.'); + } + UNITY_OUTPUT_CHAR(buf[--digits]); + } + + /* print exponent if needed */ + if (exponent != 0) + { + UNITY_OUTPUT_CHAR('e'); + + if (exponent < 0) + { + UNITY_OUTPUT_CHAR('-'); + exponent = -exponent; + } + else + { + UNITY_OUTPUT_CHAR('+'); + } + + digits = 0; + while ((exponent != 0) || (digits < 2)) + { + buf[digits++] = (char)('0' + exponent % 10); + exponent /= 10; + } + while (digits > 0) + { + UNITY_OUTPUT_CHAR(buf[--digits]); + } + } + } +} +#endif /* ! UNITY_EXCLUDE_FLOAT_PRINT */ + +/*-----------------------------------------------*/ +static void UnityTestResultsBegin(const char* file, const UNITY_LINE_TYPE line) +{ +#ifdef UNITY_OUTPUT_FOR_ECLIPSE + UNITY_OUTPUT_CHAR('('); + UnityPrint(file); + UNITY_OUTPUT_CHAR(':'); + UnityPrintNumber((UNITY_INT)line); + UNITY_OUTPUT_CHAR(')'); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(Unity.CurrentTestName); + UNITY_OUTPUT_CHAR(':'); +#else +#ifdef UNITY_OUTPUT_FOR_IAR_WORKBENCH + UnityPrint("'); + UnityPrint(Unity.CurrentTestName); + UnityPrint(" "); +#else +#ifdef UNITY_OUTPUT_FOR_QT_CREATOR + UnityPrint("file://"); + UnityPrint(file); + UNITY_OUTPUT_CHAR(':'); + UnityPrintNumber((UNITY_INT)line); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(Unity.CurrentTestName); + UNITY_OUTPUT_CHAR(':'); +#else + UnityPrint(file); + UNITY_OUTPUT_CHAR(':'); + UnityPrintNumber((UNITY_INT)line); + UNITY_OUTPUT_CHAR(':'); + UnityPrint(Unity.CurrentTestName); + UNITY_OUTPUT_CHAR(':'); +#endif +#endif +#endif +} + +/*-----------------------------------------------*/ +static void UnityTestResultsFailBegin(const UNITY_LINE_TYPE line) +{ + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint(UnityStrFail); + UNITY_OUTPUT_CHAR(':'); +} + +/*-----------------------------------------------*/ +void UnityConcludeTest(void) +{ + if (Unity.CurrentTestIgnored) + { + Unity.TestIgnores++; + } + else if (!Unity.CurrentTestFailed) + { + UnityTestResultsBegin(Unity.TestFile, Unity.CurrentTestLineNumber); + UnityPrint(UnityStrPass); + } + else + { + Unity.TestFailures++; + } + + Unity.CurrentTestFailed = 0; + Unity.CurrentTestIgnored = 0; + UNITY_PRINT_EXEC_TIME(); + UNITY_PRINT_EOL(); + UNITY_FLUSH_CALL(); +} + +/*-----------------------------------------------*/ +static void UnityAddMsgIfSpecified(const char* msg) +{ +#ifdef UNITY_PRINT_TEST_CONTEXT + UnityPrint(UnityStrSpacer); + UNITY_PRINT_TEST_CONTEXT(); +#endif +#ifndef UNITY_EXCLUDE_DETAILS + if (Unity.CurrentDetail1) + { + UnityPrint(UnityStrSpacer); + UnityPrint(UnityStrDetail1Name); + UnityPrint(Unity.CurrentDetail1); + if (Unity.CurrentDetail2) + { + UnityPrint(UnityStrDetail2Name); + UnityPrint(Unity.CurrentDetail2); + } + } +#endif + if (msg) + { + UnityPrint(UnityStrSpacer); + UnityPrint(msg); + } +} + +/*-----------------------------------------------*/ +static void UnityPrintExpectedAndActualStrings(const char* expected, const char* actual) +{ + UnityPrint(UnityStrExpected); + if (expected != NULL) + { + UNITY_OUTPUT_CHAR('\''); + UnityPrint(expected); + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrint(UnityStrNull); + } + UnityPrint(UnityStrWas); + if (actual != NULL) + { + UNITY_OUTPUT_CHAR('\''); + UnityPrint(actual); + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrint(UnityStrNull); + } +} + +/*-----------------------------------------------*/ +static void UnityPrintExpectedAndActualStringsLen(const char* expected, + const char* actual, + const UNITY_UINT32 length) +{ + UnityPrint(UnityStrExpected); + if (expected != NULL) + { + UNITY_OUTPUT_CHAR('\''); + UnityPrintLen(expected, length); + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrint(UnityStrNull); + } + UnityPrint(UnityStrWas); + if (actual != NULL) + { + UNITY_OUTPUT_CHAR('\''); + UnityPrintLen(actual, length); + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrint(UnityStrNull); + } +} + +/*----------------------------------------------- + * Assertion & Control Helpers + *-----------------------------------------------*/ + +/*-----------------------------------------------*/ +static int UnityIsOneArrayNull(UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_LINE_TYPE lineNumber, + const char* msg) +{ + /* Both are NULL or same pointer */ + if (expected == actual) { return 0; } + + /* print and return true if just expected is NULL */ + if (expected == NULL) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrNullPointerForExpected); + UnityAddMsgIfSpecified(msg); + return 1; + } + + /* print and return true if just actual is NULL */ + if (actual == NULL) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrNullPointerForActual); + UnityAddMsgIfSpecified(msg); + return 1; + } + + return 0; /* return false if neither is NULL */ +} + +/*----------------------------------------------- + * Assertion Functions + *-----------------------------------------------*/ + +/*-----------------------------------------------*/ +void UnityAssertBits(const UNITY_INT mask, + const UNITY_INT expected, + const UNITY_INT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + RETURN_IF_FAIL_OR_IGNORE; + + if ((mask & expected) != (mask & actual)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintMask((UNITY_UINT)mask, (UNITY_UINT)expected); + UnityPrint(UnityStrWas); + UnityPrintMask((UNITY_UINT)mask, (UNITY_UINT)actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertEqualNumber(const UNITY_INT expected, + const UNITY_INT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) +{ + RETURN_IF_FAIL_OR_IGNORE; + + if (expected != actual) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(expected, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(actual, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold, + const UNITY_INT actual, + const UNITY_COMPARISON_T compare, + const char *msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) +{ + int failed = 0; + RETURN_IF_FAIL_OR_IGNORE; + + if ((threshold == actual) && (compare & UNITY_EQUAL_TO)) { return; } + if ((threshold == actual)) { failed = 1; } + + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + if ((actual > threshold) && (compare & UNITY_SMALLER_THAN)) { failed = 1; } + if ((actual < threshold) && (compare & UNITY_GREATER_THAN)) { failed = 1; } + } + else /* UINT or HEX */ + { + if (((UNITY_UINT)actual > (UNITY_UINT)threshold) && (compare & UNITY_SMALLER_THAN)) { failed = 1; } + if (((UNITY_UINT)actual < (UNITY_UINT)threshold) && (compare & UNITY_GREATER_THAN)) { failed = 1; } + } + + if (failed) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(actual, style); + if (compare & UNITY_GREATER_THAN) { UnityPrint(UnityStrGt); } + if (compare & UNITY_SMALLER_THAN) { UnityPrint(UnityStrLt); } + if (compare & UNITY_EQUAL_TO) { UnityPrint(UnityStrOrEqual); } + if (compare == UNITY_NOT_EQUAL) { UnityPrint(UnityStrNotEqual); } + UnityPrintNumberByStyle(threshold, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +#define UnityPrintPointlessAndBail() \ +do { \ + UnityTestResultsFailBegin(lineNumber); \ + UnityPrint(UnityStrPointless); \ + UnityAddMsgIfSpecified(msg); \ + UNITY_FAIL_AND_BAIL; \ +} while (0) + +/*-----------------------------------------------*/ +void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style, + const UNITY_FLAGS_T flags) +{ + UNITY_UINT32 elements = num_elements; + unsigned int length = style & 0xF; + unsigned int increment = 0; + + RETURN_IF_FAIL_OR_IGNORE; + + if (num_elements == 0) + { +#ifdef UNITY_COMPARE_PTRS_ON_ZERO_ARRAY + UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, lineNumber, msg); +#else + UnityPrintPointlessAndBail(); +#endif + } + + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + + if (UnityIsOneArrayNull(expected, actual, lineNumber, msg)) + { + UNITY_FAIL_AND_BAIL; + } + + while ((elements > 0) && (elements--)) + { + UNITY_INT expect_val; + UNITY_INT actual_val; + + switch (length) + { + case 1: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)actual; + if (style & (UNITY_DISPLAY_RANGE_UINT | UNITY_DISPLAY_RANGE_HEX)) + { + expect_val &= 0x000000FF; + actual_val &= 0x000000FF; + } + increment = sizeof(UNITY_INT8); + break; + + case 2: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)actual; + if (style & (UNITY_DISPLAY_RANGE_UINT | UNITY_DISPLAY_RANGE_HEX)) + { + expect_val &= 0x0000FFFF; + actual_val &= 0x0000FFFF; + } + increment = sizeof(UNITY_INT16); + break; + +#ifdef UNITY_SUPPORT_64 + case 8: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT64*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT64*)actual; + increment = sizeof(UNITY_INT64); + break; +#endif + + default: /* default is length 4 bytes */ + case 4: + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)actual; +#ifdef UNITY_SUPPORT_64 + if (style & (UNITY_DISPLAY_RANGE_UINT | UNITY_DISPLAY_RANGE_HEX)) + { + expect_val &= 0x00000000FFFFFFFF; + actual_val &= 0x00000000FFFFFFFF; + } +#endif + increment = sizeof(UNITY_INT32); + length = 4; + break; + } + + if (expect_val != actual_val) + { + if ((style & UNITY_DISPLAY_RANGE_UINT) && (length < (UNITY_INT_WIDTH / 8))) + { /* For UINT, remove sign extension (padding 1's) from signed type casts above */ + UNITY_INT mask = 1; + mask = (mask << 8 * length) - 1; + expect_val &= mask; + actual_val &= mask; + } + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(expect_val, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(actual_val, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + /* Walk through array by incrementing the pointers */ + if (flags == UNITY_ARRAY_TO_ARRAY) + { + expected = (UNITY_INTERNAL_PTR)((const char*)expected + increment); + } + actual = (UNITY_INTERNAL_PTR)((const char*)actual + increment); + } +} + +/*-----------------------------------------------*/ +#ifndef UNITY_EXCLUDE_FLOAT +/* Wrap this define in a function with variable types as float or double */ +#define UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff) \ + if (UNITY_IS_INF(expected) && UNITY_IS_INF(actual) && (((expected) < 0) == ((actual) < 0))) return 1; \ + if (UNITY_NAN_CHECK) return 1; \ + (diff) = (actual) - (expected); \ + if ((diff) < 0) (diff) = -(diff); \ + if ((delta) < 0) (delta) = -(delta); \ + return !(UNITY_IS_NAN(diff) || UNITY_IS_INF(diff) || ((diff) > (delta))) + /* This first part of this condition will catch any NaN or Infinite values */ +#ifndef UNITY_NAN_NOT_EQUAL_NAN + #define UNITY_NAN_CHECK UNITY_IS_NAN(expected) && UNITY_IS_NAN(actual) +#else + #define UNITY_NAN_CHECK 0 +#endif + +#ifndef UNITY_EXCLUDE_FLOAT_PRINT + #define UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual) \ + do { \ + UnityPrint(UnityStrExpected); \ + UnityPrintFloat(expected); \ + UnityPrint(UnityStrWas); \ + UnityPrintFloat(actual); \ + } while (0) +#else + #define UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual) \ + UnityPrint(UnityStrDelta) +#endif /* UNITY_EXCLUDE_FLOAT_PRINT */ + +/*-----------------------------------------------*/ +static int UnityFloatsWithin(UNITY_FLOAT delta, UNITY_FLOAT expected, UNITY_FLOAT actual) +{ + UNITY_FLOAT diff; + UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff); +} + +/*-----------------------------------------------*/ +void UnityAssertWithinFloatArray(const UNITY_FLOAT delta, + UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* expected, + UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags) +{ + UNITY_UINT32 elements = num_elements; + UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* ptr_expected = expected; + UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* ptr_actual = actual; + UNITY_FLOAT in_delta = delta; + UNITY_FLOAT current_element_delta = delta; + + RETURN_IF_FAIL_OR_IGNORE; + + if (elements == 0) + { +#ifdef UNITY_COMPARE_PTRS_ON_ZERO_ARRAY + UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, lineNumber, msg); +#else + UnityPrintPointlessAndBail(); +#endif + } + + if (UNITY_IS_INF(in_delta)) + { + return; /* Arrays will be force equal with infinite delta */ + } + + if (UNITY_IS_NAN(in_delta)) + { + /* Delta must be correct number */ + UnityPrintPointlessAndBail(); + } + + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + + if (UnityIsOneArrayNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg)) + { + UNITY_FAIL_AND_BAIL; + } + + /* fix delta sign if need */ + if (in_delta < 0) + { + in_delta = -in_delta; + } + + while (elements--) + { + current_element_delta = *ptr_expected * UNITY_FLOAT_PRECISION; + + if (current_element_delta < 0) + { + /* fix delta sign for correct calculations */ + current_element_delta = -current_element_delta; + } + + if (!UnityFloatsWithin(in_delta + current_element_delta, *ptr_expected, *ptr_actual)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT((UNITY_DOUBLE)*ptr_expected, (UNITY_DOUBLE)*ptr_actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + if (flags == UNITY_ARRAY_TO_ARRAY) + { + ptr_expected++; + } + ptr_actual++; + } +} + +/*-----------------------------------------------*/ +void UnityAssertFloatsWithin(const UNITY_FLOAT delta, + const UNITY_FLOAT expected, + const UNITY_FLOAT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + RETURN_IF_FAIL_OR_IGNORE; + + + if (!UnityFloatsWithin(delta, expected, actual)) + { + UnityTestResultsFailBegin(lineNumber); + UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT((UNITY_DOUBLE)expected, (UNITY_DOUBLE)actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertFloatsNotWithin(const UNITY_FLOAT delta, + const UNITY_FLOAT expected, + const UNITY_FLOAT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + RETURN_IF_FAIL_OR_IGNORE; + + if (UnityFloatsWithin(delta, expected, actual)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintFloat((UNITY_DOUBLE)expected); + UnityPrint(UnityStrNotEqual); + UnityPrintFloat((UNITY_DOUBLE)actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertGreaterOrLessFloat(const UNITY_FLOAT threshold, + const UNITY_FLOAT actual, + const UNITY_COMPARISON_T compare, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + int failed; + + RETURN_IF_FAIL_OR_IGNORE; + + failed = 0; + + /* Checking for "not success" rather than failure to get the right result for NaN */ + if (!(actual < threshold) && (compare & UNITY_SMALLER_THAN)) { failed = 1; } + if (!(actual > threshold) && (compare & UNITY_GREATER_THAN)) { failed = 1; } + + if ((compare & UNITY_EQUAL_TO) && UnityFloatsWithin(threshold * UNITY_FLOAT_PRECISION, threshold, actual)) { failed = 0; } + + if (failed) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintFloat(actual); + if (compare & UNITY_GREATER_THAN) { UnityPrint(UnityStrGt); } + if (compare & UNITY_SMALLER_THAN) { UnityPrint(UnityStrLt); } + if (compare & UNITY_EQUAL_TO) { UnityPrint(UnityStrOrEqual); } + UnityPrintFloat(threshold); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertFloatSpecial(const UNITY_FLOAT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style) +{ + const char* trait_names[] = {UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet}; + UNITY_INT should_be_trait = ((UNITY_INT)style & 1); + UNITY_INT is_trait = !should_be_trait; + UNITY_INT trait_index = (UNITY_INT)(style >> 1); + + RETURN_IF_FAIL_OR_IGNORE; + + switch (style) + { + case UNITY_FLOAT_IS_INF: + case UNITY_FLOAT_IS_NOT_INF: + is_trait = UNITY_IS_INF(actual) && (actual > 0); + break; + case UNITY_FLOAT_IS_NEG_INF: + case UNITY_FLOAT_IS_NOT_NEG_INF: + is_trait = UNITY_IS_INF(actual) && (actual < 0); + break; + + case UNITY_FLOAT_IS_NAN: + case UNITY_FLOAT_IS_NOT_NAN: + is_trait = UNITY_IS_NAN(actual) ? 1 : 0; + break; + + case UNITY_FLOAT_IS_DET: /* A determinate number is non infinite and not NaN. */ + case UNITY_FLOAT_IS_NOT_DET: + is_trait = !UNITY_IS_INF(actual) && !UNITY_IS_NAN(actual); + break; + + case UNITY_FLOAT_INVALID_TRAIT: /* Supress warning */ + default: /* including UNITY_FLOAT_INVALID_TRAIT */ + trait_index = 0; + trait_names[0] = UnityStrInvalidFloatTrait; + break; + } + + if (is_trait != should_be_trait) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + if (!should_be_trait) + { + UnityPrint(UnityStrNot); + } + UnityPrint(trait_names[trait_index]); + UnityPrint(UnityStrWas); +#ifndef UNITY_EXCLUDE_FLOAT_PRINT + UnityPrintFloat((UNITY_DOUBLE)actual); +#else + if (should_be_trait) + { + UnityPrint(UnityStrNot); + } + UnityPrint(trait_names[trait_index]); +#endif + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +#endif /* not UNITY_EXCLUDE_FLOAT */ + +/*-----------------------------------------------*/ +#ifndef UNITY_EXCLUDE_DOUBLE +static int UnityDoublesWithin(UNITY_DOUBLE delta, UNITY_DOUBLE expected, UNITY_DOUBLE actual) +{ + UNITY_DOUBLE diff; + UNITY_FLOAT_OR_DOUBLE_WITHIN(delta, expected, actual, diff); +} + +/*-----------------------------------------------*/ +void UnityAssertWithinDoubleArray(const UNITY_DOUBLE delta, + UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* expected, + UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags) +{ + UNITY_UINT32 elements = num_elements; + UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* ptr_expected = expected; + UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* ptr_actual = actual; + UNITY_DOUBLE in_delta = delta; + UNITY_DOUBLE current_element_delta = delta; + + RETURN_IF_FAIL_OR_IGNORE; + + if (elements == 0) + { +#ifdef UNITY_COMPARE_PTRS_ON_ZERO_ARRAY + UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, lineNumber, msg); +#else + UnityPrintPointlessAndBail(); +#endif + } + + if (UNITY_IS_INF(in_delta)) + { + return; /* Arrays will be force equal with infinite delta */ + } + + if (UNITY_IS_NAN(in_delta)) + { + /* Delta must be correct number */ + UnityPrintPointlessAndBail(); + } + + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + + if (UnityIsOneArrayNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg)) + { + UNITY_FAIL_AND_BAIL; + } + + /* fix delta sign if need */ + if (in_delta < 0) + { + in_delta = -in_delta; + } + + while (elements--) + { + current_element_delta = *ptr_expected * UNITY_DOUBLE_PRECISION; + + if (current_element_delta < 0) + { + /* fix delta sign for correct calculations */ + current_element_delta = -current_element_delta; + } + + if (!UnityDoublesWithin(in_delta + current_element_delta, *ptr_expected, *ptr_actual)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(*ptr_expected, *ptr_actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + if (flags == UNITY_ARRAY_TO_ARRAY) + { + ptr_expected++; + } + ptr_actual++; + } +} + +/*-----------------------------------------------*/ +void UnityAssertDoublesWithin(const UNITY_DOUBLE delta, + const UNITY_DOUBLE expected, + const UNITY_DOUBLE actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + RETURN_IF_FAIL_OR_IGNORE; + + if (!UnityDoublesWithin(delta, expected, actual)) + { + UnityTestResultsFailBegin(lineNumber); + UNITY_PRINT_EXPECTED_AND_ACTUAL_FLOAT(expected, actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertDoublesNotWithin(const UNITY_DOUBLE delta, + const UNITY_DOUBLE expected, + const UNITY_DOUBLE actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + RETURN_IF_FAIL_OR_IGNORE; + + if (UnityDoublesWithin(delta, expected, actual)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintFloat((UNITY_DOUBLE)expected); + UnityPrint(UnityStrNotEqual); + UnityPrintFloat((UNITY_DOUBLE)actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertGreaterOrLessDouble(const UNITY_DOUBLE threshold, + const UNITY_DOUBLE actual, + const UNITY_COMPARISON_T compare, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + int failed; + + RETURN_IF_FAIL_OR_IGNORE; + + failed = 0; + + /* Checking for "not success" rather than failure to get the right result for NaN */ + if (!(actual < threshold) && (compare & UNITY_SMALLER_THAN)) { failed = 1; } + if (!(actual > threshold) && (compare & UNITY_GREATER_THAN)) { failed = 1; } + + if ((compare & UNITY_EQUAL_TO) && UnityDoublesWithin(threshold * UNITY_DOUBLE_PRECISION, threshold, actual)) { failed = 0; } + + if (failed) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintFloat(actual); + if (compare & UNITY_GREATER_THAN) { UnityPrint(UnityStrGt); } + if (compare & UNITY_SMALLER_THAN) { UnityPrint(UnityStrLt); } + if (compare & UNITY_EQUAL_TO) { UnityPrint(UnityStrOrEqual); } + UnityPrintFloat(threshold); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertDoubleSpecial(const UNITY_DOUBLE actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style) +{ + const char* trait_names[] = {UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet}; + UNITY_INT should_be_trait = ((UNITY_INT)style & 1); + UNITY_INT is_trait = !should_be_trait; + UNITY_INT trait_index = (UNITY_INT)(style >> 1); + + RETURN_IF_FAIL_OR_IGNORE; + + switch (style) + { + case UNITY_FLOAT_IS_INF: + case UNITY_FLOAT_IS_NOT_INF: + is_trait = UNITY_IS_INF(actual) && (actual > 0); + break; + case UNITY_FLOAT_IS_NEG_INF: + case UNITY_FLOAT_IS_NOT_NEG_INF: + is_trait = UNITY_IS_INF(actual) && (actual < 0); + break; + + case UNITY_FLOAT_IS_NAN: + case UNITY_FLOAT_IS_NOT_NAN: + is_trait = UNITY_IS_NAN(actual) ? 1 : 0; + break; + + case UNITY_FLOAT_IS_DET: /* A determinate number is non infinite and not NaN. */ + case UNITY_FLOAT_IS_NOT_DET: + is_trait = !UNITY_IS_INF(actual) && !UNITY_IS_NAN(actual); + break; + + case UNITY_FLOAT_INVALID_TRAIT: /* Supress warning */ + default: /* including UNITY_FLOAT_INVALID_TRAIT */ + trait_index = 0; + trait_names[0] = UnityStrInvalidFloatTrait; + break; + } + + if (is_trait != should_be_trait) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + if (!should_be_trait) + { + UnityPrint(UnityStrNot); + } + UnityPrint(trait_names[trait_index]); + UnityPrint(UnityStrWas); +#ifndef UNITY_EXCLUDE_FLOAT_PRINT + UnityPrintFloat(actual); +#else + if (should_be_trait) + { + UnityPrint(UnityStrNot); + } + UnityPrint(trait_names[trait_index]); +#endif + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +#endif /* not UNITY_EXCLUDE_DOUBLE */ + +/*-----------------------------------------------*/ +void UnityAssertNumbersWithin(const UNITY_UINT delta, + const UNITY_INT expected, + const UNITY_INT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) +{ + RETURN_IF_FAIL_OR_IGNORE; + + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + if (actual > expected) + { + Unity.CurrentTestFailed = (((UNITY_UINT)actual - (UNITY_UINT)expected) > delta); + } + else + { + Unity.CurrentTestFailed = (((UNITY_UINT)expected - (UNITY_UINT)actual) > delta); + } + } + else + { + if ((UNITY_UINT)actual > (UNITY_UINT)expected) + { + Unity.CurrentTestFailed = (((UNITY_UINT)actual - (UNITY_UINT)expected) > delta); + } + else + { + Unity.CurrentTestFailed = (((UNITY_UINT)expected - (UNITY_UINT)actual) > delta); + } + } + + if (Unity.CurrentTestFailed) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrDelta); + UnityPrintNumberByStyle((UNITY_INT)delta, style); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(expected, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(actual, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertNumbersArrayWithin(const UNITY_UINT delta, + UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style, + const UNITY_FLAGS_T flags) +{ + UNITY_UINT32 elements = num_elements; + unsigned int length = style & 0xF; + unsigned int increment = 0; + + RETURN_IF_FAIL_OR_IGNORE; + + if (num_elements == 0) + { +#ifdef UNITY_COMPARE_PTRS_ON_ZERO_ARRAY + UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, lineNumber, msg); +#else + UnityPrintPointlessAndBail(); +#endif + } + + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + + if (UnityIsOneArrayNull(expected, actual, lineNumber, msg)) + { + UNITY_FAIL_AND_BAIL; + } + + while ((elements > 0) && (elements--)) + { + UNITY_INT expect_val; + UNITY_INT actual_val; + + switch (length) + { + case 1: + /* fixing problems with signed overflow on unsigned numbers */ + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT8*)actual; + increment = sizeof(UNITY_INT8); + } + else + { + expect_val = (UNITY_INT)*(UNITY_PTR_ATTRIBUTE const UNITY_UINT8*)expected; + actual_val = (UNITY_INT)*(UNITY_PTR_ATTRIBUTE const UNITY_UINT8*)actual; + increment = sizeof(UNITY_UINT8); + } + break; + + case 2: + /* fixing problems with signed overflow on unsigned numbers */ + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT16*)actual; + increment = sizeof(UNITY_INT16); + } + else + { + expect_val = (UNITY_INT)*(UNITY_PTR_ATTRIBUTE const UNITY_UINT16*)expected; + actual_val = (UNITY_INT)*(UNITY_PTR_ATTRIBUTE const UNITY_UINT16*)actual; + increment = sizeof(UNITY_UINT16); + } + break; + +#ifdef UNITY_SUPPORT_64 + case 8: + /* fixing problems with signed overflow on unsigned numbers */ + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT64*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT64*)actual; + increment = sizeof(UNITY_INT64); + } + else + { + expect_val = (UNITY_INT)*(UNITY_PTR_ATTRIBUTE const UNITY_UINT64*)expected; + actual_val = (UNITY_INT)*(UNITY_PTR_ATTRIBUTE const UNITY_UINT64*)actual; + increment = sizeof(UNITY_UINT64); + } + break; +#endif + + default: /* default is length 4 bytes */ + case 4: + /* fixing problems with signed overflow on unsigned numbers */ + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + expect_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)expected; + actual_val = *(UNITY_PTR_ATTRIBUTE const UNITY_INT32*)actual; + increment = sizeof(UNITY_INT32); + } + else + { + expect_val = (UNITY_INT)*(UNITY_PTR_ATTRIBUTE const UNITY_UINT32*)expected; + actual_val = (UNITY_INT)*(UNITY_PTR_ATTRIBUTE const UNITY_UINT32*)actual; + increment = sizeof(UNITY_UINT32); + } + length = 4; + break; + } + + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + if (actual_val > expect_val) + { + Unity.CurrentTestFailed = (((UNITY_UINT)actual_val - (UNITY_UINT)expect_val) > delta); + } + else + { + Unity.CurrentTestFailed = (((UNITY_UINT)expect_val - (UNITY_UINT)actual_val) > delta); + } + } + else + { + if ((UNITY_UINT)actual_val > (UNITY_UINT)expect_val) + { + Unity.CurrentTestFailed = (((UNITY_UINT)actual_val - (UNITY_UINT)expect_val) > delta); + } + else + { + Unity.CurrentTestFailed = (((UNITY_UINT)expect_val - (UNITY_UINT)actual_val) > delta); + } + } + + if (Unity.CurrentTestFailed) + { + if ((style & UNITY_DISPLAY_RANGE_UINT) && (length < (UNITY_INT_WIDTH / 8))) + { /* For UINT, remove sign extension (padding 1's) from signed type casts above */ + UNITY_INT mask = 1; + mask = (mask << 8 * length) - 1; + expect_val &= mask; + actual_val &= mask; + } + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrDelta); + UnityPrintNumberByStyle((UNITY_INT)delta, style); + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(expect_val, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(actual_val, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + /* Walk through array by incrementing the pointers */ + if (flags == UNITY_ARRAY_TO_ARRAY) + { + expected = (UNITY_INTERNAL_PTR)((const char*)expected + increment); + } + actual = (UNITY_INTERNAL_PTR)((const char*)actual + increment); + } +} + +/*-----------------------------------------------*/ +void UnityAssertEqualString(const char* expected, + const char* actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + UNITY_UINT32 i; + + RETURN_IF_FAIL_OR_IGNORE; + + /* if both pointers not null compare the strings */ + if (expected && actual) + { + for (i = 0; expected[i] || actual[i]; i++) + { + if (expected[i] != actual[i]) + { + Unity.CurrentTestFailed = 1; + break; + } + } + } + else + { /* fail if either null but not if both */ + if (expected || actual) + { + Unity.CurrentTestFailed = 1; + } + } + + if (Unity.CurrentTestFailed) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrintExpectedAndActualStrings(expected, actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertEqualStringLen(const char* expected, + const char* actual, + const UNITY_UINT32 length, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + UNITY_UINT32 i; + + RETURN_IF_FAIL_OR_IGNORE; + + /* if both pointers not null compare the strings */ + if (expected && actual) + { + for (i = 0; (i < length) && (expected[i] || actual[i]); i++) + { + if (expected[i] != actual[i]) + { + Unity.CurrentTestFailed = 1; + break; + } + } + } + else + { /* fail if either null but not if both */ + if (expected || actual) + { + Unity.CurrentTestFailed = 1; + } + } + + if (Unity.CurrentTestFailed) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrintExpectedAndActualStringsLen(expected, actual, length); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertEqualStringArray(UNITY_INTERNAL_PTR expected, + const char** actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags) +{ + UNITY_UINT32 i = 0; + UNITY_UINT32 j = 0; + const char* expd = NULL; + const char* act = NULL; + + RETURN_IF_FAIL_OR_IGNORE; + + /* if no elements, it's an error */ + if (num_elements == 0) + { +#ifdef UNITY_COMPARE_PTRS_ON_ZERO_ARRAY + UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, lineNumber, msg); +#else + UnityPrintPointlessAndBail(); +#endif + } + + if ((const void*)expected == (const void*)actual) + { + return; /* Both are NULL or same pointer */ + } + + if (UnityIsOneArrayNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg)) + { + UNITY_FAIL_AND_BAIL; + } + + if (flags != UNITY_ARRAY_TO_ARRAY) + { + expd = (const char*)expected; + } + + do + { + act = actual[j]; + if (flags == UNITY_ARRAY_TO_ARRAY) + { + expd = ((const char* const*)expected)[j]; + } + + /* if both pointers not null compare the strings */ + if (expd && act) + { + for (i = 0; expd[i] || act[i]; i++) + { + if (expd[i] != act[i]) + { + Unity.CurrentTestFailed = 1; + break; + } + } + } + else + { /* handle case of one pointers being null (if both null, test should pass) */ + if (expd != act) + { + Unity.CurrentTestFailed = 1; + } + } + + if (Unity.CurrentTestFailed) + { + UnityTestResultsFailBegin(lineNumber); + if (num_elements > 1) + { + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(j); + } + UnityPrintExpectedAndActualStrings(expd, act); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + } while (++j < num_elements); +} + +/*-----------------------------------------------*/ +void UnityAssertEqualMemory(UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 length, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags) +{ + UNITY_PTR_ATTRIBUTE const unsigned char* ptr_exp = (UNITY_PTR_ATTRIBUTE const unsigned char*)expected; + UNITY_PTR_ATTRIBUTE const unsigned char* ptr_act = (UNITY_PTR_ATTRIBUTE const unsigned char*)actual; + UNITY_UINT32 elements = num_elements; + UNITY_UINT32 bytes; + + RETURN_IF_FAIL_OR_IGNORE; + + if (elements == 0) + { +#ifdef UNITY_COMPARE_PTRS_ON_ZERO_ARRAY + UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, lineNumber, msg); +#else + UnityPrintPointlessAndBail(); +#endif + } + if (length == 0) + { + UnityPrintPointlessAndBail(); + } + + if (expected == actual) + { + return; /* Both are NULL or same pointer */ + } + + if (UnityIsOneArrayNull(expected, actual, lineNumber, msg)) + { + UNITY_FAIL_AND_BAIL; + } + + while (elements--) + { + bytes = length; + while (bytes--) + { + if (*ptr_exp != *ptr_act) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrMemory); + if (num_elements > 1) + { + UnityPrint(UnityStrElement); + UnityPrintNumberUnsigned(num_elements - elements - 1); + } + UnityPrint(UnityStrByte); + UnityPrintNumberUnsigned(length - bytes - 1); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(*ptr_exp, UNITY_DISPLAY_STYLE_HEX8); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(*ptr_act, UNITY_DISPLAY_STYLE_HEX8); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + ptr_exp++; + ptr_act++; + } + if (flags == UNITY_ARRAY_TO_VAL) + { + ptr_exp = (UNITY_PTR_ATTRIBUTE const unsigned char*)expected; + } + } +} + +/*-----------------------------------------------*/ + +static union +{ + UNITY_INT8 i8; + UNITY_INT16 i16; + UNITY_INT32 i32; +#ifdef UNITY_SUPPORT_64 + UNITY_INT64 i64; +#endif +#ifndef UNITY_EXCLUDE_FLOAT + float f; +#endif +#ifndef UNITY_EXCLUDE_DOUBLE + double d; +#endif +} UnityQuickCompare; + +UNITY_INTERNAL_PTR UnityNumToPtr(const UNITY_INT num, const UNITY_UINT8 size) +{ + switch(size) + { + case 1: + UnityQuickCompare.i8 = (UNITY_INT8)num; + return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i8); + + case 2: + UnityQuickCompare.i16 = (UNITY_INT16)num; + return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i16); + +#ifdef UNITY_SUPPORT_64 + case 8: + UnityQuickCompare.i64 = (UNITY_INT64)num; + return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i64); +#endif + + default: /* 4 bytes */ + UnityQuickCompare.i32 = (UNITY_INT32)num; + return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.i32); + } +} + +#ifndef UNITY_EXCLUDE_FLOAT +/*-----------------------------------------------*/ +UNITY_INTERNAL_PTR UnityFloatToPtr(const float num) +{ + UnityQuickCompare.f = num; + return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.f); +} +#endif + +#ifndef UNITY_EXCLUDE_DOUBLE +/*-----------------------------------------------*/ +UNITY_INTERNAL_PTR UnityDoubleToPtr(const double num) +{ + UnityQuickCompare.d = num; + return (UNITY_INTERNAL_PTR)(&UnityQuickCompare.d); +} +#endif + +#ifdef UNITY_INCLUDE_PRINT_FORMATTED + +/*----------------------------------------------- + * printf length modifier helpers + *-----------------------------------------------*/ + +enum UnityLengthModifier { + UNITY_LENGTH_MODIFIER_NONE, + UNITY_LENGTH_MODIFIER_LONG_LONG, + UNITY_LENGTH_MODIFIER_LONG, +}; + +#define UNITY_EXTRACT_ARG(NUMBER_T, NUMBER, LENGTH_MOD, VA, ARG_T) \ +do { \ + switch (LENGTH_MOD) \ + { \ + case UNITY_LENGTH_MODIFIER_LONG_LONG: \ + { \ + NUMBER = (NUMBER_T)va_arg(VA, long long ARG_T); \ + break; \ + } \ + case UNITY_LENGTH_MODIFIER_LONG: \ + { \ + NUMBER = (NUMBER_T)va_arg(VA, long ARG_T); \ + break; \ + } \ + case UNITY_LENGTH_MODIFIER_NONE: \ + default: \ + { \ + NUMBER = (NUMBER_T)va_arg(VA, ARG_T); \ + break; \ + } \ + } \ +} while (0) + +static enum UnityLengthModifier UnityLengthModifierGet(const char *pch, int *length) +{ + enum UnityLengthModifier length_mod; + switch (pch[0]) + { + case 'l': + { + if (pch[1] == 'l') + { + *length = 2; + length_mod = UNITY_LENGTH_MODIFIER_LONG_LONG; + } + else + { + *length = 1; + length_mod = UNITY_LENGTH_MODIFIER_LONG; + } + break; + } + case 'h': + { + // short and char are converted to int + length_mod = UNITY_LENGTH_MODIFIER_NONE; + if (pch[1] == 'h') + { + *length = 2; + } + else + { + *length = 1; + } + break; + } + case 'j': + case 'z': + case 't': + case 'L': + { + // Not supported, but should gobble up the length specifier anyway + length_mod = UNITY_LENGTH_MODIFIER_NONE; + *length = 1; + break; + } + default: + { + length_mod = UNITY_LENGTH_MODIFIER_NONE; + *length = 0; + } + } + return length_mod; +} + +/*----------------------------------------------- + * printf helper function + *-----------------------------------------------*/ +static void UnityPrintFVA(const char* format, va_list va) +{ + const char* pch = format; + if (pch != NULL) + { + while (*pch) + { + /* format identification character */ + if (*pch == '%') + { + pch++; + + if (pch != NULL) + { + int length_mod_size; + enum UnityLengthModifier length_mod = UnityLengthModifierGet(pch, &length_mod_size); + pch += length_mod_size; + + switch (*pch) + { + case 'd': + case 'i': + { + UNITY_INT number; + UNITY_EXTRACT_ARG(UNITY_INT, number, length_mod, va, int); + UnityPrintNumber((UNITY_INT)number); + break; + } +#ifndef UNITY_EXCLUDE_FLOAT_PRINT + case 'f': + case 'g': + { + const double number = va_arg(va, double); + UnityPrintFloat((UNITY_DOUBLE)number); + break; + } +#endif + case 'u': + { + UNITY_UINT number; + UNITY_EXTRACT_ARG(UNITY_UINT, number, length_mod, va, unsigned int); + UnityPrintNumberUnsigned(number); + break; + } + case 'b': + { + UNITY_UINT number; + UNITY_EXTRACT_ARG(UNITY_UINT, number, length_mod, va, unsigned int); + const UNITY_UINT mask = (UNITY_UINT)0 - (UNITY_UINT)1; + UNITY_OUTPUT_CHAR('0'); + UNITY_OUTPUT_CHAR('b'); + UnityPrintMask(mask, number); + break; + } + case 'x': + case 'X': + { + UNITY_UINT number; + UNITY_EXTRACT_ARG(UNITY_UINT, number, length_mod, va, unsigned int); + UNITY_OUTPUT_CHAR('0'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex(number, UNITY_MAX_NIBBLES); + break; + } + case 'p': + { + UNITY_UINT number; + char nibbles_to_print = 8; + if (UNITY_POINTER_WIDTH == 64) + { + length_mod = UNITY_LENGTH_MODIFIER_LONG_LONG; + nibbles_to_print = 16; + } + UNITY_EXTRACT_ARG(UNITY_UINT, number, length_mod, va, unsigned int); + UNITY_OUTPUT_CHAR('0'); + UNITY_OUTPUT_CHAR('x'); + UnityPrintNumberHex((UNITY_UINT)number, nibbles_to_print); + break; + } + case 'c': + { + const int ch = va_arg(va, int); + UnityPrintChar((const char *)&ch); + break; + } + case 's': + { + const char * string = va_arg(va, const char *); + UnityPrint(string); + break; + } + case '%': + { + UnityPrintChar(pch); + break; + } + default: + { + /* print the unknown format character */ + UNITY_OUTPUT_CHAR('%'); + UnityPrintChar(pch); + break; + } + } + } + } +#ifdef UNITY_OUTPUT_COLOR + /* print ANSI escape code */ + else if ((*pch == 27) && (*(pch + 1) == '[')) + { + pch += UnityPrintAnsiEscapeString(pch); + continue; + } +#endif + else if (*pch == '\n') + { + UNITY_PRINT_EOL(); + } + else + { + UnityPrintChar(pch); + } + + pch++; + } + } +} + +void UnityPrintF(const UNITY_LINE_TYPE line, const char* format, ...) +{ + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint("INFO"); + if(format != NULL) + { + UnityPrint(": "); + va_list va; + va_start(va, format); + UnityPrintFVA(format, va); + va_end(va); + } + UNITY_PRINT_EOL(); +} +#endif /* ! UNITY_INCLUDE_PRINT_FORMATTED */ + + +/*----------------------------------------------- + * Control Functions + *-----------------------------------------------*/ + +/*-----------------------------------------------*/ +void UnityFail(const char* msg, const UNITY_LINE_TYPE line) +{ + RETURN_IF_FAIL_OR_IGNORE; + + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint(UnityStrFail); + if (msg != NULL) + { + UNITY_OUTPUT_CHAR(':'); + +#ifdef UNITY_PRINT_TEST_CONTEXT + UNITY_PRINT_TEST_CONTEXT(); +#endif +#ifndef UNITY_EXCLUDE_DETAILS + if (Unity.CurrentDetail1) + { + UnityPrint(UnityStrDetail1Name); + UnityPrint(Unity.CurrentDetail1); + if (Unity.CurrentDetail2) + { + UnityPrint(UnityStrDetail2Name); + UnityPrint(Unity.CurrentDetail2); + } + UnityPrint(UnityStrSpacer); + } +#endif + if (msg[0] != ' ') + { + UNITY_OUTPUT_CHAR(' '); + } + UnityPrint(msg); + } + + UNITY_FAIL_AND_BAIL; +} + +/*-----------------------------------------------*/ +void UnityIgnore(const char* msg, const UNITY_LINE_TYPE line) +{ + RETURN_IF_FAIL_OR_IGNORE; + + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint(UnityStrIgnore); + if (msg != NULL) + { + UNITY_OUTPUT_CHAR(':'); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(msg); + } + UNITY_IGNORE_AND_BAIL; +} + +/*-----------------------------------------------*/ +void UnityMessage(const char* msg, const UNITY_LINE_TYPE line) +{ + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint("INFO"); + if (msg != NULL) + { + UNITY_OUTPUT_CHAR(':'); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(msg); + } + UNITY_PRINT_EOL(); +} + +/*-----------------------------------------------*/ +/* If we have not defined our own test runner, then include our default test runner to make life easier */ +#ifndef UNITY_SKIP_DEFAULT_RUNNER +void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum) +{ + Unity.CurrentTestName = FuncName; + Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)FuncLineNum; + Unity.NumberOfTests++; + UNITY_CLR_DETAILS(); + UNITY_EXEC_TIME_START(); + if (TEST_PROTECT()) + { + setUp(); + Func(); + } + if (TEST_PROTECT()) + { + tearDown(); + } + UNITY_EXEC_TIME_STOP(); + UnityConcludeTest(); +} +#endif + +/*-----------------------------------------------*/ +void UnitySetTestFile(const char* filename) +{ + Unity.TestFile = filename; +} + +/*-----------------------------------------------*/ +void UnityBegin(const char* filename) +{ + Unity.TestFile = filename; + Unity.CurrentTestName = NULL; + Unity.CurrentTestLineNumber = 0; + Unity.NumberOfTests = 0; + Unity.TestFailures = 0; + Unity.TestIgnores = 0; + Unity.CurrentTestFailed = 0; + Unity.CurrentTestIgnored = 0; + + UNITY_CLR_DETAILS(); + UNITY_OUTPUT_START(); +} + +/*-----------------------------------------------*/ +int UnityEnd(void) +{ + UNITY_PRINT_EOL(); + UnityPrint(UnityStrBreaker); + UNITY_PRINT_EOL(); + UnityPrintNumber((UNITY_INT)(Unity.NumberOfTests)); + UnityPrint(UnityStrResultsTests); + UnityPrintNumber((UNITY_INT)(Unity.TestFailures)); + UnityPrint(UnityStrResultsFailures); + UnityPrintNumber((UNITY_INT)(Unity.TestIgnores)); + UnityPrint(UnityStrResultsIgnored); + UNITY_PRINT_EOL(); + if (Unity.TestFailures == 0U) + { + UnityPrint(UnityStrOk); + } + else + { + UnityPrint(UnityStrFail); +#ifdef UNITY_DIFFERENTIATE_FINAL_FAIL + UNITY_OUTPUT_CHAR('E'); UNITY_OUTPUT_CHAR('D'); +#endif + } + UNITY_PRINT_EOL(); + UNITY_FLUSH_CALL(); + UNITY_OUTPUT_COMPLETE(); + return (int)(Unity.TestFailures); +} + +/*----------------------------------------------- + * Command Line Argument Support + *-----------------------------------------------*/ +#ifdef UNITY_USE_COMMAND_LINE_ARGS + +char* UnityOptionIncludeNamed = NULL; +char* UnityOptionExcludeNamed = NULL; +int UnityVerbosity = 1; + +/*-----------------------------------------------*/ +int UnityParseOptions(int argc, char** argv) +{ + int i; + UnityOptionIncludeNamed = NULL; + UnityOptionExcludeNamed = NULL; + + for (i = 1; i < argc; i++) + { + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'l': /* list tests */ + return -1; + case 'n': /* include tests with name including this string */ + case 'f': /* an alias for -n */ + if (argv[i][2] == '=') + { + UnityOptionIncludeNamed = &argv[i][3]; + } + else if (++i < argc) + { + UnityOptionIncludeNamed = argv[i]; + } + else + { + UnityPrint("ERROR: No Test String to Include Matches For"); + UNITY_PRINT_EOL(); + return 1; + } + break; + case 'q': /* quiet */ + UnityVerbosity = 0; + break; + case 'v': /* verbose */ + UnityVerbosity = 2; + break; + case 'x': /* exclude tests with name including this string */ + if (argv[i][2] == '=') + { + UnityOptionExcludeNamed = &argv[i][3]; + } + else if (++i < argc) + { + UnityOptionExcludeNamed = argv[i]; + } + else + { + UnityPrint("ERROR: No Test String to Exclude Matches For"); + UNITY_PRINT_EOL(); + return 1; + } + break; + default: + UnityPrint("ERROR: Unknown Option "); + UNITY_OUTPUT_CHAR(argv[i][1]); + UNITY_PRINT_EOL(); + /* Now display help */ + /* FALLTHRU */ + case 'h': + UnityPrint("Options: "); UNITY_PRINT_EOL(); + UnityPrint("-l List all tests and exit"); UNITY_PRINT_EOL(); + UnityPrint("-f NAME Filter to run only tests whose name includes NAME"); UNITY_PRINT_EOL(); + UnityPrint("-n NAME (deprecated) alias of -f"); UNITY_PRINT_EOL(); + UnityPrint("-h show this Help menu"); UNITY_PRINT_EOL(); + UnityPrint("-q Quiet/decrease verbosity"); UNITY_PRINT_EOL(); + UnityPrint("-v increase Verbosity"); UNITY_PRINT_EOL(); + UnityPrint("-x NAME eXclude tests whose name includes NAME"); UNITY_PRINT_EOL(); + UNITY_OUTPUT_FLUSH(); + return 1; + } + } + } + + return 0; +} + +/*-----------------------------------------------*/ +int IsStringInBiggerString(const char* longstring, const char* shortstring) +{ + const char* lptr = longstring; + const char* sptr = shortstring; + const char* lnext = lptr; + + if (*sptr == '*') + { + return 1; + } + + while (*lptr) + { + lnext = lptr + 1; + + /* If they current bytes match, go on to the next bytes */ + while (*lptr && *sptr && (*lptr == *sptr)) + { + lptr++; + sptr++; + + /* We're done if we match the entire string or up to a wildcard */ + if (*sptr == '*') + return 1; + if (*sptr == ',') + return 1; + if (*sptr == '"') + return 1; + if (*sptr == '\'') + return 1; + if (*sptr == ':') + return 2; + if (*sptr == 0) + return 1; + } + + /* Otherwise we start in the long pointer 1 character further and try again */ + lptr = lnext; + sptr = shortstring; + } + + return 0; +} + +/*-----------------------------------------------*/ +int UnityStringArgumentMatches(const char* str) +{ + int retval; + const char* ptr1; + const char* ptr2; + const char* ptrf; + + /* Go through the options and get the substrings for matching one at a time */ + ptr1 = str; + while (ptr1[0] != 0) + { + if ((ptr1[0] == '"') || (ptr1[0] == '\'')) + { + ptr1++; + } + + /* look for the start of the next partial */ + ptr2 = ptr1; + ptrf = 0; + do + { + ptr2++; + if ((ptr2[0] == ':') && (ptr2[1] != 0) && (ptr2[0] != '\'') && (ptr2[0] != '"') && (ptr2[0] != ',')) + { + ptrf = &ptr2[1]; + } + } while ((ptr2[0] != 0) && (ptr2[0] != '\'') && (ptr2[0] != '"') && (ptr2[0] != ',')); + + while ((ptr2[0] != 0) && ((ptr2[0] == ':') || (ptr2[0] == '\'') || (ptr2[0] == '"') || (ptr2[0] == ','))) + { + ptr2++; + } + + /* done if complete filename match */ + retval = IsStringInBiggerString(Unity.TestFile, ptr1); + if (retval == 1) + { + return retval; + } + + /* done if testname match after filename partial match */ + if ((retval == 2) && (ptrf != 0)) + { + if (IsStringInBiggerString(Unity.CurrentTestName, ptrf)) + { + return 1; + } + } + + /* done if complete testname match */ + if (IsStringInBiggerString(Unity.CurrentTestName, ptr1) == 1) + { + return 1; + } + + ptr1 = ptr2; + } + + /* we couldn't find a match for any substrings */ + return 0; +} + +/*-----------------------------------------------*/ +int UnityTestMatches(void) +{ + /* Check if this test name matches the included test pattern */ + int retval; + if (UnityOptionIncludeNamed) + { + retval = UnityStringArgumentMatches(UnityOptionIncludeNamed); + } + else + { + retval = 1; + } + + /* Check if this test name matches the excluded test pattern */ + if (UnityOptionExcludeNamed) + { + if (UnityStringArgumentMatches(UnityOptionExcludeNamed)) + { + retval = 0; + } + } + + return retval; +} + +#endif /* UNITY_USE_COMMAND_LINE_ARGS */ +/*-----------------------------------------------*/ diff --git a/tests/unity.h b/tests/unity.h new file mode 100644 index 0000000..6ab36d6 --- /dev/null +++ b/tests/unity.h @@ -0,0 +1,1868 @@ +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef UNITY_FRAMEWORK_H +#define UNITY_FRAMEWORK_H +#define UNITY + +#define UNITY_VERSION_MAJOR 2 +#define UNITY_VERSION_MINOR 6 +#define UNITY_VERSION_BUILD 0 +#define UNITY_VERSION ((UNITY_VERSION_MAJOR << 16) | (UNITY_VERSION_MINOR << 8) | UNITY_VERSION_BUILD) + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* === BEGIN inlined unity_internals.h === */ +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef UNITY_INTERNALS_H +#define UNITY_INTERNALS_H + +#ifdef UNITY_INCLUDE_CONFIG_H +#include "unity_config.h" +#endif + +#ifndef UNITY_EXCLUDE_SETJMP_H +#include +#endif + +#ifndef UNITY_EXCLUDE_MATH_H +#include +#endif + +#ifndef UNITY_EXCLUDE_STDDEF_H +#include +#endif + +#ifdef UNITY_INCLUDE_PRINT_FORMATTED +#include +#endif + +/* Unity Attempts to Auto-Detect Integer Types + * Attempt 1: UINT_MAX, ULONG_MAX in , or default to 32 bits + * Attempt 2: UINTPTR_MAX in , or default to same size as long + * The user may override any of these derived constants: + * UNITY_INT_WIDTH, UNITY_LONG_WIDTH, UNITY_POINTER_WIDTH */ +#ifndef UNITY_EXCLUDE_STDINT_H +#include +#endif + +#ifndef UNITY_EXCLUDE_LIMITS_H +#include +#endif + +#if defined(__GNUC__) || defined(__clang__) + #define UNITY_FUNCTION_ATTR(a) __attribute__((a)) +#else + #define UNITY_FUNCTION_ATTR(a) /* ignore */ +#endif + +#ifndef UNITY_NORETURN + #if defined(__cplusplus) + #if __cplusplus >= 201103L + #define UNITY_NORETURN [[ noreturn ]] + #endif + #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #if defined(_WIN32) && defined(_MSC_VER) + /* We are using MSVC compiler on Windows platform. */ + /* Not all Windows SDKs supports , but compiler can support C11: */ + /* https://devblogs.microsoft.com/cppblog/c11-and-c17-standard-support-arriving-in-msvc/ */ + /* Not sure, that Mingw compilers has Windows SDK headers at all. */ + #include + #endif + + /* Using Windows SDK predefined macro for detecting supported SDK with MSVC compiler. */ + /* Mingw GCC should work without that fixes. */ + /* Based on: */ + /* https://docs.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt?view=msvc-170 */ + /* NTDDI_WIN10_FE is equal to Windows 10 SDK 2104 */ + #if defined(_MSC_VER) && ((!defined(NTDDI_WIN10_FE)) || WDK_NTDDI_VERSION < NTDDI_WIN10_FE) + /* Based on tests and: */ + /* https://docs.microsoft.com/en-us/cpp/c-language/noreturn?view=msvc-170 */ + /* https://en.cppreference.com/w/c/language/_Noreturn */ + #define UNITY_NORETURN _Noreturn + #else /* Using newer Windows SDK or not MSVC compiler */ + #include + #define UNITY_NORETURN noreturn + #endif + #endif +#endif +#ifndef UNITY_NORETURN + #define UNITY_NORETURN UNITY_FUNCTION_ATTR(__noreturn__) +#endif + +/*------------------------------------------------------- + * Guess Widths If Not Specified + *-------------------------------------------------------*/ + +/* Determine the size of an int, if not already specified. + * We cannot use sizeof(int), because it is not yet defined + * at this stage in the translation of the C program. + * Also sizeof(int) does return the size in addressable units on all platforms, + * which may not necessarily be the size in bytes. + * Therefore, infer it from UINT_MAX if possible. */ +#ifndef UNITY_INT_WIDTH + #ifdef UINT_MAX + #if (UINT_MAX == 0xFFFF) + #define UNITY_INT_WIDTH (16) + #elif (UINT_MAX == 0xFFFFFFFF) + #define UNITY_INT_WIDTH (32) + #elif (UINT_MAX == 0xFFFFFFFFFFFFFFFF) + #define UNITY_INT_WIDTH (64) + #endif + #else /* Set to default */ + #define UNITY_INT_WIDTH (32) + #endif /* UINT_MAX */ +#endif + +/* Determine the size of a long, if not already specified. */ +#ifndef UNITY_LONG_WIDTH + #ifdef ULONG_MAX + #if (ULONG_MAX == 0xFFFF) + #define UNITY_LONG_WIDTH (16) + #elif (ULONG_MAX == 0xFFFFFFFF) + #define UNITY_LONG_WIDTH (32) + #elif (ULONG_MAX == 0xFFFFFFFFFFFFFFFF) + #define UNITY_LONG_WIDTH (64) + #endif + #else /* Set to default */ + #define UNITY_LONG_WIDTH (32) + #endif /* ULONG_MAX */ +#endif + +/* Determine the size of a pointer, if not already specified. */ +#ifndef UNITY_POINTER_WIDTH + #ifdef UINTPTR_MAX + #if (UINTPTR_MAX <= 0xFFFF) + #define UNITY_POINTER_WIDTH (16) + #elif (UINTPTR_MAX <= 0xFFFFFFFF) + #define UNITY_POINTER_WIDTH (32) + #elif (UINTPTR_MAX <= 0xFFFFFFFFFFFFFFFF) + #define UNITY_POINTER_WIDTH (64) + #endif + #else /* Set to default */ + #define UNITY_POINTER_WIDTH UNITY_LONG_WIDTH + #endif /* UINTPTR_MAX */ +#endif + +/*------------------------------------------------------- + * Int Support (Define types based on detected sizes) + *-------------------------------------------------------*/ + +#if (UNITY_INT_WIDTH == 32) + typedef unsigned char UNITY_UINT8; + typedef unsigned short UNITY_UINT16; + typedef unsigned int UNITY_UINT32; + typedef signed char UNITY_INT8; + typedef signed short UNITY_INT16; + typedef signed int UNITY_INT32; +#elif (UNITY_INT_WIDTH == 16) + typedef unsigned char UNITY_UINT8; + typedef unsigned int UNITY_UINT16; + typedef unsigned long UNITY_UINT32; + typedef signed char UNITY_INT8; + typedef signed int UNITY_INT16; + typedef signed long UNITY_INT32; +#else + #error Invalid UNITY_INT_WIDTH specified! (16 or 32 are supported) +#endif + +/*------------------------------------------------------- + * 64-bit Support + *-------------------------------------------------------*/ + +/* Auto-detect 64 Bit Support */ +#ifndef UNITY_SUPPORT_64 + #if UNITY_LONG_WIDTH == 64 || UNITY_POINTER_WIDTH == 64 + #define UNITY_SUPPORT_64 + #endif +#endif + +/* 64-Bit Support Dependent Configuration */ +#ifndef UNITY_SUPPORT_64 + /* No 64-bit Support */ + typedef UNITY_UINT32 UNITY_UINT; + typedef UNITY_INT32 UNITY_INT; + #define UNITY_MAX_NIBBLES (8) /* Maximum number of nibbles in a UNITY_(U)INT */ +#else + /* 64-bit Support */ + #if (UNITY_LONG_WIDTH == 32) + typedef unsigned long long UNITY_UINT64; + typedef signed long long UNITY_INT64; + #elif (UNITY_LONG_WIDTH == 64) + typedef unsigned long UNITY_UINT64; + typedef signed long UNITY_INT64; + #else + #error Invalid UNITY_LONG_WIDTH specified! (32 or 64 are supported) + #endif + typedef UNITY_UINT64 UNITY_UINT; + typedef UNITY_INT64 UNITY_INT; + #define UNITY_MAX_NIBBLES (16) /* Maximum number of nibbles in a UNITY_(U)INT */ +#endif + +/*------------------------------------------------------- + * Pointer Support + *-------------------------------------------------------*/ + +#if (UNITY_POINTER_WIDTH == 32) + #define UNITY_PTR_TO_INT UNITY_INT32 + #define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX32 +#elif (UNITY_POINTER_WIDTH == 64) + #define UNITY_PTR_TO_INT UNITY_INT64 + #define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX64 +#elif (UNITY_POINTER_WIDTH == 16) + #define UNITY_PTR_TO_INT UNITY_INT16 + #define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX16 +#else + #error Invalid UNITY_POINTER_WIDTH specified! (16, 32 or 64 are supported) +#endif + +#ifndef UNITY_PTR_ATTRIBUTE + #define UNITY_PTR_ATTRIBUTE +#endif + +#ifndef UNITY_INTERNAL_PTR + #define UNITY_INTERNAL_PTR UNITY_PTR_ATTRIBUTE const void* +#endif + +/* optionally define UNITY_COMPARE_PTRS_ON_ZERO_ARRAY */ + +/*------------------------------------------------------- + * Float Support + *-------------------------------------------------------*/ + +#ifdef UNITY_EXCLUDE_FLOAT + +/* No Floating Point Support */ +#ifndef UNITY_EXCLUDE_DOUBLE +#define UNITY_EXCLUDE_DOUBLE /* Remove double when excluding float support */ +#endif +#ifndef UNITY_EXCLUDE_FLOAT_PRINT +#define UNITY_EXCLUDE_FLOAT_PRINT +#endif + +#else + +/* Floating Point Support */ +#ifndef UNITY_FLOAT_PRECISION +#define UNITY_FLOAT_PRECISION (0.00001f) +#endif +#ifndef UNITY_FLOAT_TYPE +#define UNITY_FLOAT_TYPE float +#endif +typedef UNITY_FLOAT_TYPE UNITY_FLOAT; + +/* isnan macro should be provided by math.h. Override if not macro */ +#ifndef UNITY_IS_NAN +#ifndef isnan +/* NaN is the only floating point value that does NOT equal itself. + * Therefore if n != n, then it is NaN. */ +#define UNITY_IS_NAN(n) ((n != n) ? 1 : 0) +#else +#define UNITY_IS_NAN(n) isnan(n) +#endif +#endif + +/* isinf macro should be provided by math.h. Override if not macro */ +#ifndef UNITY_IS_INF +#ifndef isinf +/* The value of Inf - Inf is NaN */ +#define UNITY_IS_INF(n) (UNITY_IS_NAN((n) - (n)) && !UNITY_IS_NAN(n)) +#else +#define UNITY_IS_INF(n) isinf(n) +#endif +#endif + +#endif + +/*------------------------------------------------------- + * Double Float Support + *-------------------------------------------------------*/ + +/* unlike float, we DON'T include by default */ +#if defined(UNITY_EXCLUDE_DOUBLE) || !defined(UNITY_INCLUDE_DOUBLE) + + /* No Floating Point Support */ + #ifndef UNITY_EXCLUDE_DOUBLE + #define UNITY_EXCLUDE_DOUBLE + #else + #undef UNITY_INCLUDE_DOUBLE + #endif + + #ifndef UNITY_EXCLUDE_FLOAT + #ifndef UNITY_DOUBLE_TYPE + #define UNITY_DOUBLE_TYPE double + #endif + typedef UNITY_FLOAT UNITY_DOUBLE; + /* For parameter in UnityPrintFloat(UNITY_DOUBLE), which aliases to double or float */ + #endif + +#else + + /* Double Floating Point Support */ + #ifndef UNITY_DOUBLE_PRECISION + #define UNITY_DOUBLE_PRECISION (1e-12) + #endif + + #ifndef UNITY_DOUBLE_TYPE + #define UNITY_DOUBLE_TYPE double + #endif + typedef UNITY_DOUBLE_TYPE UNITY_DOUBLE; + +#endif + +/*------------------------------------------------------- + * Output Method: stdout (DEFAULT) + *-------------------------------------------------------*/ +#ifndef UNITY_OUTPUT_CHAR + /* Default to using putchar, which is defined in stdio.h */ + #include + #define UNITY_OUTPUT_CHAR(a) (void)putchar(a) +#else + /* If defined as something else, make sure we declare it here so it's ready for use */ + #ifdef UNITY_OUTPUT_CHAR_HEADER_DECLARATION + extern void UNITY_OUTPUT_CHAR_HEADER_DECLARATION; + #endif +#endif + +#ifndef UNITY_OUTPUT_FLUSH + #ifdef UNITY_USE_FLUSH_STDOUT + /* We want to use the stdout flush utility */ + #include + #define UNITY_OUTPUT_FLUSH() (void)fflush(stdout) + #else + /* We've specified nothing, therefore flush should just be ignored */ + #define UNITY_OUTPUT_FLUSH() (void)0 + #endif +#else + /* If defined as something else, make sure we declare it here so it's ready for use */ + #ifdef UNITY_OUTPUT_FLUSH_HEADER_DECLARATION + extern void UNITY_OUTPUT_FLUSH_HEADER_DECLARATION; + #endif +#endif + +#ifndef UNITY_OUTPUT_FLUSH +#define UNITY_FLUSH_CALL() +#else +#define UNITY_FLUSH_CALL() UNITY_OUTPUT_FLUSH() +#endif + +#ifndef UNITY_PRINT_EOL +#define UNITY_PRINT_EOL() UNITY_OUTPUT_CHAR('\n') +#endif + +#ifndef UNITY_OUTPUT_START +#define UNITY_OUTPUT_START() +#endif + +#ifndef UNITY_OUTPUT_COMPLETE +#define UNITY_OUTPUT_COMPLETE() +#endif + +#ifdef UNITY_INCLUDE_EXEC_TIME + #if !defined(UNITY_EXEC_TIME_START) && \ + !defined(UNITY_EXEC_TIME_STOP) && \ + !defined(UNITY_PRINT_EXEC_TIME) && \ + !defined(UNITY_TIME_TYPE) + /* If none any of these macros are defined then try to provide a default implementation */ + + #if defined(UNITY_CLOCK_MS) + /* This is a simple way to get a default implementation on platforms that support getting a millisecond counter */ + #define UNITY_TIME_TYPE UNITY_UINT + #define UNITY_EXEC_TIME_START() Unity.CurrentTestStartTime = UNITY_CLOCK_MS() + #define UNITY_EXEC_TIME_STOP() Unity.CurrentTestStopTime = UNITY_CLOCK_MS() + #define UNITY_PRINT_EXEC_TIME() { \ + UNITY_UINT execTimeMs = (Unity.CurrentTestStopTime - Unity.CurrentTestStartTime); \ + UnityPrint(" ("); \ + UnityPrintNumberUnsigned(execTimeMs); \ + UnityPrint(" ms)"); \ + } + #elif defined(_WIN32) + #include + #define UNITY_TIME_TYPE clock_t + #define UNITY_GET_TIME(t) t = (clock_t)((clock() * 1000) / CLOCKS_PER_SEC) + #define UNITY_EXEC_TIME_START() UNITY_GET_TIME(Unity.CurrentTestStartTime) + #define UNITY_EXEC_TIME_STOP() UNITY_GET_TIME(Unity.CurrentTestStopTime) + #define UNITY_PRINT_EXEC_TIME() { \ + UNITY_UINT execTimeMs = (Unity.CurrentTestStopTime - Unity.CurrentTestStartTime); \ + UnityPrint(" ("); \ + UnityPrintNumberUnsigned(execTimeMs); \ + UnityPrint(" ms)"); \ + } + #elif defined(__unix__) || defined(__APPLE__) + #include + #define UNITY_TIME_TYPE struct timespec + #define UNITY_GET_TIME(t) clock_gettime(CLOCK_MONOTONIC, &t) + #define UNITY_EXEC_TIME_START() UNITY_GET_TIME(Unity.CurrentTestStartTime) + #define UNITY_EXEC_TIME_STOP() UNITY_GET_TIME(Unity.CurrentTestStopTime) + #define UNITY_PRINT_EXEC_TIME() { \ + UNITY_UINT execTimeMs = ((Unity.CurrentTestStopTime.tv_sec - Unity.CurrentTestStartTime.tv_sec) * 1000L); \ + execTimeMs += ((Unity.CurrentTestStopTime.tv_nsec - Unity.CurrentTestStartTime.tv_nsec) / 1000000L); \ + UnityPrint(" ("); \ + UnityPrintNumberUnsigned(execTimeMs); \ + UnityPrint(" ms)"); \ + } + #endif + #endif +#endif + +#ifndef UNITY_EXEC_TIME_START +#define UNITY_EXEC_TIME_START() do { /* nothing*/ } while (0) +#endif + +#ifndef UNITY_EXEC_TIME_STOP +#define UNITY_EXEC_TIME_STOP() do { /* nothing*/ } while (0) +#endif + +#ifndef UNITY_TIME_TYPE +#define UNITY_TIME_TYPE UNITY_UINT +#endif + +#ifndef UNITY_PRINT_EXEC_TIME +#define UNITY_PRINT_EXEC_TIME() do { /* nothing*/ } while (0) +#endif + +/*------------------------------------------------------- + * Footprint + *-------------------------------------------------------*/ + +#ifndef UNITY_LINE_TYPE +#define UNITY_LINE_TYPE UNITY_UINT +#endif + +#ifndef UNITY_COUNTER_TYPE +#define UNITY_COUNTER_TYPE UNITY_UINT +#endif + +/*------------------------------------------------------- + * Internal Structs Needed + *-------------------------------------------------------*/ + +typedef void (*UnityTestFunction)(void); + +#define UNITY_DISPLAY_RANGE_INT (0x10) +#define UNITY_DISPLAY_RANGE_UINT (0x20) +#define UNITY_DISPLAY_RANGE_HEX (0x40) +#define UNITY_DISPLAY_RANGE_CHAR (0x80) + +typedef enum +{ + UNITY_DISPLAY_STYLE_INT = (UNITY_INT_WIDTH / 8) + UNITY_DISPLAY_RANGE_INT, + UNITY_DISPLAY_STYLE_INT8 = 1 + UNITY_DISPLAY_RANGE_INT, + UNITY_DISPLAY_STYLE_INT16 = 2 + UNITY_DISPLAY_RANGE_INT, + UNITY_DISPLAY_STYLE_INT32 = 4 + UNITY_DISPLAY_RANGE_INT, +#ifdef UNITY_SUPPORT_64 + UNITY_DISPLAY_STYLE_INT64 = 8 + UNITY_DISPLAY_RANGE_INT, +#endif + + UNITY_DISPLAY_STYLE_UINT = (UNITY_INT_WIDTH / 8) + UNITY_DISPLAY_RANGE_UINT, + UNITY_DISPLAY_STYLE_UINT8 = 1 + UNITY_DISPLAY_RANGE_UINT, + UNITY_DISPLAY_STYLE_UINT16 = 2 + UNITY_DISPLAY_RANGE_UINT, + UNITY_DISPLAY_STYLE_UINT32 = 4 + UNITY_DISPLAY_RANGE_UINT, +#ifdef UNITY_SUPPORT_64 + UNITY_DISPLAY_STYLE_UINT64 = 8 + UNITY_DISPLAY_RANGE_UINT, +#endif + + UNITY_DISPLAY_STYLE_HEX8 = 1 + UNITY_DISPLAY_RANGE_HEX, + UNITY_DISPLAY_STYLE_HEX16 = 2 + UNITY_DISPLAY_RANGE_HEX, + UNITY_DISPLAY_STYLE_HEX32 = 4 + UNITY_DISPLAY_RANGE_HEX, +#ifdef UNITY_SUPPORT_64 + UNITY_DISPLAY_STYLE_HEX64 = 8 + UNITY_DISPLAY_RANGE_HEX, +#endif + + UNITY_DISPLAY_STYLE_CHAR = 1 + UNITY_DISPLAY_RANGE_CHAR + UNITY_DISPLAY_RANGE_INT, + + UNITY_DISPLAY_STYLE_UNKNOWN +} UNITY_DISPLAY_STYLE_T; + +typedef enum +{ + UNITY_WITHIN = 0x0, + UNITY_EQUAL_TO = 0x1, + UNITY_GREATER_THAN = 0x2, + UNITY_GREATER_OR_EQUAL = 0x2 + UNITY_EQUAL_TO, + UNITY_SMALLER_THAN = 0x4, + UNITY_SMALLER_OR_EQUAL = 0x4 + UNITY_EQUAL_TO, + UNITY_NOT_EQUAL = 0x0, + UNITY_UNKNOWN +} UNITY_COMPARISON_T; + +#ifndef UNITY_EXCLUDE_FLOAT +typedef enum UNITY_FLOAT_TRAIT +{ + UNITY_FLOAT_IS_NOT_INF = 0, + UNITY_FLOAT_IS_INF, + UNITY_FLOAT_IS_NOT_NEG_INF, + UNITY_FLOAT_IS_NEG_INF, + UNITY_FLOAT_IS_NOT_NAN, + UNITY_FLOAT_IS_NAN, + UNITY_FLOAT_IS_NOT_DET, + UNITY_FLOAT_IS_DET, + UNITY_FLOAT_INVALID_TRAIT +} UNITY_FLOAT_TRAIT_T; +#endif + +typedef enum +{ + UNITY_ARRAY_TO_VAL = 0, + UNITY_ARRAY_TO_ARRAY, + UNITY_ARRAY_UNKNOWN +} UNITY_FLAGS_T; + +struct UNITY_STORAGE_T +{ + const char* TestFile; + const char* CurrentTestName; +#ifndef UNITY_EXCLUDE_DETAILS + const char* CurrentDetail1; + const char* CurrentDetail2; +#endif + UNITY_LINE_TYPE CurrentTestLineNumber; + UNITY_COUNTER_TYPE NumberOfTests; + UNITY_COUNTER_TYPE TestFailures; + UNITY_COUNTER_TYPE TestIgnores; + UNITY_COUNTER_TYPE CurrentTestFailed; + UNITY_COUNTER_TYPE CurrentTestIgnored; +#ifdef UNITY_INCLUDE_EXEC_TIME + UNITY_TIME_TYPE CurrentTestStartTime; + UNITY_TIME_TYPE CurrentTestStopTime; +#endif +#ifndef UNITY_EXCLUDE_SETJMP_H + jmp_buf AbortFrame; +#endif +}; + +extern struct UNITY_STORAGE_T Unity; + +/*------------------------------------------------------- + * Test Suite Management + *-------------------------------------------------------*/ + +void UnityBegin(const char* filename); +int UnityEnd(void); +void UnitySetTestFile(const char* filename); +void UnityConcludeTest(void); + +#ifndef RUN_TEST +void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum); +#else +#define UNITY_SKIP_DEFAULT_RUNNER +#endif + +/*------------------------------------------------------- + * Details Support + *-------------------------------------------------------*/ + +#ifdef UNITY_EXCLUDE_DETAILS +#define UNITY_CLR_DETAILS() +#define UNITY_SET_DETAIL(d1) +#define UNITY_SET_DETAILS(d1,d2) +#else +#define UNITY_CLR_DETAILS() do { Unity.CurrentDetail1 = 0; Unity.CurrentDetail2 = 0; } while (0) +#define UNITY_SET_DETAIL(d1) do { Unity.CurrentDetail1 = (d1); Unity.CurrentDetail2 = 0; } while (0) +#define UNITY_SET_DETAILS(d1,d2) do { Unity.CurrentDetail1 = (d1); Unity.CurrentDetail2 = (d2); } while (0) + +#ifndef UNITY_DETAIL1_NAME +#define UNITY_DETAIL1_NAME "Function" +#endif + +#ifndef UNITY_DETAIL2_NAME +#define UNITY_DETAIL2_NAME "Argument" +#endif +#endif + +#ifdef UNITY_PRINT_TEST_CONTEXT +void UNITY_PRINT_TEST_CONTEXT(void); +#endif + +/*------------------------------------------------------- + * Test Output + *-------------------------------------------------------*/ + +void UnityPrint(const char* string); + +#ifdef UNITY_INCLUDE_PRINT_FORMATTED +void UnityPrintF(const UNITY_LINE_TYPE line, const char* format, ...); +#endif + +void UnityPrintLen(const char* string, const UNITY_UINT32 length); +void UnityPrintMask(const UNITY_UINT mask, const UNITY_UINT number); +void UnityPrintNumberByStyle(const UNITY_INT number, const UNITY_DISPLAY_STYLE_T style); +void UnityPrintNumber(const UNITY_INT number_to_print); +void UnityPrintNumberUnsigned(const UNITY_UINT number); +void UnityPrintNumberHex(const UNITY_UINT number, const char nibbles_to_print); + +#ifndef UNITY_EXCLUDE_FLOAT_PRINT +void UnityPrintFloat(const UNITY_DOUBLE input_number); +#endif + +/*------------------------------------------------------- + * Test Assertion Functions + *------------------------------------------------------- + * Use the macros below this section instead of calling + * these directly. The macros have a consistent naming + * convention and will pull in file and line information + * for you. */ + +void UnityAssertEqualNumber(const UNITY_INT expected, + const UNITY_INT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); + +void UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold, + const UNITY_INT actual, + const UNITY_COMPARISON_T compare, + const char *msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); + +void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style, + const UNITY_FLAGS_T flags); + +void UnityAssertBits(const UNITY_INT mask, + const UNITY_INT expected, + const UNITY_INT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualString(const char* expected, + const char* actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualStringLen(const char* expected, + const char* actual, + const UNITY_UINT32 length, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualStringArray( UNITY_INTERNAL_PTR expected, + const char** actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags); + +void UnityAssertEqualMemory( UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 length, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags); + +void UnityAssertNumbersWithin(const UNITY_UINT delta, + const UNITY_INT expected, + const UNITY_INT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); + +void UnityAssertNumbersArrayWithin(const UNITY_UINT delta, + UNITY_INTERNAL_PTR expected, + UNITY_INTERNAL_PTR actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style, + const UNITY_FLAGS_T flags); + +#ifndef UNITY_EXCLUDE_SETJMP_H +UNITY_NORETURN void UnityFail(const char* message, const UNITY_LINE_TYPE line); +UNITY_NORETURN void UnityIgnore(const char* message, const UNITY_LINE_TYPE line); +#else +void UnityFail(const char* message, const UNITY_LINE_TYPE line); +void UnityIgnore(const char* message, const UNITY_LINE_TYPE line); +#endif + +void UnityMessage(const char* message, const UNITY_LINE_TYPE line); + +#ifndef UNITY_EXCLUDE_FLOAT +void UnityAssertFloatsWithin(const UNITY_FLOAT delta, + const UNITY_FLOAT expected, + const UNITY_FLOAT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertFloatsNotWithin(const UNITY_FLOAT delta, + const UNITY_FLOAT expected, + const UNITY_FLOAT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertGreaterOrLessFloat(const UNITY_FLOAT threshold, + const UNITY_FLOAT actual, + const UNITY_COMPARISON_T compare, + const char* msg, + const UNITY_LINE_TYPE linenumber); + +void UnityAssertWithinFloatArray(const UNITY_FLOAT delta, + UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* expected, + UNITY_PTR_ATTRIBUTE const UNITY_FLOAT* actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags); + +void UnityAssertFloatSpecial(const UNITY_FLOAT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style); +#endif + +#ifndef UNITY_EXCLUDE_DOUBLE +void UnityAssertDoublesWithin(const UNITY_DOUBLE delta, + const UNITY_DOUBLE expected, + const UNITY_DOUBLE actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertDoublesNotWithin(const UNITY_DOUBLE delta, + const UNITY_DOUBLE expected, + const UNITY_DOUBLE actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertGreaterOrLessDouble(const UNITY_DOUBLE threshold, + const UNITY_DOUBLE actual, + const UNITY_COMPARISON_T compare, + const char* msg, + const UNITY_LINE_TYPE linenumber); + +void UnityAssertWithinDoubleArray(const UNITY_DOUBLE delta, + UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* expected, + UNITY_PTR_ATTRIBUTE const UNITY_DOUBLE* actual, + const UNITY_UINT32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLAGS_T flags); + +void UnityAssertDoubleSpecial(const UNITY_DOUBLE actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style); +#endif + +/*------------------------------------------------------- + * Helpers + *-------------------------------------------------------*/ + +UNITY_INTERNAL_PTR UnityNumToPtr(const UNITY_INT num, const UNITY_UINT8 size); +#ifndef UNITY_EXCLUDE_FLOAT +UNITY_INTERNAL_PTR UnityFloatToPtr(const float num); +#endif +#ifndef UNITY_EXCLUDE_DOUBLE +UNITY_INTERNAL_PTR UnityDoubleToPtr(const double num); +#endif + +/*------------------------------------------------------- + * Error Strings We Might Need + *-------------------------------------------------------*/ + +extern const char UnityStrOk[]; +extern const char UnityStrPass[]; +extern const char UnityStrFail[]; +extern const char UnityStrIgnore[]; + +extern const char UnityStrErrFloat[]; +extern const char UnityStrErrDouble[]; +extern const char UnityStrErr64[]; +extern const char UnityStrErrShorthand[]; + +/*------------------------------------------------------- + * Test Running Macros + *-------------------------------------------------------*/ + +#ifdef UNITY_TEST_PROTECT +#define TEST_PROTECT() UNITY_TEST_PROTECT() +#else +#ifndef UNITY_EXCLUDE_SETJMP_H +#define TEST_PROTECT() (setjmp(Unity.AbortFrame) == 0) +#else +#define TEST_PROTECT() 1 +#endif +#endif + +#ifdef UNITY_TEST_ABORT +#define TEST_ABORT() UNITY_TEST_ABORT() +#else +#ifndef UNITY_EXCLUDE_SETJMP_H +#define TEST_ABORT() longjmp(Unity.AbortFrame, 1) +#else +#define TEST_ABORT() return +#endif +#endif + +/* Automatically enable variadic macros support, if it not enabled before */ +#ifndef UNITY_SUPPORT_VARIADIC_MACROS + #ifdef __STDC_VERSION__ + #if __STDC_VERSION__ >= 199901L + #define UNITY_SUPPORT_VARIADIC_MACROS + #endif + #endif +#endif + +/* This tricky series of macros gives us an optional line argument to treat it as RUN_TEST(func, num=__LINE__) */ +#ifndef RUN_TEST +#ifdef UNITY_SUPPORT_VARIADIC_MACROS +#define RUN_TEST(...) RUN_TEST_AT_LINE(__VA_ARGS__, __LINE__, throwaway) +#define RUN_TEST_AT_LINE(func, line, ...) UnityDefaultTestRun(func, #func, line) +#endif +#endif + +/* Enable default macros for masking param tests test cases */ +#ifdef UNITY_SUPPORT_TEST_CASES + #ifdef UNITY_SUPPORT_VARIADIC_MACROS + #if !defined(TEST_CASE) && !defined(UNITY_EXCLUDE_TEST_CASE) + #define TEST_CASE(...) + #endif + #if !defined(TEST_RANGE) && !defined(UNITY_EXCLUDE_TEST_RANGE) + #define TEST_RANGE(...) + #endif + #if !defined(TEST_MATRIX) && !defined(UNITY_EXCLUDE_TEST_MATRIX) + #define TEST_MATRIX(...) + #endif + #endif +#endif + +/* If we can't do the tricky version, we'll just have to require them to always include the line number */ +#ifndef RUN_TEST +#ifdef CMOCK +#define RUN_TEST(func, num) UnityDefaultTestRun(func, #func, num) +#else +#define RUN_TEST(func) UnityDefaultTestRun(func, #func, __LINE__) +#endif +#endif + +#define TEST_LINE_NUM (Unity.CurrentTestLineNumber) +#define TEST_IS_IGNORED (Unity.CurrentTestIgnored) +#define UNITY_NEW_TEST(a) \ + Unity.CurrentTestName = (a); \ + Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)(__LINE__); \ + Unity.NumberOfTests++; + +#ifndef UNITY_BEGIN +#define UNITY_BEGIN() UnityBegin(__FILE__) +#endif + +#ifndef UNITY_END +#define UNITY_END() UnityEnd() +#endif + +#ifndef UNITY_SHORTHAND_AS_INT +#ifndef UNITY_SHORTHAND_AS_MEM +#ifndef UNITY_SHORTHAND_AS_NONE +#ifndef UNITY_SHORTHAND_AS_RAW +#define UNITY_SHORTHAND_AS_OLD +#endif +#endif +#endif +#endif + +/*----------------------------------------------- + * Command Line Argument Support + *-----------------------------------------------*/ + +#ifdef UNITY_USE_COMMAND_LINE_ARGS +int UnityParseOptions(int argc, char** argv); +int UnityTestMatches(void); +#endif + +/*------------------------------------------------------- + * Basic Fail and Ignore + *-------------------------------------------------------*/ + +#define UNITY_TEST_FAIL(line, message) UnityFail( (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_IGNORE(line, message) UnityIgnore( (message), (UNITY_LINE_TYPE)(line)) + +/*------------------------------------------------------- + * Test Asserts + *-------------------------------------------------------*/ + +#define UNITY_TEST_ASSERT(condition, line, message) do { if (condition) { /* nothing*/ } else { UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), (message)); } } while (0) +#define UNITY_TEST_ASSERT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) == NULL), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_NOT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) != NULL), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_EMPTY(pointer, line, message) UNITY_TEST_ASSERT(((pointer[0]) == 0), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_NOT_EMPTY(pointer, line, message) UNITY_TEST_ASSERT(((pointer[0]) != 0), (UNITY_LINE_TYPE)(line), (message)) + +#define UNITY_TEST_ASSERT_EQUAL_INT(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_EQUAL_INT8(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_EQUAL_INT16(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT16)(expected), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_EQUAL_INT32(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT32)(expected), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_EQUAL_UINT(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_EQUAL_UINT8(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_EQUAL_UINT16(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_EQUAL_UINT32(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_EQUAL_HEX8(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_EQUAL_HEX16(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT16)(expected), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_EQUAL_HEX32(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT32)(expected), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_EQUAL_CHAR(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) +#define UNITY_TEST_ASSERT_BITS(mask, expected, actual, line, message) UnityAssertBits((UNITY_INT)(mask), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line)) + +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_NOT_EQUAL_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_GREATER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_GREATER_THAN_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 ) (threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16) (threshold), (UNITY_INT)(UNITY_INT16) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32) (threshold), (UNITY_INT)(UNITY_INT32) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 ) (threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT) (threshold), (UNITY_INT) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 ) (actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin( (delta), (UNITY_INT) (expected), (UNITY_INT) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_INT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_INT8 ) (expected), (UNITY_INT)(UNITY_INT8 ) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_INT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_INT16) (expected), (UNITY_INT)(UNITY_INT16) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_INT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_INT32) (expected), (UNITY_INT)(UNITY_INT32) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_UINT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin( (delta), (UNITY_INT) (expected), (UNITY_INT) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_UINT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_UINT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_UINT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_HEX8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_HEX16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT32)(delta), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(expected), (UNITY_INT)(UNITY_UINT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_CHAR_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_INT8 ) (expected), (UNITY_INT)(UNITY_INT8 ) (actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR) + +#define UNITY_TEST_ASSERT_INT_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin( (delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_INT8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin( (delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_HEX16_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT16)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT32)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_CHAR_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT8 )(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), ((UNITY_UINT32)(num_elements)), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR, UNITY_ARRAY_TO_ARRAY) + + +#define UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, line, message) UnityAssertEqualNumber((UNITY_PTR_TO_INT)(expected), (UNITY_PTR_TO_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER) +#define UNITY_TEST_ASSERT_EQUAL_STRING(expected, actual, line, message) UnityAssertEqualString((const char*)(expected), (const char*)(actual), (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len, line, message) UnityAssertEqualStringLen((const char*)(expected), (const char*)(actual), (UNITY_UINT32)(len), (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_EQUAL_MEMORY(expected, actual, len, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(len), 1, (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY) + +#define UNITY_TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualStringArray((UNITY_INTERNAL_PTR)(expected), (const char**)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(len), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_CHAR_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR, UNITY_ARRAY_TO_ARRAY) + +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT) (expected), (UNITY_INT_WIDTH / 8)), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT8(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT8 )(expected), 1), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT16(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT16 )(expected), 2), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT32(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT32 )(expected), 4), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT) (expected), (UNITY_INT_WIDTH / 8)), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT8(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT8 )(expected), 1), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT16(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT16)(expected), 2), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT32(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT32)(expected), 4), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX8(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT8 )(expected), 1), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX16(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT16 )(expected), 2), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX32(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT32 )(expected), 4), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_PTR(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_PTR_TO_INT) (expected), (UNITY_POINTER_WIDTH / 8)), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_STRING(expected, actual, num_elements, line, message) UnityAssertEqualStringArray((UNITY_INTERNAL_PTR)(expected), (const char**)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY(expected, actual, len, num_elements, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(len), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_CHAR(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT8 )(expected), 1), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_CHAR, UNITY_ARRAY_TO_VAL) + +#ifdef UNITY_SUPPORT_64 +#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)(expected), 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT64)(expected), 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)(expected), 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_NOT_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_NOT_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_NOT_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_NOT_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT64)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT64)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertNumbersArrayWithin((UNITY_UINT64)(delta), (UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64, UNITY_ARRAY_TO_ARRAY) +#else +#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#endif + +#ifdef UNITY_EXCLUDE_FLOAT +#define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_NOT_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_NOT_EQUAL_FLOAT(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_GREATER_THAN_FLOAT(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_FLOAT(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_LESS_THAN_FLOAT(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_LESS_OR_EQUAL_FLOAT(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat) +#else +#define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message) UnityAssertFloatsWithin((UNITY_FLOAT)(delta), (UNITY_FLOAT)(expected), (UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_FLOAT_NOT_WITHIN(delta, expected, actual, line, message) UnityAssertFloatsNotWithin((UNITY_FLOAT)(delta), (UNITY_FLOAT)(expected), (UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message) UNITY_TEST_ASSERT_FLOAT_WITHIN((UNITY_FLOAT)(expected) * (UNITY_FLOAT)UNITY_FLOAT_PRECISION, (UNITY_FLOAT)(expected), (UNITY_FLOAT)(actual), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_NOT_EQUAL_FLOAT(expected, actual, line, message) UNITY_TEST_ASSERT_FLOAT_NOT_WITHIN((UNITY_FLOAT)(expected) * (UNITY_FLOAT)UNITY_FLOAT_PRECISION, (UNITY_FLOAT)(expected), (UNITY_FLOAT)(actual), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_FLOAT_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertWithinFloatArray((UNITY_FLOAT)(delta), (const UNITY_FLOAT*)(expected), (const UNITY_FLOAT*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message) UnityAssertWithinFloatArray((UNITY_FLOAT)0, (const UNITY_FLOAT*)(expected), (const UNITY_FLOAT*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT(expected, actual, num_elements, line, message) UnityAssertWithinFloatArray((UNITY_FLOAT)0, UnityFloatToPtr(expected), (const UNITY_FLOAT*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_GREATER_THAN_FLOAT(threshold, actual, line, message) UnityAssertGreaterOrLessFloat((UNITY_FLOAT)(threshold), (UNITY_FLOAT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_FLOAT(threshold, actual, line, message) UnityAssertGreaterOrLessFloat((UNITY_FLOAT)(threshold), (UNITY_FLOAT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_LESS_THAN_FLOAT(threshold, actual, line, message) UnityAssertGreaterOrLessFloat((UNITY_FLOAT)(threshold), (UNITY_FLOAT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_LESS_OR_EQUAL_FLOAT(threshold, actual, line, message) UnityAssertGreaterOrLessFloat((UNITY_FLOAT)(threshold), (UNITY_FLOAT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NEG_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NAN) +#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_DET) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NEG_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NAN) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message) UnityAssertFloatSpecial((UNITY_FLOAT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET) +#endif + +#ifdef UNITY_EXCLUDE_DOUBLE +#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_NOT_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_NOT_EQUAL_DOUBLE(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_GREATER_THAN_DOUBLE(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_DOUBLE(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_LESS_THAN_DOUBLE(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_LESS_OR_EQUAL_DOUBLE(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble) +#else +#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message) UnityAssertDoublesWithin((UNITY_DOUBLE)(delta), (UNITY_DOUBLE)(expected), (UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_DOUBLE_NOT_WITHIN(delta, expected, actual, line, message) UnityAssertDoublesNotWithin((UNITY_DOUBLE)(delta), (UNITY_DOUBLE)(expected), (UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message) UNITY_TEST_ASSERT_DOUBLE_WITHIN((UNITY_DOUBLE)(expected) * (UNITY_DOUBLE)UNITY_DOUBLE_PRECISION, (UNITY_DOUBLE)(expected), (UNITY_DOUBLE)(actual), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_NOT_EQUAL_DOUBLE(expected, actual, line, message) UNITY_TEST_ASSERT_DOUBLE_NOT_WITHIN((UNITY_DOUBLE)(expected) * (UNITY_DOUBLE)UNITY_DOUBLE_PRECISION, (UNITY_DOUBLE)(expected), (UNITY_DOUBLE)(actual), (UNITY_LINE_TYPE)(line), (message)) +#define UNITY_TEST_ASSERT_DOUBLE_ARRAY_WITHIN(delta, expected, actual, num_elements, line, message) UnityAssertWithinDoubleArray((UNITY_DOUBLE)(delta), (const UNITY_DOUBLE*)(expected), (const UNITY_DOUBLE*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message) UnityAssertWithinDoubleArray((UNITY_DOUBLE)0, (const UNITY_DOUBLE*)(expected), (const UNITY_DOUBLE*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE(expected, actual, num_elements, line, message) UnityAssertWithinDoubleArray((UNITY_DOUBLE)0, UnityDoubleToPtr(expected), (const UNITY_DOUBLE*)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_GREATER_THAN_DOUBLE(threshold, actual, line, message) UnityAssertGreaterOrLessDouble((UNITY_DOUBLE)(threshold), (UNITY_DOUBLE)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_DOUBLE(threshold, actual, line, message) UnityAssertGreaterOrLessDouble((UNITY_DOUBLE)(threshold), (UNITY_DOUBLE)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_LESS_THAN_DOUBLE(threshold, actual, line, message) UnityAssertGreaterOrLessDouble((UNITY_DOUBLE)(threshold), (UNITY_DOUBLE)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_LESS_OR_EQUAL_DOUBLE(threshold, actual, line, message) UnityAssertGreaterOrLessDouble((UNITY_DOUBLE)(threshold), (UNITY_DOUBLE)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line)) +#define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NEG_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NAN) +#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_DET) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NEG_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NAN) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message) UnityAssertDoubleSpecial((UNITY_DOUBLE)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET) +#endif + +/* End of UNITY_INTERNALS_H */ +#endif + +/* === END inlined unity_internals.h === */ + +/*------------------------------------------------------- + * Test Setup / Teardown + *-------------------------------------------------------*/ + +/* These functions are intended to be called before and after each test. + * If using unity directly, these will need to be provided for each test + * executable built. If you are using the test runner generator and/or + * Ceedling, these are optional. */ +void setUp(void); +void tearDown(void); + +/* These functions are intended to be called at the beginning and end of an + * entire test suite. suiteTearDown() is passed the number of tests that + * failed, and its return value becomes the exit code of main(). If using + * Unity directly, you're in charge of calling these if they are desired. + * If using Ceedling or the test runner generator, these will be called + * automatically if they exist. */ +void suiteSetUp(void); +int suiteTearDown(int num_failures); + +/*------------------------------------------------------- + * Test Reset and Verify + *-------------------------------------------------------*/ + +/* These functions are intended to be called before during tests in order + * to support complex test loops, etc. Both are NOT built into Unity. Instead + * the test runner generator will create them. resetTest will run teardown and + * setup again, verifying any end-of-test needs between. verifyTest will only + * run the verification. */ +void resetTest(void); +void verifyTest(void); + +/*------------------------------------------------------- + * Configuration Options + *------------------------------------------------------- + * All options described below should be passed as a compiler flag to all files using Unity. If you must add #defines, place them BEFORE the #include above. + + * Integers/longs/pointers + * - Unity attempts to automatically discover your integer sizes + * - define UNITY_EXCLUDE_STDINT_H to stop attempting to look in + * - define UNITY_EXCLUDE_LIMITS_H to stop attempting to look in + * - If you cannot use the automatic methods above, you can force Unity by using these options: + * - define UNITY_SUPPORT_64 + * - set UNITY_INT_WIDTH + * - set UNITY_LONG_WIDTH + * - set UNITY_POINTER_WIDTH + + * Floats + * - define UNITY_EXCLUDE_FLOAT to disallow floating point comparisons + * - define UNITY_FLOAT_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_FLOAT + * - define UNITY_FLOAT_TYPE to specify doubles instead of single precision floats + * - define UNITY_INCLUDE_DOUBLE to allow double floating point comparisons + * - define UNITY_EXCLUDE_DOUBLE to disallow double floating point comparisons (default) + * - define UNITY_DOUBLE_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_DOUBLE + * - define UNITY_DOUBLE_TYPE to specify something other than double + * - define UNITY_EXCLUDE_FLOAT_PRINT to trim binary size, won't print floating point values in errors + + * Output + * - by default, Unity prints to standard out with putchar. define UNITY_OUTPUT_CHAR(a) with a different function if desired + * - define UNITY_DIFFERENTIATE_FINAL_FAIL to print FAILED (vs. FAIL) at test end summary - for automated search for failure + + * Optimization + * - by default, line numbers are stored in unsigned shorts. Define UNITY_LINE_TYPE with a different type if your files are huge + * - by default, test and failure counters are unsigned shorts. Define UNITY_COUNTER_TYPE with a different type if you want to save space or have more than 65535 Tests. + + * Test Cases + * - define UNITY_SUPPORT_TEST_CASES to include the TEST_CASE macro, though really it's mostly about the runner generator script + + * Parameterized Tests + * - you'll want to create a define of TEST_CASE(...), TEST_RANGE(...) and/or TEST_MATRIX(...) which basically evaluates to nothing + + * Tests with Arguments + * - you'll want to define UNITY_USE_COMMAND_LINE_ARGS if you have the test runner passing arguments to Unity + + *------------------------------------------------------- + * Basic Fail and Ignore + *-------------------------------------------------------*/ + +#define TEST_FAIL_MESSAGE(message) UNITY_TEST_FAIL(__LINE__, (message)) +#define TEST_FAIL() UNITY_TEST_FAIL(__LINE__, NULL) +#define TEST_IGNORE_MESSAGE(message) UNITY_TEST_IGNORE(__LINE__, (message)) +#define TEST_IGNORE() UNITY_TEST_IGNORE(__LINE__, NULL) +#define TEST_MESSAGE(message) UnityMessage((message), __LINE__) +#define TEST_ONLY() +#ifdef UNITY_INCLUDE_PRINT_FORMATTED +#define TEST_PRINTF(message, ...) UnityPrintF(__LINE__, (message), ##__VA_ARGS__) +#endif + +/* It is not necessary for you to call PASS. A PASS condition is assumed if nothing fails. + * This method allows you to abort a test immediately with a PASS state, ignoring the remainder of the test. */ +#define TEST_PASS() TEST_ABORT() +#define TEST_PASS_MESSAGE(message) do { UnityMessage((message), __LINE__); TEST_ABORT(); } while (0) + +/*------------------------------------------------------- + * Build Directives + *------------------------------------------------------- + + * These macros do nothing, but they are useful for additional build context. + * Tools (like Ceedling) can scan for these directives and make use of them for + * per-test-executable #include search paths and linking. */ + +/* Add source files to a test executable's compilation and linking. Ex: TEST_SOURCE_FILE("sandwiches.c") */ +#define TEST_SOURCE_FILE(a) + +/* Customize #include search paths for a test executable's compilation. Ex: TEST_INCLUDE_PATH("src/module_a/inc") */ +#define TEST_INCLUDE_PATH(a) + +/*------------------------------------------------------- + * Test Asserts (simple) + *-------------------------------------------------------*/ + +/* Boolean */ +#define TEST_ASSERT(condition) UNITY_TEST_ASSERT( (condition), __LINE__, " Expression Evaluated To FALSE") +#define TEST_ASSERT_TRUE(condition) UNITY_TEST_ASSERT( (condition), __LINE__, " Expected TRUE Was FALSE") +#define TEST_ASSERT_UNLESS(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expression Evaluated To TRUE") +#define TEST_ASSERT_FALSE(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expected FALSE Was TRUE") +#define TEST_ASSERT_NULL(pointer) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, " Expected NULL") +#define TEST_ASSERT_NOT_NULL(pointer) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, " Expected Non-NULL") +#define TEST_ASSERT_EMPTY(pointer) UNITY_TEST_ASSERT_EMPTY( (pointer), __LINE__, " Expected Empty") +#define TEST_ASSERT_NOT_EMPTY(pointer) UNITY_TEST_ASSERT_NOT_EMPTY((pointer), __LINE__, " Expected Non-Empty") + +/* Integers (of all sizes) */ +#define TEST_ASSERT_EQUAL_INT(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_size_t(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX8(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX16(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX32(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX64(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_CHAR(expected, actual) UNITY_TEST_ASSERT_EQUAL_CHAR((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_BITS(mask, expected, actual) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_BITS_HIGH(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT)(-1), (actual), __LINE__, NULL) +#define TEST_ASSERT_BITS_LOW(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT)(0), (actual), __LINE__, NULL) +#define TEST_ASSERT_BIT_HIGH(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT)1 << (bit)), (UNITY_UINT)(-1), (actual), __LINE__, NULL) +#define TEST_ASSERT_BIT_LOW(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT)1 << (bit)), (UNITY_UINT)(0), (actual), __LINE__, NULL) + +/* Integer Not Equal To (of all sizes) */ +#define TEST_ASSERT_NOT_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_NOT_EQUAL_CHAR((threshold), (actual), __LINE__, NULL) + +/* Integer Greater Than/ Less Than (of all sizes) */ +#define TEST_ASSERT_GREATER_THAN(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_size_t(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_CHAR(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_CHAR((threshold), (actual), __LINE__, NULL) + +#define TEST_ASSERT_LESS_THAN(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_size_t(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_CHAR(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_CHAR((threshold), (actual), __LINE__, NULL) + +#define TEST_ASSERT_GREATER_OR_EQUAL(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, NULL) + +#define TEST_ASSERT_LESS_OR_EQUAL(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_size_t(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_CHAR(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, NULL) + +/* Integer Ranges (of all sizes) */ +#define TEST_ASSERT_INT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_INT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_INT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_INT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_INT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_UINT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_size_t_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_HEX64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_CHAR_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_CHAR_WITHIN((delta), (expected), (actual), __LINE__, NULL) + +/* Integer Array Ranges (of all sizes) */ +#define TEST_ASSERT_INT_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_INT8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_INT16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_INT32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_INT64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_UINT64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_size_t_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX8_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX16_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX32_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_HEX64_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) +#define TEST_ASSERT_CHAR_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_CHAR_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, NULL) + + +/* Structs and Strings */ +#define TEST_ASSERT_EQUAL_PTR(expected, actual) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_STRING(expected, actual) UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len) UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_MEMORY(expected, actual, len) UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, NULL) + +/* Arrays */ +#define TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_size_t_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_CHAR_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_CHAR_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) + +/* Arrays Compared To Single Value */ +#define TEST_ASSERT_EACH_EQUAL_INT(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_INT8(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT8((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_INT16(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT16((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_INT32(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT32((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_INT64(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT64((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_UINT(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_UINT8(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT8((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_UINT16(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT16((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_UINT32(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT32((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_UINT64(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT64((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_size_t(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_HEX(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_HEX8(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX8((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_HEX16(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX16((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_HEX32(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_HEX64(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_HEX64((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_PTR(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_PTR((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_STRING(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_STRING((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_MEMORY(expected, actual, len, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY((expected), (actual), (len), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_CHAR(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_CHAR((expected), (actual), (num_elements), __LINE__, NULL) + +/* Floating Point (If Enabled) */ +#define TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_NOT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_FLOAT_NOT_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_FLOAT(expected, actual) UNITY_TEST_ASSERT_EQUAL_FLOAT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_FLOAT(expected, actual) UNITY_TEST_ASSERT_NOT_EQUAL_FLOAT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_FLOAT_ARRAY_WITHIN((delta), (expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_FLOAT(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_FLOAT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_FLOAT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_FLOAT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_FLOAT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_FLOAT(threshold, actual) UNITY_TEST_ASSERT_LESS_THAN_FLOAT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_FLOAT(threshold, actual) UNITY_TEST_ASSERT_LESS_OR_EQUAL_FLOAT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NEG_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NAN(actual) UNITY_TEST_ASSERT_FLOAT_IS_NAN((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_DETERMINATE(actual) UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, NULL) + +/* Double (If Enabled) */ +#define TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_NOT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_DOUBLE_NOT_WITHIN((delta), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_DOUBLE(expected, actual) UNITY_TEST_ASSERT_EQUAL_DOUBLE((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL_DOUBLE(expected, actual) UNITY_TEST_ASSERT_NOT_EQUAL_DOUBLE((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_ARRAY_WITHIN(delta, expected, actual, num_elements) UNITY_TEST_ASSERT_DOUBLE_ARRAY_WITHIN((delta), (expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_EACH_EQUAL_DOUBLE(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE((expected), (actual), (num_elements), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_DOUBLE(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_DOUBLE((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_DOUBLE(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_DOUBLE((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_DOUBLE(threshold, actual) UNITY_TEST_ASSERT_LESS_THAN_DOUBLE((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_DOUBLE(threshold, actual) UNITY_TEST_ASSERT_LESS_OR_EQUAL_DOUBLE((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NEG_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NAN(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NAN((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, NULL) + +/* Shorthand */ +#ifdef UNITY_SHORTHAND_AS_OLD +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal") +#endif +#ifdef UNITY_SHORTHAND_AS_INT +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +#ifdef UNITY_SHORTHAND_AS_MEM +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_MEMORY((&expected), (&actual), sizeof(expected), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +#ifdef UNITY_SHORTHAND_AS_RAW +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) == (actual)), __LINE__, " Expected Equal") +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal") +#endif +#ifdef UNITY_SHORTHAND_AS_NONE +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif + +/*------------------------------------------------------- + * Test Asserts (with additional messages) + *-------------------------------------------------------*/ + +/* Boolean */ +#define TEST_ASSERT_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, (message)) +#define TEST_ASSERT_TRUE_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, (message)) +#define TEST_ASSERT_UNLESS_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message)) +#define TEST_ASSERT_FALSE_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, (message)) +#define TEST_ASSERT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, (message)) +#define TEST_ASSERT_NOT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, (message)) +#define TEST_ASSERT_EMPTY_MESSAGE(pointer, message) UNITY_TEST_ASSERT_EMPTY( (pointer), __LINE__, (message)) +#define TEST_ASSERT_NOT_EMPTY_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_EMPTY((pointer), __LINE__, (message)) + +/* Integers (of all sizes) */ +#define TEST_ASSERT_EQUAL_INT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_size_t_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_BITS_MESSAGE(mask, expected, actual, message) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_BITS_HIGH_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(-1), (actual), __LINE__, (message)) +#define TEST_ASSERT_BITS_LOW_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (UNITY_UINT32)(0), (actual), __LINE__, (message)) +#define TEST_ASSERT_BIT_HIGH_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(-1), (actual), __LINE__, (message)) +#define TEST_ASSERT_BIT_LOW_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(0), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_CHAR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_CHAR((expected), (actual), __LINE__, (message)) + +/* Integer Not Equal To (of all sizes) */ +#define TEST_ASSERT_NOT_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_CHAR((threshold), (actual), __LINE__, (message)) + + +/* Integer Greater Than/ Less Than (of all sizes) */ +#define TEST_ASSERT_GREATER_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_CHAR((threshold), (actual), __LINE__, (message)) + +#define TEST_ASSERT_LESS_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_CHAR((threshold), (actual), __LINE__, (message)) + +#define TEST_ASSERT_GREATER_OR_EQUAL_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, (message)) + +#define TEST_ASSERT_LESS_OR_EQUAL_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_size_t_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_CHAR_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_CHAR((threshold), (actual), __LINE__, (message)) + +/* Integer Ranges (of all sizes) */ +#define TEST_ASSERT_INT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_INT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_INT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_INT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_INT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_UINT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_size_t_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_HEX64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_CHAR_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_CHAR_WITHIN((delta), (expected), (actual), __LINE__, (message)) + +/* Integer Array Ranges (of all sizes) */ +#define TEST_ASSERT_INT_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_INT8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_INT16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_INT32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_INT64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_INT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_UINT64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_size_t_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_UINT_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX8_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX8_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX16_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX16_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX32_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX32_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_HEX64_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_HEX64_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) +#define TEST_ASSERT_CHAR_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_CHAR_ARRAY_WITHIN((delta), (expected), (actual), num_elements, __LINE__, (message)) + + +/* Structs and Strings */ +#define TEST_ASSERT_EQUAL_PTR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_STRING_LEN_MESSAGE(expected, actual, len, message) UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_MEMORY_MESSAGE(expected, actual, len, message) UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, (message)) + +/* Arrays */ +#define TEST_ASSERT_EQUAL_INT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_INT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_size_t_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_HEX64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_PTR_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_STRING_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_MEMORY_ARRAY_MESSAGE(expected, actual, len, num_elements, message) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_CHAR_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_CHAR_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) + +/* Arrays Compared To Single Value*/ +#define TEST_ASSERT_EACH_EQUAL_INT_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_INT((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_INT8_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_INT8((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_INT16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_INT16((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_INT32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_INT32((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_INT64_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_INT64((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_UINT_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_UINT8_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT8((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_UINT16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT16((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_UINT32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT32((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_UINT64_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT64((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_size_t_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX8_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX8((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX16((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX64_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX64((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_PTR_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_PTR((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_STRING_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_STRING((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_MEMORY_MESSAGE(expected, actual, len, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_MEMORY((expected), (actual), (len), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_CHAR_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_CHAR((expected), (actual), (num_elements), __LINE__, (message)) + +/* Floating Point (If Enabled) */ +#define TEST_ASSERT_FLOAT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_FLOAT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_FLOAT((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_FLOAT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_FLOAT((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_FLOAT_ARRAY_WITHIN((delta), (expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_FLOAT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_FLOAT_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_FLOAT((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_FLOAT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_FLOAT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_FLOAT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_FLOAT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_FLOAT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_LESS_THAN_FLOAT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_FLOAT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_LESS_OR_EQUAL_FLOAT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NAN((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NOT_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, (message)) +#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, (message)) + +/* Double (If Enabled) */ +#define TEST_ASSERT_DOUBLE_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_DOUBLE_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_DOUBLE((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_DOUBLE_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_NOT_EQUAL_DOUBLE((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_ARRAY_WITHIN_MESSAGE(delta, expected, actual, num_elements, message) UNITY_TEST_ASSERT_DOUBLE_ARRAY_WITHIN((delta), (expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EQUAL_DOUBLE_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_DOUBLE_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_DOUBLE((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_DOUBLE_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_DOUBLE((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_DOUBLE_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_DOUBLE((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_DOUBLE_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_LESS_THAN_DOUBLE((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_DOUBLE_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_LESS_OR_EQUAL_DOUBLE((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NAN((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NOT_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, (message)) +#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, (message)) + +/* Shorthand */ +#ifdef UNITY_SHORTHAND_AS_OLD +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message)) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, (message)) +#endif +#ifdef UNITY_SHORTHAND_AS_INT +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, message) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +#ifdef UNITY_SHORTHAND_AS_MEM +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_MEMORY((&expected), (&actual), sizeof(expected), __LINE__, message) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif +#ifdef UNITY_SHORTHAND_AS_RAW +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) == (actual)), __LINE__, message) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, message) +#endif +#ifdef UNITY_SHORTHAND_AS_NONE +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_FAIL(__LINE__, UnityStrErrShorthand) +#endif + +/* end of UNITY_FRAMEWORK_H */ +#ifdef __cplusplus +} +#endif +#endif