Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,21 @@ Keep all source files (`.cpp`/`.h`) plain ASCII, including comments. MSVC reads

- Insert new class methods in alphabetical order within their existing section. If the class has named or visibly separated sections, preserve those sections and alphabetize only within the relevant section.
- Insert new free functions in alphabetical order within their existing section. Apply the same section rule when functions are grouped.
- Lay out a new class's members by kind, each kind in a section of its own with its own access label, even when the label repeats: nested types first, then static data, then data members, then the methods, grouped by access (private, then protected, then public), with each group's static methods in a section before its other methods. See `TWin32GUIMainWindow` (`win32/gui/src/ASWUnitTests_Win32GUI_MainWindow.h`) and `TStringCheckProbe` (`tests/UT_Helper_StringChecks.h`).
- Follow the surrounding naming, indentation, brace, include, and comment style. Avoid unrelated formatting changes.
- Keep declarations and definitions consistent, and update all relevant project or build files when adding, removing or renaming source files, including `Deploy.bat`, which copies an explicit list of files, and the `*_Sources.cmake` files (`src/`, `gui/src/`, `win32/gui/src/`), which list each folder's sources for projects that use this repository as a submodule.
- Add or update focused tests for behavior changes, including error and platform-specific cases where applicable.
- Each unit under test has exactly one test module: `ASWUnitTests_X` is tested by `Test_ASWUnitTests_X.cpp`/`.h` (class `TTest_ASWUnitTests_X`, group name `"ASWUnitTests_X_Tests"`), in the matching tests folder, and its tests go there, however large it grows. Supporting code that isn't a test itself, such as a fixture group or a probe whose templates are instantiated for the tests, may go in a helper module named `UT_Helper_<what>.cpp`/`.h` in the same folder (e.g. `tests/UT_Helper_StringChecks`), listed in the projects and build files like any other source file.
- RAD Studio's Win32 linker (ilink32) limits the line-number debug information of each module (its "Line number cache"), and `tests/Test_ASWUnitTests_TestBase.cpp` is close to that limit. A Win32 Debug build then fails with "Fatal: Exceeded memory limit for block Line number cache in module ...". Every distinct lambda registered as a test costs a `std::function` instantiation, so prefer a few tests that each check many cases (or parameterized tests, which share one callback) to hundreds of registered lambdas, and move heavy template instantiations into a `UT_Helper_` module, defined and explicitly instantiated in its `.cpp`. Check with the VCL console's Win32 Debug build, which links the most modules.

## Naming and Style

- New enums take an `E` prefix (`EWin32GUICommand`); classes and structs take `T`. Existing enums that use `T` (e.g. `TLogKind`, `TTestOutcome`) keep it.
- Write acronyms in identifiers and file names in uppercase: `GUI`, `CLI`, `RTL`, `UTF8`, `XML` (e.g. `TCLIParser`, `ToUTF8`, `ASWUnitTests_GUI_TestList`). `JUnit` is a name, not an acronym. Check an existing name against this rule before copying its casing.
- Compare a pointer, `std::function` or other nullable value with `nullptr` explicitly (`if (filter != nullptr)`), rather than relying on its conversion to `bool` (`if (filter)`).
- In a `.cpp` file, describe a function in a block comment between its `//----` separator line and its definition (`/*`, the function's name, a blank line, the description, `*/`), not in `//` lines above it; a function that needs no explanation gets no comment. Declarations in a header keep `//` comments. See `win32/gui/src/ASWUnitTests_Win32GUI_System.cpp`.
- Suppress an intentional MSVC warning with `#pragma warning(push)`, `#pragma warning(disable: N)` and `#pragma warning(pop)` around the whole function or block, guarded by `#if defined(_MSC_VER)`, never with `#pragma warning(suppress: N)`: MSVC checks some warnings (e.g. C4702) against the state at the end of the function, after a `suppress` has lapsed.
- Don't name an identifier `assert`, even a parameter: `assert()` is a macro wherever `<cassert>` is included, and the VCL headers include it.

## Building and Testing

Expand Down Expand Up @@ -90,4 +102,6 @@ git config --local core.hooksPath .githooks/

Wrap Markdown prose at 100 columns in `README.md`, `CONTRIBUTING.md` and `CHANGELOG.md`, re-wrapping the edited paragraph when a change makes a line too long. Don't split inline code or a link's text across lines. Code blocks and tables are exempt, and so is a line that only overflows because a single link or URL can't be split.

Don't use em dashes in anything written for this repository (documentation, comments, messages): use a hyphen with a space on each side (" - "), or restructure the sentence.

Review the final diff for accidental file changes, ordering regressions, missing includes, platform assumptions, and tests that do not actually exercise the changed behavior. Do not commit changes unless the user explicitly requests a commit.
77 changes: 77 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,40 @@ versioned baseline.
before.
- `gui\src\ASWUnitTests_GUI_Sources.cmake`, which lists the GUI runners' shared units as
`ASWUNITTESTS_GUI_SOURCES`.
- A `TCLIParser::ParseArguments()` overload that takes the arguments as a
`std::vector<std::string>`, the program name first, as in `argv`.
- `UTF8ToWide()` in `ASWUnitTests_Utils.h`, which converts UTF-8 to wide text (UTF-16 on Windows,
UTF-32 on Linux), and, on Windows, `CommandLineArguments()` and `SystemErrorText()`: a command
line split into UTF-8 arguments, and a `GetLastError()` code's description.
- `TConsoleUTF8Output` (`ASWUnitTests_Console.h`), which sets the Windows console's output code page
to UTF-8 while it exists and then restores it. The console runner uses it for the whole run.
- The string checks (`Equals`, `Contains`, `StartsWith`, `EndsWith` and `Matches`, with their `Not`
and `IC` forms) take two texts of different types: a `std::string` with a C string, and narrow
text with wide text, which didn't compile before. Two narrow or two wide texts are compared as
they are; any other pair as UTF-8. The README's "Comparing Strings of Different Types" has the
details.
- `Matches` and `NotMatches` take two C strings, narrow or wide, and in RTL builds a
`System::String`.
- In RTL builds, the string checks also take an `AnsiString`, a `UTF8String` or another
`AnsiStringT`, and two RTL strings or an RTL string with any other text.
- `CheckEmpty`/`AssertEmpty` and `CheckNotEmpty`/`AssertNotEmpty` take a C string, narrow or wide,
including a character array, which is checked as the text it holds rather than by its size. A
null C string fails both, shown as `(null)`. In RTL builds they also take an `AnsiString`, a
`UTF8String` or another `AnsiStringT`.
- A `TExceptNotEmpty` constructor that takes a detail, which `AssertNotEmpty` uses for a null C
string.
- `CheckNear`/`AssertNear` and `CheckNotNear`/`AssertNotNear` take any three integer or
floating-point types except `bool`, in any mix, e.g. `CheckNear(2.0, aFloat, 0.01, ...)` or
`CheckNear(10, count, 1, ...)`, which were ambiguous before, and `long double`. With any
floating-point value, all three are compared as their common type; three integers are compared
exactly and shown as integers.
- `SetExceptionExpected<TException>()`, `CheckThrows<TException>` and `AssertThrows<TException>`
take any type that can be thrown, e.g. `int`, `char const*` or a class that doesn't derive from
`std::exception`. Before, the Throws methods didn't compile with one, and
`SetExceptionExpected<TException>()` didn't compile with `int` and never matched a class.
Expecting a message substring from a type with no message (neither a `std::exception` nor an RTL
exception) fails, naming the type that was caught, e.g. `an object of type "int"`. A class also
matches a `std::exception` subclass derived from it, whose `what()` is then checked.

### Changed

Expand All @@ -50,6 +84,32 @@ versioned baseline.
written the same way. A size or position written in hexadecimal by hand is now ignored, as an
invalid value. The selection file's first line, a comment, now reads "ASWUnitTests GUI test
selection" instead of "ASWUnitTests VCL GUI test selection"; files saved before still load.
- On Windows, the console runner reads its arguments from the UTF-16 command line instead of
`argv`, which holds them in the ANSI code page, so a `--filter` pattern, `--project-name` or
`--report-junit` path can hold characters outside that code page; before, those became `?` or a
lookalike. While it runs, it also sets the console's output code page to UTF-8, so non-ASCII test
names and messages show correctly, and restores it afterwards.
- On Windows, `main.cpp` defines `_tmain` instead of `main`, so a project whose `TCHAR` maps to
`wchar_t` (in RAD Studio, "TCHAR maps to" set to `wchar_t`) links too. It stays `main` elsewhere.
- `TJUnitReportWriter::Write()` now takes its path as UTF-8 on Windows too, as the console runner
passes it. Code that calls it with a path in the ANSI code page that has non-ASCII characters must
convert the path to UTF-8 first.
- In RTL builds, a null C string compared with a `System::String` follows the same rules as with any
other text, instead of being empty text: it equals only another null C string, so it no longer
equals an empty `System::String`, and it matches nothing in `Contains`, `StartsWith` and
`EndsWith`. A test that relied on it being empty text must compare with an empty string instead.
- A negative or NaN tolerance now fails `CheckNotNear`/`AssertNotNear` as well as
`CheckNear`/`AssertNear`, with "Invalid tolerance ...: it must be zero or more". Before, the
NotNear methods passed with one, whatever the values. A test that passes a negative tolerance must
pass its absolute value instead.
- When a test expects a specific type with `SetExceptionExpected<TException>()` and throws an object
of another type that is neither a `std::exception` nor an RTL exception, the failure now reads
"expected exception type was not thrown (caught a different exception): a non-std::exception
object", as for any other wrong type, instead of "expected a specific exception type, but a
non-std::exception object was thrown instead."
- In RTL builds, `SetExceptionExpected<TException>()` no longer compiles with an RTL class that
isn't an `Exception` or a subclass (e.g. `TStringList`), which could never match, as the Throws
methods already didn't. Expect `Exception` or the class that's actually raised instead.

### Fixed

Expand All @@ -58,6 +118,23 @@ versioned baseline.
full. It now shows every finished test, and starts each run empty.
- The VCL GUI runner's tooltips for Run Selected and Copy Details showed their keyboard shortcut
twice, e.g. "(F9) (F9)".
- With `--catch-crashes` and `--test-timeout-seconds` together, a crash that came while a test was
logging or recording a result, such as one in a run observer's `OnLog()`, left the run waiting
forever at the next test. The run now continues with the next test, as after any other crash.
- A null C string compared with a `std::string` or `std::wstring` (e.g.
`CheckEquals(expectedText, nameOrNull, ...)`), or given to `Matches`, was converted to a string,
which is undefined behavior and usually crashed. It now follows the same rules as two C strings:
it equals only another null C string, matches nothing in the other checks, and a failure shows it
as `(null)`.
- With `--test-timeout-seconds`, on Windows, a test ran with the default floating-point environment
instead of the one the run started with: rounding to nearest, whatever rounding mode was set, and
with llvm-mingw, `long double` arithmetic at `double` precision. Each test now starts with the
floating-point environment of the thread that runs the tests, as it does without a timeout.
- With RAD Studio's 32-bit compiler (`bcc32c`), type names in failure messages, such as
`CheckIsType`'s, were shown as the compiler mangles them, e.g. `$N@TShape` or `$i`. They're now
shown as written, e.g. `N::TShape` or `int`, as with the other compilers. A pointer to a `const`
or `volatile` class, and a template whose argument is in an anonymous namespace, are still shown
as mangled.

## [1.4.0] - 2026-10-14

Expand Down
8 changes: 8 additions & 0 deletions Deploy.bat
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,14 @@ call :CopyFile "tests\Test_ASWUnitTests_Version.cpp" "tests\Test_ASWUnitTests_Ve
if errorlevel 1 exit /b 1
call :CopyFile "tests\Test_ASWUnitTests_Version.h" "tests\Test_ASWUnitTests_Version.h"
if errorlevel 1 exit /b 1
call :CopyFile "tests\UT_Helper_ExceptionTypes.cpp" "tests\UT_Helper_ExceptionTypes.cpp"
if errorlevel 1 exit /b 1
call :CopyFile "tests\UT_Helper_ExceptionTypes.h" "tests\UT_Helper_ExceptionTypes.h"
if errorlevel 1 exit /b 1
call :CopyFile "tests\UT_Helper_StringChecks.cpp" "tests\UT_Helper_StringChecks.cpp"
if errorlevel 1 exit /b 1
call :CopyFile "tests\UT_Helper_StringChecks.h" "tests\UT_Helper_StringChecks.h"
if errorlevel 1 exit /b 1
call :CopyFile "toTest\ASWTools_Common.cpp" "toTest\ASWTools_Common.cpp"
if errorlevel 1 exit /b 1
call :CopyFile "toTest\ASWTools_Common.h" "toTest\ASWTools_Common.h"
Expand Down
Loading
Loading