Compare commits

...

615 Commits
v1.1 ... master

Author SHA1 Message Date
David Korth
12d6ec439f README.md: Add a badge for Crowdin. 2025-06-19 01:53:26 -04:00
David Korth
0ed8c449fa README.md: Put the Wii U unbricking advice in the nusresign block, not wadresign. 2025-06-17 21:33:02 -04:00
David Korth
e3723e3477 README.md: Mention two possible unbricking methods for Wii U. 2025-06-17 21:32:23 -04:00
David Korth
5effa63216 Version bump for development. (v2.0.1+) 2025-06-17 21:27:15 -04:00
David Korth
5b3286af4d rvthtool 2.0.1 2025-06-17 21:19:17 -04:00
David Korth
b27996b154 NEWS.md: Mention the Windows UI issues. 2025-06-17 20:22:07 -04:00
David Korth
2a5551b616 [qrvthtool] Fix UI issues on Windows 10.
- Always use the Oxygen icon theme. Qt6 has a built-in monochrome icon
  theme on Windows 10, but it's missing some icons.

- On Windows 10, set the style to fusion. Qt's "Windows Vista" style
  (now "Modern Windows") doesn't support Dark Mode, but fusion does.

- Manifest: Add Windows 8, 8.1, and 10 OS GUIDs.

- resource.rc: Use the CreateProcess manifest ID, not IsolationAware.
  IsolationAware is only for DLLs. Without the CreateProcess ID,
  on Windows 10, GetVersion() and the version helper functions will
  assume we're actually using Windows 8.
2025-06-17 20:18:47 -04:00
David Korth
43b9691078 [cmake] 64BitTimeSupportFcntl.cpp: This file was missing...
Copied it from rom-properties.

This broke the Launchpad Ubuntu 20.04 armhf build. Not going to resubmit
it, because I don't think anyone will be using rvthtool on that OS and
platform...

(cherry picked from commit d9f4ec96f1)
2025-06-17 00:43:32 -04:00
David Korth
d0498b9e7d [debian] rules: Explicitly set QT_VERSION=5.
CMake failed to find Qt on the Launchpad build server for Ubuntu 18.04
for some reason. (...though it worked on 16.04?)

(cherry picked from commit 99988fb273)

Conflicts:
	debian/changelog
2025-06-17 00:43:18 -04:00
David Korth
c2ee653c2e Version bump for development. (v2.0+) 2025-06-17 00:42:36 -04:00
David Korth
b0bdcdfa22 rvthtool 2.0 2025-06-16 23:33:16 -04:00
David Korth
91ee6b11d6 [debian] changelog: Another version bump for Launchpad shenanigans. 2025-06-16 23:31:08 -04:00
David Korth
253af29292 [debian] rules: Don't bother deleting the extra LICENSE file.
It's failing on Launchpad for some reason.
2025-06-16 23:30:50 -04:00
David Korth
c96e470e1b Move NETWORK.md installation from CMakeLists.txt to doc/CMakeLists.txt. 2025-06-16 23:30:30 -04:00
David Korth
efafcc8471 [debian] changelog: Bump version for Launchpad shenanigans. 2025-06-16 23:18:39 -04:00
David Korth
6abbec0522 [qrvthtool] CMakeLists.txt: Fix source path for com.gerbilsoft.qrvthtool.metainfo.xml. 2025-06-16 23:16:43 -04:00
David Korth
8801fb9432 [locale] Updated the translation files using lupdate.sh. 2025-06-16 22:52:49 -04:00
David Korth
4c93b1d4ce [locale] rvthtool_de.ts: More translations from Moddimation. 2025-06-16 22:52:18 -04:00
David Korth
914af5a55d [qrvthtool] CMakeLists.txt: Remove quotes for windeployqt.
Otherwise, it tries using the entire --exclude-plugins line as a single
option, which fails miserably.
2025-06-16 22:45:10 -04:00
David Korth
1d0f8e86ef [qrvthtool] SelectDeviceDialog.cpp: Mask the device serial number here, too.
Add ConfigStore as a constructor parameter. QRvtHToolWindow's
ConfigStore object must be passed here.

Listen for the option change, even though it shouldn't be possible
for the option to change while the dialog is open.

QRvtHToolWindow::on_actionOpenDevice_triggered():
- Pass the ConfigStore to SelectDeviceDialog.
- Also pass `this` as parent to ensure that the user realizes the
  window is modal. On KDE, this dims the main window. Previously,
  the main window wouldn't be dimmed, but it wouldn't be usable
  while SelectDeviceDialog was open.
2025-06-16 22:36:04 -04:00
David Korth
54b78ac69d [qrvthtool] AboutDialog.cpp: Update copyright years for Qt and Nettle. 2025-06-16 22:17:34 -04:00
David Korth
ef6645c559 [qrvthtool] CmakeLists.txt: Update the windeployqt exclusions to work with Qt 5.15.
Exclude Qt ANGLE, and make sure ffmpeg and WebKit2 are excluded.
The last two are "just in case", since I didn't see those installed
in my testing, though Qt ANGLE was definitely installed in qt5.
(Note that ffmpeg is a qt6 option.)
2025-06-16 22:16:13 -04:00
David Korth
56d20b41b8 [qrvthtool] CMakeLists.txt: Exclude unnecessary DLLs in the distribution.
This significantly reduces the distribution size, since, among other
things, we don't need QtNetwork.

Also removed:
- DirectX compiler libraries
- MSVC runtime (debug build only; release builds didn't include the DLLs)
2025-06-16 22:05:00 -04:00
David Korth
72d151eedd [qrvthtool] ConfigStore.cpp: #include <cassert>
Needed with gcc-5.4.0 on Ubuntu 16.04, but wasn't needed on my
main Gentoo system with gcc-15.1.0 for some reason.
2025-06-16 21:49:05 -04:00
David Korth
7a831a342c CMakeLists.txt: CMake 3.5.1 on Ubuntu 16.04 doesn't have VERSION_GREATER_EQUAL. 2025-06-16 21:44:11 -04:00
David Korth
af94beb75e [debian] *.docs: Add NETWORK.md. 2025-06-16 21:39:55 -04:00
David Korth
690f4f99ba [qrvthtool] QRvtHToolWindow::closeRvtH(): Clear the status bar. 2025-06-16 21:38:37 -04:00
David Korth
1c9fadf673 [extlib] Add qtbase-6.8.3-win7.patch .
This is a diff between qtbase-6.8.3 upstream and the version from:
https://github.com/crystalidea/qt6windows7
2025-06-16 21:34:27 -04:00
David Korth
b2b4421515 NEWS.md: Cleaned up formatting; added more Qt information. 2025-06-16 21:33:05 -04:00
David Korth
266431070f [qrvthtool] qrvthtool.ico: Add 16-color versions of 48x48, 32x32, and 16x16.
These were created by tracing over the full-color versions.

These are mostly for testing icon directory display in rom-properties,
and likely won't actually be used.
2025-06-13 21:51:01 -04:00
David Korth
fb9d9f5a2e [qrvthtool] qrvthtool.ico: Optimize the PNG-format 256x256 image within the icon.
Had to do this manually via hex editor...

Size reduction: 23,520 -> 20,770 (-2,750)
2025-06-08 13:41:10 -04:00
David Korth
603243205e [qrvthtool] Set KAboutData.
TODO:
- Use KCrash, but it shows bugs.kde.org as the bug reporting address...
- KIO writes to qrvthtoolrc in ~/.config/, and it doesn't seem like
  there's any way to easily fix this, since KIO uses the default
  path (QStandardPaths::GenericConfigLocation) for KSharedConfig.
2025-06-07 11:21:33 -04:00
David Korth
a823d358d6 NETWORK.md: Add a file to indicate what network access is performed.
rvthtool (and other programs included with rvthtool) does not access the
network directly, but may access the network if you attempt to open files
located on network shares.

Install NETWORK.md in the documents directory.

[cmake] options.cmake: Add OPTION(INSTALL_DOC).
2025-06-01 13:11:52 -04:00
David Korth
6d70248b7d [qrvthtool] TranslationManager::enumerate(): MSVC 2015 doesn't like constexpr on QDir::Filters.
...though interestingly, *only* the 64-bit builds failed. 32-bit seemed
to handle it just fine.

src\qrvthtool\TranslationManager.cpp(231): error C2127: 'filters': illegal initialization of 'constexpr' entity with a non-constant expression
  c:\qt\5.13\msvc2015_64\include\qtcore\qdir.h(83): note: failure was because type 'QFlags<QDir::Filter>' is not a literal type (compiling source file src\qrvthtool\TranslationManager.cpp)
2025-05-30 21:47:45 -04:00
David Korth
a6cc86d6da appveyor.cmd: Switch to MSVC 2015 and Qt 5.13.
MSVC 2013 doesn't like the updated Google Test:

extlib\googletest\googletest\include\gtest/internal/gtest-port.h(2102):
	error C3409: empty attribute block is not allowed

Also, Qt 5.8 isn't present on AppVeyor anymore. Use Qt 5.13, which is
available for MSVC 2015.
2025-05-30 21:01:53 -04:00
David Korth
ef4532d1b6 [googletest] Update from 1.8.0 to 1.12.1.
Using changes from rom-properties, which includes building gtest as a
DLL on Windows.

This update fixes a bunch of -Wsuggest-override warnings, e.g.:

In file included from extlib/googletest/googletest/include/gtest/gtest-death-test.h:41,
                 from extlib/googletest/googletest/include/gtest/gtest.h:60,
                 from src/libwiicrypto/tests/CertVerifyTest.cpp:10:
extlib/googletest/googletest/include/gtest/internal/gtest-death-test-internal.h:150:16: warning: ‘virtual bool testing::internal::DefaultDeathTestFactory::Create(const char*, const testing::internal::RE*, const char*, int, testing::internal::DeathTest**)’ can be marked override [-Wsuggest-override]
  150 |   virtual bool Create(const char* statement, const RE* regex,
      |                ^~~~~~
2025-05-30 20:19:21 -04:00
David Korth
c215903bde [librvth] rvth_error.c: Remove the '.' from the RVTH_ERROR_NDEV_GCN_NOT_SUPPORTED message.
FIXME: rvth_error.h's message comments don't all match rvth_error.c.

[locale] Update for these changes.
2025-05-30 19:47:38 -04:00
David Korth
5e7233cb89 [qrvthtool] TranslationManager::setTranslation(): Remove a stray ')' in the Qt5 build path.
lupdate noticed this:

src/qrvthtool/TranslationManager.cpp:155: Excess closing parenthesis in
C++ code (or abuse of the C++ preprocessor)

This fixes a regression from commit 4e0f741910.
([qrvthtool] TranslationManager: Made some adjustments, including removing translators before updating them.)
2025-05-30 19:43:49 -04:00
David Korth
84d2fae156 [qrvthtool] TranslationManager: Some more fiddling.
- Get the translation file info directly from d->prgTranslator, before
  installing it into the QCoreApplication.

- If tsLocale is empty, or is "1337", set it to "C".
2025-05-30 19:41:32 -04:00
David Korth
11cfd9cd62 [qrvthtool] TranslationManager: Set LANG and LC_ALL.
This helps a bit with KDE's Open dialog, but the "Cancel" button isn't
getting translated for some reason. Similarly, SelectDeviceDialog's
"OK" button isn't getting translated, and "Cancel" uses whatever the
LC_ALL value was on startup.
2025-05-30 19:25:08 -04:00
David Korth
4e0f741910 [qrvthtool] TranslationManager: Made some adjustments, including removing translators before updating them.
FIXME: qt_* and qtbase_* don't seem to be reloading properly when
changing the language at runtime, at least on Linux. Setting LC_ALL
seems to be the only way to get Qt's translations to switch.
2025-05-30 19:19:45 -04:00
David Korth
b8c7cc7c09 [qrvthtool] Add a cropped version of the 128x128 rvth.png image for AboutDialog.
This reduces wasted space in the dialog.

NOTE: This file is *not* installed as part of the icon theme. It's only
compiled into the executable as part of hw.qrc.
2025-05-30 19:07:01 -04:00
David Korth
afa93e5950 [librvth] RvtH::verifyWiiPartitions(): Use a struct for the hash error count.
Essentially the same as an array, but more explicit.
2025-05-30 18:52:40 -04:00
David Korth
76746231ca Use std::array<> in more places.
This lets us get rid of a few NULL terminators, too.
2025-05-30 18:47:47 -04:00
David Korth
cb09464faa [qrvthtool] Switch from foreach() to range-based for loops. 2025-05-30 18:39:19 -04:00
David Korth
35505dc1ed [qrvthtool] TranslationManager: Also load qtbase_*.qm.
qtbase_*.qm has some POSIX error codes, which still need to be handled
properly in qrvthtool.
2025-05-30 18:36:18 -04:00
David Korth
8d34c3e3dd [librvth] rvth_error.c: Mark RVT-H error strings for Qt localization.
[locale] Update for these changes.

[qrvthtool] Update for localized RVT-H error strings:

- WorkerObject: Don't include the error code in the message when
  emitting finished().

- QRvtHWindow: Handle RVT-H error codes better:
  - If -ECANCELED is returned, show the message as-is, since the operation
    was cancelled.
  - If it's an RVT-H error, use QCoreApplication::translate() with the
    "RvtH|Error" context and rvth_error(err) string.
  - If it's a POSIX error, use rvth_error() anyway for now.

FIXME: Need to properly translate POSIX errors.
2025-05-30 18:35:04 -04:00
David Korth
3a0c7f6632 [qrvthtool] WorkerObject: Consolidate various error messages.
Use a '%1' placeholder for "doExtract" and "doImport", since the messages
are all the same except for the function name.

[locale] Update localizations for this change.
2025-05-30 00:02:34 -04:00
David Korth
039d225794 [locale] rvthtool_de.ts: Initial German translation.
German translation provided by crediar and Moddimation.

[qrvthtool] AboutDialog.cpp: Add German translation credits.
2025-05-29 23:36:26 -04:00
David Korth
4e769ef07c [qrvthtool] Update Oxygen icons to v6.1.0.
Includes icon optimization using optipng, advdef, and oxipng.
2025-05-29 23:23:28 -04:00
David Korth
ccb22bc8e1 [qrvthtool] FormatSize: Consolidate the size formatting code into a single file.
This consolidates the code and translations from BankEntryView and
SelectDeviceDialog,

[locale] Update localizations for this change.
2025-05-29 23:18:54 -04:00
David Korth
fafc331c26 [qrvthtool] Use process-stop for the "Cancel" button icon.
dialog-close is black in the KDE Breeze theme.
process-stop is red.

Add process-stop from KDE Oxygen.

Un-indent some stuff and add more braces.

Fix "~/." for the home directory, similar to "./." for the
application directory.
2025-05-29 23:01:34 -04:00
David Korth
e36c938ced [qrvthtool] QRvtHToolWindowPrivate::updateGrpBankListTitle(): Remove the TODO about adding an option to hide the serial number. 2025-05-26 20:26:55 -04:00
David Korth
c78ecdfa21 [qrvthtool] QRvtHToolWindow.cpp: Restore a few changes that were actually useful. 2025-05-26 19:48:22 -04:00
David Korth
be390d9258 Revert "[qrvthtool] QRvtHToolWindow.cpp: Forgot to commit this file in the maskDeviceSerialNumbers commit."
I *did* commit this file, but something screwed up when I reverted some
changes locally but didn't commit them...

This reverts commit da6fee3603.
2025-05-26 19:47:21 -04:00
David Korth
44886ecc95 [locale] Updated the translation files using lupdate.sh. 2025-05-26 19:46:21 -04:00
David Korth
da6fee3603 [qrvthtool] QRvtHToolWindow.cpp: Forgot to commit this file in the maskDeviceSerialNumbers commit.
See commit: a976decd6c
([qrvthtool] Add an option to mask the last 5 digits of the RVT-H Reader serial number.)
2025-05-26 19:45:24 -04:00
David Korth
59f5ecf497 [qrvthtool] QRvtHToolWindow.ui: Remove splitterInfo.
Leftover from mcrecover.
2025-05-26 15:32:59 -04:00
David Korth
9f3f9b3bf7 [qrvthtool] QRvtHToolWindow.ui: Shorten the toolTip/statusTip for actionMaskDeviceSerialNumbers.
TODO: Add statusTip for other menu actions?
2025-05-26 15:21:43 -04:00
David Korth
82af365205 [qrvthtool] ConfigStore::set(): Also prevent deadlocks here. 2025-05-26 15:13:37 -04:00
David Korth
a976decd6c [qrvthtool] Add an option to mask the last 5 digits of the RVT-H Reader serial number.
Useful for screenshots.

The digits are replaced with 'x'.
2025-05-26 15:13:10 -04:00
David Korth
fd77b7a024 [qrvthtool] Show the window before attempting to open the RVT-H Reader.
This noticeably reduces lag when starting qrvthtool with a device name
specified on the command line.
2025-05-26 14:55:43 -04:00
David Korth
93b442a8ed [qrvthtool] UnityLauncher::update(): FIXME: Broken on Qt6 for some reason...
It's crashing in QtDBus when built with Qt6. Not sure why.
2025-05-26 14:54:16 -04:00
David Korth
fd4a4ad0a9 [qrvthtool] ConfigStore::notifyAll(): Fix a deadlock if the config file has an invalid language tag.
The language tag is initially loaded by ConfigStore, but when notifyAll()
is called, LanguageMenu realizes it's invalid and calls ConfigStore::set()
with an empty tag, which causes a deadlock due to d->mtxSignalMaps being
locked.

To fix this, populate a single vector of methods to invoke, then unlock
the mutex and invoke the methods.
2025-05-26 14:51:27 -04:00
David Korth
8d8925ed0b [qrvthtool] QRvtHToolWindow: Make use of 'lastPath' from ConfigStore.
PathFuncs::makeRelative(): WORKAROUND: Convert "./." to ".".

QRvtHToolWindow: Handle "." as the application directory.
2025-05-26 13:59:23 -04:00
David Korth
1cf87bc6fa [qrvthtool] ConfigDefaults: Make ValidationType a uint8_t.
This doesn't reduce any struct sizes, yet...
2025-05-26 13:48:10 -04:00
David Korth
5c45800816 [qrvthtool] ConfigDefaults: Move stuff to a private class.
Add an accessor to get all setting names, which is needed by ConfigStore.

ConfigStore: Use ConfigDefaults::getAllSettingNames().
2025-05-26 13:46:01 -04:00
David Korth
3f48d275b9 [qrvthtool] ConfigStorePrivate::Validate(): Use QVariant::canConvert(QMetaType::Type) on Qt6. 2025-05-26 13:19:34 -04:00
David Korth
5e6c8b6078 [qrvthtool] ConfigStore: Convert settingsMap to std::map<>. 2025-05-26 13:16:21 -04:00
David Korth
7cb1e7f4f0 [qrvthtool] ConfigStore: Convert signalMaps to C++ STL classes.
Also make use of references instead of pointers to reduce malloc() and
dereferencing overhead.
2025-05-26 13:07:42 -04:00
David Korth
b29fb9f0b1 [qrvthtool] Initial port of ConfigStore and ConfigDefaults from mcrecover.
Currently only handles the language code. lastPath is present, but isn't
set up yet.

LanguageMenu: Skip languages with an empty name. These are placeholder
translations that don't have any actual data yet.
2025-05-26 12:44:01 -04:00
David Korth
fa966aef95 [qrvthtool] CMakeLists.txt: Enable CMAKE_AUTOMOC.
This eliminates the need to explicitly use QT_WRAP_CPP().
2025-05-26 12:16:00 -04:00
David Korth
a884372d37 appveyor.yml: Switch the Linux image from 'Ubuntu' (18.04) to 'Ubuntu2204'.
The Linux builds have been failing for a while due to an image
configuration issue, and seemingly no one at AppVeyor has noticed:

W: GPG error: https://dl.google.com/linux/chrome/deb stable InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 32EE5355A6BC6E42
E: The repository 'https://dl.google.com/linux/chrome/deb stable InRelease' is not signed.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
2025-05-24 15:09:33 -04:00
David Korth
589856cd94 [rvthtool] mainc.: Move 'show-table' to below 'verify'.
It's a debugging command that likely won't be used often, so it shouldn't
be the second command in the list.
2025-05-22 23:55:01 -04:00
David Korth
96627e10bd [rvthtool] show-table.cpp, print_table(): Show a raw view of the entire header sector.
Not just header->unk[].

Also, print the offset at the beginning of the line and print
16 bytes per line instead of 12.
2025-05-22 23:46:03 -04:00
David Korth
f6636f3593 [rvthtool] show-table.cpp: Use _tprintf(...) instead of _ftprintf(stdout, ...). 2025-05-22 23:36:26 -04:00
David Korth
ffbecabbd4 [rvthtool] show-table.cpp, show_table(): Use a single _ftprintf() for the bank table status. 2025-05-22 23:35:44 -04:00
David Korth
c1692f55cd [rvthtool] show-table.cpp, print_table(): Improve formatting.
- Don't use '#' in the printf format specifiers. Explicitly specify
  "0x" for each one.
- Right-align the descriptions for each entry.
- Put expected on the right side of the actual values.

Before:

[/dev/nvme0n1] NHCD Bank Table:
- Status: HAS_GPT
- Table Magic (Expected Value: 0x0x4443484e): 0x00000000
- x004 (expected: 0x00000001): 0x00000000
- bank_count (expected: 0x00000008): 0x00000000
- x00C (expected: 0x00000000): 0x00000000
- x010 (expected: 0x002FF000): 0x00000000
- unk table:

After:

[/dev/nvme0n1] NHCD Bank Table:
-      Status: HAS_GPT
- Table Magic: 0x00000000 (expected: 0x4443484E, "NHCD")
-        x004: 0x00000000 (expected: 0x00000001)
-  Bank Count: 0x00000000 (expected: 0x00000008)
-        x00C: 0x00000000 (expected: 0x00000000)
-        x010: 0x00000000 (expected: 0x002FF000)
- unk table:

(Yeah, I used my laptop's NVMe SSD for testing instead of connecting the
RVT-H Reader. It takes effort to connect the RVT-H Reader...)
2025-05-22 23:32:05 -04:00
David Korth
b738376971 [locale] Updated the translation files using lupdate.sh.
Seemingly no changes since the last time I ran it, other than
line number updates...
2025-05-22 22:48:25 -04:00
David Korth
6953ed1961 [librvth] RvtH: Move another function to the private class. 2025-05-22 18:26:07 -04:00
David Korth
3e3abd3c45 Fix compile errors when building the debug 32-bit and 64-bit builds on MSVC with -DENABLE_WERROR=ON.
[qrvthtool] SelectDeviceDialog, [rvthtool] query.c:
- TODO: Switch to VersionHelpers at some point.
- For now, suppress C4996 for GetVersionEx().

[rvthtool] query.c: Likewise.

[nusresign] Cast off64_t to size_t where necessary.
2025-05-21 23:37:47 -04:00
David Korth
140ad7a6d5 Fix compile errors when building the debug build on Linux with -DENABLE_WERROR=ON.
Mostly just complaints about using strncpy(), which have been fixed
by switching to snprintf():

src/libwiicrypto/sig_tools.c: In function ‘sig_recrypt_ticket’:
src/libwiicrypto/sig_tools.c:298:9: error: ‘__builtin_strncpy’ specified bound 64 equals destination size [-Werror=stringop-truncation]
  298 |         strncpy(ticket->issuer, issuer, sizeof(ticket->issuer));
      |         ^

src/librvth/recrypt.cpp: In member function ‘int RvtH::recryptWiiPartitions(unsigned int, RVL_CryptoType_e, RvtH_Progress_Callback, void*, int)’:
src/librvth/recrypt.cpp:587:24: error: ‘char* __builtin_strncpy(char*, const char*, long unsigned int)’ specified bound 64 equals destination size [-Werror=stringop-truncation]
  587 |                 strncpy(tmdHeader->issuer, issuer_TMD, sizeof(tmdHeader->issuer));
      |                        ^
src/nusresign/resign-nus.cpp:358:16: error: ‘char* __builtin_strncpy(char*, const char*, long unsigned int)’ specified bound 64 equals destination size [-Werror=stringop-truncation]
  358 |         strncpy(pTicket->issuer, s_issuer_xs, sizeof(pTicket->issuer));
      |                ^
src/nusresign/resign-nus.cpp:359:16: error: ‘char* __builtin_strncpy(char*, const char*, long unsigned int)’ specified bound 64 equals destination size [-Werror=stringop-truncation]
  359 |         strncpy(pTmdHeader->rvl.issuer, s_issuer_cp, sizeof(pTmdHeader->rvl.issuer));
      |                ^
src/wadresign/resign-wad.cpp:639:16: error: ‘char* __builtin___strncpy_chk(char*, const char*, long unsigned int, long unsigned int)’ specified bound 64 equals destination size [-Werror=stringop-truncation]
  639 |         strncpy(tmdHeader->issuer, issuer_TMD, sizeof(tmdHeader->issuer));
      |                ^
2025-05-21 23:18:47 -04:00
David Korth
c989b382e4 Fix compile errors when building the debug build on Linux with -DENABLE_WERROR=ON.
Mostly just need to check the result of fread(), e.g.:

src/libwiicrypto/bin2h.c: In function ‘main’:
src/libwiicrypto/bin2h.c:66:9: error: ignoring return value of ‘fread’ declared with attribute ‘warn_unused_result’ [-Werror=unused-result]
   66 |         fread(bin, 1, fsize, f);
      |         ^~~~~~~~~~~~~~~~~~~~~~~
2025-05-21 23:13:16 -04:00
David Korth
6fb8daa8fb [qrvthtool] Optimize all .png images using optipng, advdef, and oxipng.
qrc_*.o size differences: (64-bit Gentoo Linux, gcc-15.1.0, release build, no LTO)

   text    data     bss     dec     hex filename
   8029      16       1    8046    1f6e qrc_flags.cpp.o [before]
   7513      16       1    7530    1d6a qrc_flags.cpp.o [after]
   -516       0       0    -516    -204 Difference

   text    data     bss     dec     hex filename
  95132      16       1   95149   173ad qrc_hw.cpp.o
  92098      16       1   92115   167d3 qrc_hw.cpp.o
  -3034       0       0   -3034    -bda Difference

   text    data     bss     dec     hex filename
  87257      16       1   87274   154ea qrc_oxygen.cpp.o
  84901      16       1   84918   14bb6 qrc_oxygen.cpp.o
  -2356       0       0   -2356    -934 Difference
2025-05-21 23:06:38 -04:00
David Korth
fafc35430f Update Win32 .rc file copyright notices for 2025. 2025-05-21 21:09:32 -04:00
David Korth
b4fda57d59 Update displayed copyright notices for 2025. 2025-05-21 21:08:43 -04:00
David Korth
c827cb69f4 [librvth] Note that the serial number ranges might not be accurate.
I was considering adding an "HxA" prefix, but that looks ugly.

We can't easily determine if it's HMA (wireless) or HUA (wired) through
the numeric part of the serial number, so just leave it out.
2025-05-21 21:04:35 -04:00
David Korth
d447d795ee Convert various static const and #define to constexpr. 2025-05-21 20:59:48 -04:00
David Korth
47e7dd8d7c [qrvthtool] Consolidate Win32 nativeEvent() stuff.
- Use a typedef for Qt5/Qt6 differences in both versions.
- Use consistent comments.
2025-05-21 20:46:21 -04:00
David Korth
2d8d68a3aa [rvthtool] Un-indent *all* the classes.
QRvtHToolWindow::openRvtH(): This function takes a filename using Qt
separators ('/'), *not* native separators.
2025-05-21 20:44:08 -04:00
David Korth
3114107a4b [librvth] RefFile: Remove reference-counting; use shared_ptr<> instead.
NOTE: Several functions still take RefFile* if they don't need to store
the file pointer. May change them to `const RefFilePtr&` later.

RvtHPrivate: Move the enum variables to after the STL objects.

rvth_init_BankEntry(): Needs to take `const RefFilePtr&` in order to
call Reader::open().
2025-05-21 20:12:42 -04:00
David Korth
f204ddb0a1 [librvth] RvtH::~RvtH(): Delete d_ptr.
Move the private class destruction code to RvtHPrivate::~RvtHPrivate().
2025-05-21 20:02:01 -04:00
David Korth
4395eb37a9 Switch from include guards to #pragma once.
This improves performance with some compilers, especially MSVC.

NOTE: Some include guards are left in because a few files check for them:

- secoptions_win8.h: Checks for __RVTHTOOL_LIBWIICRYPTO_WIN32_SECOPTIONS_H__.
2025-05-21 19:44:47 -04:00
David Korth
400a4ac76c [librvth] RvtH: Moved openGcm(), checkMBR(), and openHDD() to RvtHPrivate. 2025-05-21 19:28:56 -04:00
David Korth
635fd8c89e [librvth] RvtH: Move private fields into an actual private class, RvtHPrivate.
Reworked RvtH's inline accessors into non-inline accessors.

Moved the private functions from rvth.cpp to rvth_p.cpp.
2025-05-21 19:22:44 -04:00
David Korth
86a5f70c76 [librvth] RvtH: Move m_nhcdHeader to after the enum values. 2025-05-21 19:01:20 -04:00
David Korth
e7e28046ad [librvth] RvtH: Change m_entries to std::vector<>; remove m_bankCount.
Update everything else for this change.

Call bankCount() to get the bank count, even from within RvtH.
2025-05-21 18:56:26 -04:00
David Korth
227abaec5a [librvth] RvtH: Change m_nhcdHeader to an std::unique_ptr<>.
Reduces manual memory management shenanigans.
2025-05-21 18:44:53 -04:00
David Korth
f9f3834711 [librvth] RvtH::nhcd_header(): Fix memory leak.
openHDD(): Save the NHCD header in the RvtH class as m_nhcdHeader.
This field will remain nullptr for non-HDD images.

RvtH::~RvtH(): Free m_nhcdHeader.
2025-05-21 18:42:38 -04:00
David Korth
58d4a3cbed [librvth] rvth.hpp: Un-indent the RvtH class declaration. 2025-05-21 18:35:43 -04:00
David Korth
e989160c16 Merge remote-tracking branch 'Mythra/dev/mythra/dump-table-cmd'
Conflicts:
	src/rvthtool/main.c
2025-05-21 18:31:59 -04:00
David Korth
accb14e4b7 [qrvthtool] CMakeLists.txt: WinDeployQt in Qt6 does *not* have --no-svg.
This fixes all of the build errors so far.

TODO: Test -DENABLE_WERROR=ON.
2025-05-21 18:30:00 -04:00
David Korth
5372801003 [qrvthtool] QRvtHToolWindow: Qt6 changes nativeEvent()'s result parameter from long to qintptr. 2025-05-21 18:30:00 -04:00
David Korth
c2be2517da [qrvthtool] SelectDeviceDialog: Set the window icon.
On KDE, with no icon set, it automatically uses the main window icon.
On Windows, it uses a generic icon instead.

Explicitly set the window icon to the RVT-H Reader icon.
2025-05-21 18:30:00 -04:00
David Korth
71c41db758 Improve Qt version detection.
- Set the default to "AUTO".

- For "AUTO", check for Qt6 first, then Qt5.

- Instead of linking to ${QT_NS}::WinMain, which doesn't exist on Qt6,
  just don't set QtX_NO_LINK_QTMAIN. (This works for Qt5, too.)
  - NOTE: Qt6 has QtEntryPoint instead.
2025-05-21 18:30:00 -04:00
David Korth
7f7f903d02 CMakeLists.txt: Change CMAKE_MINIMUM_REQUIRED() from 3.5 to 3.5..3.10.
CMake 4.0 requires a minimum of 3.5, and shows warnings for anything
less than 3.10.
2025-05-21 18:30:00 -04:00
David Korth
ef496a2a0d [getopt_msvc] Update to v1.1.0.
CMakeLists.txt: Set the required version to 3.5..3.10.

CMake 4.0 requires a minimum of 3.5, and shows warnings for anything
less than 3.10.
2025-05-21 18:29:59 -04:00
David Korth
3087f2afe4 [nettle] Update the Win32 precompiled build of Nettle from 3.9.1 to 3.10.1.
Compiled using gcc-15.1.0 and MinGW-w64 12.0.0.
2025-05-21 18:15:54 -04:00
David Korth
27ba56c693 [cmake] Backport more changes from rom-properties.
Changes include:
- Add RelWithDebugInfo flags.
- Add NixOS handling.
- Add ENABLE_WERROR.
- Add more warning flags.
- Add "-fprofile-update=atomic" for code coverage.
- Fix DT_RELR.
- Enable C++ assertions for libstdc++ and libc++.
2025-05-21 18:14:39 -04:00
David Korth
e1350356f6 [libwiicrypto] sig_tools.c: Allow dev Wii U titles with the CTR DPKI issuer.
It seems that various Wii U dev system titles use the CTR DPKI issuer
instead of the WUP DPKI issuer for some reason...
2025-05-02 18:49:51 -04:00
David Korth
9a80f5f390 appveyor.yml: Switch from MSVC 2013 to MSVC 2015.
The AppVeyor MSVC 2013 failed with this error:

src\qrvthtool\RvtHModel.cpp(162): error C2057: expected constant expression

This doesn't happen locally or with newer MSVC.
[static_assert() with an array::size(), which is constexpr.]
2025-02-01 14:45:40 -05:00
David Korth
3c240dde95 Merge remote-tracking branch 'ihaveamac/fix-clang-compile-error' 2025-01-31 22:31:18 -05:00
David Korth
a6cfb21c99 Merge remote-tracking branch 'Tilka/master' 2025-01-31 22:30:33 -05:00
Tillmann Karras
9d3417a544 [librvth] extract.cpp: fix typo that caused incomplete extraction 2025-02-01 02:37:31 +00:00
ihaveahax
a2fb831d2c
Fix compile error with newer clang
Build failed with clang 19 due to integer promotion.
2024-12-26 22:29:48 -06:00
David Korth
5c6102fa22 Convert some more C arrays to std::array<>. 2024-12-15 15:40:13 -05:00
David Korth
4f9761837a Add .clang-tidy (from rom-properties) and fix several clang-tidy warnings.
- Use std::array<> in some places.

- Use std::unique_ptr<> instead of manual memory management in some places.

- Use static_cast<> instead of C casting.

- Use nullptr instead of NULL.

- Use constexpr instead of macros in some places.

- Reduce the scope of some variables.
2024-12-15 15:31:01 -05:00
David Korth
8c649ec405 [qrvthtool] BankEntryViewPrivate::updateWidgetDisplay(): Use QTimeZone instead of Qt::TimeSpec on Qt6.
Qt::TimeSpec is deprecated:

src/qrvthtool/widgets/BankEntryView.cpp:278:62: warning: ‘static QDateTime QDateTime::fromMSecsSinceEpoch(qint64, Qt::TimeSpec, int)’ is deprecated: Pass QTimeZone instead of time-spec, offset [-Wdeprecated-declarations]
  278 |                 QDateTime ts = QDateTime::fromMSecsSinceEpoch(
      |                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
  279 |                         (qint64)bankEntry->timestamp * 1000, Qt::UTC);
      |                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/qt6/QtCore/QDateTime:1,
                 from src/qrvthtool/widgets/BankEntryView.cpp:19:
/usr/include/qt6/QtCore/qdatetime.h:486:22: note: declared here
2024-12-15 14:10:40 -05:00
David Korth
f1ba178d60 [libwiicrypto] Remove PACKED from structs that don't need it.
Also, use #pragma once.
2024-12-15 14:02:17 -05:00
David Korth
2029a71346 [cmake] CheckNettle2or3.cmake: Also export NETTLE_FOUND in the PARENT_SCOPE.
NETTLE_FOUND may be used to determine if libnettle should be
linked to other libraries and/or executables.

This fixes a regression from commit 03ce73c612.
([cmake] CheckNettle2or3.cmake: Convert the macro to a function.)
2024-05-17 22:42:35 -04:00
David Korth
f86d5c4ad4 [cmake] CheckNettle2or3.cmake: Set HAVE_NETTLE locally *and* in PARENT_SCOPE.
Otherwise, encryption will be disabled, even if Nettle is available.

This fixes a regression from commit 03ce73c612.
([cmake] CheckNettle2or3.cmake: Convert the macro to a function.)

Also, remove the ENABLE_DECRYPTION section. That's a leftover from
rom-properties, and rvthtool *requires* support for decryption.
2024-05-17 22:37:44 -04:00
David Korth
86d340d407 [nusresign] print-info.cpp: Open the TMD using "rb", not "rb+".
We don't need to write to the TMD here.
2024-05-17 22:29:46 -04:00
David Korth
3aaa8363a4 appveyor-dpkg.sh: Missing '#' in the shebang. 2024-04-27 00:40:06 -04:00
David Korth
634438cc4a appveyor.yml: Remove clone_folder.
It's not needed, and it confuses the Linux builds.
2024-04-27 00:23:26 -04:00
David Korth
36324703d8 appveyor.cmd: Assume MSVC 2013 if %compiler% isn't set.
TODO: Restore MinGW-w64 support?
2024-04-27 00:05:20 -04:00
David Korth
17bf805ee3 Add AppVeyor Linux compile testing; remove travis-ci configuration files. 2024-04-27 00:01:41 -04:00
David Korth
658e84f06c appveyor.yml: Ignore the l10n_master branch from Crowdin. 2024-04-26 23:55:40 -04:00
David Korth
e2f342d38a [locale] Add initial (blank) translation files for de and es. 2024-04-26 22:37:02 -04:00
David Korth
fa815bb2b8 crowdin.yml: Initial Crowdin configuration file.
FIXME: rvthtool_en.ts is both a source *and* a translation file.
2024-04-26 22:31:58 -04:00
David Korth
a05900e7a1 README.md: No more travis-ci. 2024-04-26 21:47:57 -04:00
David Korth
e7c1eda56c [locale] Updated the translation files using lupdate.sh. 2024-04-26 21:46:45 -04:00
David Korth
736d626554 [cmake] CPUInstructionSetFlags.cmake: PowerPC should set CPU_ppc64 or CPU_ppc, *not* CPU_arm64 or CPU_arm.
Copy/paste error. Oops.

(copied over from rom-properties)
2024-04-26 21:30:17 -04:00
David Korth
eec1d68907 [cmake] Check64BitTimeSupport.cmake: Don't set TMP_TIME64_FOUND_TIME_BITS if C++ support is broken.
Not sure how I didn't notice this before... (probably because
I don't regularly test the 32-bit i386 version, and Ubuntu
didn't ship glibc-2.34 in any LTS releases.)

(copied over from rom-properties)
2024-04-26 21:29:20 -04:00
David Korth
8ef919bbcb [cmake] cmake_uninstall.cmake.in: Use EXECUTE_PROCESS() instead of EXEC_PROGRAM().
EXECUTE_PROCESS() has been around since at least 3.0, and EXEC_PROGRAM()
is deprecated as of 3.28:

CMake Warning (dev) at cmake/cmake_uninstall.cmake:12 (EXEC_PROGRAM):
  Policy CMP0153 is not set: The exec_program command should not be called.
  Run "cmake --help-policy CMP0153" for policy details.  Use the cmake_policy
  command to set the policy and suppress this warning.

  Use execute_process() instead.

(copied over from rom-properties)
2024-04-26 21:26:51 -04:00
David Korth
a2d0f7b31f [librvth] RefFile.hpp: Remove the C compatibility hack.
It's no longer needed.
2024-02-21 23:17:40 -05:00
David Korth
2c1220988e [librvth] RvtH::extract(): Fix a potential memory leak in an error path.
Found using clang-tidy from clang-17.0.1:

src/librvth/extract.cpp:513:11: warning: Potential leak of memory pointed to by 'sdk_header' [clang-analyzer-unix.Malloc]
  513 |                         ret = -errno;
      |                                ^
2024-02-20 23:56:20 -05:00
David Korth
fdc8c01367 [libwiicrypto] cert.c, cert_realsign_ticketOrTMD(): Remove duplicate initialization of hash_size.
Found using clang-tidy from clang-17.0.1.:

src/libwiicrypto/cert.c:533:4: warning: Value stored to 'hash_size' is never read [clang-analyzer-deadcode.DeadStores]
  533 |                         hash_size = SHA1_DIGEST_SIZE;
      |                         ^
src/libwiicrypto/cert.c:533:4: note: Value stored to 'hash_size' is never read
src/libwiicrypto/cert.c:537:4: warning: Value stored to 'hash_size' is never read [clang-analyzer-deadcode.DeadStores]
  537 |                         hash_size = SHA256_DIGEST_SIZE;
      |                         ^
src/libwiicrypto/cert.c:537:4: note: Value stored to 'hash_size' is never read
2024-02-20 23:53:09 -05:00
David Korth
e3f6c26281 [cmake] SplitDebugInformation.cmake: Add --strip-all to the second objcopy command.
Combining the removal of .gnu_debuglink into the objcopy command had the
effect of losing `strip`'s usual stripping functionality. Add the
`--strip-all` parameter to restore it.

Copied over from rom-properties.

This fixes a regression from commit 43372103cb.
(Port over CMake changes from rom-properties.)
2024-02-20 23:44:36 -05:00
David Korth
03ce73c612 [cmake] CheckNettle2or3.cmake: Convert the macro to a function.
Set HAVE_NETTLE in PARENT_SCOPE.
2024-02-20 23:43:07 -05:00
David Korth
6c0cd37d14 Update the startup message copyright years in command-line tools. 2024-02-20 23:33:50 -05:00
David Korth
1d2731e2e4 [qrvthtool] Update copyright years. 2024-02-20 23:32:51 -05:00
David Korth
c3e5186d58 [qrvthtool] MessageSound: The KF6 Framework Integration Plugin is in kf6/. 2024-02-20 23:28:14 -05:00
David Korth
754a2da58b [qrvthtool] Replace deprecated <=qt-4.7 QtDBus annotations with current ones. 2024-02-20 19:49:49 -05:00
David Korth
5eef2e9221 [qrvthtool] Update to build with KF6 if QT_VERSION == 6.
- Set KF_NS == KF5 or KF6.
- Increase the minimum version for ECM for KF6.
- Link to the correct KF WidgetsAddons library.
- Use HAVE_KF_WidgetsAddons instead of HAVE_KF5WIDGETSADDONS.
- Use HAVE_QtDBus instead of HAVE_Qt5DBus.
2024-02-20 19:40:01 -05:00
David Korth
66c8afb410 Increase minimum CMake version to 3.5; move CMP0048/CMP0063 settings to the top-level CMakeLists.txt file.
Ubuntu 16.04 has CMake 3.5, so we can target that as the minimum
version. Also, recent CMake versions (3.27+) have started printing
warnings if the minimum is less than 3.5.

CMake Deprecation Warning at CMakeLists.txt:2 (CMAKE_MINIMUM_REQUIRED):
  Compatibility with CMake < 3.5 will be removed from a future version of
  CMake.

  Update the VERSION argument <min> value or use a ...<max> suffix to tell
  CMake that the project does not need compatibility with older versions.

Also, remove CMAKE_MINIMUM_REQUIRED() from all subdirectories.
2024-02-20 19:23:06 -05:00
David Korth
46b533520b [nusresign] print-info.cpp: If lowercase CID files don't exist, try with an uppercase CID.
This is needed in some cases on Linux systems.
2024-01-24 22:34:58 -05:00
David Korth
1ceacfffa1 [nusresign] print-info.cpp: Explicitly cast title version values to unsigned int.
Should fix a printf format string error on some systems where gcc
implicitly converts the shifted value to int.
2024-01-21 20:34:55 -05:00
David Korth
f00669ca87 [wadresign] Increase maximum WAD size from 128 MB to 256 MB. 2023-12-10 18:02:21 -05:00
David Korth
b2f5d8977d [qrvthtool] AboutDialog: nettle-3.9.1 was released in 2023. 2023-11-25 12:09:30 -05:00
David Korth
fcf321dea7 [nettle] Update the Win32 precompiled build of Nettle from 3.8.1 to 3.9.1.
Compiled using gcc-13.2.0 and MinGW-w64 11.0.0.

NOTE: The .debug files are no longer included because no one used them.
2023-11-25 12:05:48 -05:00
David Korth
983d6c624b [qrvthtool] AboutDialog: MSVC 2013 doesn't like it when we put the git version macros in QStringLiteral. 2023-11-25 11:32:14 -05:00
David Korth
abd8543660 [qrvthtool] MSVC 2013 doesn't like concatenated strings within QStringLiteral.
We're still using MSVC 2013 in the AppVeyor build right now.

Also, the APLERR_SIMMEMSIZE_NOT_LE_PHYSMEMSIZE message was missing a space
after the first line. In the rvthtool CLI, a newline is used instead of a
space.
2023-11-25 11:09:08 -05:00
David Korth
bc65a8b5a1 [qrvthtool] Use the multi-string QString::arg() functions instead of repeated arg() calls where possible. 2023-11-25 10:58:28 -05:00
David Korth
22ce6af987 [qrvthtool] Use QStringLiteral instead of QLatin1String, QString::fromLatin1(), or QString::fromUtf8() where possible.
QStringLiteral encodes a QString struct directly into the executable.
This has some more overhead compared to a Latin-1 or UTF-8 string,
but it means nothing needs to be copied into RAM at runtime.

Related changes:
- Consolidate some string building into QStringLiteral().arg().
- Update copyrights for 2023 where applicable.
2023-11-25 10:53:23 -05:00
David Korth
5e0a1ba149 [qrvthtool] QRvtHToolWindowPrivate::getDisplayFileName(): Use a case-insensitive string comparison on Windows.
Similar to qrvthtool.cpp.
2023-11-25 10:49:25 -05:00
David Korth
0f4d834813 [qrvthtool] qrvthtool.cpp: Also fix Qt::CaseInsensitive's position.
It's an argument for filename.startsWith(), not QLatin1String().

This seemingly didn't cause a problem with QLatin1String, since the
constructor takes an optional size parameter. It didn't *work*
correctly, though.

This *does* cause a problem when switching to QStringLiteral.
2023-11-25 10:43:55 -05:00
David Korth
c68875d5c0 [qrvthtool] qrvthtool.cpp: The device name check was backwards.
It's "\\\\.\\PhysicalDrive" for Windows, and "/dev/" for Linux and other
Unix-like operating systems.
2023-11-25 10:41:22 -05:00
David Korth
64e16c74bd [qrvthtool] qrvthtool.cpp: Remove ".desktop" from the desktop filename.
Qt6 complains:

QGuiApplication::setDesktopFileName: the specified desktop file name ends
with .desktop. For compatibility reasons, the .desktop suffix will be
removed. Please specify a desktop file name without .desktop suffix
2023-11-25 10:20:43 -05:00
David Korth
3dc3a473ed [qrvthtool] MessageWidgetStack: Delete all MessageWidgets before clearing d->messageWidgets.
Otherwise, stray deletion signals could trigger messageWidget_destroyed_slot()
after the std::set is deleted, which results in a crash.
2023-11-25 10:17:16 -05:00
David Korth
46430299a7 [qrvthtool] MessageWidgetStack: Use std::set instead of QSet.
It's crashing on Windows if a MessageWidget is visible when closing
the main window. Something is trying to use the std::set (and previously
the QSet) after it's destroyed...
2023-11-25 10:13:51 -05:00
David Korth
43372103cb Port over CMake changes from rom-properties.
- CPUInstructionSetFlags.cmake: Add more CPU architectures.

- DirInstallPaths.cmake: Set ${TARGET_CPU_ARCH} and add more
  CPU architectures.

- FindNETTLE.cmake: Use ${TARGET_CPU_ARCH}.

- SplitDebugInformation.cmake: Add the `mold` workaround.

- options.cmake: Disable split debug by default on macOS.

- platform.cmake: Minor cleanups.

- gcc.cmake: Code coverage cleanup, check for "--no-undefined" and
  "--no-allow-shlib-undefined" (but only allow them on Linux),
  and check for "-ftree-vectorize".

- msvc.cmake:
  - Add: /we4477 /MP /guard:cf /guard:ehcont /permissive-
  - On i386 only: /SAFESEH
  - Disable /Zc:externC /Zc:noexceptTypes on Clang.
  - Disable thread-safe statics only on i386 and amd64.

- win32-gcc.cmake, win32-msvc.cmake:
  - Various flag changes.
2023-11-25 10:09:48 -05:00
David Korth
6b49dfaa0f CMakeLists.txt: FIXME: Windows SDK prior to 10.0.18362.0 has issues when compiling as either C11 or C17.
C:\Program Files (x86)\Windows Kits\8.1\Include\um\winbase.h(8816,5): warning C5105: macro expansion producing 'defined' has undefined behavior
C:\Program Files (x86)\Windows Kits\8.1\Include\um\oaidl.h(473,17): warning C5103: pasting '/' and '/' does not result in a valid preprocessing token
C:\Program Files (x86)\Windows Kits\8.1\Include\shared\wtypes.h(742,1): message : in expansion of macro '_VARIANT_BOOL'
C:\Program Files (x86)\Windows Kits\8.1\Include\um\oaidl.h(473,17): error C2059: syntax error: '/'

Force C99 when compiling with MSVC for now.
2023-11-25 09:44:46 -05:00
David Korth
af560c4ee9 Use CMAKE_<LANG>_STANDARD instead of custom macros.
CMake 3.1 added CMAKE_<LANG>_STANDARD, which allows CMake to determine
what flags are needed to select a particular language version.

Set it to C17 and C++17. Previously, we were using C11 and C++11,
though gcc11 switched the default C++ version to C++17. The custom
macro handled this by not adding flags for C++, but it still added
the C11 flag, which prevented use of C17.

Ported over from rom-properties.
2023-11-25 09:43:53 -05:00
David Korth
f43a461c35 [rvthtool] verify.cpp: Fix a few TCHAR errors. [missing _T() macros]
verify.cpp(180,13): warning C4477: 'wprintf' : format string '%s' requires
an argument of type 'wchar_t *', but variadic argument 3 has type 'const char *'

verify.cpp(182,13): warning C4477: 'wprintf' : format string '%s' requires
an argument of type 'wchar_t *', but variadic argument 2 has type 'const char *'
2023-11-25 09:37:14 -05:00
David Korth
95d3c50b7f .gitignore: Don't ignore .a files.
Add the 64-bit versions of libhogweed.dll.a and libnettle.dll.a
to the repository.

NOTE: This was originally done on 2022/08/07 06:25 PM EDT, but I forgot
to commit the changes...
2023-11-25 09:31:53 -05:00
Cynthia
595be12d74 use hex specifiers 2023-05-06 10:35:41 -06:00
Cynthia
53bdcd6b4f added show-table command, for inspecting NHCDTable
since you mentioned wanting to add in a command for repairing a
NHCD Bank Table, I figured a command to inspect your current NHCD
Bank Table would also be useful.

even in the absence of a repair command, it still would be useful
to see the bank table status. I was particularly curious if my RVT-H
had it's bank fully zero'd or if only a few values were unexpected.

this only adds the command to the CLI, as displaying raw bytes in a
QT window didn't feel like the best way to print that information.
If you want it to be there a UI before merging I understand, and can try
playing around with QT to get something decent.
2023-05-04 12:39:55 -06:00
David Korth
a2bcb8ac1e [librvth] Reader.cpp: Add some more SDK header detection code from rom-properties. 2022-09-17 21:11:33 -04:00
David Korth
4179a5dcdf [rvthtool] verify.cpp: Print better messages for disc images. 2022-08-16 01:04:26 -04:00
David Korth
d92bfecd7b [rvthtool] verify.cpp: Print the total number of hash errors.
[librvth] RvtH::verifyWiiPartitions(): Accept a pointer to a 5-element
unsigned int array to get the total number of hash errors. This is for
both actual hash errors and hash table copy errors.
2022-08-16 01:00:42 -04:00
David Korth
5601647630 [rvthtool] query.c: #include "tcharx.h"
The no-query path uses _fputts(), which requires tcharx.h on Linux.
2022-08-16 00:48:49 -04:00
David Korth
1c3b110143 [doc] disc_image.md: Add some missing backticks for monospaced text. 2022-08-10 22:33:09 -04:00
David Korth
93489d8561 [librvth] query_udev.c: Actually check listener->stop to stop the listener thread.
Otherwise, if qrvthtool's "Select Device" dialog is opened and closed,
and then an RVT-H Reader is connected or disconnected, the program will
crash, since it tries sending a message to the now-deleted dialog.
2022-08-08 18:51:46 -04:00
David Korth
99917b6273 [qrvthtool] CMakeLists.txt: Exclude QtSvg when copying the Windows DLLs.
windeployqt copies over QtSvg even though we're not using it:

  Creating C:\projects\rvthtool\build\src\qrvthtool\windeployqt...
  C:\projects\rvthtool\build\bin\Debug\qrvthtool.exe 32 bit, debug executable
  Adding Qt5Svg for qsvgicond.dll
  Skipping plugin qtvirtualkeyboardplugind.dll due to disabled dependencies.
  Direct dependencies: Qt5Core Qt5Gui Qt5Widgets
  All dependencies   : Qt5Core Qt5Gui Qt5Widgets
  To be deployed     : Qt5Core Qt5Gui Qt5Svg Qt5Widgets

Explicitly disable QtSvg to prevent it from being copied over.
2022-08-08 00:32:12 -04:00
David Korth
a1e23b5880 [qrvthtool] CMakeLists.txt: Add Nettle includes for AboutDialog.
This should fix the AppVeyor build.
2022-08-08 00:17:34 -04:00
David Korth
9b81bcfd6e appveyor.cmd: The MSVC 2013 VMs only have Qt 5.8.
I'd need to switch to the MSVC 2019 VMs for Qt 5.15.2 or Qt 6.
2022-08-08 00:11:28 -04:00
David Korth
a65321428e appveyor.cmd: Try to find *.cmake in C:\Qt\. 2022-08-08 00:09:05 -04:00
David Korth
099065207d appveyor.cmd: Try to fix Qt5 build issues on AppVeyor.
It doesn't set Qt5_DIR properly for some reason.
2022-08-08 00:00:30 -04:00
David Korth
1296392e2f appveyor.cmd: Set Qt5_DIR to build qrvthtool. 2022-08-07 21:36:24 -04:00
David Korth
011e261972 [cmake] FindNETTLE.cmake: Set NETTLE_FOUND and HAVE_NETTLE on Windows.
Otherwise, the include paths aren't set correctly, and the AppVeyor
build fails.
2022-08-07 21:33:31 -04:00
David Korth
be979181cc [librvth] rvth_init_BankEntry_AppLoader(): Verify that lba_start is in range.
Corrupted disk images could put it out of range, resulting in an
assertion failure.
2022-08-07 20:06:18 -04:00
David Korth
0ee8f055f9 [qrvthtool] AboutDialog: Use RichText in the Libraries tab.
Also optimized linebreak usage to be more constant.

Code size difference: (64-bit Gentoo Linux, gcc-12.1.0, release build, no LTO)

   text    data     bss     dec     hex filename
  17797       8       0   17805    458d AboutDialog.cpp.o [before]
  16616       8       0   16624    40f0 AboutDialog.cpp.o [after]
  -1181       0       0   -1181    -49d Difference
2022-08-07 19:43:13 -04:00
David Korth
994ae2046b [qrvthtool] AboutDialog: Display the GNU Nettle version.
[libwiicrypto] config.libwiicrypto.h.in: Nettle version macros.

[cmake] CheckNettle2or3.cmake: Check if it's Nettle 3.x.

TODO: The Libraries tab needs to be RichText now.
2022-08-07 19:33:45 -04:00
David Korth
fa08e296c8 [cmake] FindNETTLE.cmake: s/Nettle/NETTLE/
This fixes a CMake warning:

CMake Warning (dev) at /usr/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:438 (message):
  The package name passed to `find_package_handle_standard_args` (Nettle)
  does not match the name of the calling package (NETTLE).  This can lead to
  problems in calling code that expects `find_package` result variables
  (e.g., `_FOUND`) to follow a certain pattern.
Call Stack (most recent call first):
  cmake/libs/FindNETTLE.cmake:22 (find_package_handle_standard_args)
  src/CMakeLists.txt:74 (FIND_PACKAGE)
This warning is for project developers.  Use -Wno-dev to suppress it.
2022-08-07 19:15:00 -04:00
David Korth
31ee8efcfb [cmake] Renamed 'modules' to 'libs'. 2022-08-07 19:13:14 -04:00
David Korth
8b6e4377e5 [nettle] Updated the Win32 precompiled build of Nettle from 3.7.2 to 3.8.1.
Compiled using gcc-12.1.0 and MinGW-w64 10.0.0.
2022-08-07 19:10:18 -04:00
David Korth
9431c1ed57 [qrvthtool] UnityLauncher.cpp: Update the .desktop filename.
The .desktop fileanme was changed last week, but UnityLauncher.cpp wasn't
updated with the new filename, which broke the progress bar functionality.

This fixes a regression from commit 1a992e41ff.
([qrvthtool] CMakeLists.txt: Use macros for the XDG paths.)
2022-08-07 19:05:09 -04:00
David Korth
7f5079b9ff [qrvthtool] QRvtHToolWindow.ui: Add the "Close" button to the toolbar. 2022-08-07 19:00:53 -04:00
David Korth
a3f197c32a [qrvthtool] Install Qt DLLs when running cpack on Windows builds.
References:
- https://stackoverflow.com/questions/41193584/deploy-all-qt-dependencies-when-building
- https://stackoverflow.com/a/41199492
2022-08-07 19:00:41 -04:00
David Korth
41977b819b [cmake] DirInstallPaths.cmake: Don't install to architecture-specific subdirectories.
This is needed for rom-properties, since we have to provide both
32-bit and 64-bit DLLs for proper shell integration, but rvthtool
is only packaged for a single architecture.
2022-08-07 18:02:01 -04:00
David Korth
ae7ef2d241 [rvthtool] list-banks.cpp: Another TCHAR fix.
src\rvthtool\list-banks.cpp(387,12): warning C4477: 'wprintf' :
	format string '%s' requires an argument of type 'wchar_t *',
	but variadic argument 3 has type 'const char *'
2022-08-07 17:58:54 -04:00
David Korth
911fd8f9ab [qrvthtool] CMakeLists.txt: MessageSound.hpp doesn't have any QObjects.
Don't wrap it using QT_WRAP_CPP().
2022-08-07 17:57:38 -04:00
David Korth
38673d19f5 [debian] *.install: Remove the leading slashes.
Not needed, and can potentially cause issues when building.
2022-08-07 15:08:31 -04:00
David Korth
a3ed8f82cd [debian] Added the rvthtool-lang package.
TODO: After 2.0, switch to gettext like rom-properties, and localize
the command line tools?
2022-08-07 15:08:03 -04:00
David Korth
d61158dbbc [rvthtool] Need to use fputs() for rvth_error().
TODO: Add a TCHAR version.
2022-08-06 13:07:45 -04:00
David Korth
767126305d [rvthtool] main.c: Fix some more TCHAR string concatenation issues.
This one was caused by missing _T() macros.
2022-08-06 13:03:52 -04:00
David Korth
a5029d9788 [qrvthtool] LanguageMenu: d->locale =, not ==.
Found using scan-build from clang-14.0.6:

src/qrvthtool/widgets/LanguageMenu.cpp:249:13: warning: equality comparison result unused [-Wunused-comparison]
                d->locale == locale;
                ~~~~~~~~~~^~~~~~~~~
src/qrvthtool/widgets/LanguageMenu.cpp:249:13: note: use '=' to turn this equality comparison into an assignment
                d->locale == locale;
                          ^~
                          =
2022-08-06 12:56:59 -04:00
David Korth
1a9f3d9452 [libwiicrypto] bin2h.c: free(basename) before returning.
Found using scan-build from clang-14.0.6:

src/libwiicrypto/bin2h.c:93:3: warning: Potential leak of memory pointed to by 'p' [unix.Malloc]
                fprintf(stderr, "*** ERROR creating destination file: %s\n", strerror(errno));
                ^~~~~~~
2022-08-06 12:55:44 -04:00
David Korth
54b54ae20d MSVC didn't like turning RP_GIT_VERSION into a TCHAR string.
src\nusresign\main.c(136): error C2308: concatenating mismatched strings
          Concatenating wide "git: " with narrow "(no branch)"

TODO: Get this working.
2022-08-06 11:35:49 -04:00
David Korth
1445d532b3 Consolidate multiple stdout/stderr function calls by using TCHAR more consistently.
This lets us combine e.g. fputs() + _fputts() + fputs() into a single
_fputts(), which reduces overhead. It also makes it slightly faster on
Windows, since it won't have to do ANSI conversion for these strings.

Code size differences: (64-bit Gentoo Linux, gcc-12.1.0, release build, no LTO)

   text    data     bss     dec     hex filename
 108526    2980      80  111586   1b3e2 rvthtool [before]
 108014    2980      80  111074   1b1e2 rvthtool [after]
   -512       0       0    -512    -200 Difference

   text    data     bss     dec     hex filename
  57537    1992      80   59609    e8d9 wadresign [before]
  57334    1984      80   59398    e806 wadresign [after]
   -203      -8       0    -211     -d3 Difference

   text    data     bss     dec     hex filename
  53384    1976      80   55440    d890 nusresign [before]
  53464    1976      80   55520    d8e0 nusresign [after]
    +80       0       0     +80     +50 Difference

Interestingly, nusresign only had one change, and it caused the code size
to go up by a bit.
2022-08-06 11:15:23 -04:00
David Korth
57da28509f [qrvthtool] CMakeLists.txt: Actually install the AppStream metainfo XML file. 2022-08-06 11:11:17 -04:00
David Korth
1a204f9cbc [debian] Update qrvthtool; add wadresign and nusresign packages.
The qrvthtool package now includes the .desktop file, icons, and the
metainfo XML file.
2022-08-06 11:10:07 -04:00
David Korth
9fcc17d6bf [qrvthtool] Add an AppStream metainfo XML.
Unlike rom-properties, this is only installed as part of qrvthtool.

The metainfo XML lists all of the installed executables, not just
qrvthtool.
2022-08-06 11:05:16 -04:00
David Korth
01334c3a97 [cmake] gcc.cmake: Reorder DT_RELR detection to show the status message before checking ld. 2022-08-06 02:05:28 -04:00
David Korth
420fa1bc31 [cmake] platform/gcc.cmake: Initial support for detecting DT_RELR.
Currently only supported if using glibc-2.36 and binutils-2.38.

TODO:
- Detect more systems with DT_RELR.
- Handle cross-compiling better?
2022-08-05 00:43:45 -04:00
David Korth
08e76cc03c [librvth] recrypt.cpp: Add more reader->flush() calls when writing. 2022-08-04 23:36:04 -04:00
David Korth
1a992e41ff [qrvthtool] CMakeLists.txt: Use macros for the XDG paths.
Rename the .desktop file to com.gerbilsoft.qrvthtool.desktop.

TODO: Maybe com.gerbilsoft.rvthtool.qrvthtool.desktop? Not that
I'd be making a GTK+ UI frontend anytime soon...
2022-08-03 18:44:01 -04:00
David Korth
6e6ce69afe [librvth] RefFile: Un-inline RefFile::flush().
HANDLE is defined in Windows SDK headers, and we don't want to include
those in RefFile.hpp, so move it to RefFile.cpp.
2022-08-02 00:49:30 -04:00
David Korth
a2093854f2 [locale] Updated the translation files using lupdate.sh. 2022-08-02 00:18:54 -04:00
David Korth
7afdb08d9a [qrvthtool] AboutDialog: +'.' 2022-08-02 00:15:48 -04:00
David Korth
f35f2c1513 [rvthtool] list-banks.cpp: free() the string from rvth_get_device_serial_number() after it's no longer needed.
This fixes a small memory leak.
2022-08-01 23:58:07 -04:00
David Korth
223a67f81b [qrvthtool] Show a status bar message when opening an RVT-H Reader device.
It takes around 2-3 seconds to open for me for some reason.

Also cleaned up some stuff with native separators. librvth expects
filenames to use native separators, but QFileDialog does not.
2022-08-01 21:52:57 -04:00
David Korth
dd2fdeea98 [librvth] extract.cpp, copyToGcm(): Disable the extra flushes.
It's not as important when extracting from an RVT-H Reader as it is
when importing *to* an RVT-H Reader. This should improve performance
by a bit in some cases.
2022-08-01 21:45:57 -04:00
David Korth
78d938e25d [librvth] extract.cpp: Call flush() after every write().
This is basically the same as O_SYNC, though we have up to a 1 MB buffer
that gets written to disk at once.

I tried with 32 MB flushing at first, but it just resulted in the
progress bar going up in 32 MB increments with freezes due to the
32 MB hitting the I/O cache first.

RefFile::flush(): Call fsync() on Linux and FlushFileBuffers() on Windows
to ensure the file is actually flushed to disk. fflush() only clears the
stdio buffers.

TODO: Use Win32 and/or POSIX I/O directly? I tried this with open(),
lseek(), read(), write(), etc., but it wasn't able to read the ticket/TMD
signatures for some reason. This solution should be good enough for now.
2022-08-01 21:24:03 -04:00
David Korth
08a108b6bf [librvth] RefFile::makeWritable(): FIXME: O_SYNC breaks recryption with New Super Mario Bros. Wii.
Not sure why this happens...

TODO: Rewrite RefFile to use raw I/O instead of stdio, then use O_DIRECT
with 512-byte aligned buffers and maybe O_SYNC again.
2022-08-01 20:51:50 -04:00
David Korth
12609b8a62 [qrvthtool] QRvtHToolWindow::workerObject_finished(): Call d->updateActionEnableStatus().
Needed to ensure the buttons are in the correct state after
importing a disc image.
2022-08-01 20:07:30 -04:00
David Korth
af5b6c59c6 [qrvthtool] QRvtHToolWindow: Update BankEntryView after importing a bank.
TODO: Occurs after importing *or* extracting. We should limit it
to only update after importing.

Added some convenience functions to get the selected bank entry,
either as a bank number or as a bank entry.
2022-08-01 20:00:49 -04:00
David Korth
f006b2fa26 [qrvthtool] RvtHModel: Increase the V component of "deleted" banks when using dark themes. 2022-08-01 19:53:45 -04:00
David Korth
76c1511ba2 [qrvthtool] qrvthtool.desktop: Remove Version; add StartupNotify and Terminal.
Version indicates the Desktop Entry Specification version,
not the application version.
2022-08-01 19:41:16 -04:00
David Korth
624a4a4c35 [qrvthtool] QRvtHToolWindow: Call d->updateActionEnableStatus() when necessary.
Otherwise, the actions don't get enabled/disabled properly.

Among other things, the "Close" action remains enabled on startup with
no device loaded, and remains enabled after closing a device in some
cases.
2022-08-01 19:18:24 -04:00
David Korth
c853e94705 [qrvthtool] CMakeLists.txt: s/QT_ADD_DBUS_INTERFACE/QT_ADD_DBUS_INTERFACES/
Fixes D-Bus interface generation on Qt 5.5.1.
2022-08-01 19:11:21 -04:00
David Korth
8b8cc807e5 [qrvthtool] CMakeLists.txt: Fix the QT_WRAP_*() functions on Qt 5.5.1.
QT_WRAP_CPP is somehow being detected as a "command", even though
it's not a valid function. Use a version check instead.

This fixes QT_WRAP_*() issues on Xubuntu 16.04, which has Qt 5.5.1.
2022-08-01 19:07:56 -04:00
David Korth
1d98eb4eee [qrvthtool] SelectDeviceDialog.cpp: #include <cassert> 2022-08-01 19:01:34 -04:00
David Korth
e0b94c8eda [qrvthtool] LanguageMenu.cpp: #include <assert>: fix QString::split() for Qt <5.14. 2022-08-01 18:45:44 -04:00
David Korth
07c078dcd1 [qrvthtool] qrvthtool.cpp: QCoreApplication::setDesktopFileName() was added in Qt 5.7. 2022-08-01 18:41:23 -04:00
David Korth
2e04a36303 [locale] CMakeLists.txt: Fix QT_ADD_TRANSLATION check.
Fixes the build on Qt5 versions earlier than 5.15.
2022-08-01 18:29:52 -04:00
David Korth
93b8a615fc [qrvthtool] Fix the window icon on Wayland.
On Wayland systems, the window icon is obtained from the .desktop file,
so we need to call QGuiApplication::setDesktopFileName().

QRvtHToolWindow.cpp: Update the Mac proxy icon comment.
2022-07-24 05:28:42 -04:00
David Korth
0ac25bfd59 NEWS.md: Mention nusresign. 2022-07-20 22:00:42 -04:00
David Korth
e823bc7b27 [qrvthtool] LanguageMenu: Hide the menu if only one language is available.
- Moved init() into the private class constructor.
- Moved actLanguageSysDefault creation from retranslateSystemDefault()
  to the private class constructor.
2022-07-15 18:52:19 -04:00
David Korth
08e3f66cee Fix a bunch of PVS-Studio warnings.
- Use fseeko()/ftello() instead of fseek()/ftell().
- Explicitly check memcmp() != 0.
- Reorganized a few structs to use less memory.
- Save pointers instead of calling functions repeatedly.
- Remove NULL checks for delete.

MessageWidget::paintEvent(): Reduce the scope of painter so it's only
constructed when it's needed.

QRvtHToolWindow::openRvtH(): Properly delete rvth_tmp instead of deleting
d->rvth again, which may result in a double-free.

QRvtHToolWindow::on_actionOpenDevice_triggered(): delete selectdeviceDialog
when we're done using it.

SelectDeviceDialog.hpp, DeviceQueryData(): Initialize size in the zero-arg
constructor.

libwiicrypto/cert.c, cert_fakesign_ticket(): Use size_t for signing_offset.
2022-07-14 23:23:31 -04:00
David Korth
2d0c965422 Port over the off64_t changes from rom-properties.
Use off64_t where necessary.

config.libc.h is now force-included in every translation unit.

FIXME: Some things are truncating 64-bit file sizes to uint32_t...
2022-07-14 02:53:17 -04:00
David Korth
484efeeec9 [librvth] query_udev.c, rvth_listener_thread(): Missing 'pErr' parameter. 2022-07-14 02:28:18 -04:00
David Korth
f588ffd8c2 [nusresign, wadresign] main.c: Remove the stray ')'s. 2022-07-14 02:26:18 -04:00
David Korth
35710d7b1c [nusresign, wadresign] main.c: Don't use _T() with fputs(). 2022-07-14 02:12:27 -04:00
David Korth
557dd540e3 [nusresign, wadresign] main.c: _T() doesn't seem to work with the RP_GIT_* strings.
The RP_GIT_* strings are made up of multiple strings themselves, so MSVC
gets confused.

From the AppVeyor build:

src\nusresign\main.c(135): error C2308: concatenating mismatched strings [C:\projects\rvthtool\build\src\nusresign\nusresign.vcxproj]
          Concatenating wide "NUS Resigner v1.1.1+
  Copyright (c) 2018-2022 by David Korth.
  git: " with narrow "(no branch)"
2022-07-14 02:11:10 -04:00
David Korth
367d93997e [librvth] query_udev.c: rvth_parse_udev_device(): Return an error code if malloc() fails.
Similar to the query_win32.c version.
2022-07-14 02:05:51 -04:00
David Korth
7fe60c5c8e [librvth] query_win32.c: Split parsing the device node out of rvth_query_devices().
Similar to the query_udev.c version.
2022-07-14 02:05:26 -04:00
David Korth
37833e42e9 [nusresign, wadresign] Use TCHAR printf() functions where possible.
This lets us consolidate sets of fputs() and printf()-style functions
into a single printf(), which reduces code size. Note that it will
definitely increase the size on Windows due to more UTF-16 strings.

- Converted some more printf()-style functions to fputs()-style.
  gcc does this automatically if possible, but MSVC does not.

- Updated copyright years.

[nusresign] main.c: Remove a few extra leading spaces in print_help().

[nusresign] resign-nus.cpp:
- Removed a line of debugging code.
- Ticket type change from Disc to Installable should be on stdout,
  not stderr.

TODO: There's a few more functions that need TCHAR conversions, but they
require changing more code elsewhere.

Code size differences: (64-bit Gentoo Linux, gcc-12.1.0, release build, no LTO)
[NOTE: Windows builds will increase due to more TCHAR usage.]

   text    data     bss     dec     hex filename
   3151     160       0    3311     cef main.c.o [wadresign, before]
   3132     160       0    3292     cdc main.c.o [wadresign, after]
    -19       0       0     -19     -13 Difference

   text    data     bss     dec     hex filename
   6581       0       0    6581    19b5 print-info.c.o [wadresign, before]
   6146       0       0    6146    1802 print-info.c.o [wadresign, after]
   -435       0       0    -435    -1b3 Difference

   text    data     bss     dec     hex filename
  14164       8       0   14172    375c resign-wad.cpp.o [wadresign, before]
  11888       8       0   11896    2e78 resign-wad.cpp.o [wadresign, after]
  -2276       0       0   -2276    -8e4 Difference

   text    data     bss     dec     hex filename
   2561      96       0    2657     a61 main.c.o [nusresign, before]
   2526      96       0    2622     a3e main.c.o [nusresign, after]
    -35       0       0     -35     -23 Difference

   text    data     bss     dec     hex filename
   8787       8       0    8795    225b print-info.cpp.o [nusresign, before]
   8574       8       0    8582    2186 print-info.cpp.o [nusresign, after]
   -213       0       0    -213     -d5 Difference

   text    data     bss     dec     hex filename
   5374       8       0    5382    1506 resign-nus.cpp.o [nusresign, before]
   5341       8       0    5349    14e5 resign-nus.cpp.o [nusresign, after]
    -33       0       0     -33     -21 Difference
2022-07-14 01:33:32 -04:00
David Korth
6eafbf3ff4 [librvth] query: Add is_readable, is_writable, and not_readable_error.
This lets the query interface know if the device is accessible.

NOTE: Currently only implemented on Linux/udev.

[rvthtool] query.c: On Linux, print the device accessibility.
If not accessible, the access() error will be displayed.

TODO: qrvthtool; Windows support.
2022-07-14 00:09:00 -04:00
David Korth
3cb4f1e78f Add stdboolx.h.in from rom-properties.
Add #include "stdboolx.h" where necessary.

[libwiicrypto] common.h: Remove our own stdbool implementation.
2022-07-13 23:59:52 -04:00
David Korth
eeb9ae7b67 [wadresign] resign-wad.cpp: Fix fputs() shenanigans. 2022-07-13 22:33:46 -04:00
David Korth
69faaee2fc [wadresign] resign-wad.cpp: Use unique_ptr<>; optimize some printf()s.
Use _fputts(_tcserror()) instead of using strerror() as an argument
to fprintf().
2022-07-13 20:31:10 -04:00
David Korth
8095c22d10 [wadresign] resign-wad.c -> resign-wad.cpp
This will make it easier to simplify some things by using e.g.
unique_ptr<>, similar to nusresign.
2022-07-13 20:13:59 -04:00
David Korth
31bd1567c6 [qrvthtool] SelectDeviceDialog: Hacky method for auto-refresh on Windows.
Listen for device notifications. If we get a notification that a disk
device was added or removed, refresh the entire list. This isn't as
nice as the udev method, since that one only adds or removes the
specific device, but it works for now.

TODO: Make the Windows one a listener by creating a hidden window?
2022-07-13 20:06:46 -04:00
David Korth
7a7899a9ec [qrvthtool] BankEntryView: Some minor improvements.
- Don't cache the QLocale.

- Iterate through q->children() to hide all the widgets instead of
  hard-coding them.

- QEvent::LocaleChange should retranslate the UI instead of just
  caching the locale.
2022-07-13 20:06:22 -04:00
David Korth
ce85d0481e Ported over C99 and C++11 compatibility changes from rom-properties.
Among other things, we're no longer defining `nullptr` in C code,
so remove all uses of `nullptr` in C code.
2022-07-13 19:26:14 -04:00
David Korth
3c0574dabc [locale] Updated the translation files using lupdate.sh. 2022-07-13 01:22:43 -04:00
David Korth
41516609fd [qrvthtool] BankEntryView: Show megabytes instead of gigabytes.
Wii discs can't be larger than around 8 GB, so we should show megabytes
as the largest unit instead of gigabytes.
2022-07-13 01:21:48 -04:00
David Korth
b1b24cfd7b [qrvthtool] QRvtHToolWindow: s/automaticlaly/automatically/ 2022-07-13 01:21:33 -04:00
David Korth
8c87baca05 [qrvthtool] QRvtHToolWindow: Mark the UI as busy when opening the RVT-H Reader.
markUiBusy(), markUiNotBusy(): Call QCoreApplication::processEvents()
to make sure the mouse cursor actually gets set, since opening the
RVT-H Reader is a blocking operation.
2022-07-13 01:15:04 -04:00
David Korth
fa990d126e [qrvthtool] TranslationManager: s/MemCard Recover/rvthtool/ 2022-07-13 01:08:22 -04:00
David Korth
50b930afe0 [locale] Updated the translation files using lupdate.sh. 2022-07-13 01:06:50 -04:00
David Korth
7259d9498d [qrvthtool] SelectDeviceDialog: Fix advertent comment caused by "/dev/*".
Also, add an "is" to the message.
2022-07-13 01:05:00 -04:00
David Korth
cdf4789e77 [qrvthtool] Fix lots of warnings when compiling with Qt6.
src/qrvthtool/RvtHSortFilterProxyModel.cpp:38:23: warning:
‘QVariant::Type QVariant::type() const’ is deprecated: Use
typeId() or metaType(). [-Wdeprecated-declarations]

qrvthtool.cpp: Don't set the high-DPI attributes when building with
Qt6. These are deprecated and are set by default.

TranslationManager: QLibraryInfo::location() was renamed to
QLibraryInfo::path() for "consistency".
2022-07-13 01:04:56 -04:00
David Korth
7f60df49dd [qrvthtool] AboutDialog: Remove the Singleton functionality.
Instead, keep a pointer to AboutDialog in QRvtHToolWindow. If the window
is closed, it will be deleted, and a QObject::destroyed() handler will
NULL out the AboutDialog pointer.
2022-07-13 00:18:24 -04:00
David Korth
63d1fefa92 [librvth] query_udev.c: Remove #include <stdio.h>.
Debugging leftover from commit 1ead35105d.
([qrvthtool] SelectDeviceDialog: Initial support for automatically detecting connected/disconnected RVT-H Readers.)
2022-07-13 00:15:50 -04:00
David Korth
9474fa154d [qrvthtool] Set object names to make introspection easier. 2022-07-13 00:09:16 -04:00
David Korth
8d557c172e [qrvthtool] AboutDialog: (c) 2022 2022-07-12 23:47:46 -04:00
David Korth
854d6b467e [qrvthtool] AboutDialog: Improve the centering of the logo and text. 2022-07-12 23:47:24 -04:00
David Korth
826b2dd85a [qrvthtool] SelectDeviceDialog: Implement deviceStateChanged().
It now shows RVT-H Readers when they're plugged in, and removes them
when they're unplugged.

...at least on systems where the query listener is implemented, i.e.
Linux with udev.
2022-07-12 23:40:58 -04:00
David Korth
c80b1d1444 [qrvthtool] SelectDeviceDialog: Refactor to store a QList<DeviceQueryData> instead of multiple QVectors.
The selected device is a DeviceQueryData*, which points to an element
in the QList.

New function addDevice() that's called by refreshDeviceList(), and will
eventually be called by deviceStateChanged().
2022-07-12 23:32:04 -04:00
David Korth
1ead35105d [qrvthtool] SelectDeviceDialog: Initial support for automatically detecting connected/disconnected RVT-H Readers.
[librvth] query_udev.c: Added a thread-based callback function.

The thread is started when SelectDeviceDialog is opened and stopped when
SelectDeviceDialog is closed.

The "Refresh" button is hidden if a listener is available.

TODO: It currently only prints a message. Make it update the QListWidget.

TODO: Windows implementation?
2022-07-12 23:21:25 -04:00
David Korth
a3565596ff [wadresign] resign-wad.c: Fix the WAD data_size field if it's incorrect.
Some copies of various IOSes have data_size fields that don't match the
actual contents. The content sizes are now checked, and if it differs,
the correct size is written in the re-signed WAD's header.

TODO: Padding after the last content? Check Wii update partitions.
2022-07-12 19:33:08 -04:00
David Korth
e30cf92691 [wadresign] print-info.c: Verify the data size and print an error if it's wrong.
Remove the TODO about returning an error if the contents are wrong,
since it does that already.

Next: Fix the data size!
2022-07-12 18:50:32 -04:00
David Korth
e68778ea3c [wadresign] print-info.c: Print an error if a content could not be read.
It seems that some WADs have an incorrect data size value in the header.
This size isn't checked, so re-signing the WAD results in a corrupt
output WAD.

Detect the corrupt WAD when verifying.

NOTE: The exit code was already set to 1 in this case, but no one checks
that when running the command directly instead of through a script.
2022-07-12 18:48:16 -04:00
David Korth
9baf290b1c [wadresign] main.c: Remove extra indentation for 'resign' and 'verify' command help; skip 'verify' parameter when processing filenames for verification. 2022-07-12 18:45:41 -04:00
David Korth
bace9c6825 [nusresign] main.c: New function is_directory().
Split this out of main(). Previously, we were using stat() on all
platforms, but stat() is ANSI on Windows, and it returns 32-bit filesizes.
We only want to use 64-bit filesizes, so we'd have to use _tstati64(),
but we don't actually need any of that; we just need the attributes.

The is_directory() function calls GetFileAttributes() on Windows and
stat() on Linux.
2022-07-12 18:43:17 -04:00
David Korth
2a5e19ac43 Rename FindNettle and FindSeccomp to FindNETTLE and FindSECCOMP.
CMake 3.17's FIND_PACKAGE() is complaining that the package name
doesn't match the filename. Rename the filenames to match.
2022-07-12 18:33:18 -04:00
David Korth
c13e700bfd [cmake] Backport more CMake changes from rom-properties.
This includes string format strictness, so update stuff to handle
those changes correctly.

[qrvthtool] BankEntryView: Mark changeEvent() as final.
2022-07-12 18:29:44 -04:00
David Korth
17f03eb4a8 [cmake] FindNettle.cmake: DirInstallPaths is still needed for installation on Windows. 2022-07-12 18:28:11 -04:00
David Korth
425db80b54 [cmake] INCLUDE(CPUInstructionSetFlags) where necessary.
Needed as part of the previous rom-properties backport.
2022-07-12 18:10:55 -04:00
David Korth
67de549aff [cmake] Backported a lot of CMake changes from rom-properties. 2022-07-12 18:04:42 -04:00
David Korth
d68b84381b [librvth] #include "time_r.h" instead of <time.h> to ensure reentrant functions work on Windows. 2022-02-14 22:17:16 -05:00
David Korth
d098813869 [librvth] recrypt.cpp: #include "time_r.h"
Otherwise, gmtime_r() and localtime_r() won't be found on Windows.
2022-02-14 22:15:42 -05:00
David Korth
e5ca7d909e Move w32time.h from librvth/ to libwiicrypto/win32/. 2022-02-14 22:14:10 -05:00
David Korth
1032459deb Use SPDX license identifiers instead of the license notice.
...except bin2h.c, since it was written by FIX94.
2022-02-14 22:11:10 -05:00
David Korth
823db0d0c8 Merge branch 'feature/verify-wii-disc-image'
Verification still needs some improvements, but it works for the most
part for most disc images I've tested.

TODO:
- Look up where a sector is located in the FST to determine what file(s)
  are affected by a bad hash.
- Calculate garbage data to determine if a bad kilobyte should actually
  be garbage data.
2022-02-14 21:50:24 -05:00
David Korth
8c867dc2cc Merge branch 'feature/Qt6'
The Qt6 build isn't usable yet, but we might as well get it merged
into master for more testing.

Also has some other useful updates, including nettle-3.7.3, reentrant
time functions, mtime for GCMs, and statx().
2022-02-14 21:49:22 -05:00
David Korth
31336277b3 [librvth] RefFile: Use statx() if available. 2022-02-14 21:47:26 -05:00
David Korth
4e5d89ed35 Use reentrant time functions if available.
Copied the following from rom-properties:
- time_r.h
- config.libc.h.in
- CheckSymbolExistsOrInline.cmake
2022-02-14 21:36:32 -05:00
David Korth
2a52eb5e2a [librvth] RefFile::mtime(): Use GetFileTime() on Windows.
Copied w32time.h over from rom-properties.
2022-02-14 20:49:20 -05:00
David Korth
ef202e55e8 [nettle.win32] Update: 3.7.2 -> 3.7.3 2022-02-14 20:48:56 -05:00
David Korth
85629becc0 [qrvthtool] BankEntryView: Cache the QLocale. 2022-02-12 12:29:35 -05:00
David Korth
3eda2084b8 [librvth] For GCM files, use the file's mtime as the bank timestamp.
RefFile: Add an mtime() function.

TODO:
- Use statx() and/or Win32 API.
- Also use localtime_r() or localtime_s() if available.
2022-02-12 12:28:25 -05:00
David Korth
0d3b555cad Initial support for compiling with Qt6.
TODO:
- Toolbar icons aren't showing up.
- BankEntryView: Qt::DefaultLocaleShortDate was removed in Qt6,
  so using QLocale instead. Cache the QLocale?
- viewOptions() is final in most widgets, so it's disabled in Qt6 builds.
  See if we can reimplement this better.
- Qt6's moc doesn't like incomplete structs.
2022-02-12 11:20:27 -05:00
David Korth
ff4d03e220 tcharx.h: Forgot to add a _tcstol() macro. 2022-02-12 11:00:28 -05:00
David Korth
92c49e34fe [librvth] verify: KB value for errors should be 1-31, not 0-30.
The first kilobyte of encrypted Wii sectors contains hashes, so we
shouldn't use 0 to prevent confusion.
2022-02-12 02:42:55 -05:00
David Korth
bd6869ad23 [nettle.win32] README.txt: Nettle was updated to 3.7.2 a while ago.
TODO: Update to 3.7.3 and update the compilers used.
2022-02-12 02:40:15 -05:00
David Korth
5653f77fcb [rvthtool] main.c: 'I' option: Some TCHAR fixes for Windows. 2022-02-12 01:34:55 -05:00
David Korth
8a68170c1d [nusresign] print-info.cpp: Some TCHAR fixes for Windows. 2022-02-12 01:33:59 -05:00
David Korth
0800b93156 [cmake] FindNettle.cmake: s/NETTLE_/Nettle_/g
CMake was complaining about this:

CMake Warning (dev) at /usr/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:438 (message):
  The package name passed to `find_package_handle_standard_args` (NETTLE)
  does not match the name of the calling package (Nettle).  This can lead to
  problems in calling code that expects `find_package` result variables
  (e.g., `_FOUND`) to follow a certain pattern.
Call Stack (most recent call first):
  cmake/modules/FindNettle.cmake:22 (find_package_handle_standard_args)
  src/CMakeLists.txt:22 (FIND_PACKAGE)
This warning is for project developers.  Use -Wno-dev to suppress it.
2022-02-12 00:42:25 -05:00
David Korth
ca0292fa85 [librvth] verify.cpp: Sanity check: Only the last group can be truncated. 2022-02-12 00:08:01 -05:00
David Korth
b75e883377 [librvth] verify.cpp: Update max_sector in the "incomplete group" path.
This fixes swupdate discs.
2022-02-12 00:05:58 -05:00
David Korth
fefe1315c8 [rvthtool] verify.cpp: Move pt_current++ to the top to prevent an extra '\n' from duplicating the line when finished. 2022-02-12 00:03:43 -05:00
David Korth
9c7e2b0e96 [rvthtool] verify.cpp: +'\n' 2022-02-12 00:01:27 -05:00
David Korth
27ed887d79 [rvthtool] verify.cpp: fflush(stdout) before verifying. 2022-02-12 00:01:00 -05:00
David Korth
8e80d806d6 [librvth] verify.cpp: Fall back to H3 counting if the partition header has a 0 data length.
This partially fixes an RVT-H image I dumped a while back, but it
results in the zeroed sector warnings again. Better than failing
outright, I guess...
2022-02-11 23:59:30 -05:00
David Korth
a73972bbbc [librvth] verify.cpp: Make sure data_size is under 9 GiB. 2022-02-11 23:41:34 -05:00
David Korth
2b094576f1 verify: Check the partition's data length to determine how much to check in the last group.
The data in the last group past the partition data length has invalid
hashed data. It might be algorithmically generated; I should check
how nkit handles this. For now, ignore it.

Note that we're no longer checking for the "last block group" in the
H3 hash table.

This fixes Sonic Colours (RVT-R), but not swupdate_SDK-3_2_us.gcm.
2022-02-11 23:38:10 -05:00
David Korth
777a3e60c1 [librvth] RvtH::verifyWiiPartitions(): Add pte->lba_start when checking lba for incomplete groups.
Fixes I/O errors occurring near, but not at, the end of the second
partition on multi-partition discs (i.e. most of them).
2022-02-11 22:46:10 -05:00
David Korth
9d6a158075 [rvthtool] verify.cpp: Fix "partition 3/2" when finished verifying. 2022-02-11 22:43:00 -05:00
David Korth
0ffeff4d6a verify: Partition ID improvements.
- librvth: Update state.pt_current so it actually shows the
  correct partition ID.
- rvthtool: Print the partition number (0-based) in errors.
2022-02-11 22:35:26 -05:00
David Korth
f5274f3760 [rvthtool] verify.cpp: Partition 1/2, not 0/2. (current partition) 2022-02-11 22:31:15 -05:00
David Korth
284913a727 [librvth] verify: Add error messages to the callback.
Error messages include hash verification and table copies.

NOTE: We're also checking for zeroed sectors (scrubbed/truncated).
Since this would be zeroed *before* decryption, we have to maintain
two group buffers, one for the encrypted contents, and one for the
decrypted contents. This means 4 MB RAM. Most systems should be able
to handle this in 2022...
2022-02-11 22:26:18 -05:00
David Korth
5a68c4f4ea [librvth] RvtH::verifyWiiPartitions(): Actually call the callback after each group. 2022-02-11 21:59:24 -05:00
David Korth
19f6efcd18 rvthtool: Initial implementation of the 'verify' command.
This command allows verifying encrypted discs using the built-in hash
tables. Note that if the signature is invalid, the hashes can't be
guaranteed to be accurate, but it can at least help identify data
corruption (versus intentional malicious modifications).

Errors are currently reported using printf()s in verifyWiiPartitions(),
which isn't ideal. An error list and improved callback need to be added.

Split several things from extract_crypt.cpp:
- title_key.c: decrypt_title_key()
- wii_sector.h: Wii_Disc_Hashes_t and related

TODO:
- Better error reporting.
- Detect zeroed sectors, e.g. scrubbed images and/or truncated.
- Tested with swupdate_SDK-3_2_us.gcm, which is truncated.
2022-02-11 21:43:09 -05:00
David Korth
60fd817bf7 README.md: Mention Dolphin supports debug-signed images, and also mention nusresign.
This was updated locally on 2021/04/16 11:47 AM EDT, but I never
committed it for some reason.
2022-02-11 18:48:49 -05:00
David Korth
4798c01548 [cmake] platform.cmake: Fix ARM CPU detection. 2021-05-19 18:15:20 -04:00
David Korth
3b4181c5f2 [nettle] Updated the Win32 precompiled build of Nettle from 3.5.1 to 3.7.2. 2021-04-03 04:14:29 -04:00
David Korth
0d98bea72a [cmake] platform.cmake: Detect other 32-bit ARM variants. 2021-03-07 12:21:53 -05:00
David Korth
ef9dada963 cmake/platform.cmake: Fix 32-bit ARM platform detection.
Reported by @vaguerant.
2021-03-03 20:43:10 -05:00
David Korth
f396d8f6a8 [qrvthtool] MessageSound: s/s_notifyInterface/iface/ 2020-09-06 23:03:33 -04:00
David Korth
ebf492c487 [qrvthtool] MessageSound: Always instantiate QPluginLoader when needed.
The older method may technically be undefined behavior...
2020-09-06 22:49:15 -04:00
David Korth
de27111915 [rvthtool] main.c: Added _T() for options; return EXIT_SUCCESS if displaying help.
This was originally added to my working copy on 2020/08/14, but I forgot
to commit it.
2020-09-06 22:48:32 -04:00
David Korth
33455d47d0 [doc] compiling.md: Added qttools5-dev; fixed qttools5-dev-tools. 2020-07-24 18:21:12 -04:00
David Korth
da40efbdbb [qrvthtool] CMakeLists.txt: Fix debug file installation. 2020-07-24 18:20:56 -04:00
David Korth
c60cc17143 [nusresign] resign-nus.cpp: #include <errno.h>
Needed for Mac OS X.
2020-07-13 02:21:37 -04:00
David Korth
c61413c0c5 [libwiicrypto] bin2h.c: Remove #include <malloc.h>.
It's not available on Mac OS X, and it shouldn't be needed elsewhere.
2020-07-13 02:16:19 -04:00
David Korth
f625fdb66b [libwiicrypto] CMakeLists.txt: Make sure the output certs directory exists.
This should fix the travis-ci build, and local builds when using `make`
instead of `ninja`. (I *think* that's the cause?)
2020-07-13 02:12:08 -04:00
David Korth
427eb3fa20 [libwiicrypto] bin2h.c: Handle errors if a file couldn't be opened.
Better to show an error message than to crash.
2020-07-13 02:11:02 -04:00
David Korth
010bb6672f Revert "travis.sh: Enable verbose Makefile to debug bin2h issues."
This reverts commit 06fa24d1db.
2020-07-13 02:06:08 -04:00
David Korth
06fa24d1db travis.sh: Enable verbose Makefile to debug bin2h issues. 2020-07-13 01:44:08 -04:00
David Korth
346f95f06c Added partial support for the Korean debug key.
Taken from a CAT-DEV OTP.

TODO: Add RVL_CryptoType_Korean_Debug? (and vWii)

[librvth] recrypt.cpp: Set signature statuses to OK, not fake, when
recrypting with the vWii debug key, though we don't actually support
this operation right now.
2020-07-11 02:58:14 -04:00
David Korth
b893ab93a8 [nusresign] print-info.cpp: The H0 hashes cover the data area of the 64 KB block.
It covers 63 KB out of 64 KB.
2020-07-10 19:14:26 -04:00
David Korth
dac43c6af4 [nusresign] resign-nus.cpp: Another Windows Unicode compile error... 2020-07-10 18:47:39 -04:00
David Korth
6c1677543e [nusresign] resign-nus.cpp: Write an updated title.cert file.
title.cert is always the same based on the PKI in use.
2020-07-10 18:36:26 -04:00
David Korth
9d69efdc65 [nusresign] resign-nus.cpp: Print the NUS information before re-signing. 2020-07-10 18:35:37 -04:00
David Korth
ff7cd6c754 [nusresign] print-info.cpp: Added maximum sizes for ticket and TMD.
resign-nus.cpp: Check minimum and maximum sizes for ticket and TMD.
2020-07-08 22:08:22 -04:00
David Korth
f0d3e24510 [nusresign] print-info.cpp: Only check the WUP_Ticket portion of the ticket.
There might be a certificate chain appended to it, and we don't want to
include that in the signature.
2020-07-08 22:06:18 -04:00
David Korth
a281fc4e96 [nusresign] main.c: Fix issues with 'info' trying to use 'info' as a filename.
Also updated the filename check code at the end to look for directories,
since nusresign works on directories, not files.
2020-07-08 21:51:01 -04:00
David Korth
8a628636a4 [nusresign] print-info.cpp: Remove debugging code that will definitely crash on other systems.
...and fail to build on Windows due to TCHAR shenanigans.
2020-07-08 21:12:44 -04:00
David Korth
7f94c1d22d [nusresign] print-info.cpp: Fix more Windows TCHAR issues, again... 2020-07-08 20:28:28 -04:00
David Korth
2676dc1ca8 Merge branch 'feature/nusresign'
Everything seems to be mostly up to par with wadresign, aside from
WAD-specific stuff like BWF format.
2020-07-08 20:21:49 -04:00
David Korth
468efd44db [nusresign] print-info.cpp: The content index filenames always use lowercase hex. 2020-07-08 20:18:25 -04:00
David Korth
dbd23445d8 [nusresign] main.c: Uncomment help for commands that are now available. 2020-07-08 20:16:46 -04:00
David Korth
94fe24d827 [nusresign] print-info.cpp: Implement H3 table verification.
The .h3 file has one SHA-1 hash for every 256 MB of data.

The final H4 hash is stored in the TMD content entry and is equal to
the SHA-1 hash of the .h3 file.
2020-07-08 20:14:16 -04:00
David Korth
0a80471626 [nusresign] print-info.cpp: Another fopen() -> _tfopen() fix. 2020-07-08 19:44:57 -04:00
David Korth
50b96d33d5 [nusresign] CMakeLists.txt: We need to link to GMP and Nettle.
Otherwise, the Windows build fails.
2020-07-08 19:43:58 -04:00
David Korth
eae936bd05 [nusresign] Fix some Windows build errors related to TCHAR. 2020-07-08 19:32:05 -04:00
David Korth
f68150f56e [nusresign] print-info.cpp: Implemented the 'verify' command.
FIXME: Contents with an H3 table aren't handled correctly.
Need to figure out how to handle these...
2020-07-08 19:17:26 -04:00
David Korth
26aa36379d [nusresign] print-info.cpp: Print the contents table. 2020-07-08 19:05:54 -04:00
David Korth
7437fc2bf4 [wadresign] print-info.c: Minor changes, including unexporting issuer_type(). 2020-07-08 19:01:17 -04:00
David Korth
e080894eca [nusresign] Initial print-info command.
Based on wadresign.

For TMD signature verification, the TMD's content info table hashes are
checked in addition to the TMD header.
2020-07-08 18:59:11 -04:00
David Korth
cb474fcb66 [libwiicrypto] cert_store.c: Use switch/case here.
This optimizes into a lookup table.
2020-07-08 18:15:59 -04:00
David Korth
e0c93941d7 [wadresign] Minor changes I made during the previous nusresign commit. 2020-07-08 18:14:08 -04:00
David Korth
4fc0b6d8d7 [resign-nus] Refactored; use NUS directories instead of individual files.
Copied over the main getopt_long() parser from wadresign.

Moved the actual resigning code to resign-nus.cpp.

Allow resigning from debug to retail. This won't use fakesigning; instead,
the signature will be overwritten with 0xD15EA5ED, and the ECDH data will
be overwritten with 0xFEEDFACE.
2020-07-08 18:12:32 -04:00
David Korth
62458e7643 Fix the Windows build.
- Moved RVTH_CDECL to common.h

[nusresign] main.c: Use RVTH_CDECL and tcharx.h.
2020-07-07 22:11:50 -04:00
David Korth
544f1b405a [nusresign] New tool for re-signing Wii U NUS packages.
Syntax: `nusresign title.tik title.tmd`

The title.cert file must be replaced manually at the moment.

Tickets and TMDs downloaded directly from the Nintendo CDN have a
partial certificate chain (CA and CP/XS) appended to them. These
certificates are replaced with the correct ones if they're found.

This uses the existing libwiicrypto library, which has been extended
to support Wii U:

- Added the Wii U debug and retail common keys.

- Added the vWii debug common key, though it isn't used by anything
  right now. (Some infrastructure has been added to detect it, but I
  can't really test it because vWii isn't officially supported on
  Wii U devkits.)

- cert_realsign_ticket() and cert_realsign_ticketOrTMD() have been
  combined into a single function, cert_realsign_ticketOrTMD(), since
  they're basically the same (except for the data size).

- cert_realsign_ticketOrTMD() now checks the signature type field to
  determine what type of hash to use in the signature.

- cert_fakesign_*(): Verify that the signature is RSA2048 with SHA-1.
  Wii U doesn't have the fakesign bug, so fake signing is useless there.
  For re-signing to retail when using CFW, we should just zero out the
  signature without doing any sort of fakesigning brute-forcing.

- Renamed rsaw_sha1_sign() to rsaw_rsa2048_sign() and added a parameter
  to indicate use of SHA-256 instead of SHA-1.

- sig_recrypt_ticket(): Added Wii U issuers and keys.

- sig_recrypt_ticket_WUP(): Wrapper that casts WUP_Ticket* to
  RVL_Ticket*. The tickets aren't exactly the same, but the title key
  and issuer fields are in the same place in both of them.

- wii_structs.h:
  - Removed unnecessary struct packing.
  - Changed `uint8_t ticket_id[0x08]` to `uint64_t`.
  - Changed `uint8_t console_id[4]` to `uint32_t console_id`.
2020-07-07 21:39:51 -04:00
David Korth
25af63a6a5 [libwiicrypto] priv_key_store.c: rvth_privkey_WUP_dpki_tmd had p and q swapped. 2020-07-07 21:39:34 -04:00
David Korth
1eefbf1cc5 [libwiicrypto] priv_key_store.c: Added Wii U dpki private keys.
Not currently used for anything, though...
2020-07-05 22:18:46 -04:00
David Korth
ce7b1b93c2 [libwiicrypto] rsaw_nettle.c: Calculate a, b, and c at runtime.
The Wii U tools have p and q, but not a, b, and c. These can be calculated
at runtime, so we don't need to have them here.

Tested by converting a retail WAD to debug and verifying the signature.
2020-07-05 21:59:53 -04:00
David Korth
3e1d4c177e [libwiicrypto] cert_store.c: Missing "Root-CA00000004-SP0000000e".
Root-CA00000003 ended up being tested twice, which caused a Google Test
assertion failure due to duplicate test names.
2020-07-05 20:59:16 -04:00
David Korth
36930b7169 [libwiicrypto] cert_store.h: Added the Wii U disc flag for the signature type.
TODO: Handle this flag when implementing Wii U support at some point.
Flipping this flag is needed in order to convert a disc title to an
installable title and vice-versa.
2020-07-05 18:38:32 -04:00
David Korth
789fd33156 [libwiicrypto] Added definitions for Wii U ppki (Retail) certificates.
Wii U ppki is apparently identical to 3DS ppki. 🤔
2020-07-05 18:36:05 -04:00
David Korth
96d7ed6a78 [libwiicrypto] The RVL Root certificates are also used on CTR and WUP. 2020-07-05 18:27:15 -04:00
David Korth
49d655e08e [libwiicrypto] Added 3DS dpki certificates.
NOTE: The 3DS uses the same CA certificates as Wii U for both
ppki and dpki.
2020-07-05 18:19:58 -04:00
David Korth
fe21dc0946 [libwiicrypto] Added 3DS prod certs (except for Root).
NOTE: 3DS and Wii U might share Root and CA.
2020-07-05 17:58:47 -04:00
David Korth
4910f0cb02 [libwiicrypto] cert_store.c: Split the certificate data into separate files.
This reduces the clutter in cert_store.c.

bin2h.c: Based on bin2h from Nintendont, but with some changes to make
it work better for libwiicrypto.

The .cert files are converted from binary format to .h format during
the build.

NOTE: All certificates aside from the root certificate are used in the
original format found on their respective Nintendo systems. The root
certificates use a dummy format that's similar, but different. (The
original systems had the moduluses and exponents stored directly without
using a certificate format.)
2020-07-05 17:47:13 -04:00
David Korth
caf6467f89 [libwiicrypto] cert_store.c: Make sure we assign max for WUP_PKI_DPKI. 2020-07-05 17:05:56 -04:00
David Korth
dca2ad1b3d [libwiicrypto] cert_store.c: Added missing break; statements. 2020-07-05 17:05:23 -04:00
David Korth
5917f9651e [libwiicrypto] cert_store.c: Added Wii U DPKI certificates.
The constants for Wii U certificates use WUP_ prefixes, though they're
still part of the same RVL_ enums.

Wii U uses new certificate types with SHA-256 hashes. The corresponding
functions have been updated to support SHA-256.

cert_store.c: Reordered certificates such that RVL Debug is first,
followed by RVL Retail, then WUP Debug.

CertVerifyTest: Added tests for the ticket, TMD, and SP certs.

TODO:
- Add the Root Wii U DPKI certificate.
- Add the Wii U DPKI keys.
- Add the PPKI certificates.
- Add 3DS certificates? (Same CAs as Wii U.)
- What is the SP certificate used for?
2020-07-05 16:42:43 -04:00
David Korth
b8b691e370 [libwiicrypto] cert_store.c: Added the correct modulus for the Root DPKI certificate.
This fixes CertVerifyTest for Root-CA00000002.
2020-07-05 15:59:52 -04:00
David Korth
8a8e4ad546 [libwiicrypto] Added two new certs: CA02-XS04 and CA02-CP05.
These are present in my RVT-H Reader's cert.sys. I have no idea what
they're used for.
2020-07-05 15:50:46 -04:00
David Korth
ba151cbb35 Reworked the certificate store to support multiple Root certificates.
dpki and ppki have unique root certificates, so in order to properly
verify certificates, we have to store each of them. They both have
the name "Root", so we use other methods to distinguish them.

Renamed "Retail" issuers to "ppki" and "Debug" issuers to "dpki"
internally, which matches how Nintendo refers to them.
(devel pki, prod pki)

Renamed the "dev" certificate to "MS" (Mastering Server).

cert_verify(): Split the actual verification code into a separate
function. This makes it easier to verify Root certificates, since we
can't get the PKI specification here. Both Root certificates will
be tested, and if one of them succeeds, it'll verify.
- TODO: Maybe add a PKI specification to prevent cases where it's
  signed by the wrong Root certificate? This isn't likely, since
  the Root keys for both PKIs aren't public.

Added a placeholder for the DPKI Root certificate.

CertVerifyTest: Added a test for DPKI Root CA. Note that it currently
fails because we don't have the DPKI Root certificate.
2020-07-05 14:49:00 -04:00
David Korth
af1c0d389a CMakeLists.txt: Check for the existence of the CMAKE_PROJECT variables instead of the CMake version. 2020-06-25 23:04:01 -04:00
David Korth
4302058aee CMakeLists.txt: CMAKE_PROJECT_VERSION was introduced in 3.12.
Set the variables manually for older versions.
2020-06-25 23:01:05 -04:00
David Korth
49e9aa76a7 [wadresign] resign-wad.c: We need to check for recrypt_key == -1.
Otherwise, if the output format is specified, then recrypt key is ignored.

This fixes e.g. converting Devkit Menu 1.00 from BWF Debug to WAD Retail
in a single step.
2020-06-23 19:16:16 -04:00
David Korth
c3714d869a appveyor.yml: Disable the MinGW-w64 builds for now.
- It ends up using MinGW-w64's getopt_long() instead of our version,
  which doesn't support TCHAR.

- Linking is failing due to multiple definitions of various inline
  functions in the Windows headers.
2020-06-21 23:07:16 -04:00
David Korth
7e72ea998f AppVeyor: Package artifacts for MSVC 2013 Release builds. 2020-06-21 22:54:05 -04:00
David Korth
9171d4c3c3 [librvth] RefFile: Use O_SYNC when writing on Linux.
Otherwise, it might end up writing gigabytes nearly "instantaneously",
but the actual writes only occur when the program exits (rvthtool) or
the RVT-H Reader is closed (qrvthtool).

TODO: Windows equivalent; check other systems.
2020-06-21 22:52:53 -04:00
David Korth
b84d437caf [rvthtool] main.c: FIXME: gcc doesn't support printf attributes for wide strings. 2020-06-20 19:00:35 -04:00
David Korth
ea1142abbc appveyor.cmd: Disable gtest in MinGW-w64 builds for now.
In file included from C:/projects/rvthtool/extlib/googletest/googletest/include/gtest/internal/gtest-internal.h:40:0,
                 from C:/projects/rvthtool/extlib/googletest/googletest/include/gtest/gtest.h:58,
                 from C:\projects\rvthtool\extlib\googletest\googletest\src\gtest-all.cc:39:
C:/projects/rvthtool/extlib/googletest/googletest/include/gtest/internal/gtest-port.h:1782:3: error: 'AutoHandle' does not name a type
   AutoHandle thread_;
   ^~~~~~~~~~
2020-06-20 18:08:09 -04:00
David Korth
013c2c939f [wadresign] verify: Detect incorrectly-encrypted vWii WAD files.
TODO: Add a way to fix this by recrypting the contents with the
correct key.
2020-06-20 14:56:24 -04:00
David Korth
b6a9cde7f7 Added support for the vWii common key.
It's technically supported in both wadresign and rvthtool, but rvthtool
doesn't allow using the vWii common key for encryption because it doesn't
make sense to recrypt a disc image to vWii.

FIXME: Is there a debug vWii common key?

TODO: A lot of vWii WADs are incorrectly encrypted using the retail
common key, even though the ticket's key index is set correctly.
Add an option to fix the encryption.
2020-06-20 14:50:37 -04:00
David Korth
d467b413db NEWS.md: Update wadresign details. 2020-06-20 14:27:06 -04:00
David Korth
899ea23c31 Merge branch 'feature/wadresign-convert-to-bwf'
Still need to properly copy over the meta and CRL sections, but that's
basically the same as before for bwf->wad.
2020-06-20 14:25:18 -04:00
David Korth
e7ce689b14 AppVeyor: Build with MinGW-w64 in addition to MSVC 2013.
May need to adjust things for Qt...
2020-06-20 14:06:31 -04:00
David Korth
6ca6180f43 Copied various CMake module updates from rom-properties.
- Changed several macros to functions, e.g. C/C++ language version checks.
- Improved CPU architecture detection.
- Improved LFS detection on some *BSD platforms.
- Preliminary support for Windows on ARM.
- Added toolchain files for i686 and x86_64 MinGW-w64.
2020-06-20 14:01:52 -04:00
David Korth
556ced2327 [rvthtool] Copied the VERSION changes from rom-properties.
The CMake minimum version in the base project was set to 3.1, so I'm
keeping that instead of reducing it to 3.0. Not sure why I used 3.1,
though...
2020-06-20 13:48:38 -04:00
David Korth
a6cbd897c3 [wadresign] Change the default behavior of format conversion.
If no parameters are specified, the encryption key is changed, but
the format is kept the same. This also applies if the encrpytion key
is specified but the format is not.

If the format is specified but the key is not specified, then only
the format is changed.
2020-06-18 20:02:36 -04:00
David Korth
c91fee0e84 [wadresign] Added the CRL field; renamed "footer" and "name" to "meta".
NOTE: CRL is not currently copied for either format, and metadata is
only copied when the destination format is WAD.
2020-06-18 19:53:14 -04:00
David Korth
e32c53544e [wadresign] resign-wad.c: Use a bool for isDestBwf; fix a bunch of logic errors.
Stupid logic errors for wad->wad, wad->bwf, etc. due to hard-to-understand
comparisons instead of using boolean logic.

All of my local tests work now.

TODO: Handle the meta and crl sections better.
2020-06-18 19:36:11 -04:00
David Korth
35f1d5eade [wadresign] resign-wad.c: Allow converting BWF to WAD without recryption.
Tested with a devel-signed BootMii and it worked.
2020-06-18 19:27:55 -04:00
David Korth
58ede14a1b [wadresign] main.c: The standard format uses "wad", not "standard". 2020-06-18 19:20:22 -04:00
David Korth
f1af2ec6b8 [wadresign] Added BWF output format.
This allows conversion of retail BWF to debug and vice-versa.

BWFs are no longer converted to WAD format by default. Specify the
`--format` option to select the format.

TODO:
- BWF->BWF was tested. Need to test BWF->WAD.
- Allow converting just the format without recrypting.
2020-06-18 19:18:15 -04:00
David Korth
f8f1872481 [wadresign] resign-wad.c: Fix copying WAD contents that isn't a multiple of 16 bytes.
While the actual contents might not be a multiple of 16 bytes, AES
operates in blocks of 16 bytes, so we have to copy the extra unused
bytes in order to decrypt the data properly.

This fixes recryption of various IOSes (including IOS58-64-v6176.wad)
and possibly other WADs.

This fixes issue #7: wadresign: Re-signing an IOS misses the last 8
data bytes, resulting in a broken WAD.
2020-06-18 17:50:52 -04:00
David Korth
28e0c89724 [libwiicrypto] common.h: Renamed ALIGN() to ALIGN_BYTES().
ALIGN() is already defined in FreeBSD's machine/align.h. It takes a
single parameter (byte count) which it aligns to the system's native
register size.

ALIGN_BYTES() takes a byte count and aligns it to the specified value.

Based on rom-properties commit b9bd306bb57bc28fb94a87865db4870403b73e57.
2020-06-18 17:50:24 -04:00
David Korth
cc131991c1 [wadresign] Improved labelling of BroadOn WAD Format files.
Also indicate the actual WAD types instead of the two-byte codes.
2020-06-01 17:19:57 -04:00
David Korth
5aab0a0540 [doc] COMPILING.md: +cmake for Debian systems. 2020-06-01 17:19:36 -04:00
David Korth
4de6105c56 [wadresign] wad-fns.[ch]: Convert from CRLF to LF line endings.
Not sure how that happened...
2020-02-20 21:32:13 -05:00
David Korth
c0c24c9d09 [wadresign] Increase maximum footer size from 128 KB to 1 MB.
Pokémon Rumble and My Pokémon Ranch both have large footers for some
reason. These might be actual data files instead of build info.

resign-wad.c: Print the footer size, not the TMD size, when printing
an error indicating that the footer size is too big.
2020-02-20 20:35:25 -05:00
David Korth
9a5c2b1815 [librvth] RefFile.hpp: #include <cerrno>
This should fix the Mac OS X build on travis-ci.
2020-02-18 20:44:00 -05:00
David Korth
1c73d0e416 tchar.x: Moved up to src/; synchronized with rom-properties. 2020-02-18 20:43:37 -05:00
David Korth
599b40f069 [rvthtool] list-banks.cpp: Remove an extra newline when listing non-HDD images. 2020-01-06 01:29:15 -05:00
David Korth
4c0b05ea54 [qrvthtool] Removed some unnecessary Q_D() and Q_Q() macros. 2020-01-06 01:26:52 -05:00
David Korth
f12e2f4da3 [qrvthtool] QRvtHToolWindow: Show NHCD status as both a status message and in the frame title.
Frame title shows "!NHCD", "MBR?", or "GPT?", depending on status.
2020-01-06 01:14:38 -05:00
David Korth
3e3e4d5d20 [qrvthtool] QRvtHToolWindow: Disable writing actions if writing is disabled due to a missing NHCD table. 2020-01-06 01:10:56 -05:00
David Korth
b137965cd7 Updated some copyright headers for 2020 and using SPDX-License-Identifier.
All of these files were modified in the previous two commits.
2020-01-06 01:05:15 -05:00
David Korth
c1bf04b661 [qrvthtool] QRvtHToolWindow: Show a warning for missing NHCD tables.
TODO: Actually disable writing operations in the UI if the NHCD table is
missing. Currently, the buttons are still enabled, but attempting to do
a write operation will fail with an error message. (Well, error code,
since it doesn't show an actual message yet...)
2020-01-06 01:02:23 -05:00
David Korth
bbce6e7729 [librvth] Detect if the HDD is partitioned using MBR or GPT if there's no NHCD header.
This usually means the user specified the wrong device.

[rvthtool] list-banks.cpp: Show a warning if the HDD is partitioned
using MBR or GPT.
2020-01-06 00:56:34 -05:00
David Korth
2c654ed80a [rvthtool] Added an option to change the IOS version when importing a disc image.
This is useful for e.g. Super Smash Bros. Brawl, which uses IOS36.
The debug version of IOS36 seems to be MIA, so we can change it to
IOS56 and it basically works, though Apploader will show a warning.

TODO: Detect the IOS mismatch and show an Apploader warning here
when listing bank information.
2019-12-30 16:50:36 -05:00
David Korth
10deb96898 Added a notice saying this program is NOT licensed or endorsed by Nintendo Co., Ltd. 2019-12-30 15:19:12 -05:00
David Korth
63aff8465c [qrvthtool] BankEntryView: Show type and size for empty and unknown banks. 2019-12-30 15:14:59 -05:00
David Korth
0a5e36f73a NEWS.md: Mention the dual-layer import fix. 2019-12-30 15:01:56 -05:00
David Korth
9b85b08517 [qrvthtool] BankEntryView.ui: Set lblGameTitle's vertical size policy to Minimum.
MinimumExpanding made it use too much space if the selected bank was
deleted.
2019-12-30 14:59:06 -05:00
David Korth
e34d19f02d [qrvthtool] QRvtHToolWindow: Use the windowFilePath property.
If we don't set windowTitle, then Qt will use windowFilePath to
automatically prepend the filename portion to the application title.

It will also automatically handle the Mac OS X proxy icon.
(TODO: Adjust our own proxy icon code for this?)
2019-12-30 14:58:13 -05:00
David Korth
a66cd48ad5 [qrvthtool] Added an About dialog.
Based on GCN MemCard Recover's version, with some changes from
rom-properties' KDE rp-config.

The scroll area code from mcrecover is kept here because I think that's
needed for certain Windows versions, whereas rom-properties doesn't use
Qt on Windows.
2019-12-30 14:47:41 -05:00
David Korth
1245d127b7 [cmake] FindNettle.cmake: Use CPU_* instead of CMAKE_SYSTEM_PROCESSOR.
The 32-bit AppVeyor build ended up using lib.amd64, which failed.
2019-12-30 14:29:02 -05:00
David Korth
666f02a98f [qrvthtool] MessageWidgetStack: Use a lambda function instead of QSignalMapper. 2019-12-30 14:21:13 -05:00
David Korth
36aaca94aa [nettle] Updated the Win32 precompiled build of Nettle from 3.4 to 3.5.1.
Reorganized directories to match rom-properties' gettext.win32 layout.
- Single include directory.
- lib.i386 and lib.amd64 library directories.
2019-12-30 14:16:18 -05:00
David Korth
feda58ac7e [extlib] Moved the precompiled Win32 Nettle from win32/ to extlib/nettle.win32/. 2019-12-30 13:33:07 -05:00
David Korth
4200b256b7 [qrvthtool] LanguageMenu: Use lambda functions instead of QSignalMapper.
QSignalMapper is deprecated, and using a lambda function reduces
code size slightly.
2019-12-30 13:30:20 -05:00
David Korth
57cf00cf59 [wadresign] print_wad_info_FILE(): wad_filename is const TCHAR*, not const char*. 2019-12-30 13:29:09 -05:00
David Korth
2716a4eee1 [cmake] FindNettle.cmake: DirInstallPaths is still needed for the install destinations. 2019-12-30 13:17:41 -05:00
David Korth
5f7d92636e [cmake] FindNettle.cmake: ${arch} isn't set by DirInstallPaths anymore. 2019-12-30 13:13:57 -05:00
David Korth
67c4bd045e [cmake] Copied CMake updates from rom-properties. 2019-12-30 13:10:03 -05:00
David Korth
6931de19a2 [rvthtool] import(): s/GCM/disc/ 2019-12-30 12:15:08 -05:00
David Korth
a7d94cade9 [rvthtool] import(): Print the source disc information. 2019-12-30 12:13:15 -05:00
David Korth
78af024d2d [librvth] Also delete the RvtH object after checking for errors.
Fixes some memory leaks that are probably unnoticeable because rvthtool
exits immediately afterwards.
2019-12-30 12:06:48 -05:00
David Korth
e57f4d89d9 [rvthtool] Fix RvtH constructor error checking.
`new RvtH` will *always* return non-NULL. Check the value of `ret`
and rvth->isOpen() instead.
2019-12-30 12:04:46 -05:00
David Korth
7eef42fbfa [librvth] query.c: 1xxxxxxx vs. 2xxxxxxx does NOT necessarily indicate HUA vs. HMA.
Both wired and wireless systems have been seen with 2xxxxxxx
serial numbers.

TODO: Find a reliable method to determine this.
2019-12-30 11:57:53 -05:00
David Korth
7d7e0be020 [librvth] extract.cpp: Fix statvfs() for relative paths without a "./" prefix if the file doesn't exist.
There's no slashes in these relative paths, so we end up trying to
statvfs() a file that doesn't exist, which results in ENOENT.

This is probably a regression from commit 6683d7fbc7.
([librvth] RvtH::extract(): Check free disk space before extracting.)
2019-05-03 20:13:41 -04:00
David Korth
84ddbf6d51 [wadresign] Handle larger tickets correctly for verification and resigning.
cert_fakesign_ticket() and cert_realsign_ticket() now take uint8_t* and
size parameters instead of RVL_Ticket*. This allows us to correctly sign
larger tickets.

TODO: librvth, rvthtool: Handle larger tickets. I haven't seen any larger
tickets in disc images yet, though...
2019-04-07 13:32:53 -04:00
David Korth
5518029a4b Wrap rvth_get_device_serial_number() calls in #ifdef HAVE_QUERY.
This should fix the Mac OS X build on travis-ci.
2019-04-07 13:14:44 -04:00
David Korth
45b0dd818f [wadresign] Handle a larger ticket as a warning instead of an error.
Some broken WAD files have a slightly-too-big ticket for some reason.
2019-04-07 13:11:45 -04:00
David Korth
21caac7e63 [libwiicrypto] cert_store.c: Handle an empty issuer as unknown.
The root certificate isn't found on discs or WADs, so that's not a valid
return value here.

This fixes an issue where certain broken WADs with a NULL byte located
before the issuer showed up as signed by "Root". (Should be unknown.)
2019-04-07 13:05:40 -04:00
David Korth
7e161ee93e [wadresign] main.c: Allow specifying multiple filenames for the 'verify' command. 2019-04-07 13:01:35 -04:00
David Korth
784b28c050 [wadresign] main.c: Allow specifying multiple filenames for the 'info' command.
Also handles no command.
2019-04-07 12:59:56 -04:00
David Korth
c39dd0c9e3 [wadresign] print-info.c: Print the WAD filename before printing information. 2019-04-07 12:54:33 -04:00
David Korth
84afe4d510 [qrvthtool] SelectDeviceDialog.cpp: Remove the Help button.
References:
- https://stackoverflow.com/questions/81627/how-can-i-hide-delete-the-help-button-on-the-title-bar-of-a-qt-dialog
- https://stackoverflow.com/a/81927
- https://doc.qt.io/Qt-5/qt.html#WindowType-enum

NOTE: Qt::WindowCloseButtonHint is needed on Windows in order for the
Close button to be enabled. (On KDE, it's enabled even without this.)
2019-03-25 02:08:12 -04:00
David Korth
903bd5b47d [qrvthtool] resources/oxygen/: Optimized icons with various tools.
optipng, advdef, advpng, pngout
2019-03-25 02:03:13 -04:00
David Korth
b7baf6ae7b [qrvthtool] Added a minimal KDE Oxygen icon theme.
Based on KDE's oxygen-icons 5.56.0.

NOTE: Qt 5.x has :/icons/ as the default icon theme search path, so the
icon theme is located in :/icons/oxygen/. Previously, in mcrecover, it
was located in :/oxygen/. I thought that worked on Qt 5.x, but maybe I
didn't test it on Windows...

TODO: Move all icons to :/icons/ ?
2019-03-25 01:58:27 -04:00
David Korth
051de22b38 [qrvthtool] TaskbarButtonManager: Set the default progress values to -1.
Otherwise, a tiny sliver of progress shows up on Windows 7
on startup.
2019-03-25 00:55:22 -04:00
David Korth
60e89d0631 [qrvthtool] CMakeLists.txt: "-fpic -fPIC" is for Linux only, not Windows. 2019-03-25 00:51:40 -04:00
David Korth
81fe9c1741 [qrvthtool] SelectDeviceDialog.cpp: Run as administrator, not from an elevated command prompt.
That's something you'd do with rvthtool, not qrvthtool.
2019-03-25 00:50:53 -04:00
David Korth
98da12bd5d [qrvthtool] SelectDeviceDialog.cpp: Removed an extra 'return;' that prevented error messages from being displayed.
TODO: Add an internal icon theme in Windows builds. Toolbar buttons
are currently blank due to no standard icon theme on Windows.
2019-03-25 00:49:27 -04:00
David Korth
328555fb8f [librvth] query_win32.c: Implemented rvth_get_device_serial_number().
TODO: Reduce the code required here, besides splitting out the
VID/PID checks.
2019-03-25 00:47:28 -04:00
David Korth
b32880bb08 [rvthtool] list-banks.cpp: Print the serial number for RVT-H Reader systems. 2019-03-25 00:10:19 -04:00
David Korth
8afcaf34b2 [qrvthtool] QRvtHToolWindow: Added some consts. 2019-03-25 00:08:47 -04:00
David Korth
44e651795a [qrvthtool] QRvtHToolWindow: Show the RVT-H Reader's serial number.
query.h: New function rvth_get_device_serial_number(). This function
returns an allocated serial number for the specified device filename.

query_udev.c: Implemented rvth_get_device_serial_number().
- TODO: Instead of enumerating devices, see if we can get a device
  based on the device node.
2019-03-24 23:27:35 -04:00
David Korth
e6c09d62c0 [qrvthtool] QRvtHToolWindow: Reduce the size of the "cancel" button.
Same as MessageWidget in commit 27d6b7317d.
([qrvthtool] MessageWidget: Set margins and padding for btnDismiss to 0px to eliminate unnecessary space between the icon and the edges of the button.)
2019-03-24 22:52:13 -04:00
David Korth
a7c79b0a44 [qrvthtool] QRvtHToolWindow: Only do an initial update for import, not extract. 2019-03-24 22:50:49 -04:00
David Korth
dc898c1380 [qrvthtool] QRvtHToolWindow: Update the RvtHModel on the first progress
update.

This ensures that the bank listing is correct while the import operation
is in progress.

TODO: Only do this if importing?
2019-03-24 22:50:02 -04:00
David Korth
abcee66557 [librvth] RvtH::import(): Check the correct bank entry for recryption.
This appears to be a temporary placeholder that I added while converting
RvtH to a C++ class.

This fixes a regression from commit d31763f792.
([librvth] Converted `struct RvtH` into a C++ class.)
2019-03-24 22:34:44 -04:00
David Korth
70ad9f11a5 [librvth] extract.cpp: Fixed importing dual-layer images.
This broke when rewriting Reader in C++, since we didn't re-create
the Reader object with the correct size.

Update the RvtH_BankEntry object for the second bank in memory.
This is needed for qrvthtool.

TODO:
- When importing, qrvthtool still shows the second bank row, but
  it's empty. Reloading the disk image works correctly.
- The disc image isn't recrypted for debug...
2019-03-24 22:30:47 -04:00
David Korth
9daf069643 [qrvthtool] QRvtHToolWindow::on_actionImport_triggered(): Need to create d->workerObject here.
Otherwise, it'll be nullptr, and we'll crash.
2019-03-24 22:04:48 -04:00
David Korth
1add262899 [qrvthtool] Delete, Undelete: Play a message sound. 2019-03-24 22:02:53 -04:00
David Korth
98a32535e1 [librvth] deleteBank(), undeleteBank(): Update the timestamp in the in-memory bank entry.
This is needed for qrvthtool in order to show the new timestamp.

writeBankEntry(): Optional parameter `pTimestamp` that returns the
written timestamp in UNIX format. Note that we can't simply use
time(nullptr) here due to timezone conversions, so we end up converting
to NHCD format, then back to UNIX format.
2019-03-24 21:36:22 -04:00
David Korth
b08dcec125 [qrvthtool] QRvtHToolWindow: Update the action enable status after delete/undelete.
Otherwise, the wrong button will be enabled unless the user selects
a different bank and then clicks back.
2019-03-24 21:29:36 -04:00
David Korth
095161672d [qrvthtool] QRvtHToolWindow: Implemented the delete and undelete actions.
- RvtHModel::forceBankUpdate(): New function to force an update to
  the model. This always updates the specified bank and, if it's not
  the last bank, the bank after it, in case the deleted image was
  dual-layer.

- BankEntryView::update(): New function to force an update for the
  currently displayed bank.

- TODO: Prompt the user to confirm deletions?
2019-03-24 21:20:24 -04:00
David Korth
847e708248 [qrvthtool] QRvtHToolWindow::on_actionImport_triggered(): Make sure d->workerThread is not nullptr before using it.
Otherwise, it crashes.
2019-03-24 21:14:45 -04:00
David Korth
72d2872e25 [qrvthtool] QRvtHToolWindow: New function getDisplayName().
Use getDisplayName() to get the display name for the filename.

This function leaves the filename as-is for device files, and removes
all subdirectories for regular files.
2019-03-24 21:11:16 -04:00
David Korth
27d6b7317d [qrvthtool] MessageWidget: Set margins and padding for btnDismiss to 0px to eliminate unnecessary space between the icon and the edges of the button. 2019-03-24 21:05:08 -04:00
David Korth
858fe62acf [qrvthtool] Added MessageWidgetStack and MessageWidget from mcrecover to show error messages.
QRvtHToolWindow: Show an error message using MessageWidgetStack if the
file could not be opened.
2019-03-24 21:04:24 -04:00
David Korth
dfca13898b README.md: s/read/real/ 2019-03-21 00:05:58 -04:00
David Korth
0c6b3a86ff Switch travis-ci distro from trusty to xenial; updated Debian rules.
The Qt5 version included with trusty (5.2.1) attempts to use
QStyleOptionViewItem as if it's a QObject, which results in errors:

build/src/qrvthtool/widgets/moc_QItemView_Text.cpp:71:10: error: ‘staticMetaObject’ is not a member of
‘QStyleOptionViewItem’
         &QStyleOptionViewItem::staticMetaObject,
          ^

Added separate packages for rvthtool and qrvthtool.
Updated COMPILING.md with Qt packages.
2019-03-21 00:03:50 -04:00
David Korth
00071cf446 [rvthtool] extract.h: Removed an unnecessary #include <stdint.h>. 2019-03-20 21:57:05 -04:00
David Korth
20d129805d [rvthtool] main.c: argc/argv aren't unused anymore, and haven't been for a long time.
Command line processing was added in commit a461bd7ee0.
([rvthtool] main.c: Reworked the command line interface to take a command name and parameters.)
[Date:   Wed Jan 17 21:11:10 2018 -0500]
2019-03-20 21:46:06 -04:00
David Korth
f27a2aee8f [qrvthtool] SelectDeviceDialog.ui: Don't allow icons to be moved around. 2019-03-20 21:23:55 -04:00
David Korth
55087d6c99 [qrvthtool] QItemView_Text: Added a "decorationPosition" property.
SelectDeviceDialog: Set the decorationPosition property.
2019-03-20 21:14:11 -04:00
David Korth
366a97f723 [qrvthtool] QItemView_Text: Split most of the code into a .cpp file.
Marked paintEvent() as final.
2019-03-20 20:52:30 -04:00
David Korth
d2da304b95 [qrvthtool] QItemView_Text.hpp: Move the icon to the left side of the text, rather than being on top of the text.
This is similar to Windows Explorer's "Tiles" view.

TODO: Switch to QListView and use a model.
2019-03-20 20:40:00 -04:00
David Korth
66543d5830 [librvth] RefFile::size(): BLKGETSIZE64 requires an int64_t for the return value.
Otherwise, we end up smashing the stack.

This fixes a regression from commit 34171a2231.
([librvth] Rewrote RefFile as a C++ class.)
2019-03-20 20:28:20 -04:00
David Korth
8f5bfc21c3 [librvth] query_udev.c: Unreference the udev_device object if the serial number is invalid. 2019-03-18 23:15:36 -04:00
David Korth
ee3d72cb12 [librvth] query_udev.c: Don't create the list head until we verify the device serial number.
Otherwise, if the serial number is invalid, we'll have dangling pointers
in the first list entry.
2019-03-18 23:10:47 -04:00
David Korth
47efd0a060 [qrvthtool] SelectDeviceDialog: Fix build if UDEV isn't available on Linux.
TODO: Fall back to /dev/* scanning?
2019-03-18 22:42:03 -04:00
David Korth
074ed9d010 [qrvthtool] QRvtHToolWindow::lstBankList_selectionModel_selectionChanged(): Use the selected parameter.
The previous method mostly worked, but if the user held down the mouse
button and dragged the selection cursor across the banks, the selected
bank would be the *previously* selected bank, causing the BankEntryView
to get out of sync.

Using the `selected` parameter also eliminates the need to separately
obtain the selection model.
2019-03-16 21:16:13 -04:00
David Korth
bff5e03faf [qrvthtool] QRvtHToolWindow: Show the image type in the QGroupBox title.
TODO: Get the serial number for RVT-H Readers.
TODO: Option to hide the serial number?
2019-03-16 12:55:05 -04:00
David Korth
06b0b070ce [qrvthtool] QRvtHToolWindow: Added "Delete" and "Undelete" actions.
The actions don't currently do anything.

Updated the action enable/disable code to handle all cases correctly.
2019-03-16 12:28:26 -04:00
David Korth
21c6cbb9fb [qrvthtool] QRvtHToolWindow.cpp: Added 4px left/right padding to lblRecryptionKey.
The label was "too close" to the separator and QComboBox.
2019-03-16 12:23:40 -04:00
David Korth
d872dc19b4 [qrvthtool] QRvtHToolWindow.cpp: s/McRecoverWindow/QRvtHToolWindow/
Copy/paste error from mcrecover.
2019-03-16 12:21:49 -04:00
David Korth
b114031094 [qrvthtool] qrvthtool.cpp: #define MSGFLT_ADD if it isn't defined.
MSGFLT_ADD is only defined if _WIN32_WINNT >= 0x0600.
2019-03-16 03:50:29 -04:00
David Korth
1d208dbc22 [qrvthtool] qrvthtool.cpp: #include <tchar.h> for _T(). 2019-03-16 03:19:03 -04:00
David Korth
94cc99d8df [qrvthtool] QRvtHToolWindow.ui: Added the "Open Disk Image" and "Open RVT-H Reader" buttons to the toolbar. 2019-03-16 02:50:07 -04:00
David Korth
3b89745db7 [qrvthtool] qrvthtool.cpp: Set application name and version information.
config.qrvthtool.h.in: Added VERSION_STRING.

QRvtHToolWindow.cpp: Since we're setting QGuiApplication::applicationDisplayName,
the program name is automatically appended to the title on
Windows and Unix/Linux. Hence, we only have to set the window
title to the loaded filename.

TODO: Mac OS X handling.
2019-03-16 02:47:45 -04:00
David Korth
b97a43608d [qrvthtool] CMakeLists.txt: Install rvth.png as the application icon.
TODO:
- The icon might need some shading or something. Not sure if that should
  just be for the application icon, or if the icons used in the program
  should also be like that.
- .ico version for Windows.
2019-03-16 02:36:09 -04:00
David Korth
dab7206a88 [qrvthtool] UnityLauncher.cpp: Rewrote to use D-Bus directly instead of libunity.
Based on the commit in QtCreator:
https://codereview.qt-project.org/#/c/33051/2/src/plugins/coreplugin/progressmanager/progressmanager_x11.cpp

Taskbar progress now works on KDE5 systems that don't have libunity.

qrvthtool.desktop: Desktop file needed for taskbar progress.

TODO: Install icons.
2019-03-16 02:30:35 -04:00
David Korth
80ce9ecfe4 [qrvthtool] CMakeLists.txt: Fixed typos that prevented DockManager from being compiled.
Still not supported on KDE5, though...

DockManager.cpp: Removed a line of debugging code that didn't actually
compile due to public vs. private classes, but I didn't notice due to
the aforementioned typos.
2019-03-16 02:28:07 -04:00
David Korth
2255359dea [qrvthtool] Copied over TaskbarButtonManager from mcrecover.
It doesn't seem to work on KDE5. Apparently, the standard task manager
in Plasma 5 uses Unity's protocol, but we don't have libunity on all
systems.

Unity has a D-Bus protocol, but it's supposedly not guaranteed to be
stable. In practice, it is.

QtCreator added support for the D-Bus protocol a while back:
https://codereview.qt-project.org/#/c/33051/2/src/plugins/coreplugin/progressmanager/progressmanager_x11.cpp
2019-03-16 02:01:28 -04:00
David Korth
51efdad1c0 [qrvthtool] Added a Cancel button to cancel the current operation.
TODO: Delete the destination .gcm if necessary?
TODO: Improve the ECANCELED message output. (and error messages
in general)
2019-03-16 01:22:32 -04:00
David Korth
17f2105ac3 [qrvthtool] MessageSound: Don't try FrameworkIntegrationPlugin if we don't have KF5. 2019-03-16 01:15:33 -04:00
David Korth
43918adf25 [qrvthtool] MessageSound: Added message and parent parameters.
These are used by KMessageBoxNotifyInterface.

Windows: These aren't used.

Renamed `icon` to `notificationType`, since we aren't actually showing
an icon. (This matches KMessageBoxNotifyInterface.)
2019-03-16 01:02:08 -04:00
David Korth
04e7d21bdd [qrvthtool] Use nullptr as the default parent value instead of 0.
No effective change, but it makes it more obvious that it's a pointer.
2019-03-16 00:59:17 -04:00
David Korth
830c3b02c9 [qrvthtool] MessageSound: New static class for playing message sounds.
On Windows, this uses MessageBeep().

On Linux, this currently uses KDE's notification subsystem, though it's
dynamically loaded using QPluginLoader. (Based on code from KMessageBox.)

TODO: Add libcanberra support and/or other notification systems.
2019-03-16 00:52:41 -04:00
David Korth
3df5db4490 [qrvthtool] QRvtHToolWindow: Create the QThread on demand.
It seems that reusing the QThread caused it to invoke the previous worker
object, even though it was deleted. Then again, it was actually deleted
using QObject::deleteLater(), so maybe it wasn't really deleted...

This ensures that even if the old QThread or worker object is still around
for a bit due to QObject::deleteLater(), it won't be invoked twice.
2019-03-16 00:49:43 -04:00
David Korth
60e61c61b9 [qrvthtool] QRvtHToolWindow: Recryption *key*, not *Hey*. 2019-03-16 00:29:27 -04:00
David Korth
ac32f668e3 [locale] Updated the translation files using lupdate.sh.
[qrvthtool] QRvtHToolWindow.ui: Removed the title from the toolBar.
2019-03-15 23:52:51 -04:00
David Korth
95c7e321bd TODO: RVTH_PROGRESS_RECRYPT only seems to be used for ticket/TMD, not conversion from unencrypted to encrypted. 2019-03-15 23:50:13 -04:00
David Korth
84c6c3f7e2 [qrvthtool] QRvtHToolWindow: Disable writing functions if the image isn't an actual RVT-H Reader.
These functions will return an error from librvth if the RvtH object
isn't an actual RVT-H Reader, since it intentionally does not support
writing to RVT-H disk images.
2019-03-15 23:42:33 -04:00
David Korth
30d0824136 [librvth] Removed RVTH_ERROR_IS_RETAIL_CRYPTO and renumbered error codes.
The last use of this error code was removed in commit bad936d382.
([librvth] rvth_extract.c: Preparation for recrypting retail images to debug when importing a game.)

Error codes aren't exposed publicly (except in qrvthtool, which is only
for debugging purposes right now anyway), so this isn't an issue.

TODO: Remove the explicit numbering?
2019-03-15 23:37:50 -04:00
David Korth
df1cb15dbb [librvth] extract.cpp: Fixed inverted logic when checking for an HDD image.
This fixes a regression from commit d31763f792.
([librvth] Converted `struct RvtH` into a C++ class.)
2019-03-15 23:33:23 -04:00
David Korth
83ddb2ca4f [qrvthtool] Added the "Import" action.
TODO: Test this with an RVT-H Reader connected. With an HDD image,
it fails with error 13: RVTH_ERROR_IS_HDD_IMAGE. This is intentional;
importing is only supported for actual RVT-H Reader systems, since
HDD images are assumed to be used for preservation purposes only.
2019-03-15 23:24:43 -04:00
David Korth
c8e3b1f202 [qrvthtool] QRvtHToolWindow: err == 0 on success, not err != 0. 2019-03-15 23:23:50 -04:00
David Korth
424e62f792 [qrvthtool] QRvtHToolWindow: cur_filenameOnly is no longer used.
This was moved to WorkerObject.
2019-03-15 23:13:45 -04:00
David Korth
634fa07c6f RvtH::bankEntry()'s second parameter is optional now. 2019-03-15 22:54:33 -04:00
David Korth
cecbf8a7e5 [qrvthtool] QRvtHToolWindow: Don't enable the "Extract" button if the selected bank is empty.
TODO: Also Unknown?
2019-03-15 22:53:41 -04:00
David Korth
45a327888f [qrvthtool] WorkerObject: Show the bank number in the status message.
TODO: Don't show the bank number if the source image is a standalone disc image.
2019-03-15 22:49:06 -04:00
David Korth
93f525830a [qrvthtool] Use a separate thread for the extraction process.
WorkerObject: Object for the extraction process. This is attached to a
new QThread, and sends signals to update status and to indicate when
the extraction is finished.

We're not using StatusBarManager because it doesn't seem to be needed.
We can have QRvtHToolWindow manage the status bar widgets.
2019-03-15 22:47:34 -04:00
David Korth
c155b3a48a [qrvthtool] QRvtHToolWindow: Recryption key should be -1 for none.
Specifying "None" means recrypt with no encryption, which isn't supported.

FIXME: If recryption is enabled, it doesn't use sparse writes, and the
resulting filesize is much bigger than it should be.
2019-03-15 22:35:25 -04:00
David Korth
65c84b8cfa [rvthtool] extract.cpp: Use binary file size suffixes, e.g. "MiB" instead of "MB". 2019-03-15 22:10:04 -04:00
David Korth
79eacdb12c Removed some obsolete TODOs.
[librvth] Reader.cpp: Moved the SDK magic numbers into the
Reader::open() function.
2019-03-12 22:13:29 -04:00
David Korth
d9e57c1b14 [librvth] Removed RVTH_BLOCK_SIZE.
It was identical to LBA_SIZE, so let's just use LBA_SIZE everywhere.

[qrvthtool] QRvtHToolWindow: Cast the LBA values to int when using them
in the QProgressBar.
2019-03-11 22:49:50 -04:00
David Korth
57ea693961 [qrvthtool] QRvtHToolWindow: #include <cassert>
This should fix the AppVeyor build. (MSVC 2013)
2019-03-11 22:45:54 -04:00
David Korth
5cd1d4c402 [librvth] extract.cpp: Include the size of the file being overwritten in the free space count.
Since the file is being overwritten, we can reclaim its space.

Linux: `struct stat` has a field `st_blocks`, which has the number of
*allocated* 512-byte blocks. This is useful for sparse files.

Windows: `struct stat` does *not* have `st_blocks`, so divide the total
file size by LBA_SIZE.
2019-03-11 22:42:30 -04:00
David Korth
c379167384 [qrvthtool] QRvtHToolWindow: Actually update the progress bar.
We were only updating the status bar label, so the progress bar always
showed 0% during extraction.
2019-03-11 22:32:48 -04:00
David Korth
3a42eef5c4 [qrvthtool] QRvtHToolWindow: Ignore the close button if the window is busy.
TODO: Disable the close button?
2019-03-11 22:29:05 -04:00
David Korth
47a5d20635 [qrvthtool] QRvtHToolWindow: Added markUiBusy() and markUiNotBusy().
Copied from mcrecover.
2019-03-11 22:20:53 -04:00
David Korth
ac6a6fc3f6 [qrvthtool] QRvtHToolWindow: Added an "Extract" function.
TODO: Port StatusBarManager over from mcrecover and make use of it.
2019-03-11 22:15:29 -04:00
David Korth
c0af17faea [librvth] Use unsigned int for flags instead of uint32_t.
No need to explicitly specify the 32-bit size here.
2019-03-11 21:58:57 -04:00
David Korth
1206c026e5 [librvth] RvtH_Progress_Callback: Added a userdata parameter.
The various functions that take callbacks now also take a `userdata`
parameter. This will be useful for the GUI.

[rvthtool] Updated to handle the `userdata` change.
Note that `userdata` isn't actually used here.
2019-03-11 21:50:36 -04:00
David Korth
6683d7fbc7 [librvth] RvtH::extract(): Check free disk space before extracting.
If not enough free disk space is available, return -ENOSPC.
2019-03-11 21:20:39 -04:00
David Korth
21389c23a7 [librvth] query.c: rvth_create_full_serial_number() should return TCHAR.
Updated the actual function to use TCHAR.

This fixes serial number handling on Windows.
2019-03-11 21:19:18 -04:00
David Korth
53fb2100d2 [qrvthtool] QRvtHToolWindow: Added an "Extract" button.
Currently using the "document-export" icon.

Copied most of the toolbar handling code from mcrecover.
2019-03-11 20:57:47 -04:00
David Korth
e475e137c2 Added China and Taiwan region codes.
These weren't used in retail software, but some development software
with the China region code exists. I haven't seen Taiwan region yet,
but I assume it would be the next value.

Based on a similar change in rom-properties.
2019-03-11 20:31:35 -04:00
David Korth
2f5029810d [locale] Updated the translation files using lupdate.sh. 2019-03-09 17:02:48 -05:00
David Korth
9924891650 [qrvthtool] SelectDeviceDialog: qrvthtool, not rvthtool. 2019-03-09 17:00:48 -05:00
David Korth
3037a62f60 [qrvthtool] SelectDeviceDialog: Fix the build on Windows.
- Missing ')' for a QLatin1String.
- RvtH_QueryEntry has TCHAR, so we have to convert from UTF-16 on
  Windows, not UTF-8.
2019-03-09 14:04:18 -05:00
David Korth
8f68209560 [qrvthtool] SelectDeviceDialog: Added a "Refresh" button.
Technically "Reset" in the QDialogButtonBox, but we change it at runtime.
2019-03-09 13:41:15 -05:00
David Korth
5d197399a9 [qrvthtool] SelectDeviceDialog: Handle lstDevices::doubleClicked().
Double-clicking a device icon now acts like the icon was selected and
the user clicked "OK".
2019-03-09 13:34:50 -05:00
David Korth
c0428fd4cc [qrvthtool] QRvtHToolWindow: TODO: Get the device serial number.
We can get it from the query function, but we need to match it up with
the device filename. We should probably add an RvtH class function to
get the device serial number.
2019-03-09 13:29:35 -05:00
David Korth
381de00dbf [qrvthtool] SelectDeviceDialog: Initial dialog for selecting an RVT-H Reader device.
QRvtHToolWindow: Added a menu item for opening an RVT-H Reader device.

QItemView_Text.hpp: Simple QListView, QListWidget, QTreeView, and
QTreeWidget wrappers that draw a message if the list is empty.
- Reference: https://stackoverflow.com/questions/20765547/qlistview-show-text-when-list-is-empty
2019-03-09 13:25:06 -05:00
David Korth
3da784a069 [qrvthtool] QRvtHToolWindow::openRvtH(): Don't crash if the RVT-H Reader disk image couldn't be opened.
Use a temporary `RvtH*` when opening the file.

`rvth_tmp` is never nullptr, since `new` throws an exception if it fails.
We need to check `rvth_tmp->isOpen()`, and then `delete rvth_tmp;` if it
isn't open.

TODO: Show an error message.
2019-03-09 13:21:16 -05:00
David Korth
6b43d15f85 [rvthtool] query(): Make the RvtH_QueryEntry iterator const. 2019-03-09 12:00:03 -05:00
David Korth
85a23efc0b [libwiicrypto] wii_structs.h: CoD:MW3's DLC has 0x4000 set in the second content.
I'm guessing the first content is just for the WIBN data, and the second
content has the actual DLC data.
2019-03-08 01:27:56 -05:00
David Korth
29b35b6286 Explicitly indicate "realsigned" for realsigned tickets and TMDs. 2019-03-08 00:49:30 -05:00
David Korth
c0234db1d8 [rvthtool] query.c: Use binary file size suffixes, e.g. "MiB" instead of "MB". 2019-03-08 00:26:04 -05:00
David Korth
48a6f784df [librvth] query_win32.c: #include <errno.h>
This broke on AppVeyor (MSVC 2013), but not locally (MSVC 2017).
2019-03-08 00:04:07 -05:00
David Korth
e44c7c5bb1 [librvth] extract_crypt.cpp: goto end; if data_offset != 0x8000.
Also added a `goto end;` if the title key couldn't be decrypted, which
fixes a memory leak. (`aesw` wasn't freed.)

PVS-Studio warning V519 (medium): The 'ret' variable is assigned values
twice successively. Perhaps this is a mistake. Check lines: 517, 538.
2019-03-07 23:52:15 -05:00
David Korth
a5b7507636 [librvth] nhcd_structs.h: NHCD_BANK_START_LBA(): Added extra parentheses around bank_count.
PVS-Studio warning V1003 (Low): The macro 'NHCD_BANK_START_LBA' is a
dangerous expression. The parameter 'bank_count' must be surrounded by
parentheses.
2019-03-07 23:49:24 -05:00
David Korth
ff5fe05aae Merge branch 'feature/query-win32'
`query` is now supported on Windows, and it creates the full serial
number with "HUA"/"HMA" prefix and check digit.
2019-03-07 23:44:01 -05:00
David Korth
9067a223d4 [librvth] query.c: Create the full serial number based on the 8-digit serial number.
This prepends "HUA" or "HMA" depending on whether or not the system is
wired (10xxxxxx) or wireless (20xxxxxx), and calculates the check digit.

Check digit reference: https://www.3dbrew.org/wiki/Serials
2019-03-07 23:42:49 -05:00
David Korth
e24ff9ad06 NEWS.md, README.md: Querying works on Windows now. 2019-03-07 23:29:42 -05:00
David Korth
51780fbe32 [librvth] rvth_query_devices(): Return an error code using an optional pointer parameter.
query_win32.c: If ERROR_ACCESS_DENIED occurs when opening an HDD,
return immediately with EACCES and no devices. This usually means
the user isn't running with elevated permissions.

[rvthtool] query.c: Print a more useful error message if an access
denied error occurs. Note that this probably won't happen on Linux,
since udev makes everything available without actually opening the
storage device.
2019-03-07 23:28:29 -05:00
David Korth
bb03ae997d [librvth] query_win32.c: s/hDrive/hDevice/g 2019-03-07 22:50:21 -05:00
David Korth
d0867436f9 [librvth] CMakeLists.txt: Turns out cfgmgr32.lib isn't actually needed.
Just having setupapi.lib works with MSVC 2017 on Windows 7.
2019-03-07 22:49:36 -05:00
David Korth
045d6efd44 [librvth] query_win32.c: Hard-code the product name.
"Location Information" is actually location information on Windows 7.
Just hard-code it because it's always the same.
2019-03-07 22:48:48 -05:00
David Korth
d1af76f5a5 [librvth] query_win32.c: Added USB vendor and product ID, and the serial number.
Manufacturer seems to show up as "Compatible USB storage device", so
manually change it to "Nintendo Co., Ltd." if that shows up.

Get the serial number from the USB device instance ID.

The product name is stored as "Location Information" for some odd reason.
Device description is "USB Mass Storage Device".

The device query information is now complete on Windows.
2019-03-07 22:32:10 -05:00
David Korth
9a66f47349 [librvth] query_win32.c: Retrieve HDD information.
Split serial_number into usb_serial and hdd_serial, since the two devices
can have different serial numbers.

NOTE: The RVT-H Reader USB bridge doesn't seem to allow access to the HDD
serial number, so that code is disabled for now.

Renamed fw_version to hdd_fwver, since it refers to the HDD firmware
version, not the USB device.

TODO: USB firmware version?
2019-03-07 22:06:40 -05:00
David Korth
f256441c3b [librvth] query_win32.c: Initial query implementation for Windows.
Uses SetupAPI and ConfigAPI.

Currently scans for USB storage devices and gets the physical drive
number. This took a LOT of guessing and checking, since Windows has
a bunch of different device namespaces that don't necessarily correlate
to each other.

The `query` command now works on Windows, though it only shows the
'\\.\PhysicalDrive#' path. None of the other fields show up yet.

TODO: MSVC 2010 doesn't have cfgmgr32.lib. Newer versions seem to have
split some functionality out of setupapi.lib and into cfgmgr32.lib, so
we might need to do a CMake check.
2019-03-07 21:45:28 -05:00
David Korth
ab6903ec43 [rvthtool] main.c: Updated the copyright date. 2019-03-07 21:42:03 -05:00
David Korth
0584ad1cf1 Updated rvthtool and qrvthtool Win32 resource scripts for 2019.
qrvthtool: Added a version resource.
2019-03-07 20:31:27 -05:00
David Korth
2e3a326487 Merge branch 'feature/wadresign' 2019-03-07 20:30:05 -05:00
David Korth
81ebf5a03d [wadresign] resource.rc: Updated for wadresign. 2019-03-07 20:29:50 -05:00
David Korth
6e5bd84957 [wadresign] librvth isn't used here. 2019-03-07 20:29:13 -05:00
David Korth
c02fd5b4b0 [wadresign] Use macros for the various buffer sizes and maximum sizes. 2019-03-07 20:22:08 -05:00
David Korth
851c7b76db [wadresign] resign-wad.c: Copy the footer, or name for early devkit WADs.
Maximum size of 128 KB.

Added some likely() and unlikely() hints.
2019-03-07 20:18:35 -05:00
David Korth
06ea34f6de [wadresign] resign-wad.c: s/fseek(/fseeko(/g, again. 2019-03-07 20:12:26 -05:00
David Korth
96eac4b247 [wadresign] resign-wad.c: Convert early WAD headers to the standard format. 2019-03-07 20:10:43 -05:00
David Korth
0e78170c20 [libwiicrypto] wii_structs.h: Added content type bits.
TODO: Use these somewhere.
2019-03-07 02:00:15 -05:00
David Korth
bf046fdc3c [wadresign] print-info.c: Implement SHA-1 verification.
The contents are verified and compared, and both the expected and
actual SHA-1s are printed. If any of the SHA-1s fail, an error code
is returned.

The previous commit, which fixed data copying, was committed before
this commit, though I had already written the SHA-1 code. That's how
I found out the data copying was broken: SHA-1s in the resigned WADs
were completely broken, even though the originals were fine.

TODO: Check how block alignment works with early devkit WADs.
2019-03-07 01:58:22 -05:00
David Korth
631bdd4966 [wadresign] resign-wad.c: Seek to the start of the data area before copying.
Otherwise, we end up copying junk, resulting in a completely broken
WAD file.
2019-03-07 01:53:41 -05:00
David Korth
842a303ceb [wadresign] resign-wad.c: Fix certificate chain ordering; fix retail/debug copy/paste error.
The WADs actually use CA/TMD/Ticket ordering, not CA/Ticket/TMD.

Fixed a copy/paste issue that caused debug certificates to be used
when resigning to retail.
2019-03-07 01:47:37 -05:00
David Korth
a6e11afe3e [libwiicrypto] sig_tools.c: Explicitly specify "title key", not just "key". 2019-03-07 01:32:58 -05:00
David Korth
6b08e86582 [wadresign] print-info.c: More preparations for the 'verify' command.
- Determine the key to use when getting the ticket and
  TMD issuers.

- Moved the invalid common key index warning from resign_wad()
  to print_wad_info().

- New verify_content() function that doesn't do anything yet.
2019-03-07 01:31:58 -05:00
David Korth
21f45eb360 [wadresign] print-info.c: Print the contents table.
This is the initial step towards adding the new 'verify' command, which
will verify the SHA-1 of each content entry.
2019-03-07 01:16:10 -05:00
David Korth
80345ed8b5 [wadresign] resign-wad.c: Indicate the From and To keys.
The To keys are indicated as fakesigned for retail and Korean.
2019-03-07 01:01:03 -05:00
David Korth
ab09ff38ab [wadresign] resign-wad.c: Copy the data and align to 64 bytes.
This should be enough for basic testing.

TODO:
- Copy the footer.
- Handle early devkit WADs properly.
2019-03-07 00:56:00 -05:00
David Korth
d623c0d905 [wadresign] resign-wad.c: Resign the TMD. 2019-03-07 00:28:26 -05:00
David Korth
d099828962 [wadresign] resign-wad.c: Recrypt and resign the ticket. 2019-03-07 00:15:40 -05:00
David Korth
f09261ae7b [wadresign] Initial 'resign' command implementation.
Currently writes the WAD header and certificate chain, including the
extra debug certificate if recrypting as debug.

TODO:
- Write the extra debug certificate when recrypting discs.
- Verify certificate chain ordering for discs. For WADs, it's
  CA, ticket, TMD, dev; for discs, it seems to be ticket, CA, TMD.
- Convert early WAD headers to final. This also requires converting
  the name, if present, to a footer.
2019-03-06 23:58:00 -05:00
David Korth
6088b79dde [librvth] recrypt.cpp: Actually fix the ALIGN() issue.
It seems that offsetof() has too many ampersands in MSVC 2010.
Move the ALIGN() macro to a separate line.
2019-03-06 23:16:28 -05:00
David Korth
91f44c4acf [libwiicrypto] common.h: Added spaces to the ALIGN() macros.
It seems that without the spaces, use of ALIGN() with offsetof() causes
an error in MSVC 2010:

..\..\..\src\librvth\recrypt.cpp(563): error C2102: '&' requires l-value
2019-03-06 23:12:37 -05:00
David Korth
6197cdf804 [wadresign] print-info.c: Actually return ret.
Set `ret = 0` on success.
2019-03-06 23:06:59 -05:00
David Korth
3b7b36bed2 Use the ALIGN() macro instead of toNext64() and related.
NOTE: declspec() isn't available in MSVC in C mode.
Cast to uint64_t as a workaround.
2019-03-06 23:00:06 -05:00
David Korth
826701eb07 [wadresign] print-info.c: Use fseeko() instead of fseek(). 2019-03-06 22:51:08 -05:00
David Korth
cabdf3486c Explicitly clear the buffer before changing the issuer.
MSVC Secure Overloads will change strncpy() to strncpy_s(), which
doesn't clear the buffer. Hence, we'll need to explicitly clear
the buffer ourselves.

Note that this shouldn't usually be a problem, since the issuer length
is the same for both retail and debug.
2019-03-06 22:48:43 -05:00
David Korth
563e9f07ed Moved rvth_recrypt_ticket() from librvth/recrypt.cpp to libwiicrypto/sig_tools.c.
It's now called sig_recrypt_ticket().
2019-03-06 22:18:57 -05:00
David Korth
dd4fe6f5ab [libwiicrypto] sig_tools.h: Simplified signature handling.
Moved the crypto type, signature type, and signature status enums here.
Renamed them to have RVL_ prefixes instead of RVTH_/RvtH_.

Added functions to convert the enums to strings.

sig_verify(): Wrapper around cert_verify() that returns an RVL_SigType_e
value.
2019-03-06 22:17:31 -05:00
David Korth
891dbe7a43 [wadresign] print-info.c: Added ticket and TMD signature verification.
TODO: Consolidate into libwiicrypto.
2019-03-06 21:43:47 -05:00
David Korth
9ca1c4b7aa [wadresign] Initial implementation of the WAD Resigner.
Currently shows basic information about a WAD file.

Next: Check the signatures and identify them.
2019-03-06 21:21:51 -05:00
David Korth
0bf21fadf5 Merge branch 'feature/librvth-rewrite-cpp'
More C++ rewriting can be done later.
2019-03-06 20:42:37 -05:00
David Korth
d31763f792 [librvth] Converted struct RvtH into a C++ class.
All RVT-H functions that operated directly on an RVT-H obejct are
now member functions.

Moved some accessor functions to the class declaration in rvth.hpp.

rvth_open() and rvth_create_gcm() are now RvtH constructors.

extract_crypt.h, rvth_p.h: Deleted. These declarations are now in
rvth.hpp.

Removed the "rvth_" prefix from some of the source files, since it's
redundant.

Some fixes here and there for memory leaks and/or error correctness.
2019-02-06 20:01:12 -05:00
David Korth
441eb7c5b5 [librvth] Renamed rvth_imagetype.h to rvth_enums.h; moved more enums from rvth.h here. 2019-02-06 00:22:46 -05:00
David Korth
cf7bbbc350 [librvth] rvth_recrypt_partitions(): Debug realsigning has been implemented since v0.9.
Remove the TODO and set the bank entry status correctly.

The bank entry status probably isn't too important right now with the
command line rvthtool, but it might be important later with qrvthtool.
2019-02-05 23:41:38 -05:00
David Korth
ff595c96e0 [librvth] rvth_copy_to_hdd(): rvth_dest and bank_dest are both 'in' parameters, not 'out'. 2019-02-05 23:36:39 -05:00
David Korth
0887402329 [librvth] rvth.cpp, rvth_open_gcm(): CISO and WBFS are automatically handled by the Reader class. 2019-02-05 23:31:40 -05:00
David Korth
dc8bcfd4c8 [librvth] rvth_error.c: #include <assert.h> for static_assert().
This broke the Linux build, but not MSVC...
2019-02-05 22:16:28 -05:00
David Korth
20e4d28b2a [librvth] rvth_get_BankEntry(): Set *pErr to -ERANGE if the bank number is out of range.
Copy/paste error from the !rvth branch.
2019-02-05 22:08:40 -05:00
David Korth
b47aa064e0 [librvth] Split error codes from rvth.cpp to rvth_error.c.
Also split from rvth.h to rvth_error.h, so anything using the error codes
will need to #include "rvth_error.h".
2019-02-05 21:58:34 -05:00
David Korth
d382e2d585 [librvth] Reader::write(): Made this function non-pure virtual.
The base class implementation now returns an error.

Removed the CisoReader and WbfsReader implementations, since the base
class version handles it.
2019-02-05 21:35:55 -05:00
David Korth
3751e7ee8e [librvth] Rewrote the Reader base class and all subclasses as C++ classes.
- Moved the files to a subdirectory.
- Renamed the files to match the class names.

Renamed various other .c files to .cpp in order to use the new
C++ Reader base class.
2019-02-05 21:26:37 -05:00
David Korth
b79e4d149a [libwiicrypto] byteswap.h: Don't define inline if compiling as C++ with MSVC.
bank_init.c failed to compile with MSVC 2017 once switched to C++:

c:\program files (x86)\microsoft visual studio\2017\professional\vc\tools\msvc\14.16.27023\include\xkeycheck.h(207): error C4005: 'inline': macro redefinition
2019-02-05 21:06:27 -05:00
David Korth
d54c98cb78 [librvth] Renamed ref_file.hpp to RefFile.hpp.
We should use title case for C++ class filenames.
2019-02-04 23:41:50 -05:00
David Korth
34171a2231 [librvth] Rewrote RefFile as a C++ class.
This is the first step in porting librvth to C++, which will make it
easier to maintain. For example, it will allow us to add Apploader
DOL verification for encrypted images more easily, since we will be
able to layer a decrypted partition reader, similar to rom-properties.

Renamed many files to .cpp in order to compile as C++.

TODO:
- RefFile's wrapper functions still use errno instead of m_lastError.
- Remove the C compatibility hack later. (`struct RefFile;`)
2019-02-04 23:35:38 -05:00
David Korth
1011bde8aa travis.sh: Disable NLS.
Ubuntu 14.04 doesn't have FindQt5LinguistTools.cmake, so we can't
build the localization files in the travis-ci build.
2018-09-30 21:53:02 -04:00
David Korth
56929bf421 [locale] Added localization files.
Based on similar files from mcrecover.

[qrvthtool] TranslationManager: Search for rvthtool_*.qm,
not mcrecover_*.qm.
2018-09-30 21:48:58 -04:00
David Korth
6404db3781 [qrvthtool] Added LanguageMenu and TranslationManager.
Based on the same classes from mcrecover.

TODO:
- Add some translations.
- Persistent configuration. I don't think porting mcrecover's ConfigStore
  is the right thing to do here.
2018-09-30 21:24:22 -04:00
David Korth
7ae8c89218 [qrvthtool] RvtHModel: Show ICON_WII if the encryption is unknown.
Something isn't quite right here, but the application icon shouldn't show
an RVT-H Reader if this is a standalone disc image.
2018-09-30 21:02:13 -04:00
David Korth
2326cc648a [qrvthtool] RvtHModel: Return ICON_WII for retail-encrypted Wii games, not ICON_GCN.
Forgot to update this when adding the Wii icons earlier.

This should have been done in commit e822d9042f.
([qrvthtool] Added icons for Wii, RVT-R Reader, and RVT-H Reader.)
2018-09-30 21:00:44 -04:00
David Korth
cdd338bd48 [qrvthtool] BankEntryView: Display "Unknown" for RVTH_CryptoType_Unknown.
Only show the ID if it's out of range.
2018-09-30 20:57:53 -04:00
David Korth
d7557ede05 [qrvthtool] resource.h: Use IDI_QRVTHTOOL instead of IDI_APPLICATION.
IDI_APPLICATION is defined in Windows headers as the "default" application
icon, with resource ID 32512.

resource.rc: IDI_QRVTHTOOL, not IDI_KEY_VALID. Besides the fact that this
is wrong (and is a copy/paste error from rom-properties), this caused the
icon to be defined using a name instead of an ID.
2018-09-30 20:51:05 -04:00
David Korth
bbcc6c2b38 Added the C++ 2011 compatibility headers from rom-properties.
Updated copyright headers.

This is needed to build the GUI with MSVC 2010 because MSVC 2010
doesn't support C++ 2011's `final` keyword.
2018-09-30 20:48:41 -04:00
David Korth
ed9be9ddbf CMakeLists.txt: Added a dummy git_version target if sh could not be found. 2018-09-30 20:44:54 -04:00
David Korth
1189e6b3c1 [qrvthtool] CMakeLists.txt: Fix the manifest source path.
Also disable manifest processing on non-Windows platforms.

resource.rc: Subdirectory path is probably needed for the icon and
manifest files.
2018-09-30 00:19:28 -04:00
David Korth
4be9b028e1 [qrvthtool] Added a Windows icon and manifest.
TODO: Needs testing. I don't have Qt5 installed in my VM at the moment,
so I can't easily test this locally.
2018-09-30 00:10:44 -04:00
David Korth
021cfae81f [rvthtool] rvthtool.exe.manifest.in: Use a proper assembly name. 2018-09-29 23:58:51 -04:00
David Korth
685295cf93 [qrvthtool] QRvtHToolWindow: Improve the Mac icon logic.
- Always remove the icon if no image is loaded.
- If an image is loaded and no icon is present, force the icon to
  be loaded.

Bugfix: Forgot to set lastIconID.
2018-09-29 23:44:32 -04:00
David Korth
42365e6959 [qrvthtool] QRvtHToolWindow: Set the application icon.
The icon is set to RVT-H Reader if either no image is loaded or an
RVT-H Reader device or disk image is loaded. If a standalone image
file is loaded, the icon is set to that image file's icon.

RvtHModel: Reworked the icon functions to make them static. The private
class's QIcon array is now also static. Added wrapper functions to the
public interface and moved the IconID enum to the public class.

Added 16x16, 22x22, and 24x24 icons, which will be used for the window
icon.
2018-09-29 23:24:47 -04:00
David Korth
c7f3948354 [qrvthtool] CMakeLists.txt: Skip *everything* if Qt5 isn't available.
Otherwise, CMake will fail because it can't find QT5_WRAP_CPP().
2018-09-23 15:47:18 -04:00
David Korth
dc61193e62 [qrvthtool] Don't make it an error if Qt5 wasn't found.
Simply skip building qrvthtool if it's missing.

TODO: Add ENABLE_QT and make it a three-state variable, defaulting to
AUTO. If it's set to ON and Qt5 was not found, *then* fail.
2018-09-23 15:43:36 -04:00
David Korth
ede2b3dde7 [librvth] rvth_open(): Removed an unused variable.
The `ret` variable was incorrectly added in commit 05acbb1198.
([librvth] rvth.c, rvth_open(): Cleaned up ref_close() issues.)
2018-09-23 15:39:36 -04:00
David Korth
7708203283 [cmake] DirInstallPaths.cmake: Added Mac OS X install paths. 2018-09-23 15:35:56 -04:00
David Korth
cf95ac107f .travis.yml: Build for Mac OS X. (rvthtool only)
travis-ci doesn't have Qt5 for Mac set up (or it's not immediately
obvious how to access it), so let's disable that for now.
2018-09-23 15:32:12 -04:00
David Korth
f23e561b36 appveyor.yml: Updated the version number to reflect the v1.1.1 release. 2018-09-23 11:53:44 -04:00
David Korth
d9a6c5d9bb [libwiicrypto] Actually add wii_structs.h.
Forgot to do this in commit 2a1fbf8923.
([libwiicrypto] Split Wii-specific stuff out of gcn_structs.)
2018-09-23 11:36:54 -04:00
David Korth
f3ab064757 [qrvthtool] BankEntryView: Display the bank's timestamp. 2018-09-23 11:25:53 -04:00
David Korth
33702aa7cf [qrvthtool] QRvtHToolWindow: Don't remove the directory from a physical drive filename.
We want to include "/dev/" or "\\\\.\\PhysicalDrive" in the filename
to make it obvious that it's a physical drive.
2018-09-23 11:15:05 -04:00
David Korth
7b20221e7b [qrvthtool] Remove NUL bytes from strings before converting to QString.
These were showing up as "[NUL]" when running qrvthtool as root on my
system.
2018-09-23 11:08:45 -04:00
David Korth
2a1fbf8923 [libwiicrypto] Split Wii-specific stuff out of gcn_structs.
Similar to rom-properties.
2018-09-23 11:02:09 -04:00
David Korth
2343a0eb75 Split Wii encryption code from librvth into libwiicrypto.
This will allow us to reuse the encryption code for the new wadtool,
which will allow converting debug WADs to retail and vice-versa.

This also moves common.h, byteorder.h, byteswap.h, gcn_structs.h,
and win32/.

Moved nettle detection to src/CMakeLists.txt and a separate config file.
2018-09-23 10:48:42 -04:00
David Korth
9b8f13604b [qrvthtool] Removed the encryption, ticket signature, TMD signature, and apploader status columns.
These aren't too important for the main display. Encryption and signature
are represented by the icon.

These fields can be seen in the "Bank Information" panel.
2018-09-23 10:02:12 -04:00
David Korth
e822d9042f [qrvthtool] Added icons for Wii, RVT-R Reader, and RVT-H Reader.
These icons are used for Wii disc images.
- Retail signature: Wii
- Debug signature:
  - Encrypted: RVT-R Reader
  - Unencrypted: RVT-H Reader

NOTE: Some images, e.g. RVL_DIAG, are unencrypted, but were probably
available on RVT-R discs too. We're still going to show RVT-H Reader
for these, though. (Maybe check the partition size? Unencrypted should
be 4.0 GiB max, but encrypted and RVL_DIAG are 4.38 GiB.)
2018-09-23 00:28:26 -04:00
David Korth
78f8f8d68d [qrvthtool] RvtHModel.cpp: Use ICON_NR for Wii discs if the disc is debug-signed.
TODO: Wii icons.
2018-09-22 22:20:22 -04:00
David Korth
cdae234916 CMakeLists.txt, NEWS.md: Updated version and NEWS from the v1.1 branch.
Updated with v1.1 and v1.1.1.
2018-09-18 22:11:23 -04:00
David Korth
5799480423 [librvth] reader_plain_open(): Don't fail if the file is 0 bytes.
This happens when creating new files for extraction.

This fixes a regression from commit 13b00700e2.
([librvth] ref_get_size(): New function to get a file's size.)

(cherry picked from commit fedd31add2)
2018-09-18 00:41:54 -04:00
937 changed files with 56900 additions and 150530 deletions

4
.gitignore vendored
View File

@ -18,5 +18,5 @@ CMakeFiles/
cmake_install.cmake cmake_install.cmake
git_version.h git_version.h
# Allow *.a files in the win32/ directory. # Allow *.a files for GNU Nettle.
!/win32/*/lib/*.a !/extlib/nettle.win32/lib.*/*.a

View File

@ -1,26 +0,0 @@
language: c
# Compiler selection.
compiler:
- clang
- gcc
# Use Ubuntu 14.04 as the build environment.
sudo: required
dist: trusty
# Build dependencies.
addons:
apt:
packages:
- cmake
- libgmp-dev
- nettle-dev
- libudev-dev
- qtbase5-dev
# Run the build script.
script: ./travis.sh
notifications:
irc: "ircs://irc.badnik.zone:6697/#GensGS"

View File

@ -1,9 +1,30 @@
PROJECT(rvthtool-base) # RVT-H Tool
CMAKE_MINIMUM_REQUIRED(VERSION 3.1) CMAKE_MINIMUM_REQUIRED(VERSION 3.5..3.10)
# CMP0048: Set VERSION variables based on the project version specified in PROJECT().
# Introduced in CMake 3.0.
CMAKE_POLICY(SET CMP0048 NEW)
# CMP0063: Honor visibility properties for all target types,
# including static libraries and executables.
# Introduced in CMake 3.3.
CMAKE_POLICY(SET CMP0063 NEW)
SET(RVTHTOOL_VERSION 2.0.1.1)
PROJECT(rvthtool-base VERSION ${RVTHTOOL_VERSION})
# CMAKE_PROJECT_VERSION was introduced in 3.12.
IF(NOT CMAKE_PROJECT_VERSION OR NOT CMAKE_PROJECT_VERSION_MAJOR)
SET(CMAKE_PROJECT_VERSION ${PROJECT_VERSION})
SET(CMAKE_PROJECT_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
SET(CMAKE_PROJECT_VERSION_MINOR ${PROJECT_VERSION_MINOR})
SET(CMAKE_PROJECT_VERSION_PATCH ${PROJECT_VERSION_PATCH})
SET(CMAKE_PROJECT_VERSION_TWEAK ${PROJECT_VERSION_TWEAK})
ENDIF(NOT CMAKE_PROJECT_VERSION OR NOT CMAKE_PROJECT_VERSION_MAJOR)
LIST(APPEND CMAKE_MODULE_PATH LIST(APPEND CMAKE_MODULE_PATH
"${CMAKE_SOURCE_DIR}/cmake/macros" "${CMAKE_SOURCE_DIR}/cmake/macros"
"${CMAKE_SOURCE_DIR}/cmake/modules" "${CMAKE_SOURCE_DIR}/cmake/libs"
) )
# If no build type is set, default to "Debug". # If no build type is set, default to "Debug".
@ -29,6 +50,36 @@ SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE INTERNAL "Put
# enough tests are added. # enough tests are added.
ENABLE_TESTING() ENABLE_TESTING()
# Set the standards versions: C11, C++17
# C17 was added in CMake 3.21; for older versions, use C11.
# C++17 was added in CMake 3.8; for older versions, use C++14.
# NOTE: These aren't set as hard requirements, though if the compiler
# doesn't support them, code will either be less optimal or will fail
# to compile.
SET(CMAKE_C_STANDARD_REQUIRED OFF)
SET(CMAKE_C_EXTENSIONS ON)
SET(CMAKE_CXX_STANDARD_REQUIRED OFF)
SET(CMAKE_CXX_EXTENSIONS ON)
IF(CMAKE_VERSION VERSION_GREATER 3.20.99) # >= 3.21
SET(CMAKE_C_STANDARD 17)
SET(CMAKE_CXX_STANDARD 17)
ELSEIF(CMAKE_VERSION VERSION_GREATER 3.7.99) # >= 3.8
SET(CMAKE_C_STANDARD 11)
SET(CMAKE_CXX_STANDARD 17)
ELSE()
SET(CMAKE_C_STANDARD 11)
SET(CMAKE_CXX_STANDARD 14)
ENDIF()
IF(MSVC)
# FIXME: Windows SDK prior to 10.0.18362.0 has issues when compiling as either C11 or C17.
# C:\Program Files (x86)\Windows Kits\8.1\Include\um\winbase.h(8816,5): warning C5105: macro expansion producing 'defined' has undefined behavior
# C:\Program Files (x86)\Windows Kits\8.1\Include\um\oaidl.h(473,17): warning C5103: pasting '/' and '/' does not result in a valid preprocessing token
# C:\Program Files (x86)\Windows Kits\8.1\Include\shared\wtypes.h(742,1): message : in expansion of macro '_VARIANT_BOOL'
# C:\Program Files (x86)\Windows Kits\8.1\Include\um\oaidl.h(473,17): error C2059: syntax error: '/'
# Reference: https://github.com/microsoft/vcpkg/issues/15035
SET(CMAKE_C_STANDARD 99)
ENDIF(MSVC)
# Set default build options. # Set default build options.
INCLUDE(cmake/options.cmake) INCLUDE(cmake/options.cmake)
# Check for platform-specific functionality. # Check for platform-specific functionality.
@ -38,25 +89,22 @@ INCLUDE(cmake/platform.cmake NO_POLICY_SCOPE)
SET(DESCRIPTION "RVT-H Tool") SET(DESCRIPTION "RVT-H Tool")
SET(PACKAGE_NAME "rvthtool") SET(PACKAGE_NAME "rvthtool")
SET(AUTHOR "David Korth") SET(AUTHOR "David Korth")
SET(VERSION_MAJOR 1) IF(CMAKE_PROJECT_VERSION_PATCH)
SET(VERSION_MINOR 0) SET(VERSION_STRING "${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}")
SET(VERSION_PATCH 0) ELSE(CMAKE_PROJECT_VERSION_PATCH)
SET(VERSION_DEVEL 1) SET(VERSION_STRING "${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}")
IF(VERSION_PATCH) ENDIF(CMAKE_PROJECT_VERSION_PATCH)
SET(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") IF(CMAKE_PROJECT_VERSION_TWEAK)
ELSE(VERSION_PATCH)
SET(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}")
ENDIF(VERSION_PATCH)
IF(VERSION_DEVEL)
SET(VERSION_STRING "${VERSION_STRING}+") SET(VERSION_STRING "${VERSION_STRING}+")
ENDIF(VERSION_DEVEL) ENDIF(CMAKE_PROJECT_VERSION_TWEAK)
SET(VERSION_STRING_WIN32 "${VERSION_MAJOR},${VERSION_MINOR},${VERSION_PATCH},${VERSION_DEVEL}") SET(VERSION_STRING_WIN32 "${CMAKE_PROJECT_VERSION_MAJOR},${CMAKE_PROJECT_VERSION_MINOR},${CMAKE_PROJECT_VERSION_PATCH},${CMAKE_PROJECT_VERSION_TWEAK}")
# Split Debug macro. # Split Debug macro.
# Also sets the image version for Windows builds. # Also sets the image version for Windows builds.
INCLUDE(Win32ImageVersionLinkerFlags) # TODO: Move to SplitDebugInformation.cmake?
MACRO(DO_SPLIT_DEBUG _target) FUNCTION(DO_SPLIT_DEBUG _target)
IF(TARGET ${_target}) GET_TARGET_PROPERTY(_target_type ${_target} TYPE)
IF(TARGET ${_target} AND NOT _target_type STREQUAL "STATIC_LIBRARY")
# Split debug information. # Split debug information.
INCLUDE(SetMSVCDebugPath) INCLUDE(SetMSVCDebugPath)
SET_MSVC_DEBUG_PATH(${_target}) SET_MSVC_DEBUG_PATH(${_target})
@ -64,13 +112,20 @@ MACRO(DO_SPLIT_DEBUG _target)
INCLUDE(SplitDebugInformation) INCLUDE(SplitDebugInformation)
SPLIT_DEBUG_INFORMATION(${_target}) SPLIT_DEBUG_INFORMATION(${_target})
ENDIF(SPLIT_DEBUG) ENDIF(SPLIT_DEBUG)
IF(WIN32)
# Set image version. # Set image version.
# Subprojects can override ${VERSION_MAJOR} and ${VERSION_MINOR}. # Subprojects can override ${PROJECT_VERSION_MAJOR} and ${PROJECT_VERSION_MINOR}.
# FIXME: If minor version is e.g. "3", Windows interprets it as "03", # FIXME: If minor version is e.g. "3", Windows interprets it as "03",
# so "1.3" will actually be "1.03". # so "1.3" will actually be "1.03".
WIN32_IMAGE_VERSION_LINKER_FLAGS(${VERSION_MAJOR} ${VERSION_MINOR}) INCLUDE(Win32ImageVersionLinkerFlags)
ENDIF(TARGET ${_target}) IF(PROJECT_VERSION_MAJOR AND PROJECT_VERSION_MINOR)
ENDMACRO(DO_SPLIT_DEBUG) WIN32_IMAGE_VERSION_LINKER_FLAGS("${PROJECT_VERSION_MAJOR}" "${PROJECT_VERSION_MINOR}")
ELSE()
WIN32_IMAGE_VERSION_LINKER_FLAGS("${CMAKE_PROJECT_VERSION_MAJOR}" "${CMAKE_PROJECT_VERSION_MINOR}")
ENDIF()
ENDIF(WIN32)
ENDIF(TARGET ${_target} AND NOT _target_type STREQUAL "STATIC_LIBRARY")
ENDFUNCTION(DO_SPLIT_DEBUG)
# Git version information. # Git version information.
FIND_PROGRAM(POSIX_SH sh) FIND_PROGRAM(POSIX_SH sh)
@ -91,6 +146,8 @@ ELSE(POSIX_SH)
# Create a blank git_version.h. # Create a blank git_version.h.
FILE(WRITE "${CMAKE_BINARY_DIR}/git_version.h" FILE(WRITE "${CMAKE_BINARY_DIR}/git_version.h"
"/* dummy file; POSIX sh is not available */\n") "/* dummy file; POSIX sh is not available */\n")
# Dummy target for dependencies.
ADD_CUSTOM_TARGET(git_version)
ENDIF(POSIX_SH) ENDIF(POSIX_SH)
# Make sure the file is deleted on `make clean`. # Make sure the file is deleted on `make clean`.
@ -108,10 +165,20 @@ ADD_CUSTOM_TARGET(uninstall
### Subdirectories. ### ### Subdirectories. ###
# Translations.
IF(ENABLE_NLS)
# NOTE: ENABLE_NLS only controls whether or not translations
# are built. TranslationManager and related are always built
# regardless.
ADD_SUBDIRECTORY(locale)
ENDIF(ENABLE_NLS)
# Project subdirectories. # Project subdirectories.
ADD_SUBDIRECTORY(extlib) ADD_SUBDIRECTORY(extlib)
ADD_SUBDIRECTORY(src) ADD_SUBDIRECTORY(src)
IF(INSTALL_DOC)
ADD_SUBDIRECTORY(doc) ADD_SUBDIRECTORY(doc)
ENDIF(INSTALL_DOC)
# TODO: Print build summary indicating what plugins will be built. # TODO: Print build summary indicating what plugins will be built.
# (Some other project had something like this...) # (Some other project had something like this...)

7
NETWORK.md Normal file
View File

@ -0,0 +1,7 @@
# Network Access Information
rvthtool, and other programs included with rvthtool (qrvthtool, wadresign,
and nusresign) do not have any code to access any network services.
If you use rvthtool (or other included programs) to access files on a network
share, it will use OS-provided facilities to access those files.

53
NEWS.md
View File

@ -1,5 +1,58 @@
# Changes # Changes
## v2.1 (released ????/??/??)
## v2.0.1 - Windows UI Bugfix (released 2025/06/17)
* Bug fixes:
* Fix Windows UI issues: missing icons, proper Dark Mode support.
## v2.0 - GUI Release (released 2025/06/16)
* New features:
* GUI frontend written using the Qt Toolkit.
* Qt5 and Qt6 are supported.
* The precompiled Windows build uses a patched version of
Qt 6.8.3 that supports Windows 7.
* [Win32] Implemented the `query` command.
* wadresign: Command line tool to recrypt and resign WAD files.
* Can decrypt WADs using any key: retail, Korean, debug
* Can encrypt WADs using any key. The resulting WAD will be fakesigned if
encrypting for retail or Korean, or realsigned if encrypting for debug.
* Both standard and BroadOn WAD format are supported for both input and
output.
* **WARNING:** Use with caution if converting system titles for use
on real hardware.
* nusresign: Command line tool to recrypt and resign NUS/WUP packages.
* Can decrypt and encrypt from and to retail and debug.
* The resulting NUS package will be fakesigned if encrypting for retail,
or realsigned if encrypting for debug.
* **WARNING:** Use with caution if converting system titles for use
on real hardware.
* Low-level changes:
* Rewrote librvth using C++ to improve maintainability.
* Other changes:
* Realsigned tickets and TMDs are now explicitly indicated as such.
* Bug fixes:
* Dual-layer images weren't imported properly before. Debug builds asserted
at 4489 MB, but release builds silently failed.
## v1.1.1 - Brown Paper Bag Release (released 2018/09/17)
* Extracting images broke because it failed when opening a file with 0 bytes
length, which always happened when creating new files.
## v1.1 - More Bug Fixes (released 2018/09/17)
* [Win32] Fixed obtaining the device size. fseek(SEEK_END) worked fine on
some systems, but not on others.
* Fixed an incorrect "Success" error message in some cases.
* Use a fake NHCD table if a real NHCD header can't be found. This should
allow recovery of banks on some systems that have a blanked-out NHCD table.
## v1.0 - Bug Fixes and Recryption (released 2018/06/07) ## v1.0 - Bug Fixes and Recryption (released 2018/06/07)
* Fixed extracting unencrypted images from RVT-H Reader devices. This broke * Fixed extracting unencrypted images from RVT-H Reader devices. This broke

View File

@ -2,14 +2,20 @@
This is an open-source tool for managing RVT-H Reader consoles. This is an open-source tool for managing RVT-H Reader consoles.
[![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)<br> [![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
[![Travis Build Status](https://travis-ci.org/GerbilSoft/rvthtool.svg?branch=master)](https://travis-ci.org/GerbilSoft/rvthtool) [![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/l83tx6d16gqr4ov2?svg=true)](https://ci.appveyor.com/project/GerbilSoft/rvthtool/branch/master)<br>
[![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/l83tx6d16gqr4ov2?svg=true)](https://ci.appveyor.com/project/GerbilSoft/rvthtool/branch/master) [![Crowdin](https://badges.crowdin.net/rvthtool/localized.svg)](https://crowdin.com/project/rvthtool)
![RVT-H Reader, RVT-R Reader, Wii RVL-001, and Commodore 1541C](doc/RVT.jpg) ![RVT-H Reader, RVT-R Reader, Wii RVL-001, and Commodore 1541C](doc/RVT.jpg)
## Current Features ## Current Features
New in v2.0:
* A graphical UI frontend using the Qt Toolkit is now included.
* New command line tools `wadresign` and `nusresign` for re-signing
Wii WADs and Wii U NUS packages, respectively.
Other features:
* Lists all disc images currently installed on the RVT-H system. * Lists all disc images currently installed on the RVT-H system.
* Can find "deleted" images that aren't accessible on the RVT-H but are still * Can find "deleted" images that aren't accessible on the RVT-H but are still
present on the HDD, and has an option to undelete these images. present on the HDD, and has an option to undelete these images.
@ -33,7 +39,7 @@ This is an open-source tool for managing RVT-H Reader consoles.
to retail, unencrypted to debug, etc. Conversion to retail will result to retail, unencrypted to debug, etc. Conversion to retail will result
in a fakesigned image. in a fakesigned image.
* Querying all available RVT-H Reader devices to determine which device name * Querying all available RVT-H Reader devices to determine which device name
is associated with which reader. (Linux with UDEV only at the moment.) is associated with which reader.
* Converting unencrypted debug-signed disc images to retail fake-signed and * Converting unencrypted debug-signed disc images to retail fake-signed and
debug-encrypted debug-signed. debug-encrypted debug-signed.
@ -44,8 +50,6 @@ This is an open-source tool for managing RVT-H Reader consoles.
* Bank 1 will be relocated to before the bank table, limiting it to GameCube * Bank 1 will be relocated to before the bank table, limiting it to GameCube
images. images.
A future version will also add a GUI.
## Usage ## Usage
The following commands assume `/dev/sdb` is the RVT-H device. The following commands assume `/dev/sdb` is the RVT-H device.
@ -89,7 +93,7 @@ $ ./rvthtool query
/dev/sdb /dev/sdb
- Manufacturer: Nintendo Co., Ltd. - Manufacturer: Nintendo Co., Ltd.
- Product Name: RVT-H READER - Product Name: RVT-H READER
- Serial Number: abcdefgh - Serial Number: 2000xxxxx
- HDD Firmware: 01.0 - HDD Firmware: 01.0
- HDD Vendor: WDC - HDD Vendor: WDC
- HDD Model: WD800BEVE-00UYT0 - HDD Model: WD800BEVE-00UYT0
@ -106,15 +110,11 @@ Disc images on the RVT-H may or may not be encrypted:
* GameCube: Not encrypted. * GameCube: Not encrypted.
* Wii: May be encrypted using the RVT-R debug key, or not encrypted. * Wii: May be encrypted using the RVT-R debug key, or not encrypted.
Wii disc images encrypted using the RVT-R debug key are playable on the Debug-signed Wii disc images (with and without encryption) are playable on
[Dolphin emulator](https://dolphin-emu.org/) with no changes. They can also the [Dolphin emulator](https://dolphin-emu.org/) with no changes. They can
be used on retail consoles with a USB loader if the image is re-encrypted also be used on retail consoles with a USB loader if the image is re-encrypted
and fakesigned using the retail encryption key. and fakesigned using the retail encryption key.
Unencrypted Wii disc images are not currently usable on Dolphin or retail
consoles. I have been working on adding unencrypted image support to Dolphin
but have not been successful yet.
### Note about Debug IOS ### Note about Debug IOS
RVT-R disc images typically include debug versions of IOS. These will not RVT-R disc images typically include debug versions of IOS. These will not
@ -122,3 +122,26 @@ install on retail consoles, since they're encrypted with debug keys.
Do **NOT** attempt to install them by re-encrypting them with the retail Do **NOT** attempt to install them by re-encrypting them with the retail
keys. Doing so will most likely result in a brick, especially if the 128 MB keys. Doing so will most likely result in a brick, especially if the 128 MB
mode IOS WADs are used. mode IOS WADs are used.
## wadresign
This is a command line tool to resign WAD files to and from any Wii keyset.
Conversion to Debug will be realsigned. Conversion to retail or Korean will
be fakesigned.
In addition, this tool supports reading early devkit WADs, which makes it
possible to convert them to run on emulators and/or later devkits.
**WARNING:** Use with caution if converting a system title for installation
on real hardware, since this may result in an unrecoverable brick.
## nusresign
This is a command line tool to resign NUS/WUP packages for Wii U to and from
any Wii U keyset. Conversion to Debug will be realsigned. Conversion to retail
will be unsigned.
**WARNING:** Use with caution if converting a system title for installation
on real hardware, since this may result in a bricked system. Bricked Wii U
systems may be recoverable using [udpih + Recovery Menu](https://github.com/GaryOderNichts/udpih)
and/or [de_Fuse](https://github.com/StroopwafelCFW/wii_u_modchip).

9
appveyor-artifacts.cmd Normal file
View File

@ -0,0 +1,9 @@
@ECHO OFF
if not "%compiler%" == "msvc2013" exit /b 0
if not "%configuration%" == "Release" exit /b 0
cpack --version
cpack -C "%configuration%"
if ERRORLEVEL 1 exit /b %ERRORLEVEL%
for %%z in (*.zip) do appveyor PushArtifact "%%z"
exit /b %ERRORLEVEL%

17
appveyor-dpkg.sh Executable file
View File

@ -0,0 +1,17 @@
#!/bin/sh
set -ev
add-apt-repository --remove "deb http://apt.postgresql.org/pub/repos/apt/ bionic-pgdg main"
apt-get update
apt-get -y install \
cmake \
pkg-config \
libgmp-dev \
nettle-dev \
libudev-dev \
\
qtbase5-dev \
qttools5-dev \
qttools5-dev-tools \
libkf5widgetsaddons-dev

View File

@ -1,7 +1,39 @@
@ECHO OFF @ECHO OFF
cmake --version cmake --version
IF "%PLATFORM%" == "x64" (
cmake . -G "Visual Studio 12 2013 Win64" -DCMAKE_GENERATOR_TOOLSET=v120_xp -DBUILD_TESTING=ON -DCMAKE_PREFIX_PATH="C:/Qt/5.8/msvc2013_64" :: FIXME: Restore MinGW-w64 support?
) ELSE ( set compiler=msvc2015
cmake . -G "Visual Studio 12 2013" -DCMAKE_GENERATOR_TOOLSET=v120_xp -DBUILD_TESTING=ON -DCMAKE_PREFIX_PATH="C:/Qt/5.8/msvc2013"
) if "%compiler%" == "msvc2015" goto :msvc2015
if "%compiler%" == "mingw-w64" goto :mingw-w64
echo *** ERROR: Unsupported compiler '%compiler%'.
exit /b 1
:msvc2015
set PreferredToolArchitecture=x64
set "CMAKE_GENERATOR=Visual Studio 14 2015"
set CMAKE_GENERATOR_TOOLSET=v140_xp
if "%platform%" == "x64" set "CMAKE_GENERATOR=%CMAKE_GENERATOR% Win64"
if "%platform%" == "x86" set Qt5_DIR=C:\Qt\5.13\msvc2015\lib\cmake\Qt5
if "%platform%" == "x64" set Qt5_DIR=C:\Qt\5.13\msvc2015_64\lib\cmake\Qt5
mkdir build
cd build
cmake .. -G "%CMAKE_GENERATOR%" -DCMAKE_GENERATOR_TOOLSET=%CMAKE_GENERATOR_TOOLSET% -DBUILD_TESTING=ON -DQt5_DIR=%Qt5_DIR%
exit /b %ERRORLEVEL%
:mingw-w64
set PATH=%PATH:C:\Program Files\Git\bin;=%
set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
set PATH=%PATH:C:\Program Files (x86)\Git\bin;=%
set PATH=%PATH:C:\Program Files (x86)\Git\usr\bin;=%
if "%platform%" == "x86" set MINGW64_ROOT=C:/mingw-w64/i686-6.3.0-posix-dwarf-rt_v5-rev1/mingw32
if "%platform%" == "x64" set MINGW64_ROOT=C:/mingw-w64/x86_64-7.2.0-posix-seh-rt_v5-rev1/mingw64
if "%playform%" == "x86" set Qt5_DIR=C:\Qt\5.8\mingw53_32\lib\cmake\Qt5
if "%playform%" == "x64" set Qt5_DIR=C:\Qt\5.8\mingw53_64\lib\cmake\Qt5
set "PATH=%MINGW64_ROOT%\bin;%PATH%"
:: FIXME: gtest is failing on AppVeyor because "AutoHandle" does not name a type.
mkdir build
cd build
cmake .. -G "MinGW Makefiles" -DCMAKE_PREFIX_PATH=%MINGW64_ROOT% -DCMAKE_C_COMPILER=%MINGW64_ROOT%/bin/gcc.exe -DCMAKE_CXX_COMPILER=%MINGW64_ROOT%/bin/g++.exe -DCMAKE_BUILD_TYPE=%configuration% -DBUILD_TESTING=OFF -DQt5_DIR=%Qt5_DIR%
exit /b %ERRORLEVEL%

12
appveyor.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh
set -ev
cmake --version
mkdir build || true
cd build
cmake .. -G Ninja \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_BUILD_TYPE=Release \
-DENABLE_NLS=OFF \
-DBUILD_TESTING=ON

View File

@ -1,16 +1,23 @@
# AppVeyor configuration file. # AppVeyor configuration file.
version: '1.0.0.{build}' version: '2.0.1.{build}'
# Build worker image (VM template) # Build worker image (VM template)
image: Visual Studio 2013 image:
- Visual Studio 2015
- Ubuntu2204
configuration:
- Debug
- Release
platform:
- x86
- x64
# TODO: Re-add MinGW-w64 compiler for Windows builds.
# scripts that are called at very beginning, before repo cloning # scripts that are called at very beginning, before repo cloning
init: init:
- git config --global core.autocrlf input - git config --global core.autocrlf input
# clone directory
clone_folder: c:\projects\rvthtool
# Don't build if source files aren't modified. # Don't build if source files aren't modified.
only_commits: only_commits:
files: files:
@ -22,24 +29,31 @@ only_commits:
- extlib/**/* - extlib/**/*
- src/**/* - src/**/*
platform: # Ignore the l10n_master branch from Crowdin.
- x86 branches:
- x64 except:
- l10n_master
configuration:
- Debug
- Release
# Run CMake.
before_build: before_build:
- cd %APPVEYOR_BUILD_FOLDER% - cmd: cd %APPVEYOR_BUILD_FOLDER%
- appveyor.cmd - cmd: appveyor.cmd
- sh: cd ${APPVEYOR_BUILD_FOLDER}
- sh: sudo ./appveyor-dpkg.sh
- sh: ./appveyor.sh
build_script: build_script:
- cd %APPVEYOR_BUILD_FOLDER% - cmd: cd %APPVEYOR_BUILD_FOLDER%\build
- msbuild ALL_BUILD.vcxproj - cmd: cmake --build . --config %configuration%
- sh: cd ${APPVEYOR_BUILD_FOLDER}/build
- sh: cmake --build . --config ${CONFIGURATION}
test_script: test_script:
- cd %APPVEYOR_BUILD_FOLDER% - cmd: cd %APPVEYOR_BUILD_FOLDER%\build
- ctest -V -C %CONFIGURATION% - cmd: ctest -V -C %configuration%
- sh: cd ${APPVEYOR_BUILD_FOLDER}/build
- sh: ctest -V -C ${CONFIGURATION}
# TODO: Automatic packaging? after_test:
- cmd: cd %APPVEYOR_BUILD_FOLDER%\build
- cmd: ..\appveyor-artifacts.cmd

View File

@ -9,10 +9,9 @@ STRING(REGEX REPLACE "\n" ";" files "${files}")
FOREACH(file ${files}) FOREACH(file ${files})
MESSAGE(STATUS "Uninstalling $ENV{DESTDIR}${file}") MESSAGE(STATUS "Uninstalling $ENV{DESTDIR}${file}")
IF(EXISTS "$ENV{DESTDIR}${file}") IF(EXISTS "$ENV{DESTDIR}${file}")
EXEC_PROGRAM( EXECUTE_PROCESS(COMMAND "@CMAKE_COMMAND@" -E remove "$ENV{DESTDIR}${file}"
"@CMAKE_COMMAND@" ARGS "-E remove $ENV{DESTDIR}${file}"
OUTPUT_VARIABLE rm_out OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval RESULT_VARIABLE rm_retval
) )
IF(NOT "${rm_retval}" STREQUAL 0) IF(NOT "${rm_retval}" STREQUAL 0)
MESSAGE(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") MESSAGE(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")

View File

@ -0,0 +1,25 @@
# Check for Nettle v2 or v3.
# If either version is found, HAVE_NETTLE will be set.
# If Nettle v3 is found, HAVE_NETTLE_3 will be set.
FUNCTION(CHECK_NETTLE_2_OR_3)
FIND_PACKAGE(NETTLE)
SET(HAVE_NETTLE ${NETTLE_FOUND})
SET(HAVE_NETTLE ${NETTLE_FOUND} PARENT_SCOPE)
SET(NETTLE_FOUND ${NETTLE_FOUND} PARENT_SCOPE)
IF(HAVE_NETTLE)
# Check if this is Nettle 3.x.
# Nettle 3.1 added version.h, which isn't available
# in older verisons, so we can't simply check that.
INCLUDE(CheckSymbolExists)
SET(CMAKE_REQUIRED_INCLUDES ${NETTLE_INCLUDE_DIRS})
SET(CMAKE_REQUIRED_LIBRARIES ${NETTLE_LIBRARY})
CHECK_SYMBOL_EXISTS(aes128_set_decrypt_key "nettle/aes.h" HAVE_NETTLE_3)
IF(HAVE_NETTLE_3)
# Check for Nettle versioning symbols.
# Nettle 3.1 added version.h.
CHECK_SYMBOL_EXISTS(NETTLE_VERSION_MAJOR "nettle/version.h" HAVE_NETTLE_VERSION_H)
CHECK_SYMBOL_EXISTS(nettle_version_major "nettle/version.h" HAVE_NETTLE_VERSION_FUNCTIONS)
ENDIF(HAVE_NETTLE_3)
ENDIF(HAVE_NETTLE)
ENDFUNCTION(CHECK_NETTLE_2_OR_3)

View File

@ -5,6 +5,7 @@
# NETTLE_LIBRARIES - List of libraries when using libnettle. # NETTLE_LIBRARIES - List of libraries when using libnettle.
# NETTLE_FOUND - True if libnettle found. # NETTLE_FOUND - True if libnettle found.
IF(NOT TARGET NETTLE_dll_target)
IF(NOT WIN32) IF(NOT WIN32)
if(NETTLE_INCLUDE_DIRS) if(NETTLE_INCLUDE_DIRS)
# Already in cache, be silent # Already in cache, be silent
@ -25,25 +26,28 @@ IF(NOT WIN32)
endif() endif()
ELSE(NOT WIN32) ELSE(NOT WIN32)
# Use the included Win32 build of Nettle. # Use the included Win32 build of Nettle.
# NOTE: DirInstallPaths sets ${arch}. INCLUDE(CPUInstructionSetFlags)
INCLUDE(DirInstallPaths) INCLUDE(DirInstallPaths)
IF(NOT arch MATCHES "^(i.|x)86$|^x86_64$|^amd64$") IF(CPU_i386 OR CPU_amd64)
MESSAGE(FATAL_ERROR "Architecture ${arch} is not supported.") # Supported CPU
ENDIF(NOT arch MATCHES "^(i.|x)86$|^x86_64$|^amd64$") ELSE()
MESSAGE(FATAL_ERROR "Unsupported CPU architecture, please fix!")
ENDIF()
SET(NETTLE_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/win32/${arch}/include") SET(NETTLE_WIN32_BASE_PATH "${CMAKE_SOURCE_DIR}/extlib/nettle.win32")
SET(NETTLE_INCLUDE_DIRS "${NETTLE_WIN32_BASE_PATH}/include")
IF(MSVC) IF(MSVC)
SET(NETTLE_LIBRARY "${CMAKE_SOURCE_DIR}/win32/${arch}/lib/libnettle-6.lib") SET(NETTLE_LIBRARY "${NETTLE_WIN32_BASE_PATH}/lib.${TARGET_CPU_ARCH}/libnettle-8.lib")
SET(HOGWEED_LIBRARY "${CMAKE_SOURCE_DIR}/win32/${arch}/lib/libhogweed-4.lib") SET(HOGWEED_LIBRARY "${NETTLE_WIN32_BASE_PATH}/lib.${TARGET_CPU_ARCH}/libhogweed-6.lib")
ELSE(MSVC) ELSE(MSVC)
SET(NETTLE_LIBRARY "${CMAKE_SOURCE_DIR}/win32/${arch}/lib/libnettle.dll.a") SET(NETTLE_LIBRARY "${NETTLE_WIN32_BASE_PATH}/lib.${TARGET_CPU_ARCH}/libnettle.dll.a")
SET(HOGWEED_LIBRARY "${CMAKE_SOURCE_DIR}/win32/${arch}/lib/libhogweed.dll.a") SET(HOGWEED_LIBRARY "${NETTLE_WIN32_BASE_PATH}/lib.${TARGET_CPU_ARCH}/libhogweed.dll.a")
ENDIF(MSVC) ENDIF(MSVC)
SET(NETTLE_LIBRARIES ${NETTLE_LIBRARY} ${HOGWEED_LIBRARY}) SET(NETTLE_LIBRARIES ${NETTLE_LIBRARY} ${HOGWEED_LIBRARY})
# Copy and install the DLLs. # Copy and install the DLLs.
SET(NETTLE_NETTLE_DLL "${CMAKE_SOURCE_DIR}/win32/${arch}/lib/libnettle-6.dll") SET(NETTLE_NETTLE_DLL "${NETTLE_WIN32_BASE_PATH}/lib.${TARGET_CPU_ARCH}/libnettle-8.dll")
SET(NETTLE_HOGWEED_DLL "${CMAKE_SOURCE_DIR}/win32/${arch}/lib/libhogweed-4.dll") SET(NETTLE_HOGWEED_DLL "${NETTLE_WIN32_BASE_PATH}/lib.${TARGET_CPU_ARCH}/libhogweed-6.dll")
# Destination directory. # Destination directory.
# If CMAKE_CFG_INTDIR is set, a Debug or Release subdirectory is being used. # If CMAKE_CFG_INTDIR is set, a Debug or Release subdirectory is being used.
@ -53,22 +57,22 @@ ELSE(NOT WIN32)
SET(DLL_DESTDIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") SET(DLL_DESTDIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
ENDIF(CMAKE_CFG_INTDIR) ENDIF(CMAKE_CFG_INTDIR)
ADD_CUSTOM_TARGET(nettle_dll_target ALL ADD_CUSTOM_TARGET(NETTLE_dll_target ALL
DEPENDS hogweed_dll_command nettle_dll_command DEPENDS HOGWEED_dll_command NETTLE_dll_command
) )
ADD_CUSTOM_COMMAND(OUTPUT nettle_dll_command ADD_CUSTOM_COMMAND(OUTPUT NETTLE_dll_command
COMMAND ${CMAKE_COMMAND} COMMAND ${CMAKE_COMMAND}
ARGS -E copy_if_different ARGS -E copy_if_different
"${NETTLE_NETTLE_DLL}" "${DLL_DESTDIR}/libnettle-6.dll" "${NETTLE_NETTLE_DLL}" "${DLL_DESTDIR}/libnettle-8.dll"
DEPENDS nettle_always_rebuild DEPENDS NETTLE_always_rebuild
) )
ADD_CUSTOM_COMMAND(OUTPUT hogweed_dll_command ADD_CUSTOM_COMMAND(OUTPUT HOGWEED_dll_command
COMMAND ${CMAKE_COMMAND} COMMAND ${CMAKE_COMMAND}
ARGS -E copy_if_different ARGS -E copy_if_different
"${NETTLE_HOGWEED_DLL}" "${DLL_DESTDIR}/libhogweed-4.dll" "${NETTLE_HOGWEED_DLL}" "${DLL_DESTDIR}/libhogweed-6.dll"
DEPENDS nettle_always_rebuild DEPENDS NETTLE_always_rebuild
) )
ADD_CUSTOM_COMMAND(OUTPUT nettle_always_rebuild ADD_CUSTOM_COMMAND(OUTPUT NETTLE_always_rebuild
COMMAND ${CMAKE_COMMAND} COMMAND ${CMAKE_COMMAND}
ARGS -E echo ARGS -E echo
) )
@ -78,5 +82,10 @@ ELSE(NOT WIN32)
COMPONENT "dll" COMPONENT "dll"
) )
SET(NETTLE_FOUND 1)
SET(HAVE_NETTLE 1)
UNSET(DLL_DESTDIR) UNSET(DLL_DESTDIR)
UNSET(arch)
ENDIF(NOT WIN32) ENDIF(NOT WIN32)
ENDIF(NOT TARGET NETTLE_dll_target)

View File

@ -0,0 +1,19 @@
/**
* 64-bit time_t test code, with fcntl.h.
* Reference: https://github.com/Benjamin-Dobell/Heimdall/blob/master/cmake/LargeFiles.c
*/
#include <stdint.h>
#include <time.h>
#include <fcntl.h>
/** static_assert() macro copied from c++11-compat.h **/
#define static_assert(expr, msg) switch (0) { case 0: case (expr): ; }
int main(int argc, char *argv[])
{
static_assert(sizeof(time_t) == sizeof(int64_t), "time_t is the wrong size");
int64_t tm64;
time_t tm = time(&tm64);
return 0;
}

View File

@ -0,0 +1,107 @@
# Determine CPU architecture.
IF(MSVC AND _MSVC_C_ARCHITECTURE_FAMILY)
# Check the MSVC architecture.
# Set CMAKE_SYSTEM_PROCESSOR to match, since it doesn't get
# set to the target architecture correctly.
# TODO: Verify 32-bit.
IF(_MSVC_C_ARCHITECTURE_FAMILY MATCHES "^[iI]?[xX3]86$")
SET(CPU_i386 1)
SET(CMAKE_SYSTEM_PROCESSOR "x86")
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "x86")
ELSEIF(_MSVC_C_ARCHITECTURE_FAMILY MATCHES "^[xX]64$")
SET(CPU_amd64 1)
SET(CMAKE_SYSTEM_PROCESSOR "AMD64")
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "amd64")
ELSEIF(_MSVC_C_ARCHITECTURE_FAMILY MATCHES "[iI][aA]64")
SET(CPU_ia64 1)
SET(CMAKE_SYSTEM_PROCESSOR "IA64")
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "ia64")
ELSEIF(_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM" OR _MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARMV7")
SET(CPU_arm 1)
SET(CMAKE_SYSTEM_PROCESSOR "ARM")
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "arm")
ELSEIF(_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM64EC")
SET(CPU_arm64 1)
SET(CPU_arm64ec 1)
SET(CMAKE_SYSTEM_PROCESSOR "ARM64")
# TODO: Does this change for ARM64EC?
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "arm64")
ELSEIF(_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM64")
SET(CPU_arm64 1)
SET(CMAKE_SYSTEM_PROCESSOR "ARM64")
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "arm64")
ELSE()
MESSAGE(FATAL_ERROR "Unsupported value for _MSVC_C_ARCHITECTURE_FAMILY: ${_MSVC_C_ARCHITECTURE_FAMILY}")
ENDIF()
ELSE()
# TODO: Verify cross-compile functionality.
# TODO: ARM/ARM64 is untested.
STRING(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" arch)
IF(arch MATCHES "^(i.|x)86$|^x86_64$|^amd64$")
IF(CMAKE_CL_64 OR ("${CMAKE_SIZEOF_VOID_P}" EQUAL 8))
SET(CPU_amd64 1)
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "amd64")
ELSE()
SET(CPU_i386 1)
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "x86")
ENDIF()
ELSEIF(arch STREQUAL "ia64")
SET(CPU_ia64 1)
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "ia64")
ELSEIF(arch MATCHES "^arm(|v[1-7](.|h[fl]|hfe[lb]))?$" OR arch STREQUAL "aarch64" OR arch STREQUAL "arm64" OR arch STREQUAL "cortex")
IF(CMAKE_CL_64 OR ("${CMAKE_SIZEOF_VOID_P}" EQUAL 8))
SET(CPU_arm64 1)
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "arm64")
ELSE()
SET(CPU_arm 1)
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "arm")
ENDIF()
ELSEIF(arch MATCHES "^ppc" OR arch STREQUAL "powerpc")
IF(arch STREQUAL "ppc64le")
SET(CPU_ppc64le 1)
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "ppc64le")
ELSEIF(CMAKE_CL_64 OR ("${CMAKE_SIZEOF_VOID_P}" EQUAL 8))
SET(CPU_ppc64 1)
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "ppc64")
ELSE()
SET(CPU_ppc 1)
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "ppc")
ENDIF()
ELSEIF(arch MATCHES "^riscv")
# TODO: Win32 manifest processor architecture, if it's ever ported to RISC-V.
IF(CMAKE_CL_64 OR ("${CMAKE_SIZEOF_VOID_P}" EQUAL 8))
SET(CPU_riscv64 1)
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "riscv64")
ELSE()
SET(CPU_riscv32 1)
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "riscv32")
ENDIF()
ELSE()
MESSAGE(FATAL_ERROR "Unable to determine CPU architecture.\nCMAKE_SYSTEM_PROCESSOR == ${CMAKE_SYSTEM_PROCESSOR}")
ENDIF()
UNSET(arch)
ENDIF()
# i386/amd64: Flags for extended instruction sets.
IF(CPU_i386 OR CPU_amd64)
# MSVC does not require anything past /arch:SSE2 for SSSE3.
# ClangCL does require -mssse3, even on 64-bit.
IF(MSVC)
IF(CPU_i386)
SET(SSE2_FLAG "/arch:SSE2")
SET(SSSE3_FLAG "/arch:SSE2")
SET(SSE41_FLAG "/arch:SSE2")
ENDIF(CPU_i386)
IF(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
SET(SSSE3_FLAG "-mssse3")
SET(SSE41_FLAG "-msse4.1")
ENDIF(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
ELSE()
IF(CPU_i386)
SET(MMX_FLAG "-mmmx")
SET(SSE2_FLAG "-msse2")
ENDIF(CPU_i386)
SET(SSSE3_FLAG "-mssse3")
SET(SSE41_FLAG "-msse4.1")
ENDIF()
ENDIF(CPU_i386 OR CPU_amd64)

View File

@ -21,6 +21,7 @@ FUNCTION(CHECK_64BIT_TIME_SUPPORT)
# NOTE: ${CMAKE_MODULE_PATH} has two directories, macros/ and libs/, # NOTE: ${CMAKE_MODULE_PATH} has two directories, macros/ and libs/,
# so we have to configure this manually. # so we have to configure this manually.
SET(TIME64_SOURCE_PATH "${CMAKE_SOURCE_DIR}/cmake/macros") SET(TIME64_SOURCE_PATH "${CMAKE_SOURCE_DIR}/cmake/macros")
SET(TMP_TIME64_FOUND_TIME_BITS 0)
# Check for 64-bit time_t. # Check for 64-bit time_t.
MESSAGE(STATUS "Checking if time_t is 64-bit") MESSAGE(STATUS "Checking if time_t is 64-bit")
@ -56,14 +57,26 @@ FUNCTION(CHECK_64BIT_TIME_SUPPORT)
ELSE() ELSE()
# Try adding 64-bit time_t macros. # Try adding 64-bit time_t macros.
# Reference: https://sourceware.org/glibc/wiki/Y2038ProofnessDesign?rev=115 # Reference: https://sourceware.org/glibc/wiki/Y2038ProofnessDesign?rev=115
# NOTE: Requires LFS.
INCLUDE(CheckLargeFileSupport)
CHECK_LARGE_FILE_SUPPORT()
SET(TMP_TIME64_DEFINITIONS -D_TIME_BITS=64) SET(TMP_TIME64_DEFINITIONS -D_TIME_BITS=64)
TRY_COMPILE(TMP_TIME64_FOUND "${CMAKE_BINARY_DIR}" TRY_COMPILE(TMP_TIME64_FOUND "${CMAKE_BINARY_DIR}"
"${TIME64_SOURCE_PATH}/64BitTimeSupport.c" "${TIME64_SOURCE_PATH}/64BitTimeSupport.c"
COMPILE_DEFINITIONS ${TMP_TIME64_DEFINITIONS}) COMPILE_DEFINITIONS ${LFS_DEFINITIONS} ${TMP_TIME64_DEFINITIONS})
IF(TMP_TIME64_FOUND) IF(TMP_TIME64_FOUND)
# TIME64 macros work. # TIME64 macros work.
# FIXME: glibc-2.34's fcntl()/ioctl() redirection is broken in C++ mode.
TRY_COMPILE(TMP_TIME64_FCNTL_OK "${CMAKE_BINARY_DIR}"
"${TIME64_SOURCE_PATH}/64BitTimeSupportFcntl.cpp"
COMPILE_DEFINITIONS ${LFS_DEFINITIONS} ${TMP_TIME64_DEFINITIONS})
IF(TMP_TIME64_FCNTL_OK)
MESSAGE(STATUS "Checking if time_t is 64-bit - yes, using -D_TIME_BITS=64") MESSAGE(STATUS "Checking if time_t is 64-bit - yes, using -D_TIME_BITS=64")
SET(TMP_TIME64_FOUND_TIME_BITS 1) SET(TMP_TIME64_FOUND_TIME_BITS 1)
ELSE()
MESSAGE(STATUS "Checking if time_t is 64-bit - no, redirection is broken in C++")
UNSET(TMP_TIME64_DEFINITIONS)
ENDIF()
ELSE() ELSE()
# TIME64 macros failed. # TIME64 macros failed.
MESSAGE(STATUS "Checking if time_t is 64-bit - no") MESSAGE(STATUS "Checking if time_t is 64-bit - no")
@ -72,7 +85,7 @@ FUNCTION(CHECK_64BIT_TIME_SUPPORT)
ENDIF() ENDIF()
ENDIF() ENDIF()
SET(TIME64_FOUND ${TMP_TIME64_FOUND} CACHE INTERNAL "Is Large File Support available?") SET(TIME64_FOUND ${TMP_TIME64_FOUND} CACHE INTERNAL "Is 64-bit time_t available?")
SET(TIME64_FOUND_MINGW ${TMP_TIME64_FOUND_TIME_BITS} CACHE INTERNAL "64-bit time_t is available using -D__MINGW_USE_VC2005_COMPAT") SET(TIME64_FOUND_MINGW ${TMP_TIME64_FOUND_TIME_BITS} CACHE INTERNAL "64-bit time_t is available using -D__MINGW_USE_VC2005_COMPAT")
SET(TIME64_FOUND_TIME_BITS ${TMP_TIME64_FOUND_TIME_BITS} CACHE INTERNAL "64-bit time_t is available using -D_TIME_BITS=64") SET(TIME64_FOUND_TIME_BITS ${TMP_TIME64_FOUND_TIME_BITS} CACHE INTERNAL "64-bit time_t is available using -D_TIME_BITS=64")
SET(TIME64_DEFINITIONS "${TMP_TIME64_DEFINITIONS}" CACHE INTERNAL "Definitions required for 64-bit time_t") SET(TIME64_DEFINITIONS "${TMP_TIME64_DEFINITIONS}" CACHE INTERNAL "Definitions required for 64-bit time_t")

View File

@ -1,97 +0,0 @@
# - Check what flag is needed to activate C11 or C99 mode.
# CHECK_C11_C99_COMPILER_FLAG(VARIABLE)
#
# VARIABLE - variable to store the result
#
# This actually calls the check_c_source_compiles macro.
# See help for CheckCSourceCompiles for a listing of variables
# that can modify the build.
# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
# Based on CHECK_C_COMPILER_FLAG(). (CheckCCompilerFlag.cmake)
INCLUDE(CheckCSourceCompiles)
MACRO(CHECK_C11_C99_COMPILER_FLAG _RESULT)
# Flag listing borrowed from GNU autoconf's AC_PROG_CC_C99 macro.
UNSET(${_RESULT})
# MSVC doesn't allow setting the C standard.
IF(NOT MSVC)
# Check if C11 is present without any flags.
# gcc-5.1 uses C11 mode by default.
MESSAGE(STATUS "Checking if C11 is enabled by default:")
CHECK_C_SOURCE_COMPILES("
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L
#error C11 is not enabled
#endif
int main() { return 0; }" CHECK_C11_ENABLED_DEFAULT)
IF (${CHECK_C11_ENABLED_DEFAULT})
UNSET(${_RESULT})
MESSAGE(STATUS "Checking if C11 is enabled by default: yes")
ELSE()
MESSAGE(STATUS "Checking if C11 is enabled by default: no")
MESSAGE(STATUS "Checking what CFLAG is required for C11:")
FOREACH(CHECK_C11_CFLAG "-std=gnu11" "-std=c11" "-c99" "-AC99" "-xc99=all" "-qlanglvl=extc1x" "-qlanglvl=stdc11")
SET(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
SET(CMAKE_REQUIRED_DEFINITIONS "${CHECK_C11_CFLAG}")
CHECK_C_SOURCE_COMPILES("int main() { return 0; }" CFLAG_${CHECK_C11_CFLAG})
SET(CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
IF(CFLAG_${CHECK_C11_CFLAG})
SET(${_RESULT} ${CHECK_C11_CFLAG})
BREAK()
ENDIF(CFLAG_${CHECK_C11_CFLAG})
UNSET(CFLAG_${CHECK_C11_CFLAG})
ENDFOREACH()
IF(${_RESULT})
MESSAGE(STATUS "Checking what CFLAG is required for C11: ${${_RESULT}}")
ELSE(${_RESULT})
MESSAGE(STATUS "Checking what CFLAG is required for C11: unavailable")
ENDIF(${_RESULT})
ENDIF()
IF(NOT CHECK_C11_ENABLED_DEFAULT AND NOT ${_RESULT})
# Could not enable C11. Try C99 instead.
MESSAGE(STATUS "Checking if C99 is enabled by default:")
CHECK_C_SOURCE_COMPILES("
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
#error C99 is not enabled
#endif
int main() { return 0; }" CHECK_C99_ENABLED_DEFAULT)
IF (${CHECK_C99_ENABLED_DEFAULT})
UNSET(${_RESULT})
MESSAGE(STATUS "Checking if C99 is enabled by default: yes")
ELSE()
MESSAGE(STATUS "Checking if C99 is enabled by default: no")
MESSAGE(STATUS "Checking what CFLAG is required for C99:")
FOREACH(CHECK_C99_CFLAG "-std=gnu99" "-std=c99" "-c99" "-AC99" "-xc99=all" "-qlanglvl=extc99")
SET(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
SET(CMAKE_REQUIRED_DEFINITIONS "${CHECK_C99_CFLAG}")
CHECK_C_SOURCE_COMPILES("int main() { return 0; }" CFLAG_${CHECK_C99_CFLAG})
SET(CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
IF(CFLAG_${CHECK_C99_CFLAG})
SET(${_RESULT} ${CHECK_C99_CFLAG})
BREAK()
ENDIF(CFLAG_${CHECK_C99_CFLAG})
UNSET(CFLAG_${CHECK_C99_CFLAG})
ENDFOREACH()
IF(${_RESULT})
MESSAGE(STATUS "Checking what CFLAG is required for C99: ${${_RESULT}}")
ELSE(${_RESULT})
MESSAGE(STATUS "Checking what CFLAG is required for C99: unavailable")
ENDIF(${_RESULT})
ENDIF()
ENDIF(NOT CHECK_C11_ENABLED_DEFAULT AND NOT ${_RESULT})
UNSET(CHECK_C11_ENABLED_DEFAULT)
UNSET(CHECK_C99_ENABLED_DEFAULT)
ENDIF(NOT MSVC)
ENDMACRO(CHECK_C11_C99_COMPILER_FLAG)

View File

@ -1,67 +0,0 @@
# - Check what flag is needed to activate C++ 2011 mode.
# CHECK_CXX11_COMPILER_FLAG(VARIABLE)
#
# VARIABLE - variable to store the result
#
# This actually calls the check_c_source_compiles macro.
# See help for CheckCSourceCompiles for a listing of variables
# that can modify the build.
# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
# C++ 2011 version Copyright (c) 2011 by David Korth.
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
# Based on CHECK_C99_COMPILER_FLAG(). (CheckC99CompilerFlag.cmake)
INCLUDE(CheckCXXSourceCompiles)
MACRO(CHECK_CXX11_COMPILER_FLAG _RESULT)
UNSET(${_RESULT})
# MSVC doesn't allow setting the C standard.
IF(NOT MSVC)
# Check if C++ 2011 is present without any flags.
# g++-5.1 uses C++ 1998 by default, but this may change
# in future versions of gcc.
MESSAGE(STATUS "Checking if C++ 2011 is enabled by default:")
CHECK_CXX_SOURCE_COMPILES("
#if !defined(__cplusplus) || __cplusplus < 201103L
#error C++ 2011 is not enabled
#endif
int main() { return 0; }" CHECK_CXX11_ENABLED_DEFAULT)
IF (${CHECK_CXX11_ENABLED_DEFAULT})
UNSET(${_RESULT})
MESSAGE(STATUS "Checking if C++ 2011 is enabled by default: yes")
ELSE()
MESSAGE(STATUS "Checking if C++ 2011 is enabled by default: no")
MESSAGE(STATUS "Checking what CXXFLAG is required for C++ 2011:")
FOREACH(CHECK_CXX11_CXXFLAG "-std=gnu++11" "-std=gnu++0x" "-std=c++11" "-std=c++0x")
# CMake doesn't like "+" characters in variable names.
STRING(REPLACE "+" "_" CHECK_CXX11_CXXFLAG_VARNAME "CHECK_CXXFLAG_${CHECK_CXX11_CXXFLAG}")
SET(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
SET(CMAKE_REQUIRED_DEFINITIONS "${CHECK_CXX11_CXXFLAG}")
CHECK_CXX_SOURCE_COMPILES("int main() { static_assert(0 == 0, \"test assertion\"); return 0; }" ${CHECK_CXX11_CXXFLAG_VARNAME})
SET(CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}")
IF(${${CHECK_CXX11_CXXFLAG_VARNAME}})
SET(${_RESULT} ${CHECK_CXX11_CXXFLAG})
UNSET(${CHECK_CXX11_CXXFLAG_VARNAME})
UNSET(CHECK_CXX11_CXXFLAG_VARNAME)
BREAK()
ENDIF(${${CHECK_CXX11_CXXFLAG_VARNAME}})
UNSET(${CHECK_CXX11_CXXFLAG_VARNAME})
UNSET(CHECK_CXX11_CXXFLAG_VARNAME)
ENDFOREACH()
IF(${_RESULT})
MESSAGE(STATUS "Checking what CXXFLAG is required for C++ 2011: ${${_RESULT}}")
ELSE(${_RESULT})
MESSAGE(STATUS "Checking what CXXFLAG is required for C++ 2011: none")
ENDIF(${_RESULT})
ENDIF()
UNSET(CHECK_CXX11_ENABLED_DEFAULT)
ENDIF(NOT MSVC)
ENDMACRO(CHECK_CXX11_COMPILER_FLAG)

View File

@ -6,7 +6,7 @@
MACRO(CHECK_HIDDEN_VISIBILITY) MACRO(CHECK_HIDDEN_VISIBILITY)
# Check for visibility symbols. # Check for visibility symbols.
IF(NOT CMAKE_VERSION VERSION_LESS 3.3.0) IF(POLICY CMP0063)
# CMake 3.3: Use CMake predefined variables. # CMake 3.3: Use CMake predefined variables.
# NOTE: CMake 3.0-3.2 do not apply these settings # NOTE: CMake 3.0-3.2 do not apply these settings
# to static libraries, so we have to fall back to the # to static libraries, so we have to fall back to the

View File

@ -18,11 +18,15 @@
# - LFS_FOUND_FSEEKI64: Set to 1 if LFS is supported using _fseeki64(). # - LFS_FOUND_FSEEKI64: Set to 1 if LFS is supported using _fseeki64().
# - LFS_DEFINITIONS: Preprocessor macros required for large file support, if any. # - LFS_DEFINITIONS: Preprocessor macros required for large file support, if any.
# Additional variables are set based on the existance of types:
# - SIZEOF_OFF_T: sizeof(off_t), if available.
# - SIZEOF_OFF64_T: sizeof(off64_t), if available.
# TODO: Use _fseeki64() and _ftelli64() on MinGW to avoid # TODO: Use _fseeki64() and _ftelli64() on MinGW to avoid
# the use of wrapper functions? # the use of wrapper functions?
FUNCTION(CHECK_LARGE_FILE_SUPPORT) FUNCTION(CHECK_LARGE_FILE_SUPPORT)
IF(NOT DEFINED LFS_FOUND) IF(NOT DEFINED LFS_FOUND OR NOT DEFINED CHECKED_OFF_T)
# NOTE: ${CMAKE_MODULE_PATH} has two directories, macros/ and libs/, # NOTE: ${CMAKE_MODULE_PATH} has two directories, macros/ and libs/,
# so we have to configure this manually. # so we have to configure this manually.
SET(LFS_SOURCE_PATH "${CMAKE_SOURCE_DIR}/cmake/macros") SET(LFS_SOURCE_PATH "${CMAKE_SOURCE_DIR}/cmake/macros")
@ -51,21 +55,18 @@ FUNCTION(CHECK_LARGE_FILE_SUPPORT)
MESSAGE(STATUS "Checking if Large File Support is available - yes") MESSAGE(STATUS "Checking if Large File Support is available - yes")
ELSE() ELSE()
# Try adding LFS macros. # Try adding LFS macros.
SET(TMP_LFS_DEFINITIONS -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64) SET(TMP_LFS_DEFINITIONS_BITS -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64)
TRY_COMPILE(TMP_LFS_FOUND "${CMAKE_BINARY_DIR}" TRY_COMPILE(TMP_LFS_FOUND "${CMAKE_BINARY_DIR}"
"${LFS_SOURCE_PATH}/LargeFileSupport_fseeko.c" "${LFS_SOURCE_PATH}/LargeFileSupport_fseeko.c"
COMPILE_DEFINITIONS ${TMP_LFS_DEFINITIONS}) COMPILE_DEFINITIONS ${TMP_LFS_DEFINITIONS_BITS})
IF(TMP_LFS_FOUND) IF(TMP_LFS_FOUND)
# LFS macros work. # LFS macros work.
MESSAGE(STATUS "Checking if Large File Support is available - yes, using LFS macros") MESSAGE(STATUS "Checking if Large File Support is available - yes, using LFS macros")
SET(TMP_LFS_FOUND_FSEEKO 1) SET(TMP_LFS_FOUND_FSEEKO 1)
# NOTE: COMPILE_DEFINITIONS requires a semicolon-separated list; SET(TMP_LFS_DEFINITIONS "${TMP_LFS_DEFINITIONS_BITS}")
# CFLAGS reqiures space-separated.
STRING(REPLACE ";" " " TMP_LFS_DEFINITIONS "${TMP_LFS_DEFINITIONS}")
ELSE() ELSE()
# LFS macros failed. # LFS macros failed.
MESSAGE(STATUS "Checking if Large File Support is available - no") MESSAGE(STATUS "Checking if Large File Support is available - no")
UNSET(TMP_LFS_DEFINITIONS)
ENDIF() ENDIF()
ENDIF() ENDIF()
ENDIF() ENDIF()
@ -73,6 +74,23 @@ FUNCTION(CHECK_LARGE_FILE_SUPPORT)
SET(LFS_FOUND ${TMP_LFS_FOUND} CACHE INTERNAL "Is Large File Support available?") SET(LFS_FOUND ${TMP_LFS_FOUND} CACHE INTERNAL "Is Large File Support available?")
SET(LFS_FOUND_FSEEKO ${TMP_LFS_FOUND_FSEEKO} CACHE INTERNAL "Large File Support is available using LFS macros") SET(LFS_FOUND_FSEEKO ${TMP_LFS_FOUND_FSEEKO} CACHE INTERNAL "Large File Support is available using LFS macros")
SET(LFS_FOUND_FSEEKI64 ${TMP_LFS_FOUND_FSEEKI64} CACHE INTERNAL "Large File Support is available using MSVC non-standard functions") SET(LFS_FOUND_FSEEKI64 ${TMP_LFS_FOUND_FSEEKI64} CACHE INTERNAL "Large File Support is available using MSVC non-standard functions")
# Check for off_t and off64_t.
INCLUDE(CheckTypeSize)
SET(CMAKE_REQUIRED_INCLUDES "unistd.h")
SET(CMAKE_REQUIRED_DEFINITIONS ${TMP_LFS_DEFINITIONS})
CHECK_TYPE_SIZE("off_t" OFF_T)
# off64_t requires -D_LARGEFILE64_SOURCE.
SET(CMAKE_REQUIRED_DEFINITIONS "${TMP_LFS_DEFINITIONS};-D_LARGEFILE64_SOURCE")
CHECK_TYPE_SIZE("off64_t" OFF64_T)
IF(HAVE_OFF64_T)
SET(TMP_LFS_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}")
ENDIF(HAVE_OFF64_T)
SET(CHECKED_OFF_T "1" CACHE INTERNAL "off_t/off64_t were checked")
# NOTE: COMPILE_DEFINITIONS requires a semicolon-separated list;
# CFLAGS reqiures space-separated.
STRING(REPLACE ";" " " TMP_LFS_DEFINITIONS "${TMP_LFS_DEFINITIONS}")
SET(LFS_DEFINITIONS "${TMP_LFS_DEFINITIONS}" CACHE INTERNAL "Definitions required for Large File Support") SET(LFS_DEFINITIONS "${TMP_LFS_DEFINITIONS}" CACHE INTERNAL "Definitions required for Large File Support")
ENDIF() ENDIF()
ENDFUNCTION(CHECK_LARGE_FILE_SUPPORT) ENDFUNCTION(CHECK_LARGE_FILE_SUPPORT)

View File

@ -17,21 +17,24 @@
INCLUDE(CheckCSourceCompiles) INCLUDE(CheckCSourceCompiles)
MACRO(CHECK_STACK_PROTECTOR_COMPILER_FLAG _RESULT) FUNCTION(CHECK_STACK_PROTECTOR_COMPILER_FLAG _result)
UNSET(${_RESULT}) UNSET(${_result} PARENT_SCOPE)
IF(NOT DEFINED _SYS_STACK_PROTECTOR_COMPILER_FLAG)
IF(MSVC) IF(MSVC)
# MSVC 2002 introduced the /GS option. # MSVC 2002 introduced the /GS option.
# MSVC 2005+ enables it by default. # MSVC 2005+ enables it by default.
IF(MSVC_VERSION GREATER 1399) IF(MSVC_VERSION GREATER 1399)
# MSVC 2005+. # MSVC 2005+.
MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: none") SET(_SYS_STACK_PROTECTOR_COMPILER_FLAG "" CACHE INTERNAL "CFLAG required for stack smashing protection.")
MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: none, enabled by default")
ELSEIF(MSVC_VERSION GREATER 1299) ELSEIF(MSVC_VERSION GREATER 1299)
# MSVC 2002 or 2003. # MSVC 2002 or 2003.
SET(${_RESULT} "/GS") SET(_SYS_STACK_PROTECTOR_COMPILER_FLAG "/GS" CACHE INTERNAL "CFLAG required for stack smashing protection.")
MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: ${${_RESULT}}") MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: ${_SYS_STACK_PROTECTOR_COMPILER_FLAG}")
ELSE() ELSE()
# MSVC 2002 or earlier. # MSVC 2002 or earlier.
SET(_SYS_STACK_PROTECTOR_COMPILER_FLAG "" CACHE INTERNAL "CFLAG required for stack smashing protection.")
MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: not available") MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: not available")
ENDIF() ENDIF()
ELSE(MSVC) ELSE(MSVC)
@ -42,13 +45,13 @@ MACRO(CHECK_STACK_PROTECTOR_COMPILER_FLAG _RESULT)
# CMake doesn't like "+" characters in variable names. # CMake doesn't like "+" characters in variable names.
STRING(REPLACE "+" "_" CHECK_STACK_CFLAG_VARNAME "CHECK_CFLAG_${CHECK_STACK_CFLAG}") STRING(REPLACE "+" "_" CHECK_STACK_CFLAG_VARNAME "CHECK_CFLAG_${CHECK_STACK_CFLAG}")
SET(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}") SET(OLD_CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS})
SET(SAFE_CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}") SET(OLD_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
SET(CMAKE_REQUIRED_DEFINITIONS "${CHECK_STACK_CFLAG}") SET(CMAKE_REQUIRED_DEFINITIONS ${CHECK_STACK_CFLAG})
IF(WIN32) IF(WIN32)
SET(CMAKE_REQUIRED_LIBRARIES "-lkernel32") SET(CMAKE_REQUIRED_LIBRARIES kernel32)
ELSE(WIN32) ELSE(WIN32)
SET(CMAKE_REQUIRED_LIBRARIES "-lc") SET(CMAKE_REQUIRED_LIBRARIES c)
ENDIF(WIN32) ENDIF(WIN32)
# NOTE: We need a function that triggers stack smashing protection # NOTE: We need a function that triggers stack smashing protection
# in order to determine if libssp is needed on MinGW-w64. # in order to determine if libssp is needed on MinGW-w64.
@ -92,25 +95,25 @@ int main(int argc, char *argv[])
puts(buf); puts(buf);
return 0; return 0;
}" ${CHECK_STACK_CFLAG_VARNAME}) }" ${CHECK_STACK_CFLAG_VARNAME})
SET(CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}") SET(CMAKE_REQUIRED_DEFINITIONS ${OLD_CMAKE_REQUIRED_DEFINITIONS})
SET(CMAKE_REQUIRED_LIBRARIES "${SAFE_CMAKE_REQUIRED_LIBRARIES}") SET(CMAKE_REQUIRED_LIBRARIES ${OLD_CMAKE_REQUIRED_LIBRARIES})
UNSET(OLD_CMAKE_REQUIRED_INCLUDES)
UNSET(OLD_CMAKE_REQUIRED_LIBRARIES)
IF(${${CHECK_STACK_CFLAG_VARNAME}}) IF(${${CHECK_STACK_CFLAG_VARNAME}})
SET(${_RESULT} ${CHECK_STACK_CFLAG}) SET(_SYS_STACK_PROTECTOR_COMPILER_FLAG "${CHECK_STACK_CFLAG}" CACHE INTERNAL "CFLAG required for stack smashing protection.")
UNSET(${CHECK_STACK_CFLAG_VARNAME})
UNSET(CHECK_STACK_CFLAG_VARNAME)
BREAK() BREAK()
ENDIF(${${CHECK_STACK_CFLAG_VARNAME}}) ENDIF(${${CHECK_STACK_CFLAG_VARNAME}})
UNSET(${CHECK_STACK_CFLAG_VARNAME})
UNSET(CHECK_STACK_CFLAG_VARNAME)
UNSET(SAFE_CMAKE_REQUIRED_DEFINITIONS)
UNSET(SAFE_CMAKE_REQUIRED_LIBRARIES)
ENDFOREACH() ENDFOREACH()
IF(${_RESULT}) IF(_SYS_STACK_PROTECTOR_COMPILER_FLAG)
MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: ${${_RESULT}}") MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: ${_SYS_STACK_PROTECTOR_COMPILER_FLAG}")
ELSE(${_RESULT}) ELSE(_SYS_STACK_PROTECTOR_COMPILER_FLAG)
SET(_SYS_STACK_PROTECTOR_COMPILER_FLAG "" CACHE INTERNAL "CFLAG required for stack smashing protection.")
MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: not available") MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: not available")
MESSAGE(WARNING "Stack smashing protection is not available.\nPlease check your toolchain installation.") MESSAGE(WARNING "Stack smashing protection is not available.\nPlease check your toolchain installation.")
ENDIF(${_RESULT}) ENDIF(_SYS_STACK_PROTECTOR_COMPILER_FLAG)
ENDIF(MSVC) ENDIF(MSVC)
ENDMACRO(CHECK_STACK_PROTECTOR_COMPILER_FLAG) ENDIF(NOT DEFINED _SYS_STACK_PROTECTOR_COMPILER_FLAG)
SET(${_result} "${_SYS_STACK_PROTECTOR_COMPILER_FLAG}" PARENT_SCOPE)
ENDFUNCTION(CHECK_STACK_PROTECTOR_COMPILER_FLAG)

View File

@ -0,0 +1,41 @@
# Check if a symbol is available either as a regular function or an inline function.
# CHECK_SYMBOL_EXISTS_OR_INLINE(_function _header _sample_code _variable)
#
# _function - function name to check
# _header - header file
# _sample_code - sample code to compile
# _variable - variable to store the result
# Based on CHECK_SYMBOL_EXISTS(). (CheckSymbolExists.cmake)
INCLUDE(CheckSymbolExists)
INCLUDE(CheckCSourceCompiles)
MACRO(CHECK_SYMBOL_EXISTS_OR_INLINE _function _header _sample_code _variable)
# MinGW defines some reentrant functions as inline functions
# that are actually wrappers around MSVC "secure" functions.
# Check for the function as a regular function first, then check
# if it's available in the specified header.
IF(NOT DEFINED ${_variable})
CHECK_SYMBOL_EXISTS(${_function} ${_header} ${_variable})
IF(NOT ${_variable})
# Function does not exist normally.
# Check if it's an inline function in the specified header.
MESSAGE(STATUS "Looking for ${_function} as an inline function")
CHECK_C_SOURCE_COMPILES(
"#define _POSIX_SOURCE
#define _POSIX_C_SOURCE 1
#include <${_header}>
int main(void) { ${_sample_code} }"
${_variable}_INLINE)
IF(${_variable}_INLINE)
MESSAGE(STATUS "Looking for ${_variable} as an inline function - found")
SET(${_variable} 1 CACHE INTERNAL "Have function ${_variable} (inline)")
ELSE(${_variable}_INLINE)
MESSAGE(STATUS "Looking for ${_variable} as an inline function - not found")
# ${_variable} is already cached by CHECK_SYMBOL_EXISTS().
ENDIF(${_variable}_INLINE)
ENDIF(NOT ${_variable})
ENDIF(NOT DEFINED ${_variable})
ENDMACRO(CHECK_SYMBOL_EXISTS_OR_INLINE _function _header _sample_code _variable)

View File

@ -7,42 +7,88 @@
# be in the root of the Windows ZIP file. On other platforms, # be in the root of the Windows ZIP file. On other platforms,
# it's the same as DIR_INSTALL_DOC. # it's the same as DIR_INSTALL_DOC.
# TARGET_CPU_ARCH is set to indicate the target CPU architecture.
IF(NOT PACKAGE_NAME) IF(NOT PACKAGE_NAME)
MESSAGE(FATAL_ERROR "PACKAGE_NAME is not set.") MESSAGE(FATAL_ERROR "PACKAGE_NAME is not set.")
ENDIF(NOT PACKAGE_NAME) ENDIF(NOT PACKAGE_NAME)
# Architecture name for arch-specific paths. # Architecture name for arch-specific paths.
STRING(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" arch) INCLUDE(CPUInstructionSetFlags)
IF(arch MATCHES "^(i.|x)86$|^x86_64$|^amd64$") IF(CPU_amd64)
# i386/amd64. Check sizeof(void*) for the actual architecture,
# since building 32-bit on 64-bit isn't considered "cross-compiling",
# so CMAKE_SYSTEM_PROCESSOR might not be accurate.
# NOTE: Checking CMAKE_CL_64 instead of sizeof(void*) for MSVC builds.
IF(MSVC AND CMAKE_CL_64)
SET(arch "amd64") SET(arch "amd64")
ELSEIF(NOT MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8) ELSEIF(CPU_i386)
SET(arch "amd64")
ELSE()
SET(arch "i386") SET(arch "i386")
ELSEIF(CPU_ia64)
SET(arch "ia64")
ELSEIF(CPU_arm)
SET(arch "arm")
ELSEIF(CPU_arm64ec)
SET(arch "arm64ec")
ELSEIF(CPU_arm64)
SET(arch "arm64")
ELSEIF(CPU_ppc)
SET(arch "ppc")
ELSEIF(CPU_ppc64)
SET(arch "ppc64")
ELSEIF(CPU_ppc64le)
SET(arch "ppc64le")
ELSEIF(CPU_riscv32)
SET(arch "riscv32")
ELSEIF(CPU_riscv64)
SET(arch "riscv64")
ELSE()
MESSAGE(FATAL_ERROR "Unsupported CPU architecture, please fix!")
ENDIF() ENDIF()
ENDIF(arch MATCHES "^(i.|x)86$|^x86_64$|^amd64$") SET(TARGET_CPU_ARCH "${arch}")
INCLUDE(GNUInstallDirs) INCLUDE(GNUInstallDirs)
IF(UNIX AND NOT APPLE) IF(UNIX AND NOT APPLE)
# Unix-style install paths.
SET(DIR_INSTALL_EXE "${CMAKE_INSTALL_BINDIR}") SET(DIR_INSTALL_EXE "${CMAKE_INSTALL_BINDIR}")
SET(DIR_INSTALL_DLL "${CMAKE_INSTALL_LIBDIR}") SET(DIR_INSTALL_DLL "${CMAKE_INSTALL_LIBDIR}")
SET(DIR_INSTALL_LIB "${CMAKE_INSTALL_LIBDIR}") SET(DIR_INSTALL_LIB "${CMAKE_INSTALL_LIBDIR}")
SET(DIR_INSTALL_LOCALE "share/locale") SET(DIR_INSTALL_TRANSLATIONS "share/${PACKAGE_NAME}/translations")
SET(DIR_INSTALL_DOC "share/doc/${PACKAGE_NAME}") SET(DIR_INSTALL_DOC "share/doc/${PACKAGE_NAME}")
SET(DIR_INSTALL_DOC_ROOT "${DIR_INSTALL_DOC}") SET(DIR_INSTALL_DOC_ROOT "${DIR_INSTALL_DOC}")
SET(DIR_INSTALL_XDG_APPSTREAM "share/metainfo")
SET(DIR_INSTALL_XDG_ICONS "share/icons")
SET(DIR_INSTALL_XDG_DESKTOP "share/applications")
SET(DIR_INSTALL_EXE_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_EXE}") SET(DIR_INSTALL_EXE_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_EXE}")
SET(DIR_INSTALL_DLL_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_DLL}") SET(DIR_INSTALL_DLL_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_DLL}")
SET(DIR_INSTALL_LIB_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_LIB}") SET(DIR_INSTALL_LIB_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_LIB}")
IF(ENABLE_NIXOS)
# NixOS ends up with a double-path issue if CMAKE_INSTALL_PREFIX is specified here.
SET(DIR_INSTALL_EXE_DEBUG "lib/debug/${DIR_INSTALL_EXE}")
SET(DIR_INSTALL_DLL_DEBUG "lib/debug/${DIR_INSTALL_DLL}")
SET(DIR_INSTALL_LIB_DEBUG "lib/debug/${DIR_INSTALL_LIB}")
SET(DIR_INSTALL_LIBEXEC_DEBUG "lib/debug/${DIR_INSTALL_LIBEXEC}")
ELSE(ENABLE_NIXOS)
SET(DIR_INSTALL_EXE_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_EXE}")
SET(DIR_INSTALL_DLL_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_DLL}")
SET(DIR_INSTALL_LIB_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_LIB}")
SET(DIR_INSTALL_LIBEXEC_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_LIBEXEC}")
ENDIF(ENABLE_NIXOS)
# AppArmor profile directory
SET(DIR_INSTALL_APPARMOR "/etc/apparmor.d")
ELSEIF(APPLE) ELSEIF(APPLE)
# Mac OS X-style install paths. # Mac OS X-style install paths.
# Install should be relative to the application bundle. # Install should be relative to the application bundle.
# TODO: Not supported... # TODO: Optimize for bundles. For now, using the same layout as Linux.
MESSAGE(STATUS "WARNING: Mac OS X is not officially supported yet.") SET(DIR_INSTALL_EXE "${CMAKE_INSTALL_BINDIR}")
SET(DIR_INSTALL_DLL "${CMAKE_INSTALL_LIBDIR}")
SET(DIR_INSTALL_LIB "${CMAKE_INSTALL_LIBDIR}")
SET(DIR_INSTALL_TRANSLATIONS "share/${PACKAGE_NAME}/translations")
SET(DIR_INSTALL_DOC "share/doc/${PACKAGE_NAME}")
SET(DIR_INSTALL_DOC_ROOT "${DIR_INSTALL_DOC}")
UNSET(DIR_INSTALL_XDG_APPSTREAM)
UNSET(DIR_INSTALL_XDG_ICONS)
UNSET(DIR_INSTALL_XDG_DESKTOP)
SET(DIR_INSTALL_EXE_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_EXE}")
SET(DIR_INSTALL_DLL_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_DLL}")
SET(DIR_INSTALL_LIB_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_LIB}")
ELSEIF(WIN32) ELSEIF(WIN32)
# Win32-style install paths. # Win32-style install paths.
# Files are installed relative to root, since the # Files are installed relative to root, since the
@ -50,9 +96,13 @@ ELSEIF(WIN32)
SET(DIR_INSTALL_EXE ".") SET(DIR_INSTALL_EXE ".")
SET(DIR_INSTALL_DLL ".") SET(DIR_INSTALL_DLL ".")
SET(DIR_INSTALL_LIB ".") SET(DIR_INSTALL_LIB ".")
SET(DIR_INSTALL_LOCALE "locale") SET(DIR_INSTALL_TRANSLATIONS "translations")
SET(DIR_INSTALL_DOC "doc") SET(DIR_INSTALL_DOC "doc")
SET(DIR_INSTALL_DOC_ROOT ".") SET(DIR_INSTALL_DOC_ROOT ".")
UNSET(DIR_INSTALL_XDG_APPSTREAM)
UNSET(DIR_INSTALL_XDG_ICONS)
UNSET(DIR_INSTALL_XDG_DESKTOP)
SET(DIR_INSTALL_EXE_DEBUG "debug")
# Installing debug symbols for DLLs in the # Installing debug symbols for DLLs in the
# same directory as the DLL. # same directory as the DLL.
SET(DIR_INSTALL_EXE_DEBUG "${DIR_INSTALL_EXE}") SET(DIR_INSTALL_EXE_DEBUG "${DIR_INSTALL_EXE}")
@ -61,3 +111,4 @@ ELSEIF(WIN32)
ELSE() ELSE()
MESSAGE(WARNING "Installation paths have not been set up for this system.") MESSAGE(WARNING "Installation paths have not been set up for this system.")
ENDIF() ENDIF()
UNSET(arch)

View File

@ -37,18 +37,24 @@ IF(MSVC)
SET(OUTPUT_NAME_EXPR "${OUTPUT_NAME_EXPR_1}${OUTPUT_NAME_EXPR_2}") SET(OUTPUT_NAME_EXPR "${OUTPUT_NAME_EXPR_1}${OUTPUT_NAME_EXPR_2}")
SET(OUTPUT_NAME_FULL "${PREFIX_EXPR_FULL}${OUTPUT_NAME_EXPR}$<TARGET_PROPERTY:${_target},POSTFIX>") SET(OUTPUT_NAME_FULL "${PREFIX_EXPR_FULL}${OUTPUT_NAME_EXPR}$<TARGET_PROPERTY:${_target},POSTFIX>")
SET(SPLITDEBUG_SOURCE "$<TARGET_FILE:${_target}>")
SET(SPLITDEBUG_TARGET "$<TARGET_FILE_DIR:${_target}>/${OUTPUT_NAME_FULL}.debug")
SET(OUTPUT_NAME_EXPR_1 "$<TARGET_PROPERTY:${_target},PREFIX>$<TARGET_PROPERTY:${_target},OUTPUT_NAME>$<TARGET_PROPERTY:${_target},POSTFIX>") SET(OUTPUT_NAME_EXPR_1 "$<TARGET_PROPERTY:${_target},PREFIX>$<TARGET_PROPERTY:${_target},OUTPUT_NAME>$<TARGET_PROPERTY:${_target},POSTFIX>")
SET(OUTPUT_NAME_EXPR_2 "$<$<STREQUAL:$<TARGET_PROPERTY:${_target},OUTPUT_NAME>,>:$<TARGET_PROPERTY:${_target},PREFIX>${_target}$<TARGET_PROPERTY:${_target},POSTFIX>>") SET(OUTPUT_NAME_EXPR_2 "$<$<STREQUAL:$<TARGET_PROPERTY:${_target},OUTPUT_NAME>,>:$<TARGET_PROPERTY:${_target},PREFIX>${_target}$<TARGET_PROPERTY:${_target},POSTFIX>>")
# FIXME: "-dll" suffix seems to be missing here.
# If it's present in the target name, add it here.
IF(${_target} MATCHES "-dll$")
SET(_target_suffix "-dll")
ELSE()
UNSET(_target_suffix)
ENDIF()
# Set the target PDB filename. # Set the target PDB filename.
SET_TARGET_PROPERTIES(${_target} SET_TARGET_PROPERTIES(${_target}
PROPERTIES PDB "$<TARGET_FILE_DIR:${_target}>/${OUTPUT_NAME_EXPR_1}${OUTPUT_NAME_EXPR_2}.pdb" PROPERTIES PDB "$<TARGET_FILE_DIR:${_target}>/${OUTPUT_NAME_EXPR_1}${OUTPUT_NAME_EXPR_2}${_target_suffix}.pdb"
) )
UNSET(OUTPUT_NAME_EXPR_1) UNSET(OUTPUT_NAME_EXPR_1)
UNSET(OUTPUT_NAME_EXPR_2) UNSET(OUTPUT_NAME_EXPR_2)
UNSET(_target_suffix)
ENDIF(MSVC) ENDIF(MSVC)
ENDMACRO(SET_MSVC_DEBUG_PATH) ENDMACRO(SET_MSVC_DEBUG_PATH)

View File

@ -15,10 +15,10 @@ IF(NOT MSVC)
INCLUDE(CMakeFindBinUtils) INCLUDE(CMakeFindBinUtils)
IF(NOT CMAKE_OBJCOPY) IF(NOT CMAKE_OBJCOPY)
MESSAGE(WARNING "'objcopy' was not found; debug information will not be split.") MESSAGE(WARNING "'objcopy' was not found; debug information will not be split.")
SET(INSTALL_DEBUG OFF CACHE "" INTERNAL FORCE) SET(INSTALL_DEBUG OFF CACHE INTERNAL "Install the split debug files." FORCE)
ELSEIF(NOT CMAKE_STRIP) ELSEIF(NOT CMAKE_STRIP)
MESSAGE(WARNING "'strip' was not found; debug information will not be split.") MESSAGE(WARNING "'strip' was not found; debug information will not be split.")
SET(INSTALL_DEBUG OFF CACHE "" INTERNAL FORCE) SET(INSTALL_DEBUG OFF CACHE INTERNAL "Install the split debug files." FORCE)
ENDIF() ENDIF()
ENDIF(NOT MSVC) ENDIF(NOT MSVC)
@ -36,6 +36,29 @@ ELSEIF(NOT CMAKE_STRIP)
ENDIF() ENDIF()
IF(SPLIT_OK) IF(SPLIT_OK)
# If the linker doesn't support --compress-debug-sections=zlib,
# check if objcopy supports --compress-debug-sections.
IF(LDFLAG_--compress-debug-sections)
# ld supports --compress-debug-sections=zlib.
SET(OBJCOPY_COMPRESS_DEBUG_SECTIONS_PARAM "" CACHE INTERNAL "objcopy parameter to compress debug sections.")
ELSEIF(NOT LDFLAG_--compress-debug-sections AND NOT DEFINED OBJCOPY_COMPRESS_DEBUG_SECTIONS_PARAM)
# Check for objcopy --compress-debug-sections.
MESSAGE(STATUS "Checking if objcopy supports --compress-debug-sections")
EXECUTE_PROCESS(COMMAND ${CMAKE_OBJCOPY} --help
OUTPUT_VARIABLE _xc_out
ERROR_QUIET)
IF(_xc_out MATCHES "--compress-debug-sections")
# objcopy has --compress-debug-sections.
MESSAGE(STATUS "Checking if objcopy supports --compress-debug-sections - yes")
SET(OBJCOPY_COMPRESS_DEBUG_SECTIONS_PARAM "--compress-debug-sections" CACHE INTERNAL "objcopy parameter to compress debug sections.")
ELSE()
# objcopy does *not* have --compress-debug-sections.
MESSAGE(STATUS "Checking if objcopy supports --compress-debug-sections - no")
SET(OBJCOPY_COMPRESS_DEBUG_SECTIONS_PARAM "" CACHE INTERNAL "objcopy parameter to compress debug sections.")
ENDIF()
UNSET(_xc_out)
ENDIF()
# Handle target prefixes if not overridden. # Handle target prefixes if not overridden.
# NOTE: Cannot easily use the TYPE property in a generator expression... # NOTE: Cannot easily use the TYPE property in a generator expression...
GET_PROPERTY(TARGET_TYPE TARGET ${_target} PROPERTY TYPE) GET_PROPERTY(TARGET_TYPE TARGET ${_target} PROPERTY TYPE)
@ -59,12 +82,15 @@ IF(SPLIT_OK)
# - .strtab: String table. # - .strtab: String table.
# These sections are split into the .debug file, so there's # These sections are split into the .debug file, so there's
# no reason to keep them in the executable. # no reason to keep them in the executable.
# NOTE 2: `mold-2.2.0` adds a bogus .gnu_debuglink section.
# Make sure we explicitly remove it with `strip`.
ADD_CUSTOM_COMMAND(TARGET ${_target} POST_BUILD ADD_CUSTOM_COMMAND(TARGET ${_target} POST_BUILD
COMMAND ${CMAKE_OBJCOPY} --only-keep-debug COMMAND ${CMAKE_OBJCOPY} --only-keep-debug ${OBJCOPY_COMPRESS_DEBUG_SECTIONS_PARAM}
${SPLITDEBUG_SOURCE} ${SPLITDEBUG_TARGET} ${SPLITDEBUG_SOURCE} ${SPLITDEBUG_TARGET}
COMMAND ${CMAKE_STRIP} COMMAND ${CMAKE_OBJCOPY}
${SPLITDEBUG_SOURCE} --strip-all
COMMAND ${CMAKE_OBJCOPY} --add-gnu-debuglink="${SPLITDEBUG_TARGET}" --remove-section=.gnu_debuglink
--add-gnu-debuglink="${SPLITDEBUG_TARGET}"
${SPLITDEBUG_SOURCE} ${SPLITDEBUG_SOURCE}
) )

View File

@ -1,13 +1,22 @@
# Build options. # Build options.
# Enable UDEV on Linux. OPTION(ENABLE_WERROR "Treat all compile warnings as errors. (Enable for development!)" OFF)
# Enable UDEV on Linux
IF(UNIX AND NOT APPLE) IF(UNIX AND NOT APPLE)
OPTION(ENABLE_UDEV "Enable UDEV for the 'query' command." ON) OPTION(ENABLE_UDEV "Enable UDEV for the 'query' command." ON)
ELSE() ELSE()
SET(ENABLE_UDEV OFF CACHE "Enable UDEV for the 'query' command." INTERAL FORCE) SET(ENABLE_UDEV OFF CACHE INTERNAL "Enable UDEV for the 'query' command." FORCE)
ENDIF() ENDIF()
# Link-time optimization. # Enable D-Bus for DockManager / Unity API
IF(UNIX AND NOT APPLE)
OPTION(ENABLE_DBUS "Enable D-Bus support for DockManager / Unity API." 1)
ELSE(UNIX AND NOT APPLE)
SET(ENABLE_DBUS 0)
ENDIF(UNIX AND NOT APPLE)
# Link-time optimization
# FIXME: Not working in clang builds and Ubuntu's gcc... # FIXME: Not working in clang builds and Ubuntu's gcc...
IF(MSVC) IF(MSVC)
SET(LTO_DEFAULT ON) SET(LTO_DEFAULT ON)
@ -16,12 +25,41 @@ ELSE()
ENDIF() ENDIF()
OPTION(ENABLE_LTO "Enable link-time optimization in release builds." ${LTO_DEFAULT}) OPTION(ENABLE_LTO "Enable link-time optimization in release builds." ${LTO_DEFAULT})
# Split debug information into a separate file. # Split debug information into a separate file
# FIXME: macOS `strip` shows an error:
# error: symbols referenced by indirect symbol table entries that can't be stripped in: [library]
IF(APPLE)
OPTION(SPLIT_DEBUG "Split debug information into a separate file." OFF)
ELSE(APPLE)
OPTION(SPLIT_DEBUG "Split debug information into a separate file." ON) OPTION(SPLIT_DEBUG "Split debug information into a separate file." ON)
ENDIF(APPLE)
# Install the split debug file. # Install the split debug file
OPTION(INSTALL_DEBUG "Install the split debug files." ON) OPTION(INSTALL_DEBUG "Install the split debug files." ON)
IF(INSTALL_DEBUG AND NOT SPLIT_DEBUG) IF(INSTALL_DEBUG AND NOT SPLIT_DEBUG)
# Cannot install debug files if we're not splitting them. # Cannot install debug files if we're not splitting them.
SET(INSTALL_DEBUG OFF CACHE "Install the split debug files." INTERNAL FORCE) SET(INSTALL_DEBUG OFF CACHE INTERNAL "Install the split debug files." FORCE)
ENDIF(INSTALL_DEBUG AND NOT SPLIT_DEBUG) ENDIF(INSTALL_DEBUG AND NOT SPLIT_DEBUG)
# Qt version
SET(QT_VERSION AUTO CACHE STRING "Qt version to use (default is 'AUTO' to auto-detect Qt6 or Qt5)")
SET_PROPERTY(CACHE QT_VERSION PROPERTY STRINGS AUTO 6 5)
# Enable KDE integration (defaults to ON on Linux)
IF(WIN32 OR APPLE)
SET(ENABLE_KDE_DEFAULT OFF)
ELSE(WIN32 OR APPLE)
SET(ENABLE_KDE_DEFAULT ON)
ENDIF(WIN32 OR APPLE)
OPTION(ENABLE_KDE "Enable KDE integration." ${ENABLE_KDE_DEFAULT})
# Translations
OPTION(ENABLE_NLS "Enable NLS using Qt's built-in localization system." ON)
# Special handling for NixOS
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
OPTION(ENABLE_NIXOS "Enable special handling for NixOS builds." OFF)
ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
# Install documentation
OPTION(INSTALL_DOC "Install documentation." ON)

View File

@ -36,6 +36,12 @@ ENDIF(NOT HAVE_STDINT_H)
# - RP_EXE_LINKER_FLAGS_RELEASE # - RP_EXE_LINKER_FLAGS_RELEASE
# - RP_SHARED_LINKER_FLAGS_RELEASE # - RP_SHARED_LINKER_FLAGS_RELEASE
# - RP_MODULE_LINKER_FLAGS_RELEASE # - RP_MODULE_LINKER_FLAGS_RELEASE
# [RelWithDebInfo]
# - RP_C_FLAGS_RELWITHDEBINFO
# - RP_CXX_FLAGS_RELWITHDEBINFO
# - RP_EXE_LINKER_FLAGS_RELWITHDEBINFO
# - RP_SHARED_LINKER_FLAGS_RELWITHDEBINFO
# - RP_MODULE_LINKER_FLAGS_RELWITHDEBINFO
# #
# DEBUG and RELEASE variables do *not* include COMMON. # DEBUG and RELEASE variables do *not* include COMMON.
IF(MSVC) IF(MSVC)
@ -98,6 +104,12 @@ SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${RP_CXX_FLAGS_RELEASE}
SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${RP_EXE_LINKER_FLAGS_RELEASE}") SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${RP_EXE_LINKER_FLAGS_RELEASE}")
SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${RP_SHARED_LINKER_FLAGS_RELEASE}") SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${RP_SHARED_LINKER_FLAGS_RELEASE}")
SET(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} ${RP_MODULE_LINKER_FLAGS_RELEASE}") SET(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} ${RP_MODULE_LINKER_FLAGS_RELEASE}")
# RelWithDebInfo
SET(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${RP_C_FLAGS_RELWITHDEBINFO}")
SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${RP_CXX_FLAGS_RELWITHDEBINFO}")
SET(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} ${RP_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
SET(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} ${RP_SHARED_LINKER_FLAGS_RELWITHDEBINFO}")
SET(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO} ${RP_MODULE_LINKER_FLAGS_RELWITHDEBINFO}")
# Unset temporary variables. # Unset temporary variables.
# Common # Common
@ -164,10 +176,8 @@ IF(WIN32)
SET(SETARGV_FLAG "setargv.obj") SET(SETARGV_FLAG "setargv.obj")
ENDIF() ENDIF()
ENDIF(_setargv) ENDIF(_setargv)
UNSET(UNICODE_FLAG)
ELSE(MSVC) ELSE(MSVC)
# MinGW does not automatically prepend an underscore. # MinGW does not automatically prepend an underscore.
# TODO: Does ARM Windows have a leading underscore?
# TODO: _setargv for MinGW. # TODO: _setargv for MinGW.
# NOTE: MinGW uses separate crt*.o files for Unicode # NOTE: MinGW uses separate crt*.o files for Unicode
@ -177,18 +187,12 @@ IF(WIN32)
STRING(SUBSTRING "${_entrypoint}" 1 -1 _entrypoint) STRING(SUBSTRING "${_entrypoint}" 1 -1 _entrypoint)
ENDIF() ENDIF()
STRING(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" arch) IF(CPU_i386)
IF(arch MATCHES "^(i.|x)86$|^x86_64$|^amd64$")
IF(CMAKE_SIZEOF_VOID_P EQUAL 4)
SET(ENTRY_POINT "_${_entrypoint}CRTStartup") SET(ENTRY_POINT "_${_entrypoint}CRTStartup")
ELSE() ELSE(CPU_i386)
SET(ENTRY_POINT "${_entrypoint}CRTStartup") SET(ENTRY_POINT "${_entrypoint}CRTStartup")
ENDIF() ENDIF(CPU_i386)
ELSE()
SET(ENTRY_POINT "${_entrypoint}CRTStartup")
ENDIF(arch MATCHES "^(i.|x)86$|^x86_64$|^amd64$")
SET(ENTRY_POINT_FLAG "-Wl,-e,${ENTRY_POINT}") SET(ENTRY_POINT_FLAG "-Wl,-e,${ENTRY_POINT}")
UNSET(SETARGV_FLAG)
ENDIF(MSVC) ENDIF(MSVC)
GET_TARGET_PROPERTY(TARGET_LINK_FLAGS ${_target} LINK_FLAGS) GET_TARGET_PROPERTY(TARGET_LINK_FLAGS ${_target} LINK_FLAGS)
@ -198,5 +202,8 @@ IF(WIN32)
SET(TARGET_LINK_FLAGS "${UNICODE_FLAG} ${ENTRY_POINT_FLAG} ${SETARGV_FLAG}") SET(TARGET_LINK_FLAGS "${UNICODE_FLAG} ${ENTRY_POINT_FLAG} ${SETARGV_FLAG}")
ENDIF() ENDIF()
SET_TARGET_PROPERTIES(${_target} PROPERTIES LINK_FLAGS "${TARGET_LINK_FLAGS}") SET_TARGET_PROPERTIES(${_target} PROPERTIES LINK_FLAGS "${TARGET_LINK_FLAGS}")
UNSET(UNICODE_FLAG)
UNSET(ENTRY_POINT_FLAG)
UNSET(SETARGV_FLAG)
ENDIF(WIN32) ENDIF(WIN32)
ENDFUNCTION() ENDFUNCTION()

View File

@ -0,0 +1,26 @@
/**
* DT_RELR test code
*/
#include <stdlib.h>
#include <stdio.h>
// Minimum glibc version requirements.
#if defined(__GLIBC__)
# if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 36)
# error glibc-2.36 is required for DT_RELR
# endif
#else
# error TODO: Detect DT_RELR on non-glibc platforms
#endif
void test_print(const char *a, const char *b)
{
printf("%s %s\n", a, b);
}
int main(void)
{
const char *tbl[] = {"quack", "moo"};
test_print(tbl[0], tbl[1]);
return 0;
}

View File

@ -14,45 +14,64 @@ ENDIF()
INCLUDE(CheckCCompilerFlag) INCLUDE(CheckCCompilerFlag)
INCLUDE(CheckCXXCompilerFlag) INCLUDE(CheckCXXCompilerFlag)
# Check what flag is needed for C11 and/or C99 support. SET(RP_C_FLAGS_COMMON "")
INCLUDE(CheckC11C99CompilerFlag) SET(RP_CXX_FLAGS_COMMON "")
CHECK_C11_C99_COMPILER_FLAG(RP_C11_CFLAG)
# Check what flag is needed for C++ 2011 support.
INCLUDE(CheckCXX11CompilerFlag)
CHECK_CXX11_COMPILER_FLAG(RP_CXX11_CXXFLAG)
SET(RP_C_FLAGS_COMMON "-D_GNU_SOURCE=1 ${RP_C11_CFLAG}")
SET(RP_CXX_FLAGS_COMMON "-D_GNU_SOURCE=1 ${RP_CXX11_CXXFLAG}")
SET(RP_EXE_LINKER_FLAGS_COMMON "") SET(RP_EXE_LINKER_FLAGS_COMMON "")
UNSET(RP_C11_CFLAG) # _GNU_SOURCE is needed for memmem() and statx().
UNSET(RP_CXX11_CXXFLAG) ADD_DEFINITIONS(-D_GNU_SOURCE=1)
UNSET(RP_CXX_NO_RTTI_CXXFLAG)
UNSET(RP_CXX_NO_EXCEPTIONS_CXXFLAG)
UNSET(RP_STACK_CFLAG)
# Test for common CFLAGS and CXXFLAGS. # Test for common CFLAGS and CXXFLAGS.
FOREACH(FLAG_TEST "-Wall" "-Wextra" "-fstrict-aliasing" "-Wno-multichar") # NOTE: Not adding -Werror=format-nonliteral because there are some
CHECK_C_COMPILER_FLAG("${FLAG_TEST}" CFLAG_${FLAG_TEST}) # legitimate uses of non-literal format strings.
IF(CFLAG_${FLAG_TEST}) SET(CFLAGS_WARNINGS -Wall -Wextra -Wno-multichar -Werror=return-type -Wheader-hygiene -Wno-psabi)
SET(CFLAGS_WERROR_FORMAT -Werror=format -Werror=format-security -Werror=format-signedness -Werror=format-truncation -Werror=format-y2k)
SET(CFLAGS_OPTIONS -fstrict-aliasing -Werror=strict-aliasing -fno-common -fcf-protection -fno-math-errno)
IF(MINGW)
# MinGW: Ignore warnings caused by casting from GetProcAddress().
SET(CFLAGS_WARNINGS ${CFLAGS_WARNINGS} -Wno-cast-function-type)
ENDIF(MINGW)
FOREACH(FLAG_TEST ${CFLAGS_WARNINGS} ${CFLAGS_WERROR_FORMAT} ${CFLAGS_OPTIONS})
# CMake doesn't like certain characters in variable names.
STRING(REGEX REPLACE "/|:|=" "_" FLAG_TEST_VARNAME "${FLAG_TEST}")
CHECK_C_COMPILER_FLAG("${FLAG_TEST}" CFLAG_${FLAG_TEST_VARNAME})
IF(CFLAG_${FLAG_TEST_VARNAME})
SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${FLAG_TEST}") SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${FLAG_TEST}")
ENDIF(CFLAG_${FLAG_TEST}) ENDIF(CFLAG_${FLAG_TEST_VARNAME})
UNSET(CFLAG_${FLAG_TEST}) UNSET(CFLAG_${FLAG_TEST_VARNAME})
CHECK_CXX_COMPILER_FLAG("${FLAG_TEST}" CXXFLAG_${FLAG_TEST}) CHECK_CXX_COMPILER_FLAG("${FLAG_TEST}" CXXFLAG_${FLAG_TEST_VARNAME})
IF(CXXFLAG_${FLAG_TEST}) IF(CXXFLAG_${FLAG_TEST_VARNAME})
SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${FLAG_TEST}") SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${FLAG_TEST}")
ENDIF(CXXFLAG_${FLAG_TEST}) ENDIF(CXXFLAG_${FLAG_TEST_VARNAME})
UNSET(CXXFLAG_${FLAG_TEST}) UNSET(CXXFLAG_${FLAG_TEST_VARNAME})
ENDFOREACH() ENDFOREACH(FLAG_TEST)
# -Wimplicit-function-declaration should be an error. (C only) # Certain warnings should be errors. (C only)
CHECK_C_COMPILER_FLAG("-Werror=implicit-function-declaration" CFLAG_IMPLFUNC) SET(CFLAGS_WERROR_C_ONLY -Werror=implicit -Werror=implicit-function-declaration -Werror=incompatible-pointer-types -Werror=int-conversion)
IF(CFLAG_IMPLFUNC) FOREACH(FLAG_TEST ${CFLAGS_WERROR_C_ONLY})
SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} -Werror=implicit-function-declaration") # CMake doesn't like certain characters in variable names.
ENDIF(CFLAG_IMPLFUNC) STRING(REGEX REPLACE "/|:|=" "_" FLAG_TEST_VARNAME "${FLAG_TEST}")
UNSET(CFLAG_IMPLFUNC)
CHECK_C_COMPILER_FLAG("${FLAG_TEST}" CFLAG_${FLAG_TEST_VARNAME})
IF(CFLAG_${FLAG_TEST_VARNAME})
SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${FLAG_TEST}")
ENDIF(CFLAG_${FLAG_TEST_VARNAME})
UNSET(CFLAG_${FLAG_TEST_VARNAME})
ENDFOREACH(FLAG_TEST)
# Enable "suggest override" if available. (C++ only)
# NOTE: If gcc, only enable on 9.2 and later, since earlier versions
# will warn if a function is marked 'final' but not 'override'
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78010
IF(NOT CMAKE_COMPILER_IS_GNUCC OR (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.1))
CHECK_CXX_COMPILER_FLAG("-Wsuggest-override" CXXFLAG_SUGGEST_OVERRIDE)
IF(CXXFLAG_SUGGEST_OVERRIDE)
SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} -Wsuggest-override -Wno-error=suggest-override")
ENDIF(CXXFLAG_SUGGEST_OVERRIDE)
UNSET(CXXFLAG_SUGGEST_OVERRIDE)
ENDIF(NOT CMAKE_COMPILER_IS_GNUCC OR (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.1))
# Code coverage checking. # Code coverage checking.
IF(ENABLE_COVERAGE) IF(ENABLE_COVERAGE)
@ -70,19 +89,10 @@ IF(ENABLE_COVERAGE)
# Don't bother checking for the coverage options. # Don't bother checking for the coverage options.
# We're assuming they're always supported. # We're assuming they're always supported.
SET(RP_C_FLAGS_COVERAGE "--coverage -fprofile-arcs -ftest-coverage") SET(RP_C_FLAGS_COVERAGE "--coverage -fprofile-arcs -ftest-coverage -fprofile-update=atomic")
SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${RP_C_FLAGS_COVERAGE}") SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${RP_C_FLAGS_COVERAGE}")
SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${RP_C_FLAGS_COVERAGE}") SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${RP_C_FLAGS_COVERAGE}")
SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${RP_C_FLAGS_COVERAGE}")
# Link gcov to all targets.
SET(GCOV_LIBRARY "-lgcov")
FOREACH(VAR "" C_ CXX_)
IF(CMAKE_${VAR}STANDARD_LIBRARIES)
SET(CMAKE_${VAR}STANDARD_LIBRARIES "${CMAKE_${VAR}STANDARD_LIBRARIES} ${GCOV_LIBRARY}")
ELSE(CMAKE_${VAR}STANDARD_LIBRARIES)
SET(CMAKE_${VAR}STANDARD_LIBRARIES "${GCOV_LIBRARY}")
ENDIF(CMAKE_${VAR}STANDARD_LIBRARIES)
ENDFOREACH(VAR)
# Create a code coverage target. # Create a code coverage target.
FOREACH(_program gcov lcov genhtml) FOREACH(_program gcov lcov genhtml)
@ -100,30 +110,141 @@ IF(ENABLE_COVERAGE)
ENDIF(ENABLE_COVERAGE) ENDIF(ENABLE_COVERAGE)
# Test for common LDFLAGS. # Test for common LDFLAGS.
# TODO: Doesn't work on OS X. (which means it's not really testing it!) # NOTE: CHECK_C_COMPILER_FLAG() doesn't seem to work, even with
IF(NOT APPLE) # CMAKE_TRY_COMPILE_TARGET_TYPE. Check `ld --help` for the various
FOREACH(FLAG_TEST "-Wl,-O1" "-Wl,--sort-common" "-Wl,--as-needed" "-Wl,-Bsymbolic-functions") # parameters instead.
CHECK_C_COMPILER_FLAG("${FLAG_TEST}" LDFLAG_${FLAG_TEST}) EXECUTE_PROCESS(COMMAND ${CMAKE_LINKER} --help
OUTPUT_VARIABLE _ld_out
ERROR_QUIET)
FOREACH(FLAG_TEST "--sort-common" "--as-needed" "--build-id" "-Bsymbolic-functions" "--no-undefined" "--no-allow-shlib-undefined")
IF(NOT DEFINED LDFLAG_${FLAG_TEST})
MESSAGE(STATUS "Checking if ld supports ${FLAG_TEST}")
IF(_ld_out MATCHES "${FLAG_TEST}")
MESSAGE(STATUS "Checking if ld supports ${FLAG_TEST} - yes")
SET(LDFLAG_${FLAG_TEST} 1 CACHE INTERNAL "Linker supports ${FLAG_TEST}")
ELSE()
MESSAGE(STATUS "Checking if ld supports ${FLAG_TEST} - no")
SET(LDFLAG_${FLAG_TEST} "" CACHE INTERNAL "Linker supports ${FLAG_TEST}")
ENDIF()
ENDIF()
IF(LDFLAG_${FLAG_TEST}) IF(LDFLAG_${FLAG_TEST})
SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} ${FLAG_TEST}") SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} -Wl,${FLAG_TEST}")
ENDIF(LDFLAG_${FLAG_TEST}) ENDIF(LDFLAG_${FLAG_TEST})
UNSET(LDFLAG_${FLAG_TEST})
ENDFOREACH() ENDFOREACH()
# Special case for -O/-O1.
SET(FLAG_TEST "-O")
IF(NOT DEFINED LDFLAG_${FLAG_TEST})
MESSAGE(STATUS "Checking if ld supports ${FLAG_TEST}")
IF(_ld_out MATCHES "${FLAG_TEST}")
MESSAGE(STATUS "Checking if ld supports ${FLAG_TEST} - yes")
SET(LDFLAG_${FLAG_TEST} 1 CACHE INTERNAL "Linker supports ${FLAG_TEST}")
ELSE()
MESSAGE(STATUS "Checking if ld supports ${FLAG_TEST} - no")
SET(LDFLAG_${FLAG_TEST} "" CACHE INTERNAL "Linker supports ${FLAG_TEST}")
ENDIF()
ENDIF()
IF(LDFLAG_${FLAG_TEST})
SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} -Wl,-O1")
ENDIF(LDFLAG_${FLAG_TEST})
UNSET(FLAG_TEST)
# Special case for --compress-debug-sections.
SET(FLAG_TEST "--compress-debug-sections")
IF(NOT DEFINED LDFLAG_${FLAG_TEST})
MESSAGE(STATUS "Checking if ld supports ${FLAG_TEST}")
IF(CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
# FIXME: Do an actual runtime test.
# NetBSD/OpenBSD ld has the option, but it fails at runtime:
# ld: error: --compress-debug-sections: zlib is not available
MESSAGE(STATUS "Checking if ld supports ${FLAG_TEST} - yes, but not usable")
SET(LDFLAG_${FLAG_TEST} "" CACHE INTERNAL "Linker supports ${FLAG_TEST}")
ELSEIF(_ld_out MATCHES "${FLAG_TEST}")
MESSAGE(STATUS "Checking if ld supports ${FLAG_TEST} - yes")
SET(LDFLAG_${FLAG_TEST} 1 CACHE INTERNAL "Linker supports ${FLAG_TEST}")
ELSE()
MESSAGE(STATUS "Checking if ld supports ${FLAG_TEST} - no")
SET(LDFLAG_${FLAG_TEST} "" CACHE INTERNAL "Linker supports ${FLAG_TEST}")
ENDIF()
ENDIF()
IF(LDFLAG_${FLAG_TEST})
SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} -Wl,${FLAG_TEST}=zlib")
ENDIF(LDFLAG_${FLAG_TEST})
UNSET(FLAG_TEST)
IF(NOT WIN32) IF(NOT WIN32)
# Bsymbolic-functions doesn't make sense on Windows. # Bsymbolic-functions doesn't make sense on Windows.
FOREACH(FLAG_TEST "-Wl,-Bsymbolic-functions") FOREACH(FLAG_TEST "-Bsymbolic-functions")
CHECK_C_COMPILER_FLAG("${FLAG_TEST}" LDFLAG_${FLAG_TEST}) IF(NOT DEFINED LDFLAG_${FLAG_TEST})
MESSAGE(STATUS "Checking if ld supports ${FLAG_TEST}")
IF(_ld_out MATCHES "${FLAG_TEST}")
MESSAGE(STATUS "Checking if ld supports ${FLAG_TEST} - yes")
SET(LDFLAG_${FLAG_TEST} 1 CACHE INTERNAL "Linker supports ${FLAG_TEST}")
ELSE()
MESSAGE(STATUS "Checking if ld supports ${FLAG_TEST} - no")
SET(LDFLAG_${FLAG_TEST} "" CACHE INTERNAL "Linker supports ${FLAG_TEST}")
ENDIF()
ENDIF()
IF(LDFLAG_${FLAG_TEST}) IF(LDFLAG_${FLAG_TEST})
SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} ${FLAG_TEST}") SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} -Wl,${FLAG_TEST}")
ENDIF(LDFLAG_${FLAG_TEST}) ENDIF(LDFLAG_${FLAG_TEST})
UNSET(LDFLAG_${FLAG_TEST})
ENDFOREACH() ENDFOREACH()
ENDIF(NOT WIN32) ENDIF(NOT WIN32)
ENDIF(NOT APPLE)
# Check for -Wl,-z,pack-relative-relocs.
# Requires binutils-2.38 and glibc-2.36. (TODO: Check other Unix systems.)
IF(UNIX AND NOT APPLE)
IF(NOT DEFINED HAVE_DT_RELR)
MESSAGE(STATUS "Checking if the system supports DT_RELR")
IF(_ld_out MATCHES "-z pack-relative-relocs")
# NOTE: ${CMAKE_MODULE_PATH} has two directories, macros/ and libs/,
# so we have to configure this manually.
SET(DT_RELR_SOURCE_PATH "${CMAKE_SOURCE_DIR}/cmake/platform")
# TODO: Better cross-compile handling.
TRY_RUN(TMP_DT_RELR_RUN TMP_DT_RELR_COMPILE
"${CMAKE_CURRENT_BINARY_DIR}"
"${DT_RELR_SOURCE_PATH}/DT_RELR_Test.c")
IF(TMP_DT_RELR_COMPILE AND (TMP_DT_RELR_RUN EQUAL 0))
SET(TMP_HAVE_DT_RELR TRUE)
MESSAGE(STATUS "Checking if the system supports DT_RELR - yes")
ELSE()
SET(TMP_HAVE_DT_RELR FALSE)
MESSAGE(STATUS "Checking if the system supports DT_RELR - no, needs glibc-2.36 or later")
ENDIF()
ELSE(_ld_out MATCHES "-z pack-relative-relocs")
SET(TMP_HAVE_DT_RELR FALSE)
MESSAGE(STATUS "Checking if the system supports DT_RELR - no, needs binutils-2.38 or later")
ENDIF(_ld_out MATCHES "-z pack-relative-relocs")
SET(HAVE_DT_RELR ${TMP_HAVE_DT_RELR} CACHE INTERNAL "System supports DT_RELR")
UNSET(TMP_HAVE_DT_RELR)
ENDIF(NOT DEFINED HAVE_DT_RELR)
IF(HAVE_DT_RELR)
SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} -Wl,-z,pack-relative-relocs")
ENDIF(HAVE_DT_RELR)
ENDIF(UNIX AND NOT APPLE)
SET(RP_SHARED_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON}") SET(RP_SHARED_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON}")
SET(RP_MODULE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON}") SET(RP_MODULE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON}")
# Check for -Og. # Special case: On non-Linux systems, remove "--no-undefined" and
# "--no-allow-shlib-undefined" from SHARED and MODULE linker flags.
# On FreeBSD 13.2, `environ` and `__progname` are intentionally undefined,
# so this *always* fails when building a shared library.
IF(NOT CMAKE_SYSTEM MATCHES "Linux")
FOREACH(FLAG_REMOVE "--no-undefined" "--no-allow-shlib-undefined")
STRING(REPLACE "-Wl,${FLAG_REMOVE}" "" RP_SHARED_LINKER_FLAGS_COMMON "${RP_SHARED_LINKER_FLAGS_COMMON}")
STRING(REPLACE "-Wl,${FLAG_REMOVE}" "" RP_MODULE_LINKER_FLAGS_COMMON "${RP_MODULE_LINKER_FLAGS_COMMON}")
ENDFOREACH(FLAG_REMOVE)
ENDIF(NOT CMAKE_SYSTEM MATCHES "Linux")
# Debug builds: Check for -Og.
# This flag was added in gcc-4.8, and enables optimizations that # This flag was added in gcc-4.8, and enables optimizations that
# don't interfere with debugging. # don't interfere with debugging.
CHECK_C_COMPILER_FLAG("-Og" CFLAG_OPTIMIZE_DEBUG) CHECK_C_COMPILER_FLAG("-Og" CFLAG_OPTIMIZE_DEBUG)
@ -133,11 +254,70 @@ ELSE(CFLAG_OPTIMIZE_DEBUG)
SET(CFLAG_OPTIMIZE_DEBUG "-O0") SET(CFLAG_OPTIMIZE_DEBUG "-O0")
ENDIF(CFLAG_OPTIMIZE_DEBUG) ENDIF(CFLAG_OPTIMIZE_DEBUG)
# Debug/release flags. # Release builds: Check for -ftree-vectorize.
# On i386, also add -mstackrealign to ensure proper stack alignment.
CHECK_C_COMPILER_FLAG("-ftree-vectorize" CFLAG_OPTIMIZE_FTREE_VECTORIZE)
IF(CFLAG_OPTIMIZE_FTREE_VECTORIZE)
IF(arch MATCHES "^(i.|x)86$" AND NOT CMAKE_CL_64 AND ("${CMAKE_SIZEOF_VOID_P}" EQUAL 4))
# i386: "-mstackrealign" is required.
CHECK_C_COMPILER_FLAG("-mstackrealign" CFLAG_OPTIMIZE_MSTACKREALIGN)
IF(CFLAG_OPTIMIZE_MSTACK_REALIGN)
SET(CFLAGS_VECTORIZE "-ftree-vectorize -mstackrealign")
ENDIF(CFLAG_OPTIMIZE_MSTACKREALIGN)
ELSE()
# Not i386. Add "-ftree-vectorize" without "-mstackrealign".
SET(CFLAGS_VECTORIZE "-ftree-vectorize")
ENDIF()
ENDIF(CFLAG_OPTIMIZE_FTREE_VECTORIZE)
# Add "-Werror" *after* checking for everything else.
IF(ENABLE_WERROR)
SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} -Werror")
SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} -Werror")
SET(CFLAGS_WNO_ERROR -Wno-error=unknown-pragmas -Wno-error=address -Wno-error=attributes -Wno-error=unused-parameter -Wno-error=unused-but-set-variable -Wno-error=ignored-qualifiers -Wno-error=missing-field-initializers -Wno-error=unused-variable -Wno-error=unused-function -Wno-error=type-limits -Wno-error=empty-body -Wno-error=address-of-packed-member -Wno-error=shift-negative-value -Wno-error=clobbered -Wno-error=overloaded-virtual -Wno-error=header-hygiene -Wno-error=cast-align -Wno-error=stringop-overread)
FOREACH(FLAG_TEST ${CFLAGS_WNO_ERROR})
# CMake doesn't like certain characters in variable names.
STRING(REGEX REPLACE "/|:|=" "_" FLAG_TEST_VARNAME "${FLAG_TEST}")
CHECK_C_COMPILER_FLAG("${FLAG_TEST}" CFLAG_${FLAG_TEST_VARNAME})
IF(CFLAG_${FLAG_TEST_VARNAME})
SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${FLAG_TEST}")
SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${FLAG_TEST}")
ENDIF(CFLAG_${FLAG_TEST_VARNAME})
UNSET(CFLAG_${FLAG_TEST_VARNAME})
ENDFOREACH(FLAG_TEST)
ENDIF(ENABLE_WERROR)
### Debug/Release flags ###
SET(RP_C_FLAGS_DEBUG "${CFLAG_OPTIMIZE_DEBUG} -ggdb -DDEBUG -D_DEBUG") SET(RP_C_FLAGS_DEBUG "${CFLAG_OPTIMIZE_DEBUG} -ggdb -DDEBUG -D_DEBUG")
SET(RP_CXX_FLAGS_DEBUG "${CFLAG_OPTIMIZE_DEBUG} -ggdb -DDEBUG -D_DEBUG") SET(RP_CXX_FLAGS_DEBUG "${CFLAG_OPTIMIZE_DEBUG} -ggdb -DDEBUG -D_DEBUG")
SET(RP_C_FLAGS_RELEASE "-O2 -ggdb -DNDEBUG")
SET(RP_CXX_FLAGS_RELEASE "-O2 -ggdb -DNDEBUG") SET(RP_C_FLAGS_RELEASE "-O2 -DNDEBUG ${CFLAGS_VECTORIZE}")
SET(RP_CXX_FLAGS_RELEASE "-O2 -DNDEBUG ${CFLAGS_VECTORIZE}")
SET(RP_C_FLAGS_RELWITHDEBINFO "-O2 -ggdb -DNDEBUG ${CFLAGS_VECTORIZE}")
SET(RP_CXX_FLAGS_RELWITHDEBINFO "-O2 -ggdb -DNDEBUG ${CFLAGS_VECTORIZE}")
# Enable C++ assertions and other hardening options. (libstdc++ / libc++)
# TODO: Check for the actual C++ runtime being used instead of
# assuming libc++ is only used with Clang.
SET(RP_CXX_FLAGS_DEBUG "${RP_CXX_FLAGS_DEBUG} -D_GLIBCXX_ASSERTIONS -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC")
# libc++ (clang only)
IF(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
SET(RP_CXX_FLAGS_DEBUG "${RP_CXX_FLAGS_DEBUG} -D_LIBCPP_ASSERT=1 -D_LIBCPP_DEBUG=1 -D_LIBCPP_ENABLE_HARDENED_MODE=1")
IF(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 16.50)
# clang-17: Use _LIBCPP_HARDENING_MODE.
SET(RP_CXX_FLAGS_DEBUG "${RP_CXX_FLAGS_DEBUG} -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG")
ELSE(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 16.50)
# clang-16 or earlier: Use _LIBCPP_ENABLE_ASSERTIONS.
# NOTE: _LIBCPP_ENABLE_ASSERTIONS causes an error if using clang-17 or later.
SET(RP_CXX_FLAGS_DEBUG "${RP_CXX_FLAGS_DEBUG} -D_LIBCPP_ENABLE_ASSERTIONS=1")
ENDIF(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 16.50)
ENDIF(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# Unset temporary variables. # Unset temporary variables.
UNSET(CFLAG_OPTIMIZE_DEBUG) UNSET(CFLAG_OPTIMIZE_DEBUG)
@ -154,6 +334,14 @@ IF(ENABLE_LTO)
# occur in gcc-4.9 due to "slim" LTO objects, and possibly # occur in gcc-4.9 due to "slim" LTO objects, and possibly
# earlier versions for various reasons. # earlier versions for various reasons.
MESSAGE(STATUS "Checking if the gcc LTO wrappers are available:") MESSAGE(STATUS "Checking if the gcc LTO wrappers are available:")
# gcc-5.4 and earlier have issues with LTO.
IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND
CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)
MESSAGE(STATUS "Checking if the gcc LTO wrappers are available: too old")
MESSAGE(FATAL_ERROR "gcc 6.1 or later is required for LTO.")
ENDIF()
IF("${CMAKE_AR}" MATCHES "gcc-ar$") IF("${CMAKE_AR}" MATCHES "gcc-ar$")
# Already using the gcc-ar wrapper. # Already using the gcc-ar wrapper.
SET(GCC_WRAPPER_AR "${CMAKE_AR}") SET(GCC_WRAPPER_AR "${CMAKE_AR}")
@ -183,6 +371,12 @@ IF(ENABLE_LTO)
SET(RP_EXE_LINKER_FLAGS_RELEASE "${RP_EXE_LINKER_FLAGS_RELEASE} -flto -fuse-linker-plugin") SET(RP_EXE_LINKER_FLAGS_RELEASE "${RP_EXE_LINKER_FLAGS_RELEASE} -flto -fuse-linker-plugin")
SET(RP_SHARED_LINKER_FLAGS_RELEASE "${RP_SHARED_LINKER_FLAGS_RELEASE} -flto -fuse-linker-plugin") SET(RP_SHARED_LINKER_FLAGS_RELEASE "${RP_SHARED_LINKER_FLAGS_RELEASE} -flto -fuse-linker-plugin")
SET(RP_MODULE_LINKER_FLAGS_RELEASE "${RP_MODULE_LINKER_FLAGS_RELEASE} -flto -fuse-linker-plugin") SET(RP_MODULE_LINKER_FLAGS_RELEASE "${RP_MODULE_LINKER_FLAGS_RELEASE} -flto -fuse-linker-plugin")
SET(RP_C_FLAGS_RELWITHDEBINFO "${RP_C_FLAGS_RELWITHDEBINFO} -flto")
SET(RP_CXX_FLAGS_RELWITHDEBINFO "${RP_CXX_FLAGS_RELWITHDEBINFO} -flto")
SET(RP_EXE_LINKER_FLAGS_RELWITHDEBINFO "${RP_EXE_LINKER_FLAGS_RELWITHDEBINFO} -flto -fuse-linker-plugin")
SET(RP_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${RP_SHARED_LINKER_FLAGS_RELWITHDEBINFO} -flto -fuse-linker-plugin")
SET(RP_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${RP_MODULE_LINKER_FLAGS_RELWITHDEBINFO} -flto -fuse-linker-plugin")
ELSE(CFLAG_LTO) ELSE(CFLAG_LTO)
MESSAGE(FATAL_ERROR "LTO optimization requested but -flto is not supported.") MESSAGE(FATAL_ERROR "LTO optimization requested but -flto is not supported.")
ENDIF(CFLAG_LTO) ENDIF(CFLAG_LTO)

View File

@ -3,50 +3,146 @@ IF(MSVC_VERSION LESS 1600)
MESSAGE(FATAL_ERROR "MSVC 2010 (10.0) or later is required.") MESSAGE(FATAL_ERROR "MSVC 2010 (10.0) or later is required.")
ENDIF() ENDIF()
# If an SDK version isn't specified by the user, set it to 10.0.
IF(NOT CMAKE_SYSTEM_VERSION)
SET(CMAKE_SYSTEM_VERSION 10.0)
ENDIF(NOT CMAKE_SYSTEM_VERSION)
# Disable useless warnings: # Disable useless warnings:
# - MSVC "logo" messages # - MSVC "logo" messages
# - C4005: macro redefinition (libpng's intprefix.out.tf1 is breaking on this...)
# - C4091: 'typedef ': ignored on left of 'tagGPFIDL_FLAGS' when no variable is declared
# - C4355: 'this' used in base member initializer list (used for Qt Dpointer pattern) # - C4355: 'this' used in base member initializer list (used for Qt Dpointer pattern)
# - C4503: 'identifier': decorated name length exceeded, name was truncated (MSVC 2015 and earlier) [generated by RomHeaderTest]
# - C4800: 'BOOL': forcing value to bool 'true' or 'false' (performance warning)
# - MSVCRT "deprecated" functions # - MSVCRT "deprecated" functions
# - std::tr1 deprecation # - std::tr1 deprecation
# Increase some warnings to errors: # Increase some warnings to errors:
# - C4013: function undefined; this is allowed in C, but will # - C4013: function undefined; this is allowed in C, but will
# probably cause a linker error. # probably cause a linker error.
SET(RP_C_FLAGS_COMMON "/nologo /wd4355 /wd4482 /we4013 -D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE") # - C4024: 'function': different types for formal and actual parameter n
SET(RP_CXX_FLAGS_COMMON "${RP_C_FLAGS_COMMON} -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING") # - C4047: 'function': 'parameter' differs in levels of indirection from 'argument'
# - C4477: 'function' : format string 'string' requires an argument of type 'type', but variadic argument number has type 'type'
SET(RP_C_FLAGS_COMMON "/nologo /W3")
IF(ENABLE_WERROR)
SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} /WX")
ENDIF(ENABLE_WERROR)
SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} /wd4005 /wd4091 /wd4355 /wd4503 /wd4800 /we4013 /we4024 /we4047 /we4477")
SET(RP_CXX_FLAGS_COMMON "${RP_C_FLAGS_COMMON}")
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS)
# NOTE: /TSAWARE is automatically set for Windows 2000 and later. (as of at least Visual Studio .NET 2003) # NOTE: /TSAWARE is automatically set for Windows 2000 and later. (as of at least Visual Studio .NET 2003)
# NOTE 2: /TSAWARE is not applicable for DLLs. # NOTE 2: /TSAWARE is not applicable for DLLs.
SET(RP_EXE_LINKER_FLAGS_COMMON "/NOLOGO /DYNAMICBASE /NXCOMPAT /LARGEADDRESSAWARE") SET(RP_EXE_LINKER_FLAGS_COMMON "/NOLOGO /DYNAMICBASE /NXCOMPAT /LARGEADDRESSAWARE")
SET(RP_SHARED_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON}") SET(RP_SHARED_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON}")
SET(RP_MODULE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON}") SET(RP_MODULE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON}")
# Test for "/sdl" and "/guard:cf". # Add /EHsc if it isn't present already.
# Default in most cases; not enabled for MSVC 2019 on ARM or ARM64.
IF(NOT CMAKE_CXX_FLAGS MATCHES "/EHsc")
SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} /EHsc")
ENDIF(NOT CMAKE_CXX_FLAGS MATCHES "/EHsc")
# Add /MP for multi-processor compilation.
SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} /MP")
SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} /MP")
# Test for MSVC-specific compiler flags.
# /utf-8 was added in MSVC 2015.
INCLUDE(CheckCCompilerFlag) INCLUDE(CheckCCompilerFlag)
FOREACH(FLAG_TEST "/sdl" "/guard:cf") FOREACH(FLAG_TEST "/sdl" "/utf-8" "/guard:cf" "/guard:ehcont")
# CMake doesn't like certain characters in variable names. # CMake doesn't like certain characters in variable names.
STRING(REGEX REPLACE "/|:" "_" FLAG_TEST_VARNAME "${FLAG_TEST}") STRING(REGEX REPLACE "/|:|=" "_" FLAG_TEST_VARNAME "${FLAG_TEST}")
CHECK_C_COMPILER_FLAG("${FLAG_TEST}" CFLAG_${FLAG_TEST_VARNAME}) CHECK_C_COMPILER_FLAG("${FLAG_TEST}" CFLAG_${FLAG_TEST_VARNAME})
IF(CFLAG_${FLAG_TEST_VARNAME}) IF(CFLAG_${FLAG_TEST_VARNAME})
SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${FLAG_TEST}") SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${FLAG_TEST}")
SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${FLAG_TEST}") SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${FLAG_TEST}")
IF(FLAG_TEST STREQUAL "/guard:cf") # "/guard:*" must be added to linker flags in addition to CFLAGS.
# "/guard:cf" must be added to linker flags as well. IF(FLAG_TEST MATCHES "^/guard:")
SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} ${FLAG_TEST}") SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} ${FLAG_TEST}")
SET(RP_SHARED_LINKER_FLAGS_COMMON "${RP_SHARED_LINKER_FLAGS_COMMON} ${FLAG_TEST}") SET(RP_SHARED_LINKER_FLAGS_COMMON "${RP_SHARED_LINKER_FLAGS_COMMON} ${FLAG_TEST}")
SET(RP_MODULE_LINKER_FLAGS_COMMON "${RP_MODULE_LINKER_FLAGS_COMMON} ${FLAG_TEST}") SET(RP_MODULE_LINKER_FLAGS_COMMON "${RP_MODULE_LINKER_FLAGS_COMMON} ${FLAG_TEST}")
ENDIF(FLAG_TEST STREQUAL "/guard:cf") ENDIF(FLAG_TEST MATCHES "^/guard:")
ENDIF(CFLAG_${FLAG_TEST_VARNAME}) ENDIF(CFLAG_${FLAG_TEST_VARNAME})
UNSET(CFLAG_${FLAG_TEST_VARNAME}) UNSET(CFLAG_${FLAG_TEST_VARNAME})
ENDFOREACH() ENDFOREACH()
# Enable /SAFESEH. (i386 only)
IF(_MSVC_C_ARCHITECTURE_FAMILY MATCHES "^([iI]?[xX3]86)$")
SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} /SAFESEH")
SET(RP_SHARED_LINKER_FLAGS_COMMON "${RP_SHARED_LINKER_FLAGS_COMMON} /SAFESEH")
SET(RP_MODULE_LINKER_FLAGS_COMMON "${RP_MODULE_LINKER_FLAGS_COMMON} /SAFESEH")
ENDIF()
# MSVC 2019: Enable /CETCOMPAT.
# NOTE: i386/amd64 only. (last checked in MSVC 2022 [17.0])
# - LINK : fatal error LNK1246: '/CETCOMPAT' not compatible with 'ARM' target machine; link without '/CETCOMPAT'
# - LINK : fatal error LNK1246: '/CETCOMPAT' not compatible with 'ARM64' target machine; link without '/CETCOMPAT'
IF(MSVC_VERSION GREATER 1919 AND _MSVC_C_ARCHITECTURE_FAMILY MATCHES "^([iI]?[xX3]86)|([xX]64)$")
SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} /CETCOMPAT")
SET(RP_SHARED_LINKER_FLAGS_COMMON "${RP_SHARED_LINKER_FLAGS_COMMON} /CETCOMPAT")
SET(RP_MODULE_LINKER_FLAGS_COMMON "${RP_MODULE_LINKER_FLAGS_COMMON} /CETCOMPAT")
ENDIF()
# MSVC: C/C++ conformance settings
FOREACH(FLAG_TEST "/Zc:wchar_t" "/Zc:inline")
# CMake doesn't like certain characters in variable names.
STRING(REGEX REPLACE "/|:|=" "_" FLAG_TEST_VARNAME "${FLAG_TEST}")
CHECK_C_COMPILER_FLAG("${FLAG_TEST}" CFLAG_${FLAG_TEST_VARNAME})
IF(CFLAG_${FLAG_TEST_VARNAME})
SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${FLAG_TEST}")
SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${FLAG_TEST}")
ENDIF(CFLAG_${FLAG_TEST_VARNAME})
UNSET(CFLAG_${FLAG_TEST_VARNAME})
ENDFOREACH()
# MSVC: C/C++ conformance settings
IF(CMAKE_SYSTEM_VERSION VERSION_GREATER 9.9)
FOREACH(FLAG_TEST "/permissive-")
# CMake doesn't like certain characters in variable names.
STRING(REGEX REPLACE "/|:|=" "_" FLAG_TEST_VARNAME "${FLAG_TEST}")
CHECK_C_COMPILER_FLAG("${FLAG_TEST}" CFLAG_${FLAG_TEST_VARNAME})
IF(CFLAG_${FLAG_TEST_VARNAME})
SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${FLAG_TEST}")
SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${FLAG_TEST}")
ENDIF(CFLAG_${FLAG_TEST_VARNAME})
UNSET(CFLAG_${FLAG_TEST_VARNAME})
ENDFOREACH()
ENDIF()
# MSVC: C++ conformance settings
INCLUDE(CheckCXXCompilerFlag)
SET(CXX_CONFORMANCE_FLAGS "/Zc:__cplusplus" "/Zc:checkGwOdr" "/Zc:rvalueCast" "/Zc:templateScope" "/Zc:ternary")
IF(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# clang-cl enables certain conformance options by default,
# and these cause warnings to be printed if specified.
# Only enable these for original MSVC.
SET(CXX_CONFORMANCE_FLAGS ${CXX_CONFORMANCE_FLAGS} "/Zc:externC" "/Zc:noexceptTypes" "/Zc:throwingNew")
ENDIF(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
FOREACH(FLAG_TEST ${CXX_CONFORMANCE_FLAGS})
# CMake doesn't like certain characters in variable names.
STRING(REGEX REPLACE "/|:|=" "_" FLAG_TEST_VARNAME "${FLAG_TEST}")
CHECK_CXX_COMPILER_FLAG("${FLAG_TEST}" CXXFLAG_${FLAG_TEST_VARNAME})
IF(CXXFLAG_${FLAG_TEST_VARNAME})
SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${FLAG_TEST}")
ENDIF(CXXFLAG_${FLAG_TEST_VARNAME})
UNSET(CXXFLAG_${FLAG_TEST_VARNAME})
ENDFOREACH()
# Disable warning C4996 (deprecated), then re-enable it. # Disable warning C4996 (deprecated), then re-enable it.
# Otherwise, it gets handled as an error due to /sdl. # Otherwise, it gets handled as an error due to /sdl.
SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} /wd4996 /w34996") SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} /wd4996 /w34996")
SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} /wd4996 /w34996") SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} /wd4996 /w34996")
# MSVC 2015 uses thread-safe statics by default. # MSVC 2015 uses thread-safe statics by default.
# This doesn't work on XP, so disable it. # This doesn't work on Windows XP or Windows Server 2003, so disable it.
IF(MSVC_VERSION GREATER 1899) # NOTE: Only for i386 and amd64; enabling elsewhere because
# Windows XP and Windows Server 2003 weren't available for ARM.
IF(MSVC_VERSION GREATER 1899 AND _MSVC_C_ARCHITECTURE_FAMILY MATCHES "^([iI]?[xX3]86)|([xX]64)$")
MESSAGE(STATUS "MSVC: Disabling thread-safe statics for Windows XP and Windows Server 2003 compatibility")
SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} /Zc:threadSafeInit-") SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} /Zc:threadSafeInit-")
SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} /Zc:threadSafeInit-") SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} /Zc:threadSafeInit-")
ENDIF() ENDIF()
@ -67,42 +163,48 @@ ENDIF()
SET(CMAKE_ASM_MASM_FLAGS "/W0 /safeseh" CACHE STRING SET(CMAKE_ASM_MASM_FLAGS "/W0 /safeseh" CACHE STRING
"Flags used by the assembler during all build types.") "Flags used by the assembler during all build types.")
# CPU architecture.
STRING(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" arch)
# Check if CMAKE_SIZEOF_VOID_P is set correctly. # Check if CMAKE_SIZEOF_VOID_P is set correctly.
IF(NOT CMAKE_SIZEOF_VOID_P) IF(NOT CMAKE_SIZEOF_VOID_P)
# CMAKE_SIZEOF_VOID_P isn't set. # CMAKE_SIZEOF_VOID_P isn't set.
# Set it based on CMAKE_SYSTEM_PROCESSOR. # Set it based on CMAKE_SYSTEM_PROCESSOR.
# FIXME: This won't work if we're cross-compiling, e.g. using # FIXME: This won't work if we're cross-compiling, e.g. using
# the x86_amd64 or amd64_x86 toolchains. # the x86_amd64 or amd64_x86 toolchains.
IF(arch MATCHES "^x86_64$|^amd64$|^ia64$") IF(CMAKE_CL_64)
SET(CMAKE_SIZEOF_VOID_P 8) SET(CMAKE_SIZEOF_VOID_P 8)
ELSEIF(arch MATCHES "^(i.|x)86$")
SET(CMAKE_SIZEOF_VOID_P 4)
ELSE() ELSE()
# Assume other CPUs are 32-bit.
SET(CMAKE_SIZEOF_VOID_P 4) SET(CMAKE_SIZEOF_VOID_P 4)
ENDIF() ENDIF()
ENDIF(NOT CMAKE_SIZEOF_VOID_P) ENDIF(NOT CMAKE_SIZEOF_VOID_P)
# MSVC needs a flag to automatically NULL-terminate strings in string tables.
# (It ignores the "\0" in string tables, too.)
SET(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} /n")
# TODO: Code coverage checking for MSVC? # TODO: Code coverage checking for MSVC?
IF(ENABLE_COVERAGE) IF(ENABLE_COVERAGE)
MESSAGE(FATAL_ERROR "Code coverage testing is currently only supported on gcc and clang.") MESSAGE(FATAL_ERROR "Code coverage testing is currently only supported on gcc and clang.")
ENDIF(ENABLE_COVERAGE) ENDIF(ENABLE_COVERAGE)
# Debug/release flags. ### Debug/Release flags ###
SET(RP_C_FLAGS_DEBUG "/Zi")
SET(RP_CXX_FLAGS_DEBUG "/Zi") SET(RP_C_FLAGS_DEBUG "/Zi ${RP_C_FLAGS_DEBUG}")
SET(RP_CXX_FLAGS_DEBUG "/Zi ${RP_CXX_FLAGS_DEBUG}")
SET(RP_EXE_LINKER_FLAGS_DEBUG "/DEBUG /INCREMENTAL") SET(RP_EXE_LINKER_FLAGS_DEBUG "/DEBUG /INCREMENTAL")
SET(RP_SHARED_LINKER_FLAGS_DEBUG "${RP_EXE_LINKER_FLAGS_DEBUG}") SET(RP_SHARED_LINKER_FLAGS_DEBUG "${RP_EXE_LINKER_FLAGS_DEBUG}")
SET(RP_MODULE_LINKER_FLAGS_DEBUG "${RP_EXE_LINKER_FLAGS_DEBUG}") SET(RP_MODULE_LINKER_FLAGS_DEBUG "${RP_EXE_LINKER_FLAGS_DEBUG}")
SET(RP_C_FLAGS_RELEASE "/Zi") SET(RP_C_FLAGS_RELEASE "/Zi")
SET(RP_CXX_FLAGS_RELEASE "/Zi") SET(RP_CXX_FLAGS_RELEASE "/Zi")
SET(RP_EXE_LINKER_FLAGS_RELEASE "/DEBUG /INCREMENTAL:NO /OPT:ICF,REF") SET(RP_EXE_LINKER_FLAGS_RELEASE "/DEBUG /INCREMENTAL:NO /OPT:ICF,REF")
SET(RP_SHARED_LINKER_FLAGS_RELEASE "${RP_EXE_LINKER_FLAGS_RELEASE}") SET(RP_SHARED_LINKER_FLAGS_RELEASE "${RP_EXE_LINKER_FLAGS_RELEASE}")
SET(RP_MODULE_LINKER_FLAGS_RELEASE "${RP_EXE_LINKER_FLAGS_RELEASE}") SET(RP_MODULE_LINKER_FLAGS_RELEASE "${RP_EXE_LINKER_FLAGS_RELEASE}")
SET(RP_C_FLAGS_RELWITHDEBINFO "/Zi")
SET(RP_CXX_FLAGS_RELWITHDEBINFO "/Zi")
SET(RP_EXE_LINKER_FLAGS_RELWITHDEBINFO "/DEBUG /INCREMENTAL:NO /OPT:ICF,REF")
SET(RP_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${RP_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
SET(RP_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${RP_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
# Check for link-time optimization. (Release builds only.) # Check for link-time optimization. (Release builds only.)
IF(ENABLE_LTO) IF(ENABLE_LTO)
SET(RP_C_FLAGS_RELEASE "${RP_C_FLAGS_RELEASE} /GL") SET(RP_C_FLAGS_RELEASE "${RP_C_FLAGS_RELEASE} /GL")
@ -110,4 +212,10 @@ IF(ENABLE_LTO)
SET(RP_EXE_LINKER_FLAGS_RELEASE "${RP_EXE_LINKER_FLAGS_RELEASE} /LTCG") SET(RP_EXE_LINKER_FLAGS_RELEASE "${RP_EXE_LINKER_FLAGS_RELEASE} /LTCG")
SET(RP_SHARED_LINKER_FLAGS_RELEASE "${RP_SHARED_LINKER_FLAGS_RELEASE} /LTCG") SET(RP_SHARED_LINKER_FLAGS_RELEASE "${RP_SHARED_LINKER_FLAGS_RELEASE} /LTCG")
SET(RP_MODULE_LINKER_FLAGS_RELEASE "${RP_MODULE_LINKER_FLAGS_RELEASE} /LTCG") SET(RP_MODULE_LINKER_FLAGS_RELEASE "${RP_MODULE_LINKER_FLAGS_RELEASE} /LTCG")
SET(RP_C_FLAGS_RELWITHDEBINFO "${RP_C_FLAGS_RELWITHDEBINFO} /GL")
SET(RP_CXX_FLAGS_RELWITHDEBINFO "${RP_CXX_FLAGS_RELWITHDEBINFO} /GL")
SET(RP_EXE_LINKER_FLAGS_RELWITHDEBINFO "${RP_EXE_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
SET(RP_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${RP_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
SET(RP_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${RP_MODULE_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
ENDIF(ENABLE_LTO) ENDIF(ENABLE_LTO)

View File

@ -2,24 +2,37 @@
# For MinGW compilers. # For MinGW compilers.
# Enable "secure" API functions: *_s() # Enable "secure" API functions: *_s()
SET(RP_C_FLAGS_WIN32 "${RP_C_FLAGS_WIN32} -DMINGW_HAS_SECURE_API") ADD_DEFINITIONS(-DMINGW_HAS_SECURE_API)
# Subsystem and minimum Windows version: # Subsystem and minimum Windows version:
# - If 32-bit: 5.01 # - If i386: 5.01
# - If 64-bit: 5.02 # - If amd64: 5.02
# - If arm or arm64: 6.02
# NOTE: MS_ENH_RSA_AES_PROV is only available starting with # NOTE: MS_ENH_RSA_AES_PROV is only available starting with
# Windows XP. Because we're actually using some XP-specific # Windows XP. Because we're actually using some XP-specific
# functionality now, the minimum version is now Windows XP. # functionality now, the minimum version is now Windows XP.
IF(CMAKE_SIZEOF_VOID_P EQUAL 8) INCLUDE(CPUInstructionSetFlags)
# 64-bit, Unicode Windows only. IF(CPU_amd64)
# (There is no 64-bit ANSI Windows.) # amd64 (64-bit), Unicode Windows only.
SET(CMAKE_CREATE_WIN32_EXE "-Wl,--subsystem,windows:5.02") # (There is no amd64 ANSI Windows.)
SET(CMAKE_CREATE_CONSOLE_EXE "-Wl,--subsystem,console:5.02") # Minimum target version is Windows Server 2003 / XP 64-bit.
ELSE() SET(RP_WIN32_SUBSYSTEM_VERSION "5.02")
ELSEIF(CPU_arm OR CPU_arm64)
# ARM (32-bit or 64-bit), Unicode windows only. (MSVC)
# (There is no ARM ANSI Windows.)
# Minimum target version is Windows 8.
SET(RP_WIN32_SUBSYSTEM_VERSION "6.02")
ELSEIF(CPU_i386)
# 32-bit, Unicode Windows only. # 32-bit, Unicode Windows only.
SET(CMAKE_CREATE_WIN32_EXE "-Wl,--subsystem,windows:5.01") # Minimum target version is Windows XP.
SET(CMAKE_CREATE_CONSOLE_EXE "-Wl,--subsystem,console:5.01") SET(RP_WIN32_SUBSYSTEM_VERSION "5.01")
ELSE()
MESSAGE(FATAL_ERROR "Unsupported CPU.")
ENDIF() ENDIF()
# FIXME: Maybe we should use RP_LINKER_FLAGS_WIN32_EXE and RP_LINKER_FLAGS_CONSOLE_EXE.
# This is what's used in win32-msvc.cmake.
SET(CMAKE_CREATE_WIN32_EXE "-Wl,--subsystem,windows:${RP_WIN32_SUBSYSTEM_VERSION}")
SET(CMAKE_CREATE_CONSOLE_EXE "-Wl,--subsystem,console:${RP_WIN32_SUBSYSTEM_VERSION}")
SET(RP_EXE_LINKER_FLAGS_WIN32 "") SET(RP_EXE_LINKER_FLAGS_WIN32 "")
SET(RP_SHARED_LINKER_FLAGS_WIN32 "") SET(RP_SHARED_LINKER_FLAGS_WIN32 "")
@ -30,32 +43,92 @@ IF(CMAKE_BUILD_TYPE MATCHES ^release)
SET(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) SET(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
ENDIF(CMAKE_BUILD_TYPE MATCHES ^release) ENDIF(CMAKE_BUILD_TYPE MATCHES ^release)
# Test for various linker flags. # Test for common LDFLAGS.
# NOTE: CHECK_C_COMPILER_FLAG() doesn't seem to work, even with
# CMAKE_TRY_COMPILE_TARGET_TYPE. Check `ld --help` for the various
# parameters instead.
# NOTE: --tsaware is only valid for EXEs, not DLLs. # NOTE: --tsaware is only valid for EXEs, not DLLs.
# TODO: Make static linkage a CMake option: --static-libgcc, --static-libstdc++ # TODO: Make static linkage a CMake option: --static-libgcc, --static-libstdc++
FOREACH(FLAG_TEST "-Wl,--large-address-aware" "-Wl,--nxcompat" "-Wl,--tsaware") EXECUTE_PROCESS(COMMAND ${CMAKE_LINKER} --help
# CMake doesn't like "+" characters in variable names. OUTPUT_VARIABLE _ld_out
STRING(REPLACE "+" "_" FLAG_TEST_VARNAME "${FLAG_TEST}") ERROR_QUIET)
IF(LDFLAG_${FLAG_TEST_VARNAME}) # NOTE: Newer ld shows things like "--[disable-]dynamicbase".
SET(RP_EXE_LINKER_FLAGS_WIN32 "${RP_EXE_LINKER_FLAGS_WIN32} ${FLAG_TEST}") IF(CPU_i386 OR CPU_arm)
ENDIF(LDFLAG_${FLAG_TEST_VARNAME}) # 32-bit only LDFLAGS
UNSET(LDFLAG_${FLAG_TEST_VARNAME}) FOREACH(FLAG_TEST "large-address-aware")
UNSET(FLAG_TEST_VARNAME) IF(NOT DEFINED LDFLAG_${FLAG_TEST})
MESSAGE(STATUS "Checking if ld supports --${FLAG_TEST}")
IF(_ld_out MATCHES "${FLAG_TEST}")
MESSAGE(STATUS "Checking if ld supports --${FLAG_TEST} - yes")
SET(LDFLAG_${FLAG_TEST} 1 CACHE INTERNAL "Linker supports --${FLAG_TEST}")
ELSE()
MESSAGE(STATUS "Checking if ld supports --${FLAG_TEST} - no")
SET(LDFLAG_${FLAG_TEST} "" CACHE INTERNAL "Linker supports --${FLAG_TEST}")
ENDIF()
ENDIF()
IF(LDFLAG_${FLAG_TEST})
SET(RP_EXE_LINKER_FLAGS_WIN32 "${RP_EXE_LINKER_FLAGS_WIN32} -Wl,--${FLAG_TEST}")
ENDIF(LDFLAG_${FLAG_TEST})
ENDFOREACH()
ELSEIF(CPU_amd64 OR CPU_arm64)
# 64-bit only LDFLAGS
FOREACH(FLAG_TEST "high-entropy-va")
IF(NOT DEFINED LDFLAG_${FLAG_TEST})
MESSAGE(STATUS "Checking if ld supports --${FLAG_TEST}")
IF(_ld_out MATCHES "${FLAG_TEST}")
MESSAGE(STATUS "Checking if ld supports --${FLAG_TEST} - yes")
SET(LDFLAG_${FLAG_TEST} 1 CACHE INTERNAL "Linker supports --${FLAG_TEST}")
ELSE()
MESSAGE(STATUS "Checking if ld supports --${FLAG_TEST} - no")
SET(LDFLAG_${FLAG_TEST} "" CACHE INTERNAL "Linker supports --${FLAG_TEST}")
ENDIF()
ENDIF()
IF(LDFLAG_${FLAG_TEST})
SET(RP_EXE_LINKER_FLAGS_WIN32 "${RP_EXE_LINKER_FLAGS_WIN32} -Wl,--${FLAG_TEST}")
ENDIF(LDFLAG_${FLAG_TEST})
ENDFOREACH()
ENDIF()
# CPU-independent LDFLAGS
FOREACH(FLAG_TEST "dynamicbase" "nxcompat")
IF(NOT DEFINED LDFLAG_${FLAG_TEST})
MESSAGE(STATUS "Checking if ld supports --${FLAG_TEST}")
IF(_ld_out MATCHES "${FLAG_TEST}")
MESSAGE(STATUS "Checking if ld supports --${FLAG_TEST} - yes")
SET(LDFLAG_${FLAG_TEST} 1 CACHE INTERNAL "Linker supports --${FLAG_TEST}")
ELSE()
MESSAGE(STATUS "Checking if ld supports --${FLAG_TEST} - no")
SET(LDFLAG_${FLAG_TEST} "" CACHE INTERNAL "Linker supports --${FLAG_TEST}")
ENDIF()
ENDIF()
IF(LDFLAG_${FLAG_TEST})
SET(RP_EXE_LINKER_FLAGS_WIN32 "${RP_EXE_LINKER_FLAGS_WIN32} -Wl,--${FLAG_TEST}")
ENDIF(LDFLAG_${FLAG_TEST})
ENDFOREACH() ENDFOREACH()
SET(RP_SHARED_LINKER_FLAGS_WIN32 "${RP_EXE_LINKER_FLAGS_WIN32}") SET(RP_SHARED_LINKER_FLAGS_WIN32 "${RP_EXE_LINKER_FLAGS_WIN32}")
SET(RP_MODULE_LINKER_FLAGS_WIN32 "${RP_EXE_LINKER_FLAGS_WIN32}") SET(RP_MODULE_LINKER_FLAGS_WIN32 "${RP_EXE_LINKER_FLAGS_WIN32}")
# EXE-only flags. # EXE-only flags.
FOREACH(FLAG_TEST "-Wl,--tsaware") FOREACH(FLAG_TEST "tsaware")
# CMake doesn't like "+" characters in variable names. IF(NOT DEFINED LDFLAG_${FLAG_TEST})
STRING(REPLACE "+" "_" FLAG_TEST_VARNAME "${FLAG_TEST}") MESSAGE(STATUS "Checking if ld supports --${FLAG_TEST}")
IF(_ld_out MATCHES "${FLAG_TEST}")
MESSAGE(STATUS "Checking if ld supports --${FLAG_TEST} - yes")
SET(LDFLAG_${FLAG_TEST} 1 CACHE INTERNAL "Linker supports --${FLAG_TEST}")
ELSE()
MESSAGE(STATUS "Checking if ld supports --${FLAG_TEST} - no")
SET(LDFLAG_${FLAG_TEST} "" CACHE INTERNAL "Linker supports --${FLAG_TEST}")
ENDIF()
ENDIF()
IF(LDFLAG_${FLAG_TEST_VARNAME}) IF(LDFLAG_${FLAG_TEST})
SET(RP_EXE_LINKER_FLAGS_WIN32 "${RP_EXE_LINKER_FLAGS_WIN32} ${FLAG_TEST}") SET(RP_EXE_LINKER_FLAGS_WIN32 "${RP_EXE_LINKER_FLAGS_WIN32} -Wl,--${FLAG_TEST}")
ENDIF(LDFLAG_${FLAG_TEST_VARNAME}) ENDIF(LDFLAG_${FLAG_TEST})
UNSET(LDFLAG_${FLAG_TEST_VARNAME})
UNSET(FLAG_TEST_VARNAME)
ENDFOREACH() ENDFOREACH()
# Test for dynamicbase (ASLR) support. # Test for dynamicbase (ASLR) support.
@ -89,7 +162,7 @@ ENABLE_LANGUAGE(RC)
# Force windres to output COFF, even though it'll use the .res extension. # Force windres to output COFF, even though it'll use the .res extension.
SET(CMAKE_RC_OUTPUT_EXTENSION .obj) SET(CMAKE_RC_OUTPUT_EXTENSION .obj)
SET(CMAKE_RC_COMPILE_OBJECT SET(CMAKE_RC_COMPILE_OBJECT
"<CMAKE_RC_COMPILER> --output-format=coff <FLAGS> <DEFINES> -o <OBJECT> <SOURCE>") "<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> <INCLUDES> -o <OBJECT> <SOURCE>")
# Append the CFLAGS and LDFLAGS. # Append the CFLAGS and LDFLAGS.
SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${RP_C_FLAGS_WIN32}") SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${RP_C_FLAGS_WIN32}")

View File

@ -1,18 +1,13 @@
# Win32-specific CFLAGS/CXXFLAGS. # Win32-specific CFLAGS/CXXFLAGS.
# For Microsoft Visual C++ compilers. # For Microsoft Visual C++ compilers.
# Basic platform flags for MSVC:
# - wchar_t should be a distinct type. (MSVC 2002+)
IF(MSVC_VERSION GREATER 1200)
SET(RP_C_FLAGS_WIN32 "${RP_C_FLAGS_WIN32} /Zc:wchar_t")
ENDIF()
# NOTE: This program is Unicode only on Windows. # NOTE: This program is Unicode only on Windows.
# No ANSI support. # No ANSI support.
# Subsystem and minimum Windows version: # Subsystem and minimum Windows version:
# - If 32-bit: 5.00 # - If i386: 5.01
# - If 64-bit: 5.02 # - If amd64: 5.02
# - If arm or arm64: 6.02
# ROM Properties does NOT support ANSI Windows. # ROM Properties does NOT support ANSI Windows.
# MSVC 2010's minimum supported target OS is XP SP2. # MSVC 2010's minimum supported target OS is XP SP2.
# MSVC 2012 and later has a minimum subsystem value of 5.01. # MSVC 2012 and later has a minimum subsystem value of 5.01.
@ -25,20 +20,23 @@ ENDIF()
# NOTE: MS_ENH_RSA_AES_PROV is only available starting with # NOTE: MS_ENH_RSA_AES_PROV is only available starting with
# Windows XP. Because we're actually using some XP-specific # Windows XP. Because we're actually using some XP-specific
# functionality now, the minimum version is now Windows XP. # functionality now, the minimum version is now Windows XP.
IF(MSVC AND CMAKE_CL_64) INCLUDE(CPUInstructionSetFlags)
# 64-bit, Unicode Windows only. (MSVC) IF(CPU_amd64)
# (There is no 64-bit ANSI Windows.) # amd64 (64-bit), Unicode Windows only. (MSVC)
# (There is no amd64 ANSI Windows.)
# Minimum target version is Windows Server 2003 / XP 64-bit. # Minimum target version is Windows Server 2003 / XP 64-bit.
SET(RP_WIN32_SUBSYSTEM_VERSION "5.02") SET(RP_WIN32_SUBSYSTEM_VERSION "5.02")
ELSEIF(NOT MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8) ELSEIF(CPU_arm OR CPU_arm64)
# 64-bit, Unicode Windows only. (MinGW) # ARM (32-bit or 64-bit), Unicode windows only. (MSVC)
# (There is no 64-bit ANSI Windows.) # (There is no ARM ANSI Windows.)
# Minimum target version is Windows Server 2003 / XP 64-bit. # Minimum target version is Windows 8.
SET(RP_WIN32_SUBSYSTEM_VERSION "5.02") SET(RP_WIN32_SUBSYSTEM_VERSION "6.02")
ELSE() ELSEIF(CPU_i386)
# 32-bit, Unicode Windows only. # i386 (32-bit), Unicode Windows only.
# Minimum target version is Windows XP. # Minimum target version is Windows XP.
SET(RP_WIN32_SUBSYSTEM_VERSION "5.01") SET(RP_WIN32_SUBSYSTEM_VERSION "5.01")
ELSE()
MESSAGE(FATAL_ERROR "Unsupported CPU.")
ENDIF() ENDIF()
SET(RP_LINKER_FLAGS_WIN32_EXE "/SUBSYSTEM:WINDOWS,${RP_WIN32_SUBSYSTEM_VERSION}") SET(RP_LINKER_FLAGS_WIN32_EXE "/SUBSYSTEM:WINDOWS,${RP_WIN32_SUBSYSTEM_VERSION}")
SET(RP_LINKER_FLAGS_CONSOLE_EXE "/SUBSYSTEM:CONSOLE,${RP_WIN32_SUBSYSTEM_VERSION}") SET(RP_LINKER_FLAGS_CONSOLE_EXE "/SUBSYSTEM:CONSOLE,${RP_WIN32_SUBSYSTEM_VERSION}")
@ -47,10 +45,6 @@ UNSET(RP_WIN32_SUBSYSTEM_VERSION)
# Append the CFLAGS and LDFLAGS. # Append the CFLAGS and LDFLAGS.
SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${RP_C_FLAGS_WIN32}") SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${RP_C_FLAGS_WIN32}")
SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${RP_C_FLAGS_WIN32} ${RP_CXX_FLAGS_WIN32}") SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${RP_C_FLAGS_WIN32} ${RP_CXX_FLAGS_WIN32}")
SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} ${RP_EXE_LINKER_FLAGS_WIN32}")
SET(RP_SHARED_LINKER_FLAGS_COMMON "${RP_SHARED_LINKER_FLAGS_COMMON} ${RP_EXE_LINKER_FLAGS_WIN32}")
SET(RP_MODULE_LINKER_FLAGS_COMMON "${RP_MODULE_LINKER_FLAGS_COMMON} ${RP_EXE_LINKER_FLAGS_WIN32}")
# Unset temporary variables. # Unset temporary variables.
UNSET(RP_C_FLAGS_WIN32) UNSET(RP_C_FLAGS_WIN32)
UNSET(RP_EXE_LINKER_FLAGS_WIN32)

View File

@ -4,39 +4,24 @@
# - Enable strict type checking in the Windows headers. # - Enable strict type checking in the Windows headers.
# - Define WIN32_LEAN_AND_MEAN to reduce the number of Windows headers included. # - Define WIN32_LEAN_AND_MEAN to reduce the number of Windows headers included.
# - Define NOMINMAX to disable the MIN() and MAX() macros. # - Define NOMINMAX to disable the MIN() and MAX() macros.
SET(RP_C_FLAGS_WIN32 "-DSTRICT -DWIN32_LEAN_AND_MEAN -DNOMINMAX") ADD_DEFINITIONS(-DSTRICT -DWIN32_LEAN_AND_MEAN -DNOMINMAX)
# NOTE: This program only supports Unicode on Windows. # NOTE: This program only supports Unicode on Windows.
# No support for ANSI Windows, i.e. Win9x. # No support for ANSI Windows, i.e. Win9x.
SET(RP_C_FLAGS_WIN32 "${RP_C_FLAGS_WIN32} -DUNICODE -D_UNICODE") ADD_DEFINITIONS(-DUNICODE -D_UNICODE)
# Minimum Windows version for the SDK is Windows XP. # Minimum Windows version for the SDK is Windows XP.
SET(RP_C_FLAGS_WIN32 "${RP_C_FLAGS_WIN32} -DWINVER=0x0501 -D_WIN32_WINNT=0x0501 -D_WIN32_IE=0x0600") ADD_DEFINITIONS(-DWINVER=0x0501 -D_WIN32_WINNT=0x0501 -D_WIN32_IE=0x0600)
# Enable secure template overloads for C++. # Enable secure template overloads for C++.
# References: # References:
# - MinGW's _mingw_secapi.h # - MinGW's _mingw_secapi.h
# - http://msdn.microsoft.com/en-us/library/ms175759%28v=VS.100%29.aspx # - http://msdn.microsoft.com/en-us/library/ms175759%28v=VS.100%29.aspx
SET(RP_CXX_FLAGS_WIN32 "-D_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES=1") ADD_DEFINITIONS(-D_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES=1)
SET(RP_CXX_FLAGS_WIN32 "${RP_CXX_FLAGS_WIN32} -D_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES_MEMORY=1") ADD_DEFINITIONS(-D_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES_MEMORY=1)
SET(RP_CXX_FLAGS_WIN32 "${RP_CXX_FLAGS_WIN32} -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1") ADD_DEFINITIONS(-D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1)
SET(RP_CXX_FLAGS_WIN32 "${RP_CXX_FLAGS_WIN32} -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1") ADD_DEFINITIONS(-D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1)
SET(RP_CXX_FLAGS_WIN32 "${RP_CXX_FLAGS_WIN32} -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_MEMORY=1") ADD_DEFINITIONS(-D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_MEMORY=1)
# Determine the processorArchitecture for the manifest files.
STRING(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" arch)
IF(arch MATCHES "^x86_64|amd64|(i.|x)86$")
IF(CMAKE_CL_64)
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "amd64")
ELSE(CMAKE_CL_64)
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "x86")
ENDIF(CMAKE_CL_64)
ELSEIF(arch MATCHES "^ia64$")
SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "ia64")
ELSE()
MESSAGE(FATAL_ERROR "Unsupported CPU architecture, please fix!")
ENDIF()
UNSET(arch)
# Compiler-specific Win32 flags. # Compiler-specific Win32 flags.
IF(MSVC) IF(MSVC)

View File

@ -0,0 +1,20 @@
SET(HOST_SYSTEM i686-w64-mingw32)
# the name of the target operating system
SET(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_SYSTEM_PROCESSOR i686)
# which compilers to use for C and C++
SET(CMAKE_C_COMPILER ${HOST_SYSTEM}-gcc)
SET(CMAKE_CXX_COMPILER ${HOST_SYSTEM}-g++)
SET(CMAKE_RC_COMPILER ${HOST_SYSTEM}-windres)
# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH /usr/${HOST_SYSTEM})
# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
# programs in the host environment
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

View File

@ -0,0 +1,20 @@
SET(HOST_SYSTEM x86_64-w64-mingw32)
# the name of the target operating system
SET(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_SYSTEM_PROCESSOR x86_64)
# which compilers to use for C and C++
SET(CMAKE_C_COMPILER ${HOST_SYSTEM}-gcc)
SET(CMAKE_CXX_COMPILER ${HOST_SYSTEM}-g++)
SET(CMAKE_RC_COMPILER ${HOST_SYSTEM}-windres)
# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH /usr/${HOST_SYSTEM})
# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
# programs in the host environment
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

3
crowdin.yml Normal file
View File

@ -0,0 +1,3 @@
files:
- source: /locale/rvthtool_en.ts
translation: /locale/rvthtool_%two_letters_code%.ts

18
debian/changelog vendored
View File

@ -1,3 +1,21 @@
rvthtool (2.0-1ppa1~xenial3) xenial; urgency=medium
* 2.0 release.
-- David Korth <gerbilsoft@gerbilsoft.com> Mon, 16 Jun 2025 22:19:14 -0400
rvthtool (1.1.1-1ppa1~xenial1) xenial; urgency=medium
* 1.1.1 release.
-- David Korth <gerbilsoft@gerbilsoft.com> Mon, 17 Sep 2018 21:32:30 -0400
rvthtool (1.1-1ppa1~xenial1) xenial; urgency=medium
* 1.1 release.
-- David Korth <gerbilsoft@gerbilsoft.com> Mon, 17 Sep 2018 20:44:00 -0400
rvthtool (1.0-1ppa1~xenial1) xenial; urgency=medium rvthtool (1.0-1ppa1~xenial1) xenial; urgency=medium
* 1.0 release. * 1.0 release.

28
debian/control vendored
View File

@ -8,7 +8,9 @@ Build-Depends:
dpkg-dev (>= 1.17.17), dpkg-dev (>= 1.17.17),
libgmp3-dev, libgmp3-dev,
nettle-dev, nettle-dev,
libudev-dev libudev-dev,
qtbase5-dev,
qttools5-dev-tools
Standards-Version: 3.9.8 Standards-Version: 3.9.8
Homepage: https://github.com/GerbilSoft/rvthtool Homepage: https://github.com/GerbilSoft/rvthtool
Vcs-Git: https://github.com/GerbilSoft/rvthtool Vcs-Git: https://github.com/GerbilSoft/rvthtool
@ -19,3 +21,27 @@ Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends} Depends: ${shlibs:Depends}, ${misc:Depends}
Description: RVT-H Tool Description: RVT-H Tool
This is an open-source tool for managing RVT-H Reader consoles. This is an open-source tool for managing RVT-H Reader consoles.
Package: qrvthtool
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Recommends: rvthtool-lang
Description: RVT-H Tool (GUI)
This is an open-source tool for managing RVT-H Reader consoles. (GUI)
Package: rvthtool-lang
Architecture: all
Description: RVT-H Tool (localization)
RVT-H Tool localization files. (Qt only for now)
Package: wadresign
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: WAD Resign
WAD Resign is a command-line tool to re-sign Nintendo Wii WAD files.
Package: nusresign
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: NUS Resign
NUS Resign is a command-line tool to re-sign Nintendo Wii U NUS packages.

6
debian/nusresign.docs vendored Normal file
View File

@ -0,0 +1,6 @@
README.md
NEWS.md
NETWORK.md
doc/disc_image.md
doc/rvth_notes.md
doc/sdk_header.md

1
debian/nusresign.install vendored Normal file
View File

@ -0,0 +1 @@
usr/bin/nusresign

6
debian/qrvthtool.docs vendored Normal file
View File

@ -0,0 +1,6 @@
README.md
NEWS.md
NETWORK.md
doc/disc_image.md
doc/rvth_notes.md
doc/sdk_header.md

4
debian/qrvthtool.install vendored Normal file
View File

@ -0,0 +1,4 @@
usr/bin/qrvthtool
usr/share/applications/com.gerbilsoft.qrvthtool.desktop
usr/share/icons/hicolor/*/apps/qrvthtool.png
usr/share/metainfo/com.gerbilsoft.qrvthtool.metainfo.xml

8
debian/rules vendored
View File

@ -10,7 +10,8 @@ DESTDIR := $(CURDIR)/debian/rvthtool
CMAKE_OPTIONS := \ CMAKE_OPTIONS := \
-DCMAKE_BUILD_TYPE=Release \ -DCMAKE_BUILD_TYPE=Release \
-DSPLIT_DEBUG=OFF \ -DSPLIT_DEBUG=OFF \
-DENABLE_LTO=OFF -DENABLE_LTO=OFF \
-DQT_VERSION=5
ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
CMAKE_OPTIONS += -DBUILD_TESTING=ON CMAKE_OPTIONS += -DBUILD_TESTING=ON
endif endif
@ -22,8 +23,3 @@ override_dh_auto_test:
ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
CTEST_OUTPUT_ON_FAILURE=1 $(MAKE) -C build test CTEST_OUTPUT_ON_FAILURE=1 $(MAKE) -C build test
endif endif
# Remove the extra LICENSE file.
override_dh_auto_install:
dh_auto_install
rm $(DESTDIR)/usr/share/doc/rvthtool/LICENSE

6
debian/rvthtool-lang.docs vendored Normal file
View File

@ -0,0 +1,6 @@
README.md
NEWS.md
NETWORK.md
doc/disc_image.md
doc/rvth_notes.md
doc/sdk_header.md

1
debian/rvthtool-lang.install vendored Normal file
View File

@ -0,0 +1 @@
usr/share/rvthtool/translations/*

6
debian/rvthtool.docs vendored Normal file
View File

@ -0,0 +1,6 @@
README.md
NEWS.md
NETWORK.md
doc/disc_image.md
doc/rvth_notes.md
doc/sdk_header.md

1
debian/rvthtool.install vendored Normal file
View File

@ -0,0 +1 @@
usr/bin/rvthtool

6
debian/wadresign.docs vendored Normal file
View File

@ -0,0 +1,6 @@
README.md
NEWS.md
NETWORK.md
doc/disc_image.md
doc/rvth_notes.md
doc/sdk_header.md

1
debian/wadresign.install vendored Normal file
View File

@ -0,0 +1 @@
usr/bin/wadresign

View File

@ -22,6 +22,7 @@ INSTALL(FILES
INSTALL(FILES INSTALL(FILES
../README.md ../README.md
../NEWS.md ../NEWS.md
../NETWORK.md
../LICENSE ../LICENSE
DESTINATION "${DIR_INSTALL_DOC_ROOT}" DESTINATION "${DIR_INSTALL_DOC_ROOT}"
COMPONENT "doc" COMPONENT "doc"

View File

@ -4,11 +4,13 @@
On Debian/Ubuntu, you will need build-essential and the following development On Debian/Ubuntu, you will need build-essential and the following development
packages: packages:
* pkg-config libgmp-dev nettle-dev libudev-dev * cmake pkg-config libgmp-dev nettle-dev libudev-dev
* For the Qt GUI: qtbase5-dev qttools5-dev qttools5-dev-tools
On Red Hat/Fedora, you will need to install "C Development Tools and Libraries" On Red Hat/Fedora, you will need to install "C Development Tools and Libraries"
and the following development packages: and the following development packages:
* cmake gmp-devel nettle-devel libudev-devel * cmake gmp-devel nettle-devel libudev-devel
* For the Qt GUI: qt-devel qt5-linguist
Clone the repository, then: Clone the repository, then:
* cd rvthtool * cd rvthtool

View File

@ -158,9 +158,9 @@ Values in bold are different from encrypted discs.
| 0x1BC | 0x03 | `00 00 00` | N/A | Padding | | 0x1BC | 0x03 | `00 00 00` | N/A | Padding |
| 0x1BF | 0x10 | Encrypted title key | See hexdump | Encrypted title key | | 0x1BF | 0x10 | Encrypted title key | See hexdump | Encrypted title key |
| 0x1CF | 0x01 | `00` | 0x00 | Unknown | | 0x1CF | 0x01 | `00` | 0x00 | Unknown |
| 0x1D0 | 0x08 | `00 01 e5 89 b2 45 95 eb | See hexdump | Ticket ID | | 0x1D0 | 0x08 | `00 01 e5 89 b2 45 95 eb` | See hexdump | Ticket ID |
| 0x1D8 | 0x04 | `00 00 00 00` | 0x00000000 | Console ID | | 0x1D8 | 0x04 | `00 00 00 00` | 0x00000000 | Console ID |
| 0x1DC | 0x08 | `00 01 00 00 53 4c 53 50 | 00010000-SLSP | Title ID / AES-CBC IV | | 0x1DC | 0x08 | `00 01 00 00 53 4c 53 50` | 00010000-SLSP | Title ID / AES-CBC IV |
| 0x1E4 | 0x02 | `ff ff` | 0xFFFF | Unknown | | 0x1E4 | 0x02 | `ff ff` | 0xFFFF | Unknown |
| 0x1E6 | 0x02 | `00 00` | 0x0000 | Ticket version | | 0x1E6 | 0x02 | `00 00` | 0x0000 | Ticket version |
| 0x1E8 | 0x04 | `00 00 00 00` | 0x00000000 | Permitted titles mask | | 0x1E8 | 0x04 | `00 00 00 00` | 0x00000000 | Permitted titles mask |

17
extlib/CMakeLists.txt vendored
View File

@ -23,12 +23,27 @@ IF(BUILD_TESTING)
SET(gtest_force_shared_crt ON CACHE BOOL "Always use msvcrt.dll") SET(gtest_force_shared_crt ON CACHE BOOL "Always use msvcrt.dll")
SET(SKIP_INSTALL_LIBRARIES ON) SET(SKIP_INSTALL_LIBRARIES ON)
SET(SKIP_INSTALL_ALL ON) SET(SKIP_INSTALL_ALL ON)
ADD_SUBDIRECTORY(googletest)
# Use shared libraries on Windows.
IF(WIN32)
SET(BUILD_STATIC_LIBS OFF)
SET(BUILD_SHARED_LIBS ON)
ELSE(WIN32)
SET(BUILD_STATIC_LIBS ON)
SET(BUILD_SHARED_LIBS OFF)
ENDIF(WIN32)
ADD_SUBDIRECTORY(googletest)
INCLUDE(SetMSVCDebugPath)
SET_EXTLIB_PROPERTIES( SET_EXTLIB_PROPERTIES(
gtest gtest_main gtest_no_exception gtest_main_no_exception gtest gtest_main gtest_no_exception gtest_main_no_exception
gtest_main_no_rtti gtest_dll gtest_main_use_own_tuple gtest_main_no_rtti gtest_dll gtest_main_use_own_tuple
gmock gmock_main gmock_main_no_exception gmock gmock_main gmock_main_no_exception
gmock_main_no_rtti gmock_main_use_own_tuple gmock_main_no_rtti gmock_main_use_own_tuple
) )
IF(WIN32)
# GTest is a DLL, so we need to set this.
TARGET_COMPILE_DEFINITIONS(gtest INTERFACE GTEST_LINKED_AS_SHARED_LIBRARY=1)
#TARGET_COMPILE_DEFINITIONS(gtest_main INTERFACE GTEST_LINKED_AS_SHARED_LIBRARY=1)
ENDIF(WIN32)
ENDIF(BUILD_TESTING) ENDIF(BUILD_TESTING)

View File

@ -1,4 +1,12 @@
PROJECT(getopt_msvc) # getopt() implementation for MSVC.
CMAKE_MINIMUM_REQUIRED(VERSION 3.5..3.10)
CMAKE_POLICY(SET CMP0048 NEW)
IF(POLICY CMP0063)
# CMake 3.3: Enable symbol visibility presets for all
# target types, including static libraries and executables.
CMAKE_POLICY(SET CMP0063 NEW)
ENDIF(POLICY CMP0063)
PROJECT(getopt_msvc LANGUAGES C)
###################### ######################
# Build the library. # # Build the library. #

View File

@ -0,0 +1,15 @@
This copy of getopt-msvc-1.1.0 is a modified version of the original.
commit c620fc78d6c098c1fda3eccad585d016dbd783f0
Updated to match most recent getopt release
Tag: v1.1.0
The following changes have been made to the original:
- Only including the source code files.
- CMakeLists.txt is completely custom.
To obtain the original getopt-msvc-1.1.0, visit:
https://github.com/ludvikjerabek/getopt-win

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@ to provide a Microsoft Visual C friendly derivative. This code
provides functionality for both Unicode and Multibyte builds. provides functionality for both Unicode and Multibyte builds.
Date: 02/03/2011 - Ludvik Jerabek - Initial Release Date: 02/03/2011 - Ludvik Jerabek - Initial Release
Version: 1.0 Version: 1.1
Comment: Supports getopt, getopt_long, and getopt_long_only Comment: Supports getopt, getopt_long, and getopt_long_only
and POSIXLY_CORRECT environment flag and POSIXLY_CORRECT environment flag
License: LGPL License: LGPL
@ -21,6 +21,8 @@ Revisions:
08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi 08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi
10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features 10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features
06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable 06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable
09/24/2022 - Ludvik Jerabek - Updated to match most recent getopt release
09/25/2022 - Ludvik Jerabek - Fixed memory allocation (malloc call) issue for wchar_t*
**DISCLAIMER** **DISCLAIMER**
THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,

4
extlib/googletest/.clang-format vendored Normal file
View File

@ -0,0 +1,4 @@
# Run manually to reformat a file:
# clang-format -i --style=file <file>
Language: Cpp
BasedOnStyle: Google

View File

@ -1,2 +1,84 @@
# Ignore CI build directory # Ignore CI build directory
build/ build/
xcuserdata
cmake-build-debug/
.idea/
bazel-bin
bazel-genfiles
bazel-googletest
bazel-out
bazel-testlogs
# python
*.pyc
# Visual Studio files
.vs
*.sdf
*.opensdf
*.VC.opendb
*.suo
*.user
_ReSharper.Caches/
Win32-Debug/
Win32-Release/
x64-Debug/
x64-Release/
# Ignore autoconf / automake files
Makefile.in
aclocal.m4
configure
build-aux/
autom4te.cache/
googletest/m4/libtool.m4
googletest/m4/ltoptions.m4
googletest/m4/ltsugar.m4
googletest/m4/ltversion.m4
googletest/m4/lt~obsolete.m4
googlemock/m4
# Ignore generated directories.
googlemock/fused-src/
googletest/fused-src/
# macOS files
.DS_Store
googletest/.DS_Store
googletest/xcode/.DS_Store
# Ignore cmake generated directories and files.
CMakeFiles
CTestTestfile.cmake
Makefile
cmake_install.cmake
googlemock/CMakeFiles
googlemock/CTestTestfile.cmake
googlemock/Makefile
googlemock/cmake_install.cmake
googlemock/gtest
/bin
/googlemock/gmock.dir
/googlemock/gmock_main.dir
/googlemock/RUN_TESTS.vcxproj.filters
/googlemock/RUN_TESTS.vcxproj
/googlemock/INSTALL.vcxproj.filters
/googlemock/INSTALL.vcxproj
/googlemock/gmock_main.vcxproj.filters
/googlemock/gmock_main.vcxproj
/googlemock/gmock.vcxproj.filters
/googlemock/gmock.vcxproj
/googlemock/gmock.sln
/googlemock/ALL_BUILD.vcxproj.filters
/googlemock/ALL_BUILD.vcxproj
/lib
/Win32
/ZERO_CHECK.vcxproj.filters
/ZERO_CHECK.vcxproj
/RUN_TESTS.vcxproj.filters
/RUN_TESTS.vcxproj
/INSTALL.vcxproj.filters
/INSTALL.vcxproj
/googletest-distribution.sln
/CMakeCache.txt
/ALL_BUILD.vcxproj.filters
/ALL_BUILD.vcxproj

View File

@ -1,46 +0,0 @@
# Build matrix / environment variable are explained on:
# http://about.travis-ci.org/docs/user/build-configuration/
# This file can be validated on:
# http://lint.travis-ci.org/
install:
# /usr/bin/gcc is 4.6 always, but gcc-X.Y is available.
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.9" CC="gcc-4.9"; fi
# /usr/bin/clang is 3.4, lets override with modern one.
- if [ "$CXX" = "clang++" ] && [ "$TRAVIS_OS_NAME" = "linux" ]; then export CXX="clang++-3.7" CC="clang-3.7"; fi
- echo ${PATH}
- echo ${CXX}
- ${CXX} --version
- ${CXX} -v
addons:
apt:
# List of whitelisted in travis packages for ubuntu-precise can be found here:
# https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise
# List of whitelisted in travis apt-sources:
# https://github.com/travis-ci/apt-source-whitelist/blob/master/ubuntu.json
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.7
packages:
- gcc-4.9
- g++-4.9
- clang-3.7
- valgrind
os:
- linux
- osx
language: cpp
compiler:
- gcc
- clang
script: ./travis.sh
env:
matrix:
- GTEST_TARGET=googletest SHARED_LIB=OFF STATIC_LIB=ON CMAKE_PKG=OFF BUILD_TYPE=debug VERBOSE_MAKE=true VERBOSE
- GTEST_TARGET=googlemock SHARED_LIB=OFF STATIC_LIB=ON CMAKE_PKG=OFF BUILD_TYPE=debug VERBOSE_MAKE=true VERBOSE
- GTEST_TARGET=googlemock SHARED_LIB=OFF STATIC_LIB=ON CMAKE_PKG=OFF BUILD_TYPE=debug CXX_FLAGS=-std=c++11 VERBOSE_MAKE=true VERBOSE
# - GTEST_TARGET=googletest SHARED_LIB=ON STATIC_LIB=ON CMAKE_PKG=ON BUILD_TYPE=release VERBOSE_MAKE=false
# - GTEST_TARGET=googlemock SHARED_LIB=ON STATIC_LIB=ON CMAKE_PKG=ON BUILD_TYPE=release VERBOSE_MAKE=false
notifications:
email: false
sudo: false

218
extlib/googletest/BUILD.bazel vendored Normal file
View File

@ -0,0 +1,218 @@
# Copyright 2017 Google Inc.
# All Rights Reserved.
#
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Bazel Build for Google C++ Testing Framework(Google Test)
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
exports_files(["LICENSE"])
config_setting(
name = "qnx",
constraint_values = ["@platforms//os:qnx"],
)
config_setting(
name = "windows",
constraint_values = ["@platforms//os:windows"],
)
config_setting(
name = "freebsd",
constraint_values = ["@platforms//os:freebsd"],
)
config_setting(
name = "openbsd",
constraint_values = ["@platforms//os:openbsd"],
)
config_setting(
name = "msvc_compiler",
flag_values = {
"@bazel_tools//tools/cpp:compiler": "msvc-cl",
},
visibility = [":__subpackages__"],
)
config_setting(
name = "has_absl",
values = {"define": "absl=1"},
)
# Library that defines the FRIEND_TEST macro.
cc_library(
name = "gtest_prod",
hdrs = ["googletest/include/gtest/gtest_prod.h"],
includes = ["googletest/include"],
)
# Google Test including Google Mock
cc_library(
name = "gtest",
srcs = glob(
include = [
"googletest/src/*.cc",
"googletest/src/*.h",
"googletest/include/gtest/**/*.h",
"googlemock/src/*.cc",
"googlemock/include/gmock/**/*.h",
],
exclude = [
"googletest/src/gtest-all.cc",
"googletest/src/gtest_main.cc",
"googlemock/src/gmock-all.cc",
"googlemock/src/gmock_main.cc",
],
),
hdrs = glob([
"googletest/include/gtest/*.h",
"googlemock/include/gmock/*.h",
]),
copts = select({
":qnx": [],
":windows": [],
"//conditions:default": ["-pthread"],
}),
defines = select({
":has_absl": ["GTEST_HAS_ABSL=1"],
"//conditions:default": [],
}),
features = select({
":windows": ["windows_export_all_symbols"],
"//conditions:default": [],
}),
includes = [
"googlemock",
"googlemock/include",
"googletest",
"googletest/include",
],
linkopts = select({
":qnx": ["-lregex"],
":windows": [],
":freebsd": [
"-lm",
"-pthread",
],
":openbsd": [
"-lm",
"-pthread",
],
"//conditions:default": ["-pthread"],
}),
deps = select({
":has_absl": [
"@com_google_absl//absl/debugging:failure_signal_handler",
"@com_google_absl//absl/debugging:stacktrace",
"@com_google_absl//absl/debugging:symbolize",
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/flags:parse",
"@com_google_absl//absl/flags:reflection",
"@com_google_absl//absl/flags:usage",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/types:any",
"@com_google_absl//absl/types:optional",
"@com_google_absl//absl/types:variant",
"@com_googlesource_code_re2//:re2",
],
"//conditions:default": [],
}),
)
cc_library(
name = "gtest_main",
srcs = ["googlemock/src/gmock_main.cc"],
features = select({
":windows": ["windows_export_all_symbols"],
"//conditions:default": [],
}),
deps = [":gtest"],
)
# The following rules build samples of how to use gTest.
cc_library(
name = "gtest_sample_lib",
srcs = [
"googletest/samples/sample1.cc",
"googletest/samples/sample2.cc",
"googletest/samples/sample4.cc",
],
hdrs = [
"googletest/samples/prime_tables.h",
"googletest/samples/sample1.h",
"googletest/samples/sample2.h",
"googletest/samples/sample3-inl.h",
"googletest/samples/sample4.h",
],
features = select({
":windows": ["windows_export_all_symbols"],
"//conditions:default": [],
}),
)
cc_test(
name = "gtest_samples",
size = "small",
# All Samples except:
# sample9 (main)
# sample10 (main and takes a command line option and needs to be separate)
srcs = [
"googletest/samples/sample1_unittest.cc",
"googletest/samples/sample2_unittest.cc",
"googletest/samples/sample3_unittest.cc",
"googletest/samples/sample4_unittest.cc",
"googletest/samples/sample5_unittest.cc",
"googletest/samples/sample6_unittest.cc",
"googletest/samples/sample7_unittest.cc",
"googletest/samples/sample8_unittest.cc",
],
linkstatic = 0,
deps = [
"gtest_sample_lib",
":gtest_main",
],
)
cc_test(
name = "sample9_unittest",
size = "small",
srcs = ["googletest/samples/sample9_unittest.cc"],
deps = [":gtest"],
)
cc_test(
name = "sample10_unittest",
size = "small",
srcs = ["googletest/samples/sample10_unittest.cc"],
deps = [":gtest"],
)

View File

@ -1,21 +1,54 @@
#cmake_minimum_required(VERSION 2.6.2) # Note: CMake support is community-based. The maintainers do not use CMake
# internally.
cmake_minimum_required(VERSION 3.5...3.10)
if (POLICY CMP0048)
cmake_policy(SET CMP0048 NEW)
endif (POLICY CMP0048)
if (POLICY CMP0077)
cmake_policy(SET CMP0077 NEW)
endif (POLICY CMP0077)
project(googletest-distribution) project(googletest-distribution)
set(GOOGLETEST_VERSION 1.12.1)
if(NOT CYGWIN AND NOT MSYS AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL QNX)
set(CMAKE_CXX_EXTENSIONS OFF)
endif()
enable_testing() enable_testing()
option(BUILD_GTEST "Builds the googletest subproject" OFF) include(CMakeDependentOption)
include(GNUInstallDirs)
#Note that googlemock target already builds googletest
option(BUILD_GMOCK "Builds the googlemock subproject" ON)
# rom-properties: Enable policy CMP0063 for visibility properties. # rom-properties: Enable policy CMP0063 for visibility properties.
IF(NOT CMAKE_VERSION VERSION_LESS 3.3.0) IF(POLICY CMP0063)
CMAKE_POLICY(SET CMP0063 NEW) CMAKE_POLICY(SET CMP0063 NEW)
ENDIF(NOT CMAKE_VERSION VERSION_LESS 3.3.0) ENDIF(POLICY CMP0063)
# rom-properties: Disable options.
IF(0)
#Note that googlemock target already builds googletest
option(BUILD_GMOCK "Builds the googlemock subproject" ON)
option(INSTALL_GTEST "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" ON)
ELSE(0) # rom-properties
SET(BUILD_GMOCK ON)
SET(INSTALL_GTEST OFF)
ENDIF(0) # rom-properties
# rom-properties: Set CMake debug/release postfix on MSVC.
IF(MSVC)
SET(CMAKE_DEBUG_POSTFIX "d")
SET(CMAKE_RELEASE_POSTFIX "")
ELSE(MSVC)
SET(CMAKE_DEBUG_POSTFIX "")
SET(CMAKE_RELEASE_POSTFIX "")
ENDIF(MSVC)
if(BUILD_GMOCK) if(BUILD_GMOCK)
add_subdirectory( googlemock ) add_subdirectory( googlemock )
elseif(BUILD_GTEST) else()
add_subdirectory( googletest ) add_subdirectory( googletest )
endif() endif()

131
extlib/googletest/CONTRIBUTING.md vendored Normal file
View File

@ -0,0 +1,131 @@
# How to become a contributor and submit your own code
## Contributor License Agreements
We'd love to accept your patches! Before we can take them, we have to jump a
couple of legal hurdles.
Please fill out either the individual or corporate Contributor License Agreement
(CLA).
* If you are an individual writing original source code and you're sure you
own the intellectual property, then you'll need to sign an
[individual CLA](https://developers.google.com/open-source/cla/individual).
* If you work for a company that wants to allow you to contribute your work,
then you'll need to sign a
[corporate CLA](https://developers.google.com/open-source/cla/corporate).
Follow either of the two links above to access the appropriate CLA and
instructions for how to sign and return it. Once we receive it, we'll be able to
accept your pull requests.
## Are you a Googler?
If you are a Googler, please make an attempt to submit an internal contribution
rather than a GitHub Pull Request. If you are not able to submit internally, a
PR is acceptable as an alternative.
## Contributing A Patch
1. Submit an issue describing your proposed change to the
[issue tracker](https://github.com/google/googletest/issues).
2. Please don't mix more than one logical change per submittal, because it
makes the history hard to follow. If you want to make a change that doesn't
have a corresponding issue in the issue tracker, please create one.
3. Also, coordinate with team members that are listed on the issue in question.
This ensures that work isn't being duplicated and communicating your plan
early also generally leads to better patches.
4. If your proposed change is accepted, and you haven't already done so, sign a
Contributor License Agreement
([see details above](#contributor-license-agreements)).
5. Fork the desired repo, develop and test your code changes.
6. Ensure that your code adheres to the existing style in the sample to which
you are contributing.
7. Ensure that your code has an appropriate set of unit tests which all pass.
8. Submit a pull request.
## The Google Test and Google Mock Communities
The Google Test community exists primarily through the
[discussion group](http://groups.google.com/group/googletestframework) and the
GitHub repository. Likewise, the Google Mock community exists primarily through
their own [discussion group](http://groups.google.com/group/googlemock). You are
definitely encouraged to contribute to the discussion and you can also help us
to keep the effectiveness of the group high by following and promoting the
guidelines listed here.
### Please Be Friendly
Showing courtesy and respect to others is a vital part of the Google culture,
and we strongly encourage everyone participating in Google Test development to
join us in accepting nothing less. Of course, being courteous is not the same as
failing to constructively disagree with each other, but it does mean that we
should be respectful of each other when enumerating the 42 technical reasons
that a particular proposal may not be the best choice. There's never a reason to
be antagonistic or dismissive toward anyone who is sincerely trying to
contribute to a discussion.
Sure, C++ testing is serious business and all that, but it's also a lot of fun.
Let's keep it that way. Let's strive to be one of the friendliest communities in
all of open source.
As always, discuss Google Test in the official GoogleTest discussion group. You
don't have to actually submit code in order to sign up. Your participation
itself is a valuable contribution.
## Style
To keep the source consistent, readable, diffable and easy to merge, we use a
fairly rigid coding style, as defined by the
[google-styleguide](https://github.com/google/styleguide) project. All patches
will be expected to conform to the style outlined
[here](https://google.github.io/styleguide/cppguide.html). Use
[.clang-format](https://github.com/google/googletest/blob/master/.clang-format)
to check your formatting.
## Requirements for Contributors
If you plan to contribute a patch, you need to build Google Test, Google Mock,
and their own tests from a git checkout, which has further requirements:
* [Python](https://www.python.org/) v2.3 or newer (for running some of the
tests and re-generating certain source files from templates)
* [CMake](https://cmake.org/) v2.8.12 or newer
## Developing Google Test and Google Mock
This section discusses how to make your own changes to the Google Test project.
### Testing Google Test and Google Mock Themselves
To make sure your changes work as intended and don't break existing
functionality, you'll want to compile and run Google Test and GoogleMock's own
tests. For that you can use CMake:
mkdir mybuild
cd mybuild
cmake -Dgtest_build_tests=ON -Dgmock_build_tests=ON ${GTEST_REPO_DIR}
To choose between building only Google Test or Google Mock, you may modify your
cmake command to be one of each
cmake -Dgtest_build_tests=ON ${GTEST_DIR} # sets up Google Test tests
cmake -Dgmock_build_tests=ON ${GMOCK_DIR} # sets up Google Mock tests
Make sure you have Python installed, as some of Google Test's tests are written
in Python. If the cmake command complains about not being able to find Python
(`Could NOT find PythonInterp (missing: PYTHON_EXECUTABLE)`), try telling it
explicitly where your Python executable can be found:
cmake -DPYTHON_EXECUTABLE=path/to/python ...
Next, you can build Google Test and / or Google Mock and all desired tests. On
\*nix, this is usually done by
make
To run the tests, do
make test
All tests should pass.

View File

@ -5,33 +5,61 @@
Ajay Joshi <jaj@google.com> Ajay Joshi <jaj@google.com>
Balázs Dán <balazs.dan@gmail.com> Balázs Dán <balazs.dan@gmail.com>
Benoit Sigoure <tsuna@google.com>
Bharat Mediratta <bharat@menalto.com> Bharat Mediratta <bharat@menalto.com>
Bogdan Piloca <boo@google.com>
Chandler Carruth <chandlerc@google.com> Chandler Carruth <chandlerc@google.com>
Chris Prince <cprince@google.com> Chris Prince <cprince@google.com>
Chris Taylor <taylorc@google.com> Chris Taylor <taylorc@google.com>
Dan Egnor <egnor@google.com> Dan Egnor <egnor@google.com>
Dave MacLachlan <dmaclach@gmail.com>
David Anderson <danderson@google.com>
Dean Sturtevant
Eric Roman <eroman@chromium.org> Eric Roman <eroman@chromium.org>
Gene Volovich <gv@cite.com>
Hady Zalek <hady.zalek@gmail.com> Hady Zalek <hady.zalek@gmail.com>
Hal Burch <gmock@hburch.com>
Jeffrey Yasskin <jyasskin@google.com> Jeffrey Yasskin <jyasskin@google.com>
Jim Keller <jimkeller@google.com>
Joe Walnes <joe@truemesh.com>
Jon Wray <jwray@google.com>
Jói Sigurðsson <joi@google.com> Jói Sigurðsson <joi@google.com>
Keir Mierle <mierle@gmail.com> Keir Mierle <mierle@gmail.com>
Keith Ray <keith.ray@gmail.com> Keith Ray <keith.ray@gmail.com>
Kenton Varda <kenton@google.com> Kenton Varda <kenton@google.com>
Kostya Serebryany <kcc@google.com>
Krystian Kuzniarek <krystian.kuzniarek@gmail.com>
Lev Makhlis
Manuel Klimek <klimek@google.com> Manuel Klimek <klimek@google.com>
Mario Tanev <radix@google.com>
Mark Paskin
Markus Heule <markus.heule@gmail.com> Markus Heule <markus.heule@gmail.com>
Martijn Vels <mvels@google.com>
Matthew Simmons <simmonmt@acm.org>
Mika Raento <mikie@iki.fi> Mika Raento <mikie@iki.fi>
Mike Bland <mbland@google.com>
Miklós Fazekas <mfazekas@szemafor.com> Miklós Fazekas <mfazekas@szemafor.com>
Neal Norwitz <nnorwitz@gmail.com>
Nermin Ozkiranartli <nermin@google.com>
Owen Carlsen <ocarlsen@google.com>
Paneendra Ba <paneendra@google.com>
Pasi Valminen <pasi.valminen@gmail.com> Pasi Valminen <pasi.valminen@gmail.com>
Patrick Hanna <phanna@google.com> Patrick Hanna <phanna@google.com>
Patrick Riley <pfr@google.com> Patrick Riley <pfr@google.com>
Paul Menage <menage@google.com>
Peter Kaminski <piotrk@google.com> Peter Kaminski <piotrk@google.com>
Piotr Kaminski <piotrk@google.com>
Preston Jackson <preston.a.jackson@gmail.com> Preston Jackson <preston.a.jackson@gmail.com>
Rainer Klaffenboeck <rainer.klaffenboeck@dynatrace.com> Rainer Klaffenboeck <rainer.klaffenboeck@dynatrace.com>
Russ Cox <rsc@google.com> Russ Cox <rsc@google.com>
Russ Rufer <russ@pentad.com> Russ Rufer <russ@pentad.com>
Sean Mcafee <eefacm@gmail.com> Sean Mcafee <eefacm@gmail.com>
Sigurður Ásgeirsson <siggi@google.com> Sigurður Ásgeirsson <siggi@google.com>
Sverre Sundsdal <sundsdal@gmail.com>
Szymon Sobik <sobik.szymon@gmail.com>
Takeshi Yoshino <tyoshino@google.com>
Tracy Bialik <tracy@pentad.com> Tracy Bialik <tracy@pentad.com>
Vadim Berman <vadimb@google.com> Vadim Berman <vadimb@google.com>
Vlad Losev <vladl@google.com> Vlad Losev <vladl@google.com>
Wolfgang Klier <wklier@google.com>
Zhanyong Wan <wan@google.com> Zhanyong Wan <wan@google.com>

View File

@ -1,32 +1,49 @@
# GoogleTest
# Google Test # ### Announcements
[![Build Status](https://travis-ci.org/google/googletest.svg?branch=master)](https://travis-ci.org/google/googletest) #### Live at Head
[![Build status](https://ci.appveyor.com/api/projects/status/4o38plt0xbo1ubc8/branch/master?svg=true)](https://ci.appveyor.com/project/BillyDonahue/googletest/branch/master)
Welcome to **Google Test**, Google's C++ test framework! GoogleTest now follows the
[Abseil Live at Head philosophy](https://abseil.io/about/philosophy#upgrade-support).
We recommend
[updating to the latest commit in the `main` branch as often as possible](https://github.com/abseil/abseil-cpp/blob/master/FAQ.md#what-is-live-at-head-and-how-do-i-do-it).
This repository is a merger of the formerly separate GoogleTest and #### Documentation Updates
GoogleMock projects. These were so closely related that it makes sense to
maintain and release them together.
Please see the project page above for more information as well as the Our documentation is now live on GitHub Pages at
mailing list for questions, discussions, and development. There is https://google.github.io/googletest/. We recommend browsing the documentation on
also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please GitHub Pages rather than directly in the repository.
join us!
Getting started information for **Google Test** is available in the #### Release 1.11.0
[Google Test Primer](googletest/docs/Primer.md) documentation.
**Google Mock** is an extension to Google Test for writing and using C++ mock [Release 1.11.0](https://github.com/google/googletest/releases/tag/release-1.11.0)
classes. See the separate [Google Mock documentation](googlemock/README.md). is now available.
More detailed documentation for googletest (including build instructions) are #### Coming Soon
in its interior [googletest/README.md](googletest/README.md) file.
## Features ## * We are planning to take a dependency on
[Abseil](https://github.com/abseil/abseil-cpp).
* More documentation improvements are planned.
* An [XUnit](https://en.wikipedia.org/wiki/XUnit) test framework. ## Welcome to **GoogleTest**, Google's C++ test framework!
This repository is a merger of the formerly separate GoogleTest and GoogleMock
projects. These were so closely related that it makes sense to maintain and
release them together.
### Getting Started
See the [GoogleTest User's Guide](https://google.github.io/googletest/) for
documentation. We recommend starting with the
[GoogleTest Primer](https://google.github.io/googletest/primer.html).
More information about building GoogleTest can be found at
[googletest/README.md](googletest/README.md).
## Features
* An [xUnit](https://en.wikipedia.org/wiki/XUnit) test framework.
* Test discovery. * Test discovery.
* A rich set of assertions. * A rich set of assertions.
* User-defined assertions. * User-defined assertions.
@ -37,106 +54,88 @@ in its interior [googletest/README.md](googletest/README.md) file.
* Various options for running the tests. * Various options for running the tests.
* XML test report generation. * XML test report generation.
## Platforms ## ## Supported Platforms
Google test has been used on a variety of platforms: GoogleTest requires a codebase and compiler compliant with the C++11 standard or
newer.
The GoogleTest code is officially supported on the following platforms.
Operating systems or tools not listed below are community-supported. For
community-supported platforms, patches that do not complicate the code may be
considered.
If you notice any problems on your platform, please file an issue on the
[GoogleTest GitHub Issue Tracker](https://github.com/google/googletest/issues).
Pull requests containing fixes are welcome!
### Operating Systems
* Linux * Linux
* Mac OS X * macOS
* Windows * Windows
* Cygwin
* MinGW
* Windows Mobile
* Symbian
## Who Is Using Google Test? ## ### Compilers
In addition to many internal projects at Google, Google Test is also used by * gcc 5.0+
the following notable projects: * clang 5.0+
* MSVC 2015+
* The [Chromium projects](http://www.chromium.org/) (behind the Chrome **macOS users:** Xcode 9.3+ provides clang 5.0+.
browser and Chrome OS).
### Build Systems
* [Bazel](https://bazel.build/)
* [CMake](https://cmake.org/)
**Note:** Bazel is the build system used by the team internally and in tests.
CMake is supported on a best-effort basis and by the community.
## Who Is Using GoogleTest?
In addition to many internal projects at Google, GoogleTest is also used by the
following notable projects:
* The [Chromium projects](http://www.chromium.org/) (behind the Chrome browser
and Chrome OS).
* The [LLVM](http://llvm.org/) compiler. * The [LLVM](http://llvm.org/) compiler.
* [Protocol Buffers](https://github.com/google/protobuf), Google's data * [Protocol Buffers](https://github.com/google/protobuf), Google's data
interchange format. interchange format.
* The [OpenCV](http://opencv.org/) computer vision library. * The [OpenCV](http://opencv.org/) computer vision library.
## Related Open Source Projects ## ## Related Open Source Projects
[Google Test UI](https://github.com/ospector/gtest-gbar) is test runner that runs [GTest Runner](https://github.com/nholthaus/gtest-runner) is a Qt5 based
your test binary, allows you to track its progress via a progress bar, and automated test-runner and Graphical User Interface with powerful features for
displays a list of test failures. Clicking on one shows failure text. Google Windows and Linux platforms.
Test UI is written in C#.
[GoogleTest UI](https://github.com/ospector/gtest-gbar) is a test runner that
runs your test binary, allows you to track its progress via a progress bar, and
displays a list of test failures. Clicking on one shows failure text. GoogleTest
UI is written in C#.
[GTest TAP Listener](https://github.com/kinow/gtest-tap-listener) is an event [GTest TAP Listener](https://github.com/kinow/gtest-tap-listener) is an event
listener for GoogleTest that implements the listener for GoogleTest that implements the
[TAP protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol) for test [TAP protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol) for test
result output. If your test runner understands TAP, you may find it useful. result output. If your test runner understands TAP, you may find it useful.
## Requirements ## [gtest-parallel](https://github.com/google/gtest-parallel) is a test runner that
runs tests from your binary in parallel to provide significant speed-up.
Google Test is designed to have fairly minimal requirements to build [GoogleTest Adapter](https://marketplace.visualstudio.com/items?itemName=DavidSchuldenfrei.gtest-adapter)
and use with your projects, but there are some. Currently, we support is a VS Code extension allowing to view GoogleTest in a tree view and run/debug
Linux, Windows, Mac OS X, and Cygwin. We will also make our best your tests.
effort to support other platforms (e.g. Solaris, AIX, and z/OS).
However, since core members of the Google Test project have no access
to these platforms, Google Test may have outstanding issues there. If
you notice any problems on your platform, please notify
<googletestframework@googlegroups.com>. Patches for fixing them are
even more welcome!
### Linux Requirements ### [C++ TestMate](https://github.com/matepek/vscode-catch2-test-adapter) is a VS
Code extension allowing to view GoogleTest in a tree view and run/debug your
tests.
These are the base requirements to build and use Google Test from a source [Cornichon](https://pypi.org/project/cornichon/) is a small Gherkin DSL parser
package (as described below): that generates stub code for GoogleTest.
* GNU-compatible Make or gmake ## Contributing Changes
* POSIX-standard shell
* POSIX(-2) Regular Expressions (regex.h)
* A C++98-standard-compliant compiler
### Windows Requirements ### Please read
[`CONTRIBUTING.md`](https://github.com/google/googletest/blob/master/CONTRIBUTING.md)
* Microsoft Visual C++ v7.1 or newer for details on how to contribute to this project.
### Cygwin Requirements ###
* Cygwin v1.5.25-14 or newer
### Mac OS X Requirements ###
* Mac OS X v10.4 Tiger or newer
* Xcode Developer Tools
### Requirements for Contributors ###
We welcome patches. If you plan to contribute a patch, you need to
build Google Test and its own tests from a git checkout (described
below), which has further requirements:
* [Python](https://www.python.org/) v2.3 or newer (for running some of
the tests and re-generating certain source files from templates)
* [CMake](https://cmake.org/) v2.6.4 or newer
## Regenerating Source Files ##
Some of Google Test's source files are generated from templates (not
in the C++ sense) using a script.
For example, the
file include/gtest/internal/gtest-type-util.h.pump is used to generate
gtest-type-util.h in the same directory.
You don't need to worry about regenerating the source files
unless you need to modify them. You would then modify the
corresponding `.pump` files and run the '[pump.py](googletest/scripts/pump.py)'
generator script. See the [Pump Manual](googletest/docs/PumpManual.md).
### Contributing Code ###
We welcome patches. Please read the
[Developer's Guide](googletest/docs/DevGuide.md)
for how you can contribute. In particular, make sure you have signed
the Contributor License Agreement, or we won't be able to accept the
patch.
Happy testing! Happy testing!

39
extlib/googletest/WORKSPACE vendored Normal file
View File

@ -0,0 +1,39 @@
workspace(name = "com_google_googletest")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "com_google_absl",
sha256 = "1a1745b5ee81392f5ea4371a4ca41e55d446eeaee122903b2eaffbd8a3b67a2b",
strip_prefix = "abseil-cpp-01cc6567cff77738e416a7ddc17de2d435a780ce",
urls = ["https://github.com/abseil/abseil-cpp/archive/01cc6567cff77738e416a7ddc17de2d435a780ce.zip"], # 2022-06-21T19:28:27Z
)
# Note this must use a commit from the `abseil` branch of the RE2 project.
# https://github.com/google/re2/tree/abseil
http_archive(
name = "com_googlesource_code_re2",
sha256 = "0a890c2aa0bb05b2ce906a15efb520d0f5ad4c7d37b8db959c43772802991887",
strip_prefix = "re2-a427f10b9fb4622dd6d8643032600aa1b50fbd12",
urls = ["https://github.com/google/re2/archive/a427f10b9fb4622dd6d8643032600aa1b50fbd12.zip"], # 2022-06-09
)
http_archive(
name = "rules_python",
sha256 = "0b460f17771258341528753b1679335b629d1d25e3af28eda47d009c103a6e15",
strip_prefix = "rules_python-aef17ad72919d184e5edb7abf61509eb78e57eda",
urls = ["https://github.com/bazelbuild/rules_python/archive/aef17ad72919d184e5edb7abf61509eb78e57eda.zip"], # 2022-06-21T23:44:47Z
)
http_archive(
name = "bazel_skylib",
urls = ["https://github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz"],
sha256 = "f7be3474d42aae265405a592bb7da8e171919d74c16f082a5457840f06054728",
)
http_archive(
name = "platforms",
sha256 = "a879ea428c6d56ab0ec18224f976515948822451473a80d06c2e50af0bbe5121",
strip_prefix = "platforms-da5541f26b7de1dc8e04c075c99df5351742a4a2",
urls = ["https://github.com/bazelbuild/platforms/archive/da5541f26b7de1dc8e04c075c99df5351742a4a2.zip"], # 2022-05-27
)

View File

@ -1,9 +1,19 @@
This copy of googletest-1.8.0 is a modified version of the original. This copy of googletest-1.12.1 is a modified version of the original.
commit 58d77fa8070e8cec2dc1ed015d66b454c8d78850 (HEAD, tag: release-1.12.1, origin/v1.12.x)
Author: Derek Mauro <761129+derekmauro@users.noreply.github.com>
Date: Mon Jun 27 13:14:55 2022 -0400
Updates the version number in CMakeLists.txt to 1.12.1 (#3919)
Due to an oversight version 1.12.0 didn't update the version in
CMakeLists.txt. A patch release will fix this issue.
I've also added a note to instructions for creating a release to check
for this issue.
The following changes have been made to the original: The following changes have been made to the original:
- Removed .travis.yml and appveyor.xml.
- Disabled INSTALL() rules. - Disabled INSTALL() rules.
- Forced static library builds. - Forced static library builds.
@ -14,4 +24,12 @@ The following changes have been made to the original:
- cmake_minimum_required() is disabled, since it interfered with - cmake_minimum_required() is disabled, since it interfered with
policies set by the main build infrastructure. policies set by the main build infrastructure.
To obtain the original googletest-1.8.0, visit https://github.com/google/googletest . - Removed test suites, scripts, and Xcode projects in order to reduce
warnings on LGTM.
- Add a workaround for std::is_trivially_copy_constructible<T> and
std::is_trivially_destructible<T> not being implemented in gcc-4.9.
(They were added in gcc-5.) Fixes the build on Debian 8.
To obtain the original googletest-1.12.1, visit:
https://github.com/google/googletest

View File

@ -1,126 +0,0 @@
Changes for 1.7.0:
* All new improvements in Google Test 1.7.0.
* New feature: matchers DoubleNear(), FloatNear(),
NanSensitiveDoubleNear(), NanSensitiveFloatNear(),
UnorderedElementsAre(), UnorderedElementsAreArray(), WhenSorted(),
WhenSortedBy(), IsEmpty(), and SizeIs().
* Improvement: Google Mock can now be built as a DLL.
* Improvement: when compiled by a C++11 compiler, matchers AllOf()
and AnyOf() can accept an arbitrary number of matchers.
* Improvement: when compiled by a C++11 compiler, matchers
ElementsAreArray() can accept an initializer list.
* Improvement: when exceptions are enabled, a mock method with no
default action now throws instead crashing the test.
* Improvement: added class testing::StringMatchResultListener to aid
definition of composite matchers.
* Improvement: function return types used in MOCK_METHOD*() macros can
now contain unprotected commas.
* Improvement (potentially breaking): EXPECT_THAT() and ASSERT_THAT()
are now more strict in ensuring that the value type and the matcher
type are compatible, catching potential bugs in tests.
* Improvement: Pointee() now works on an optional<T>.
* Improvement: the ElementsAreArray() matcher can now take a vector or
iterator range as input, and makes a copy of its input elements
before the conversion to a Matcher.
* Improvement: the Google Mock Generator can now generate mocks for
some class templates.
* Bug fix: mock object destruction triggerred by another mock object's
destruction no longer hangs.
* Improvement: Google Mock Doctor works better with newer Clang and
GCC now.
* Compatibility fixes.
* Bug/warning fixes.
Changes for 1.6.0:
* Compilation is much faster and uses much less memory, especially
when the constructor and destructor of a mock class are moved out of
the class body.
* New matchers: Pointwise(), Each().
* New actions: ReturnPointee() and ReturnRefOfCopy().
* CMake support.
* Project files for Visual Studio 2010.
* AllOf() and AnyOf() can handle up-to 10 arguments now.
* Google Mock doctor understands Clang error messages now.
* SetArgPointee<> now accepts string literals.
* gmock_gen.py handles storage specifier macros and template return
types now.
* Compatibility fixes.
* Bug fixes and implementation clean-ups.
* Potentially incompatible changes: disables the harmful 'make install'
command in autotools.
Potentially breaking changes:
* The description string for MATCHER*() changes from Python-style
interpolation to an ordinary C++ string expression.
* SetArgumentPointee is deprecated in favor of SetArgPointee.
* Some non-essential project files for Visual Studio 2005 are removed.
Changes for 1.5.0:
* New feature: Google Mock can be safely used in multi-threaded tests
on platforms having pthreads.
* New feature: function for printing a value of arbitrary type.
* New feature: function ExplainMatchResult() for easy definition of
composite matchers.
* The new matcher API lets user-defined matchers generate custom
explanations more directly and efficiently.
* Better failure messages all around.
* NotNull() and IsNull() now work with smart pointers.
* Field() and Property() now work when the matcher argument is a pointer
passed by reference.
* Regular expression matchers on all platforms.
* Added GCC 4.0 support for Google Mock Doctor.
* Added gmock_all_test.cc for compiling most Google Mock tests
in a single file.
* Significantly cleaned up compiler warnings.
* Bug fixes, better test coverage, and implementation clean-ups.
Potentially breaking changes:
* Custom matchers defined using MatcherInterface or MakePolymorphicMatcher()
need to be updated after upgrading to Google Mock 1.5.0; matchers defined
using MATCHER or MATCHER_P* aren't affected.
* Dropped support for 'make install'.
Changes for 1.4.0 (we skipped 1.2.* and 1.3.* to match the version of
Google Test):
* Works in more environments: Symbian and minGW, Visual C++ 7.1.
* Lighter weight: comes with our own implementation of TR1 tuple (no
more dependency on Boost!).
* New feature: --gmock_catch_leaked_mocks for detecting leaked mocks.
* New feature: ACTION_TEMPLATE for defining templatized actions.
* New feature: the .After() clause for specifying expectation order.
* New feature: the .With() clause for for specifying inter-argument
constraints.
* New feature: actions ReturnArg<k>(), ReturnNew<T>(...), and
DeleteArg<k>().
* New feature: matchers Key(), Pair(), Args<...>(), AllArgs(), IsNull(),
and Contains().
* New feature: utility class MockFunction<F>, useful for checkpoints, etc.
* New feature: functions Value(x, m) and SafeMatcherCast<T>(m).
* New feature: copying a mock object is rejected at compile time.
* New feature: a script for fusing all Google Mock and Google Test
source files for easy deployment.
* Improved the Google Mock doctor to diagnose more diseases.
* Improved the Google Mock generator script.
* Compatibility fixes for Mac OS X and gcc.
* Bug fixes and implementation clean-ups.
Changes for 1.1.0:
* New feature: ability to use Google Mock with any testing framework.
* New feature: macros for easily defining new matchers
* New feature: macros for easily defining new actions.
* New feature: more container matchers.
* New feature: actions for accessing function arguments and throwing
exceptions.
* Improved the Google Mock doctor script for diagnosing compiler errors.
* Bug fixes and implementation clean-ups.
Changes for 1.0.0:
* Initial Open Source release of Google Mock

View File

@ -1,18 +1,14 @@
######################################################################## ########################################################################
# Note: CMake support is community-based. The maintainers do not use CMake
# internally.
#
# CMake build script for Google Mock. # CMake build script for Google Mock.
# #
# To run the tests for Google Mock itself on Linux, use 'make test' or # To run the tests for Google Mock itself on Linux, use 'make test' or
# ctest. You can select which tests to run using 'ctest -R regex'. # ctest. You can select which tests to run using 'ctest -R regex'.
# For more options, run 'ctest --help'. # For more options, run 'ctest --help'.
# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to option(gmock_build_tests "Build all of Google Mock's own tests." OFF)
# make it prominent in the GUI.
# NOTE: Disabled for rom-properties.
#option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF)
# NOTE: Disabled for rom-properties.
#option(gmock_build_tests "Build all of Google Mock's own tests." OFF)
SET(gmock_build_tests OFF)
# A directory to find Google Test sources. # A directory to find Google Test sources.
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/gtest/CMakeLists.txt") if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/gtest/CMakeLists.txt")
@ -40,8 +36,9 @@ endif()
# as ${gmock_SOURCE_DIR} and to the root binary directory as # as ${gmock_SOURCE_DIR} and to the root binary directory as
# ${gmock_BINARY_DIR}. # ${gmock_BINARY_DIR}.
# Language "C" is required for find_package(Threads). # Language "C" is required for find_package(Threads).
project(gmock CXX C) cmake_minimum_required(VERSION 3.5...3.10)
#cmake_minimum_required(VERSION 2.6.2) cmake_policy(SET CMP0048 NEW)
project(gmock VERSION ${GOOGLETEST_VERSION} LANGUAGES CXX C)
if (COMMAND set_up_hermetic_build) if (COMMAND set_up_hermetic_build)
set_up_hermetic_build() set_up_hermetic_build()
@ -51,7 +48,17 @@ endif()
# targets to the current scope. We are placing Google Test's binary # targets to the current scope. We are placing Google Test's binary
# directory in a subdirectory of our own as VC compilation may break # directory in a subdirectory of our own as VC compilation may break
# if they are the same (the default). # if they are the same (the default).
add_subdirectory("${gtest_dir}" "${gmock_BINARY_DIR}/gtest") add_subdirectory("${gtest_dir}" "${gmock_BINARY_DIR}/${gtest_dir}")
# These commands only run if this is the main project
if(CMAKE_PROJECT_NAME STREQUAL "gmock" OR CMAKE_PROJECT_NAME STREQUAL "googletest-distribution")
# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to
# make it prominent in the GUI.
option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF)
else()
mark_as_advanced(gmock_build_tests)
endif()
# Although Google Test's CMakeLists.txt calls this function, the # Although Google Test's CMakeLists.txt calls this function, the
# changes there don't affect the current scope. Therefore we have to # changes there don't affect the current scope. Therefore we have to
@ -59,22 +66,13 @@ add_subdirectory("${gtest_dir}" "${gmock_BINARY_DIR}/gtest")
config_compiler_and_linker() # from ${gtest_dir}/cmake/internal_utils.cmake config_compiler_and_linker() # from ${gtest_dir}/cmake/internal_utils.cmake
# Adds Google Mock's and Google Test's header directories to the search path. # Adds Google Mock's and Google Test's header directories to the search path.
include_directories("${gmock_SOURCE_DIR}/include" set(gmock_build_include_dirs
"${gmock_SOURCE_DIR}/include"
"${gmock_SOURCE_DIR}" "${gmock_SOURCE_DIR}"
"${gtest_SOURCE_DIR}/include" "${gtest_SOURCE_DIR}/include"
# This directory is needed to build directly from Google # This directory is needed to build directly from Google Test sources.
# Test sources.
"${gtest_SOURCE_DIR}") "${gtest_SOURCE_DIR}")
include_directories(${gmock_build_include_dirs})
# Summary of tuple support for Microsoft Visual Studio:
# Compiler version(MS) version(cmake) Support
# ---------- ----------- -------------- -----------------------------
# <= VS 2010 <= 10 <= 1600 Use Google Tests's own tuple.
# VS 2012 11 1700 std::tr1::tuple + _VARIADIC_MAX=10
# VS 2013 12 1800 std::tr1::tuple
if (MSVC AND MSVC_VERSION EQUAL 1700)
add_definitions(/D _VARIADIC_MAX=10)
endif()
######################################################################## ########################################################################
# #
@ -84,33 +82,47 @@ endif()
# Google Mock libraries. We build them using more strict warnings than what # Google Mock libraries. We build them using more strict warnings than what
# are used for other targets, to ensure that Google Mock can be compiled by # are used for other targets, to ensure that Google Mock can be compiled by
# a user aggressive about warnings. # a user aggressive about warnings.
if (MSVC)
cxx_library(gmock cxx_library(gmock
"${cxx_strict}" "${cxx_strict}"
"${gtest_dir}/src/gtest-all.cc" "${gtest_dir}/src/gtest-all.cc"
src/gmock-all.cc) src/gmock-all.cc)
cxx_library(gmock_main # rom-properties: Disable gmock_main, since it depends on gtest_main.
"${cxx_strict}" #cxx_library(gmock_main
"${gtest_dir}/src/gtest-all.cc" # "${cxx_strict}"
src/gmock-all.cc # "${gtest_dir}/src/gtest-all.cc"
src/gmock_main.cc) # src/gmock-all.cc
# src/gmock_main.cc)
else()
cxx_library(gmock "${cxx_strict}" src/gmock-all.cc)
target_link_libraries(gmock PUBLIC gtest)
set_target_properties(gmock PROPERTIES VERSION ${GOOGLETEST_VERSION})
# rom-properties: Disable gmock_main, since it depends on gtest_main.
#cxx_library(gmock_main "${cxx_strict}" src/gmock_main.cc)
#target_link_libraries(gmock_main PUBLIC gmock)
#set_target_properties(gmock_main PROPERTIES VERSION ${GOOGLETEST_VERSION})
endif()
# If the CMake version supports it, attach header directory information # If the CMake version supports it, attach header directory information
# to the targets for when we are part of a parent build (ie being pulled # to the targets for when we are part of a parent build (ie being pulled
# in via add_subdirectory() rather than being a standalone build). # in via add_subdirectory() rather than being a standalone build).
if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")
target_include_directories(gmock INTERFACE "${gmock_SOURCE_DIR}/include") string(REPLACE ";" "$<SEMICOLON>" dirs "${gmock_build_include_dirs}")
target_include_directories(gmock_main INTERFACE "${gmock_SOURCE_DIR}/include") target_include_directories(gmock SYSTEM INTERFACE
"$<BUILD_INTERFACE:${dirs}>"
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>")
# rom-properties: Disable gmock_main, since it depends on gtest_main.
#target_include_directories(gmock_main SYSTEM INTERFACE
# "$<BUILD_INTERFACE:${dirs}>"
# "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>")
endif() endif()
######################################################################## ########################################################################
# #
# Install rules # Install rules
# NOTE: Disabled for rom-properties. # rom-properties: Disable gmock_main, since it depends on gtest_main.
#install(TARGETS gmock gmock_main #install_project(gmock gmock_main)
# DESTINATION lib) install_project(gmock)
#install(DIRECTORY ${gmock_SOURCE_DIR}/include/gmock
# DESTINATION include)
######################################################################## ########################################################################
# #
@ -128,18 +140,26 @@ if (gmock_build_tests)
# 'make test' or ctest. # 'make test' or ctest.
enable_testing() enable_testing()
if (MINGW OR CYGWIN)
if (CMAKE_VERSION VERSION_LESS "2.8.12")
add_compile_options("-Wa,-mbig-obj")
else()
add_definitions("-Wa,-mbig-obj")
endif()
endif()
############################################################ ############################################################
# C++ tests built with standard compiler flags. # C++ tests built with standard compiler flags.
cxx_test(gmock-actions_test gmock_main) cxx_test(gmock-actions_test gmock_main)
cxx_test(gmock-cardinalities_test gmock_main) cxx_test(gmock-cardinalities_test gmock_main)
cxx_test(gmock_ex_test gmock_main) cxx_test(gmock_ex_test gmock_main)
cxx_test(gmock-generated-actions_test gmock_main) cxx_test(gmock-function-mocker_test gmock_main)
cxx_test(gmock-generated-function-mockers_test gmock_main)
cxx_test(gmock-generated-internal-utils_test gmock_main)
cxx_test(gmock-generated-matchers_test gmock_main)
cxx_test(gmock-internal-utils_test gmock_main) cxx_test(gmock-internal-utils_test gmock_main)
cxx_test(gmock-matchers_test gmock_main) cxx_test(gmock-matchers-arithmetic_test gmock_main)
cxx_test(gmock-matchers-comparisons_test gmock_main)
cxx_test(gmock-matchers-containers_test gmock_main)
cxx_test(gmock-matchers-misc_test gmock_main)
cxx_test(gmock-more-actions_test gmock_main) cxx_test(gmock-more-actions_test gmock_main)
cxx_test(gmock-nice-strict_test gmock_main) cxx_test(gmock-nice-strict_test gmock_main)
cxx_test(gmock-port_test gmock_main) cxx_test(gmock-port_test gmock_main)
@ -147,7 +167,7 @@ if (gmock_build_tests)
cxx_test(gmock_link_test gmock_main test/gmock_link2_test.cc) cxx_test(gmock_link_test gmock_main test/gmock_link2_test.cc)
cxx_test(gmock_test gmock_main) cxx_test(gmock_test gmock_main)
if (CMAKE_USE_PTHREADS_INIT) if (DEFINED GTEST_HAS_PTHREAD)
cxx_test(gmock_stress_test gmock) cxx_test(gmock_stress_test gmock)
endif() endif()
@ -158,23 +178,20 @@ if (gmock_build_tests)
############################################################ ############################################################
# C++ tests built with non-standard compiler flags. # C++ tests built with non-standard compiler flags.
if (MSVC)
cxx_library(gmock_main_no_exception "${cxx_no_exception}" cxx_library(gmock_main_no_exception "${cxx_no_exception}"
"${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc)
cxx_library(gmock_main_no_rtti "${cxx_no_rtti}" cxx_library(gmock_main_no_rtti "${cxx_no_rtti}"
"${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc) "${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc)
if (NOT MSVC OR MSVC_VERSION LESS 1600) # 1600 is Visual Studio 2010. else()
# Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that cxx_library(gmock_main_no_exception "${cxx_no_exception}" src/gmock_main.cc)
# conflict with our own definitions. Therefore using our own tuple does not target_link_libraries(gmock_main_no_exception PUBLIC gmock)
# work on those compilers.
cxx_library(gmock_main_use_own_tuple "${cxx_use_own_tuple}"
"${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc)
cxx_test_with_flags(gmock_use_own_tuple_test "${cxx_use_own_tuple}" cxx_library(gmock_main_no_rtti "${cxx_no_rtti}" src/gmock_main.cc)
gmock_main_use_own_tuple test/gmock-spec-builders_test.cc) target_link_libraries(gmock_main_no_rtti PUBLIC gmock)
endif() endif()
cxx_test_with_flags(gmock-more-actions_no_exception_test "${cxx_no_exception}" cxx_test_with_flags(gmock-more-actions_no_exception_test "${cxx_no_exception}"
gmock_main_no_exception test/gmock-more-actions_test.cc) gmock_main_no_exception test/gmock-more-actions_test.cc)

View File

@ -1,40 +0,0 @@
# This file contains a list of people who've made non-trivial
# contribution to the Google C++ Mocking Framework project. People
# who commit code to the project are encouraged to add their names
# here. Please keep the list sorted by first names.
Benoit Sigoure <tsuna@google.com>
Bogdan Piloca <boo@google.com>
Chandler Carruth <chandlerc@google.com>
Dave MacLachlan <dmaclach@gmail.com>
David Anderson <danderson@google.com>
Dean Sturtevant
Gene Volovich <gv@cite.com>
Hal Burch <gmock@hburch.com>
Jeffrey Yasskin <jyasskin@google.com>
Jim Keller <jimkeller@google.com>
Joe Walnes <joe@truemesh.com>
Jon Wray <jwray@google.com>
Keir Mierle <mierle@gmail.com>
Keith Ray <keith.ray@gmail.com>
Kostya Serebryany <kcc@google.com>
Lev Makhlis
Manuel Klimek <klimek@google.com>
Mario Tanev <radix@google.com>
Mark Paskin
Markus Heule <markus.heule@gmail.com>
Matthew Simmons <simmonmt@acm.org>
Mike Bland <mbland@google.com>
Neal Norwitz <nnorwitz@gmail.com>
Nermin Ozkiranartli <nermin@google.com>
Owen Carlsen <ocarlsen@google.com>
Paneendra Ba <paneendra@google.com>
Paul Menage <menage@google.com>
Piotr Kaminski <piotrk@google.com>
Russ Rufer <russ@pentad.com>
Sverre Sundsdal <sundsdal@gmail.com>
Takeshi Yoshino <tyoshino@google.com>
Vadim Berman <vadimb@google.com>
Vlad Losev <vladl@google.com>
Wolfgang Klier <wklier@google.com>
Zhanyong Wan <wan@google.com>

View File

@ -1,224 +0,0 @@
# Automake file
# Nonstandard package files for distribution.
EXTRA_DIST = LICENSE
# We may need to build our internally packaged gtest. If so, it will be
# included in the 'subdirs' variable.
SUBDIRS = $(subdirs)
# This is generated by the configure script, so clean it for distribution.
DISTCLEANFILES = scripts/gmock-config
# We define the global AM_CPPFLAGS as everything we compile includes from these
# directories.
AM_CPPFLAGS = $(GTEST_CPPFLAGS) -I$(srcdir)/include
# Modifies compiler and linker flags for pthreads compatibility.
if HAVE_PTHREADS
AM_CXXFLAGS = @PTHREAD_CFLAGS@ -DGTEST_HAS_PTHREAD=1
AM_LIBS = @PTHREAD_LIBS@
endif
# Build rules for libraries.
lib_LTLIBRARIES = lib/libgmock.la lib/libgmock_main.la
lib_libgmock_la_SOURCES = src/gmock-all.cc
pkginclude_HEADERS = \
include/gmock/gmock-actions.h \
include/gmock/gmock-cardinalities.h \
include/gmock/gmock-generated-actions.h \
include/gmock/gmock-generated-function-mockers.h \
include/gmock/gmock-generated-matchers.h \
include/gmock/gmock-generated-nice-strict.h \
include/gmock/gmock-matchers.h \
include/gmock/gmock-more-actions.h \
include/gmock/gmock-more-matchers.h \
include/gmock/gmock-spec-builders.h \
include/gmock/gmock.h
pkginclude_internaldir = $(pkgincludedir)/internal
pkginclude_internal_HEADERS = \
include/gmock/internal/gmock-generated-internal-utils.h \
include/gmock/internal/gmock-internal-utils.h \
include/gmock/internal/gmock-port.h \
include/gmock/internal/custom/gmock-generated-actions.h \
include/gmock/internal/custom/gmock-matchers.h \
include/gmock/internal/custom/gmock-port.h
lib_libgmock_main_la_SOURCES = src/gmock_main.cc
lib_libgmock_main_la_LIBADD = lib/libgmock.la
# Build rules for tests. Automake's naming for some of these variables isn't
# terribly obvious, so this is a brief reference:
#
# TESTS -- Programs run automatically by "make check"
# check_PROGRAMS -- Programs built by "make check" but not necessarily run
TESTS=
check_PROGRAMS=
AM_LDFLAGS = $(GTEST_LDFLAGS)
# This exercises all major components of Google Mock. It also
# verifies that libgmock works.
TESTS += test/gmock-spec-builders_test
check_PROGRAMS += test/gmock-spec-builders_test
test_gmock_spec_builders_test_SOURCES = test/gmock-spec-builders_test.cc
test_gmock_spec_builders_test_LDADD = $(GTEST_LIBS) lib/libgmock.la
# This tests using Google Mock in multiple translation units. It also
# verifies that libgmock_main and libgmock work.
TESTS += test/gmock_link_test
check_PROGRAMS += test/gmock_link_test
test_gmock_link_test_SOURCES = \
test/gmock_link2_test.cc \
test/gmock_link_test.cc \
test/gmock_link_test.h
test_gmock_link_test_LDADD = $(GTEST_LIBS) lib/libgmock_main.la lib/libgmock.la
if HAVE_PYTHON
# Tests that fused gmock files compile and work.
TESTS += test/gmock_fused_test
check_PROGRAMS += test/gmock_fused_test
test_gmock_fused_test_SOURCES = \
fused-src/gmock-gtest-all.cc \
fused-src/gmock/gmock.h \
fused-src/gmock_main.cc \
fused-src/gtest/gtest.h \
test/gmock_test.cc
test_gmock_fused_test_CPPFLAGS = -I"$(srcdir)/fused-src"
endif
# Google Mock source files that we don't compile directly.
GMOCK_SOURCE_INGLUDES = \
src/gmock-cardinalities.cc \
src/gmock-internal-utils.cc \
src/gmock-matchers.cc \
src/gmock-spec-builders.cc \
src/gmock.cc
EXTRA_DIST += $(GMOCK_SOURCE_INGLUDES)
# C++ tests that we don't compile using autotools.
EXTRA_DIST += \
test/gmock-actions_test.cc \
test/gmock_all_test.cc \
test/gmock-cardinalities_test.cc \
test/gmock_ex_test.cc \
test/gmock-generated-actions_test.cc \
test/gmock-generated-function-mockers_test.cc \
test/gmock-generated-internal-utils_test.cc \
test/gmock-generated-matchers_test.cc \
test/gmock-internal-utils_test.cc \
test/gmock-matchers_test.cc \
test/gmock-more-actions_test.cc \
test/gmock-nice-strict_test.cc \
test/gmock-port_test.cc \
test/gmock_stress_test.cc
# Python tests, which we don't run using autotools.
EXTRA_DIST += \
test/gmock_leak_test.py \
test/gmock_leak_test_.cc \
test/gmock_output_test.py \
test/gmock_output_test_.cc \
test/gmock_output_test_golden.txt \
test/gmock_test_utils.py
# Nonstandard package files for distribution.
EXTRA_DIST += \
CHANGES \
CONTRIBUTORS \
make/Makefile
# Pump scripts for generating Google Mock headers.
# TODO(chandlerc@google.com): automate the generation of *.h from *.h.pump.
EXTRA_DIST += \
include/gmock/gmock-generated-actions.h.pump \
include/gmock/gmock-generated-function-mockers.h.pump \
include/gmock/gmock-generated-matchers.h.pump \
include/gmock/gmock-generated-nice-strict.h.pump \
include/gmock/internal/gmock-generated-internal-utils.h.pump \
include/gmock/internal/custom/gmock-generated-actions.h.pump
# Script for fusing Google Mock and Google Test source files.
EXTRA_DIST += scripts/fuse_gmock_files.py
# The Google Mock Generator tool from the cppclean project.
EXTRA_DIST += \
scripts/generator/LICENSE \
scripts/generator/README \
scripts/generator/README.cppclean \
scripts/generator/cpp/__init__.py \
scripts/generator/cpp/ast.py \
scripts/generator/cpp/gmock_class.py \
scripts/generator/cpp/keywords.py \
scripts/generator/cpp/tokenize.py \
scripts/generator/cpp/utils.py \
scripts/generator/gmock_gen.py
# Script for diagnosing compiler errors in programs that use Google
# Mock.
EXTRA_DIST += scripts/gmock_doctor.py
# CMake scripts.
EXTRA_DIST += \
CMakeLists.txt
# Microsoft Visual Studio 2005 projects.
EXTRA_DIST += \
msvc/2005/gmock.sln \
msvc/2005/gmock.vcproj \
msvc/2005/gmock_config.vsprops \
msvc/2005/gmock_main.vcproj \
msvc/2005/gmock_test.vcproj
# Microsoft Visual Studio 2010 projects.
EXTRA_DIST += \
msvc/2010/gmock.sln \
msvc/2010/gmock.vcxproj \
msvc/2010/gmock_config.props \
msvc/2010/gmock_main.vcxproj \
msvc/2010/gmock_test.vcxproj
if HAVE_PYTHON
# gmock_test.cc does not really depend on files generated by the
# fused-gmock-internal rule. However, gmock_test.o does, and it is
# important to include test/gmock_test.cc as part of this rule in order to
# prevent compiling gmock_test.o until all dependent files have been
# generated.
$(test_gmock_fused_test_SOURCES): fused-gmock-internal
# TODO(vladl@google.com): Find a way to add Google Tests's sources here.
fused-gmock-internal: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \
$(lib_libgmock_la_SOURCES) $(GMOCK_SOURCE_INGLUDES) \
$(lib_libgmock_main_la_SOURCES) \
scripts/fuse_gmock_files.py
mkdir -p "$(srcdir)/fused-src"
chmod -R u+w "$(srcdir)/fused-src"
rm -f "$(srcdir)/fused-src/gtest/gtest.h"
rm -f "$(srcdir)/fused-src/gmock/gmock.h"
rm -f "$(srcdir)/fused-src/gmock-gtest-all.cc"
"$(srcdir)/scripts/fuse_gmock_files.py" "$(srcdir)/fused-src"
cp -f "$(srcdir)/src/gmock_main.cc" "$(srcdir)/fused-src"
maintainer-clean-local:
rm -rf "$(srcdir)/fused-src"
endif
# Death tests may produce core dumps in the build directory. In case
# this happens, clean them to keep distcleancheck happy.
CLEANFILES = core
# Disables 'make install' as installing a compiled version of Google
# Mock can lead to undefined behavior due to violation of the
# One-Definition Rule.
install-exec-local:
echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Mock into your build system."
false
install-data-local:
echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Mock into your build system."
false

View File

@ -1,333 +1,40 @@
## Google Mock ## # Googletest Mocking (gMock) Framework
The Google C++ mocking framework. ### Overview
### Overview ### Google's framework for writing and using C++ mock classes. It can help you
derive better designs of your system and write better tests.
Google's framework for writing and using C++ mock classes.
It can help you derive better designs of your system and write better tests.
It is inspired by: It is inspired by:
* [jMock](http://www.jmock.org/), * [jMock](http://www.jmock.org/)
* [EasyMock](http://www.easymock.org/), and * [EasyMock](http://www.easymock.org/)
* [Hamcrest](http://code.google.com/p/hamcrest/), * [Hamcrest](http://code.google.com/p/hamcrest/)
and designed with C++'s specifics in mind. It is designed with C++'s specifics in mind.
Google mock: gMock:
* lets you create mock classes trivially using simple macros. - Provides a declarative syntax for defining mocks.
* supports a rich set of matchers and actions. - Can define partial (hybrid) mocks, which are a cross of real and mock
* handles unordered, partially ordered, or completely ordered expectations. objects.
* is extensible by users. - Handles functions of arbitrary types and overloaded functions.
- Comes with a rich set of matchers for validating function arguments.
We hope you find it useful! - Uses an intuitive syntax for controlling the behavior of a mock.
- Does automatic verification of expectations (no record-and-replay needed).
### Features ### - Allows arbitrary (partial) ordering constraints on function calls to be
expressed.
* Provides a declarative syntax for defining mocks. - Lets a user extend it by defining new matchers and actions.
* Can easily define partial (hybrid) mocks, which are a cross of real - Does not use exceptions.
and mock objects. - Is easy to learn and use.
* Handles functions of arbitrary types and overloaded functions.
* Comes with a rich set of matchers for validating function arguments. Details and examples can be found here:
* Uses an intuitive syntax for controlling the behavior of a mock.
* Does automatic verification of expectations (no record-and-replay needed). * [gMock for Dummies](https://google.github.io/googletest/gmock_for_dummies.html)
* Allows arbitrary (partial) ordering constraints on * [Legacy gMock FAQ](https://google.github.io/googletest/gmock_faq.html)
function calls to be expressed,. * [gMock Cookbook](https://google.github.io/googletest/gmock_cook_book.html)
* Lets a user extend it by defining new matchers and actions. * [gMock Cheat Sheet](https://google.github.io/googletest/gmock_cheat_sheet.html)
* Does not use exceptions.
* Is easy to learn and use. GoogleMock is a part of
[GoogleTest C++ testing framework](http://github.com/google/googletest/) and a
Please see the project page above for more information as well as the subject to the same requirements.
mailing list for questions, discussions, and development. There is
also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please
join us!
Please note that code under [scripts/generator](scripts/generator/) is
from [cppclean](http://code.google.com/p/cppclean/) and released under
the Apache License, which is different from Google Mock's license.
## Getting Started ##
If you are new to the project, we suggest that you read the user
documentation in the following order:
* Learn the [basics](../googletest/docs/Primer.md) of
Google Test, if you choose to use Google Mock with it (recommended).
* Read [Google Mock for Dummies](docs/ForDummies.md).
* Read the instructions below on how to build Google Mock.
You can also watch Zhanyong's [talk](http://www.youtube.com/watch?v=sYpCyLI47rM) on Google Mock's usage and implementation.
Once you understand the basics, check out the rest of the docs:
* [CheatSheet](docs/CheatSheet.md) - all the commonly used stuff
at a glance.
* [CookBook](docs/CookBook.md) - recipes for getting things done,
including advanced techniques.
If you need help, please check the
[KnownIssues](docs/KnownIssues.md) and
[FrequentlyAskedQuestions](docs/FrequentlyAskedQuestions.md) before
posting a question on the
[discussion group](http://groups.google.com/group/googlemock).
### Using Google Mock Without Google Test ###
Google Mock is not a testing framework itself. Instead, it needs a
testing framework for writing tests. Google Mock works seamlessly
with [Google Test](http://code.google.com/p/googletest/), but
you can also use it with [any C++ testing framework](googlemock/ForDummies.md#Using_Google_Mock_with_Any_Testing_Framework).
### Requirements for End Users ###
Google Mock is implemented on top of [Google Test](
http://github.com/google/googletest/), and depends on it.
You must use the bundled version of Google Test when using Google Mock.
You can also easily configure Google Mock to work with another testing
framework, although it will still need Google Test. Please read
["Using_Google_Mock_with_Any_Testing_Framework"](
docs/ForDummies.md#Using_Google_Mock_with_Any_Testing_Framework)
for instructions.
Google Mock depends on advanced C++ features and thus requires a more
modern compiler. The following are needed to use Google Mock:
#### Linux Requirements ####
* GNU-compatible Make or "gmake"
* POSIX-standard shell
* POSIX(-2) Regular Expressions (regex.h)
* C++98-standard-compliant compiler (e.g. GCC 3.4 or newer)
#### Windows Requirements ####
* Microsoft Visual C++ 8.0 SP1 or newer
#### Mac OS X Requirements ####
* Mac OS X 10.4 Tiger or newer
* Developer Tools Installed
### Requirements for Contributors ###
We welcome patches. If you plan to contribute a patch, you need to
build Google Mock and its tests, which has further requirements:
* Automake version 1.9 or newer
* Autoconf version 2.59 or newer
* Libtool / Libtoolize
* Python version 2.3 or newer (for running some of the tests and
re-generating certain source files from templates)
### Building Google Mock ###
#### Preparing to Build (Unix only) ####
If you are using a Unix system and plan to use the GNU Autotools build
system to build Google Mock (described below), you'll need to
configure it now.
To prepare the Autotools build system:
cd googlemock
autoreconf -fvi
To build Google Mock and your tests that use it, you need to tell your
build system where to find its headers and source files. The exact
way to do it depends on which build system you use, and is usually
straightforward.
This section shows how you can integrate Google Mock into your
existing build system.
Suppose you put Google Mock in directory `${GMOCK_DIR}` and Google Test
in `${GTEST_DIR}` (the latter is `${GMOCK_DIR}/gtest` by default). To
build Google Mock, create a library build target (or a project as
called by Visual Studio and Xcode) to compile
${GTEST_DIR}/src/gtest-all.cc and ${GMOCK_DIR}/src/gmock-all.cc
with
${GTEST_DIR}/include and ${GMOCK_DIR}/include
in the system header search path, and
${GTEST_DIR} and ${GMOCK_DIR}
in the normal header search path. Assuming a Linux-like system and gcc,
something like the following will do:
g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \
-isystem ${GMOCK_DIR}/include -I${GMOCK_DIR} \
-pthread -c ${GTEST_DIR}/src/gtest-all.cc
g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \
-isystem ${GMOCK_DIR}/include -I${GMOCK_DIR} \
-pthread -c ${GMOCK_DIR}/src/gmock-all.cc
ar -rv libgmock.a gtest-all.o gmock-all.o
(We need -pthread as Google Test and Google Mock use threads.)
Next, you should compile your test source file with
${GTEST\_DIR}/include and ${GMOCK\_DIR}/include in the header search
path, and link it with gmock and any other necessary libraries:
g++ -isystem ${GTEST_DIR}/include -isystem ${GMOCK_DIR}/include \
-pthread path/to/your_test.cc libgmock.a -o your_test
As an example, the make/ directory contains a Makefile that you can
use to build Google Mock on systems where GNU make is available
(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google
Mock's own tests. Instead, it just builds the Google Mock library and
a sample test. You can use it as a starting point for your own build
script.
If the default settings are correct for your environment, the
following commands should succeed:
cd ${GMOCK_DIR}/make
make
./gmock_test
If you see errors, try to tweak the contents of
[make/Makefile](make/Makefile) to make them go away.
### Windows ###
The msvc/2005 directory contains VC++ 2005 projects and the msvc/2010
directory contains VC++ 2010 projects for building Google Mock and
selected tests.
Change to the appropriate directory and run "msbuild gmock.sln" to
build the library and tests (or open the gmock.sln in the MSVC IDE).
If you want to create your own project to use with Google Mock, you'll
have to configure it to use the `gmock_config` propety sheet. For that:
* Open the Property Manager window (View | Other Windows | Property Manager)
* Right-click on your project and select "Add Existing Property Sheet..."
* Navigate to `gmock_config.vsprops` or `gmock_config.props` and select it.
* In Project Properties | Configuration Properties | General | Additional
Include Directories, type <path to Google Mock>/include.
### Tweaking Google Mock ###
Google Mock can be used in diverse environments. The default
configuration may not work (or may not work well) out of the box in
some environments. However, you can easily tweak Google Mock by
defining control macros on the compiler command line. Generally,
these macros are named like `GTEST_XYZ` and you define them to either 1
or 0 to enable or disable a certain feature.
We list the most frequently used macros below. For a complete list,
see file [${GTEST\_DIR}/include/gtest/internal/gtest-port.h](
../googletest/include/gtest/internal/gtest-port.h).
### Choosing a TR1 Tuple Library ###
Google Mock uses the C++ Technical Report 1 (TR1) tuple library
heavily. Unfortunately TR1 tuple is not yet widely available with all
compilers. The good news is that Google Test 1.4.0+ implements a
subset of TR1 tuple that's enough for Google Mock's need. Google Mock
will automatically use that implementation when the compiler doesn't
provide TR1 tuple.
Usually you don't need to care about which tuple library Google Test
and Google Mock use. However, if your project already uses TR1 tuple,
you need to tell Google Test and Google Mock to use the same TR1 tuple
library the rest of your project uses, or the two tuple
implementations will clash. To do that, add
-DGTEST_USE_OWN_TR1_TUPLE=0
to the compiler flags while compiling Google Test, Google Mock, and
your tests. If you want to force Google Test and Google Mock to use
their own tuple library, just add
-DGTEST_USE_OWN_TR1_TUPLE=1
to the compiler flags instead.
If you want to use Boost's TR1 tuple library with Google Mock, please
refer to the Boost website (http://www.boost.org/) for how to obtain
it and set it up.
### As a Shared Library (DLL) ###
Google Mock is compact, so most users can build and link it as a static
library for the simplicity. Google Mock can be used as a DLL, but the
same DLL must contain Google Test as well. See
[Google Test's README][gtest_readme]
for instructions on how to set up necessary compiler settings.
### Tweaking Google Mock ###
Most of Google Test's control macros apply to Google Mock as well.
Please see [Google Test's README][gtest_readme] for how to tweak them.
### Upgrading from an Earlier Version ###
We strive to keep Google Mock releases backward compatible.
Sometimes, though, we have to make some breaking changes for the
users' long-term benefits. This section describes what you'll need to
do if you are upgrading from an earlier version of Google Mock.
#### Upgrading from 1.1.0 or Earlier ####
You may need to explicitly enable or disable Google Test's own TR1
tuple library. See the instructions in section "[Choosing a TR1 Tuple
Library](../googletest/#choosing-a-tr1-tuple-library)".
#### Upgrading from 1.4.0 or Earlier ####
On platforms where the pthread library is available, Google Test and
Google Mock use it in order to be thread-safe. For this to work, you
may need to tweak your compiler and/or linker flags. Please see the
"[Multi-threaded Tests](../googletest#multi-threaded-tests
)" section in file Google Test's README for what you may need to do.
If you have custom matchers defined using `MatcherInterface` or
`MakePolymorphicMatcher()`, you'll need to update their definitions to
use the new matcher API (
[monomorphic](http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Monomorphic_Matchers),
[polymorphic](http://code.google.com/p/googlemock/wiki/CookBook#Writing_New_Polymorphic_Matchers)).
Matchers defined using `MATCHER()` or `MATCHER_P*()` aren't affected.
### Developing Google Mock ###
This section discusses how to make your own changes to Google Mock.
#### Testing Google Mock Itself ####
To make sure your changes work as intended and don't break existing
functionality, you'll want to compile and run Google Test's own tests.
For that you'll need Autotools. First, make sure you have followed
the instructions above to configure Google Mock.
Then, create a build output directory and enter it. Next,
${GMOCK_DIR}/configure # try --help for more info
Once you have successfully configured Google Mock, the build steps are
standard for GNU-style OSS packages.
make # Standard makefile following GNU conventions
make check # Builds and runs all tests - all should pass.
Note that when building your project against Google Mock, you are building
against Google Test as well. There is no need to configure Google Test
separately.
#### Contributing a Patch ####
We welcome patches.
Please read the [Developer's Guide](docs/DevGuide.md)
for how you can contribute. In particular, make sure you have signed
the Contributor License Agreement, or we won't be able to accept the
patch.
Happy testing!
[gtest_readme]: ../googletest/README.md "googletest"

View File

@ -0,0 +1,10 @@
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
Name: gmock
Description: GoogleMock (without main() function)
Version: @PROJECT_VERSION@
URL: https://github.com/google/googletest
Requires: gtest = @PROJECT_VERSION@
Libs: -L${libdir} -lgmock @CMAKE_THREAD_LIBS_INIT@
Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@

View File

@ -0,0 +1,10 @@
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
Name: gmock_main
Description: GoogleMock (with main() function)
Version: @PROJECT_VERSION@
URL: https://github.com/google/googletest
Requires: gmock = @PROJECT_VERSION@
Libs: -L${libdir} -lgmock_main @CMAKE_THREAD_LIBS_INIT@
Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@

View File

@ -1,146 +0,0 @@
m4_include(../googletest/m4/acx_pthread.m4)
AC_INIT([Google C++ Mocking Framework],
[1.7.0],
[googlemock@googlegroups.com],
[gmock])
# Provide various options to initialize the Autoconf and configure processes.
AC_PREREQ([2.59])
AC_CONFIG_SRCDIR([./LICENSE])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([build-aux/config.h])
AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([scripts/gmock-config], [chmod +x scripts/gmock-config])
# Initialize Automake with various options. We require at least v1.9, prevent
# pedantic complaints about package files, and enable various distribution
# targets.
AM_INIT_AUTOMAKE([1.9 dist-bzip2 dist-zip foreign subdir-objects])
# Check for programs used in building Google Test.
AC_PROG_CC
AC_PROG_CXX
AC_LANG([C++])
AC_PROG_LIBTOOL
# TODO(chandlerc@google.com): Currently we aren't running the Python tests
# against the interpreter detected by AM_PATH_PYTHON, and so we condition
# HAVE_PYTHON by requiring "python" to be in the PATH, and that interpreter's
# version to be >= 2.3. This will allow the scripts to use a "/usr/bin/env"
# hashbang.
PYTHON= # We *do not* allow the user to specify a python interpreter
AC_PATH_PROG([PYTHON],[python],[:])
AS_IF([test "$PYTHON" != ":"],
[AM_PYTHON_CHECK_VERSION([$PYTHON],[2.3],[:],[PYTHON=":"])])
AM_CONDITIONAL([HAVE_PYTHON],[test "$PYTHON" != ":"])
# TODO(chandlerc@google.com) Check for the necessary system headers.
# Configure pthreads.
AC_ARG_WITH([pthreads],
[AS_HELP_STRING([--with-pthreads],
[use pthreads (default is yes)])],
[with_pthreads=$withval],
[with_pthreads=check])
have_pthreads=no
AS_IF([test "x$with_pthreads" != "xno"],
[ACX_PTHREAD(
[],
[AS_IF([test "x$with_pthreads" != "xcheck"],
[AC_MSG_FAILURE(
[--with-pthreads was specified, but unable to be used])])])
have_pthreads="$acx_pthread_ok"])
AM_CONDITIONAL([HAVE_PTHREADS],[test "x$have_pthreads" == "xyes"])
AC_SUBST(PTHREAD_CFLAGS)
AC_SUBST(PTHREAD_LIBS)
# GoogleMock currently has hard dependencies upon GoogleTest above and beyond
# running its own test suite, so we both provide our own version in
# a subdirectory and provide some logic to use a custom version or a system
# installed version.
AC_ARG_WITH([gtest],
[AS_HELP_STRING([--with-gtest],
[Specifies how to find the gtest package. If no
arguments are given, the default behavior, a
system installed gtest will be used if present,
and an internal version built otherwise. If a
path is provided, the gtest built or installed at
that prefix will be used.])],
[],
[with_gtest=yes])
AC_ARG_ENABLE([external-gtest],
[AS_HELP_STRING([--disable-external-gtest],
[Disables any detection or use of a system
installed or user provided gtest. Any option to
'--with-gtest' is ignored. (Default is enabled.)])
], [], [enable_external_gtest=yes])
AS_IF([test "x$with_gtest" == "xno"],
[AC_MSG_ERROR([dnl
Support for GoogleTest was explicitly disabled. Currently GoogleMock has a hard
dependency upon GoogleTest to build, please provide a version, or allow
GoogleMock to use any installed version and fall back upon its internal
version.])])
# Setup various GTEST variables. TODO(chandlerc@google.com): When these are
# used below, they should be used such that any pre-existing values always
# trump values we set them to, so that they can be used to selectively override
# details of the detection process.
AC_ARG_VAR([GTEST_CONFIG],
[The exact path of Google Test's 'gtest-config' script.])
AC_ARG_VAR([GTEST_CPPFLAGS],
[C-like preprocessor flags for Google Test.])
AC_ARG_VAR([GTEST_CXXFLAGS],
[C++ compile flags for Google Test.])
AC_ARG_VAR([GTEST_LDFLAGS],
[Linker path and option flags for Google Test.])
AC_ARG_VAR([GTEST_LIBS],
[Library linking flags for Google Test.])
AC_ARG_VAR([GTEST_VERSION],
[The version of Google Test available.])
HAVE_BUILT_GTEST="no"
GTEST_MIN_VERSION="1.7.0"
AS_IF([test "x${enable_external_gtest}" = "xyes"],
[# Begin filling in variables as we are able.
AS_IF([test "x${with_gtest}" != "xyes"],
[AS_IF([test -x "${with_gtest}/scripts/gtest-config"],
[GTEST_CONFIG="${with_gtest}/scripts/gtest-config"],
[GTEST_CONFIG="${with_gtest}/bin/gtest-config"])
AS_IF([test -x "${GTEST_CONFIG}"], [],
[AC_MSG_ERROR([dnl
Unable to locate either a built or installed Google Test at '${with_gtest}'.])
])])
AS_IF([test -x "${GTEST_CONFIG}"], [],
[AC_PATH_PROG([GTEST_CONFIG], [gtest-config])])
AS_IF([test -x "${GTEST_CONFIG}"],
[AC_MSG_CHECKING([for Google Test version >= ${GTEST_MIN_VERSION}])
AS_IF([${GTEST_CONFIG} --min-version=${GTEST_MIN_VERSION}],
[AC_MSG_RESULT([yes])
HAVE_BUILT_GTEST="yes"],
[AC_MSG_RESULT([no])])])])
AS_IF([test "x${HAVE_BUILT_GTEST}" = "xyes"],
[GTEST_CPPFLAGS=`${GTEST_CONFIG} --cppflags`
GTEST_CXXFLAGS=`${GTEST_CONFIG} --cxxflags`
GTEST_LDFLAGS=`${GTEST_CONFIG} --ldflags`
GTEST_LIBS=`${GTEST_CONFIG} --libs`
GTEST_VERSION=`${GTEST_CONFIG} --version`],
[AC_CONFIG_SUBDIRS([../googletest])
# GTEST_CONFIG needs to be executable both in a Makefile environmont and
# in a shell script environment, so resolve an absolute path for it here.
GTEST_CONFIG="`pwd -P`/../googletest/scripts/gtest-config"
GTEST_CPPFLAGS='-I$(top_srcdir)/../googletest/include'
GTEST_CXXFLAGS='-g'
GTEST_LDFLAGS=''
GTEST_LIBS='$(top_builddir)/../googletest/lib/libgtest.la'
GTEST_VERSION="${GTEST_MIN_VERSION}"])
# TODO(chandlerc@google.com) Check the types, structures, and other compiler
# and architecture characteristics.
# Output the generated files. No further autoconf macros may be used.
AC_OUTPUT

View File

@ -1,562 +0,0 @@
# Defining a Mock Class #
## Mocking a Normal Class ##
Given
```
class Foo {
...
virtual ~Foo();
virtual int GetSize() const = 0;
virtual string Describe(const char* name) = 0;
virtual string Describe(int type) = 0;
virtual bool Process(Bar elem, int count) = 0;
};
```
(note that `~Foo()` **must** be virtual) we can define its mock as
```
#include "gmock/gmock.h"
class MockFoo : public Foo {
MOCK_CONST_METHOD0(GetSize, int());
MOCK_METHOD1(Describe, string(const char* name));
MOCK_METHOD1(Describe, string(int type));
MOCK_METHOD2(Process, bool(Bar elem, int count));
};
```
To create a "nice" mock object which ignores all uninteresting calls,
or a "strict" mock object, which treats them as failures:
```
NiceMock<MockFoo> nice_foo; // The type is a subclass of MockFoo.
StrictMock<MockFoo> strict_foo; // The type is a subclass of MockFoo.
```
## Mocking a Class Template ##
To mock
```
template <typename Elem>
class StackInterface {
public:
...
virtual ~StackInterface();
virtual int GetSize() const = 0;
virtual void Push(const Elem& x) = 0;
};
```
(note that `~StackInterface()` **must** be virtual) just append `_T` to the `MOCK_*` macros:
```
template <typename Elem>
class MockStack : public StackInterface<Elem> {
public:
...
MOCK_CONST_METHOD0_T(GetSize, int());
MOCK_METHOD1_T(Push, void(const Elem& x));
};
```
## Specifying Calling Conventions for Mock Functions ##
If your mock function doesn't use the default calling convention, you
can specify it by appending `_WITH_CALLTYPE` to any of the macros
described in the previous two sections and supplying the calling
convention as the first argument to the macro. For example,
```
MOCK_METHOD_1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int n));
MOCK_CONST_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, Bar, int(double x, double y));
```
where `STDMETHODCALLTYPE` is defined by `<objbase.h>` on Windows.
# Using Mocks in Tests #
The typical flow is:
1. Import the Google Mock names you need to use. All Google Mock names are in the `testing` namespace unless they are macros or otherwise noted.
1. Create the mock objects.
1. Optionally, set the default actions of the mock objects.
1. Set your expectations on the mock objects (How will they be called? What wil they do?).
1. Exercise code that uses the mock objects; if necessary, check the result using [Google Test](../../googletest/) assertions.
1. When a mock objects is destructed, Google Mock automatically verifies that all expectations on it have been satisfied.
Here is an example:
```
using ::testing::Return; // #1
TEST(BarTest, DoesThis) {
MockFoo foo; // #2
ON_CALL(foo, GetSize()) // #3
.WillByDefault(Return(1));
// ... other default actions ...
EXPECT_CALL(foo, Describe(5)) // #4
.Times(3)
.WillRepeatedly(Return("Category 5"));
// ... other expectations ...
EXPECT_EQ("good", MyProductionFunction(&foo)); // #5
} // #6
```
# Setting Default Actions #
Google Mock has a **built-in default action** for any function that
returns `void`, `bool`, a numeric value, or a pointer.
To customize the default action for functions with return type `T` globally:
```
using ::testing::DefaultValue;
// Sets the default value to be returned. T must be CopyConstructible.
DefaultValue<T>::Set(value);
// Sets a factory. Will be invoked on demand. T must be MoveConstructible.
// T MakeT();
DefaultValue<T>::SetFactory(&MakeT);
// ... use the mocks ...
// Resets the default value.
DefaultValue<T>::Clear();
```
To customize the default action for a particular method, use `ON_CALL()`:
```
ON_CALL(mock_object, method(matchers))
.With(multi_argument_matcher) ?
.WillByDefault(action);
```
# Setting Expectations #
`EXPECT_CALL()` sets **expectations** on a mock method (How will it be
called? What will it do?):
```
EXPECT_CALL(mock_object, method(matchers))
.With(multi_argument_matcher) ?
.Times(cardinality) ?
.InSequence(sequences) *
.After(expectations) *
.WillOnce(action) *
.WillRepeatedly(action) ?
.RetiresOnSaturation(); ?
```
If `Times()` is omitted, the cardinality is assumed to be:
* `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`;
* `Times(n)` when there are `n WillOnce()`s but no `WillRepeatedly()`, where `n` >= 1; or
* `Times(AtLeast(n))` when there are `n WillOnce()`s and a `WillRepeatedly()`, where `n` >= 0.
A method with no `EXPECT_CALL()` is free to be invoked _any number of times_, and the default action will be taken each time.
# Matchers #
A **matcher** matches a _single_ argument. You can use it inside
`ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value
directly:
| `EXPECT_THAT(value, matcher)` | Asserts that `value` matches `matcher`. |
|:------------------------------|:----------------------------------------|
| `ASSERT_THAT(value, matcher)` | The same as `EXPECT_THAT(value, matcher)`, except that it generates a **fatal** failure. |
Built-in matchers (where `argument` is the function argument) are
divided into several categories:
## Wildcard ##
|`_`|`argument` can be any value of the correct type.|
|:--|:-----------------------------------------------|
|`A<type>()` or `An<type>()`|`argument` can be any value of type `type`. |
## Generic Comparison ##
|`Eq(value)` or `value`|`argument == value`|
|:---------------------|:------------------|
|`Ge(value)` |`argument >= value`|
|`Gt(value)` |`argument > value` |
|`Le(value)` |`argument <= value`|
|`Lt(value)` |`argument < value` |
|`Ne(value)` |`argument != value`|
|`IsNull()` |`argument` is a `NULL` pointer (raw or smart).|
|`NotNull()` |`argument` is a non-null pointer (raw or smart).|
|`Ref(variable)` |`argument` is a reference to `variable`.|
|`TypedEq<type>(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.|
Except `Ref()`, these matchers make a _copy_ of `value` in case it's
modified or destructed later. If the compiler complains that `value`
doesn't have a public copy constructor, try wrap it in `ByRef()`,
e.g. `Eq(ByRef(non_copyable_value))`. If you do that, make sure
`non_copyable_value` is not changed afterwards, or the meaning of your
matcher will be changed.
## Floating-Point Matchers ##
|`DoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal.|
|:-------------------|:----------------------------------------------------------------------------------------------|
|`FloatEq(a_float)` |`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. |
|`NanSensitiveDoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. |
|`NanSensitiveFloatEq(a_float)`|`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. |
The above matchers use ULP-based comparison (the same as used in
[Google Test](../../googletest/)). They
automatically pick a reasonable error bound based on the absolute
value of the expected value. `DoubleEq()` and `FloatEq()` conform to
the IEEE standard, which requires comparing two NaNs for equality to
return false. The `NanSensitive*` version instead treats two NaNs as
equal, which is often what a user wants.
|`DoubleNear(a_double, max_abs_error)`|`argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as unequal.|
|:------------------------------------|:--------------------------------------------------------------------------------------------------------------------|
|`FloatNear(a_float, max_abs_error)` |`argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as unequal. |
|`NanSensitiveDoubleNear(a_double, max_abs_error)`|`argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as equal. |
|`NanSensitiveFloatNear(a_float, max_abs_error)`|`argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as equal. |
## String Matchers ##
The `argument` can be either a C string or a C++ string object:
|`ContainsRegex(string)`|`argument` matches the given regular expression.|
|:----------------------|:-----------------------------------------------|
|`EndsWith(suffix)` |`argument` ends with string `suffix`. |
|`HasSubstr(string)` |`argument` contains `string` as a sub-string. |
|`MatchesRegex(string)` |`argument` matches the given regular expression with the match starting at the first character and ending at the last character.|
|`StartsWith(prefix)` |`argument` starts with string `prefix`. |
|`StrCaseEq(string)` |`argument` is equal to `string`, ignoring case. |
|`StrCaseNe(string)` |`argument` is not equal to `string`, ignoring case.|
|`StrEq(string)` |`argument` is equal to `string`. |
|`StrNe(string)` |`argument` is not equal to `string`. |
`ContainsRegex()` and `MatchesRegex()` use the regular expression
syntax defined
[here](../../googletest/docs/AdvancedGuide.md#regular-expression-syntax).
`StrCaseEq()`, `StrCaseNe()`, `StrEq()`, and `StrNe()` work for wide
strings as well.
## Container Matchers ##
Most STL-style containers support `==`, so you can use
`Eq(expected_container)` or simply `expected_container` to match a
container exactly. If you want to write the elements in-line,
match them more flexibly, or get more informative messages, you can use:
| `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. |
|:-------------------------|:---------------------------------------------------------------------------------------------------------------------------------|
| `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. |
| `Each(e)` | `argument` is a container where _every_ element matches `e`, which can be either a value or a matcher. |
| `ElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, where the i-th element matches `ei`, which can be a value or a matcher. 0 to 10 arguments are allowed. |
| `ElementsAreArray({ e0, e1, ..., en })`, `ElementsAreArray(array)`, or `ElementsAreArray(array, count)` | The same as `ElementsAre()` except that the expected element values/matchers come from an initializer list, STL-style container, or C-style array. |
| `IsEmpty()` | `argument` is an empty container (`container.empty()`). |
| `Pointwise(m, container)` | `argument` contains the same number of elements as in `container`, and for all i, (the i-th element in `argument`, the i-th element in `container`) match `m`, which is a matcher on 2-tuples. E.g. `Pointwise(Le(), upper_bounds)` verifies that each element in `argument` doesn't exceed the corresponding element in `upper_bounds`. See more detail below. |
| `SizeIs(m)` | `argument` is a container whose size matches `m`. E.g. `SizeIs(2)` or `SizeIs(Lt(2))`. |
| `UnorderedElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, and under some permutation each element matches an `ei` (for a different `i`), which can be a value or a matcher. 0 to 10 arguments are allowed. |
| `UnorderedElementsAreArray({ e0, e1, ..., en })`, `UnorderedElementsAreArray(array)`, or `UnorderedElementsAreArray(array, count)` | The same as `UnorderedElementsAre()` except that the expected element values/matchers come from an initializer list, STL-style container, or C-style array. |
| `WhenSorted(m)` | When `argument` is sorted using the `<` operator, it matches container matcher `m`. E.g. `WhenSorted(UnorderedElementsAre(1, 2, 3))` verifies that `argument` contains elements `1`, `2`, and `3`, ignoring order. |
| `WhenSortedBy(comparator, m)` | The same as `WhenSorted(m)`, except that the given comparator instead of `<` is used to sort `argument`. E.g. `WhenSortedBy(std::greater<int>(), ElementsAre(3, 2, 1))`. |
Notes:
* These matchers can also match:
1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and
1. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#Multiargument_Matchers.md)).
* The array being matched may be multi-dimensional (i.e. its elements can be arrays).
* `m` in `Pointwise(m, ...)` should be a matcher for `::testing::tuple<T, U>` where `T` and `U` are the element type of the actual container and the expected container, respectively. For example, to compare two `Foo` containers where `Foo` doesn't support `operator==` but has an `Equals()` method, one might write:
```
using ::testing::get;
MATCHER(FooEq, "") {
return get<0>(arg).Equals(get<1>(arg));
}
...
EXPECT_THAT(actual_foos, Pointwise(FooEq(), expected_foos));
```
## Member Matchers ##
|`Field(&class::field, m)`|`argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.|
|:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------|
|`Key(e)` |`argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`.|
|`Pair(m1, m2)` |`argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. |
|`Property(&class::property, m)`|`argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.|
## Matching the Result of a Function or Functor ##
|`ResultOf(f, m)`|`f(argument)` matches matcher `m`, where `f` is a function or functor.|
|:---------------|:---------------------------------------------------------------------|
## Pointer Matchers ##
|`Pointee(m)`|`argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`.|
|:-----------|:-----------------------------------------------------------------------------------------------|
|`WhenDynamicCastTo<T>(m)`| when `argument` is passed through `dynamic_cast<T>()`, it matches matcher `m`. |
## Multiargument Matchers ##
Technically, all matchers match a _single_ value. A "multi-argument"
matcher is just one that matches a _tuple_. The following matchers can
be used to match a tuple `(x, y)`:
|`Eq()`|`x == y`|
|:-----|:-------|
|`Ge()`|`x >= y`|
|`Gt()`|`x > y` |
|`Le()`|`x <= y`|
|`Lt()`|`x < y` |
|`Ne()`|`x != y`|
You can use the following selectors to pick a subset of the arguments
(or reorder them) to participate in the matching:
|`AllArgs(m)`|Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`.|
|:-----------|:-------------------------------------------------------------------|
|`Args<N1, N2, ..., Nk>(m)`|The tuple of the `k` selected (using 0-based indices) arguments matches `m`, e.g. `Args<1, 2>(Eq())`.|
## Composite Matchers ##
You can make a matcher from one or more other matchers:
|`AllOf(m1, m2, ..., mn)`|`argument` matches all of the matchers `m1` to `mn`.|
|:-----------------------|:---------------------------------------------------|
|`AnyOf(m1, m2, ..., mn)`|`argument` matches at least one of the matchers `m1` to `mn`.|
|`Not(m)` |`argument` doesn't match matcher `m`. |
## Adapters for Matchers ##
|`MatcherCast<T>(m)`|casts matcher `m` to type `Matcher<T>`.|
|:------------------|:--------------------------------------|
|`SafeMatcherCast<T>(m)`| [safely casts](CookBook.md#casting-matchers) matcher `m` to type `Matcher<T>`. |
|`Truly(predicate)` |`predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor.|
## Matchers as Predicates ##
|`Matches(m)(value)`|evaluates to `true` if `value` matches `m`. You can use `Matches(m)` alone as a unary functor.|
|:------------------|:---------------------------------------------------------------------------------------------|
|`ExplainMatchResult(m, value, result_listener)`|evaluates to `true` if `value` matches `m`, explaining the result to `result_listener`. |
|`Value(value, m)` |evaluates to `true` if `value` matches `m`. |
## Defining Matchers ##
| `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. |
|:-------------------------------------------------|:------------------------------------------------------|
| `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a macher `IsDivisibleBy(n)` to match a number divisible by `n`. |
| `MATCHER_P2(IsBetween, a, b, std::string(negation ? "isn't" : "is") + " between " + PrintToString(a) + " and " + PrintToString(b)) { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. |
**Notes:**
1. The `MATCHER*` macros cannot be used inside a function or class.
1. The matcher body must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters).
1. You can use `PrintToString(x)` to convert a value `x` of any type to a string.
## Matchers as Test Assertions ##
|`ASSERT_THAT(expression, m)`|Generates a [fatal failure](../../googletest/docs/Primer.md#assertions) if the value of `expression` doesn't match matcher `m`.|
|:---------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------|
|`EXPECT_THAT(expression, m)`|Generates a non-fatal failure if the value of `expression` doesn't match matcher `m`. |
# Actions #
**Actions** specify what a mock function should do when invoked.
## Returning a Value ##
|`Return()`|Return from a `void` mock function.|
|:---------|:----------------------------------|
|`Return(value)`|Return `value`. If the type of `value` is different to the mock function's return type, `value` is converted to the latter type <i>at the time the expectation is set</i>, not when the action is executed.|
|`ReturnArg<N>()`|Return the `N`-th (0-based) argument.|
|`ReturnNew<T>(a1, ..., ak)`|Return `new T(a1, ..., ak)`; a different object is created each time.|
|`ReturnNull()`|Return a null pointer. |
|`ReturnPointee(ptr)`|Return the value pointed to by `ptr`.|
|`ReturnRef(variable)`|Return a reference to `variable`. |
|`ReturnRefOfCopy(value)`|Return a reference to a copy of `value`; the copy lives as long as the action.|
## Side Effects ##
|`Assign(&variable, value)`|Assign `value` to variable.|
|:-------------------------|:--------------------------|
| `DeleteArg<N>()` | Delete the `N`-th (0-based) argument, which must be a pointer. |
| `SaveArg<N>(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. |
| `SaveArgPointee<N>(pointer)` | Save the value pointed to by the `N`-th (0-based) argument to `*pointer`. |
| `SetArgReferee<N>(value)` | Assign value to the variable referenced by the `N`-th (0-based) argument. |
|`SetArgPointee<N>(value)` |Assign `value` to the variable pointed by the `N`-th (0-based) argument.|
|`SetArgumentPointee<N>(value)`|Same as `SetArgPointee<N>(value)`. Deprecated. Will be removed in v1.7.0.|
|`SetArrayArgument<N>(first, last)`|Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.|
|`SetErrnoAndReturn(error, value)`|Set `errno` to `error` and return `value`.|
|`Throw(exception)` |Throws the given exception, which can be any copyable value. Available since v1.1.0.|
## Using a Function or a Functor as an Action ##
|`Invoke(f)`|Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor.|
|:----------|:-----------------------------------------------------------------------------------------------------------------|
|`Invoke(object_pointer, &class::method)`|Invoke the {method on the object with the arguments passed to the mock function. |
|`InvokeWithoutArgs(f)`|Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. |
|`InvokeWithoutArgs(object_pointer, &class::method)`|Invoke the method on the object, which takes no arguments. |
|`InvokeArgument<N>(arg1, arg2, ..., argk)`|Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments.|
The return value of the invoked function is used as the return value
of the action.
When defining a function or functor to be used with `Invoke*()`, you can declare any unused parameters as `Unused`:
```
double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); }
...
EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance));
```
In `InvokeArgument<N>(...)`, if an argument needs to be passed by reference, wrap it inside `ByRef()`. For example,
```
InvokeArgument<2>(5, string("Hi"), ByRef(foo))
```
calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference.
## Default Action ##
|`DoDefault()`|Do the default action (specified by `ON_CALL()` or the built-in one).|
|:------------|:--------------------------------------------------------------------|
**Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error.
## Composite Actions ##
|`DoAll(a1, a2, ..., an)`|Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. |
|:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------|
|`IgnoreResult(a)` |Perform action `a` and ignore its result. `a` must not return void. |
|`WithArg<N>(a)` |Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. |
|`WithArgs<N1, N2, ..., Nk>(a)`|Pass the selected (0-based) arguments of the mock function to action `a` and perform it. |
|`WithoutArgs(a)` |Perform action `a` without any arguments. |
## Defining Actions ##
| `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. |
|:--------------------------------------|:---------------------------------------------------------------------------------------|
| `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. |
| `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. |
The `ACTION*` macros cannot be used inside a function or class.
# Cardinalities #
These are used in `Times()` to specify how many times a mock function will be called:
|`AnyNumber()`|The function can be called any number of times.|
|:------------|:----------------------------------------------|
|`AtLeast(n)` |The call is expected at least `n` times. |
|`AtMost(n)` |The call is expected at most `n` times. |
|`Between(m, n)`|The call is expected between `m` and `n` (inclusive) times.|
|`Exactly(n) or n`|The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0.|
# Expectation Order #
By default, the expectations can be matched in _any_ order. If some
or all expectations must be matched in a given order, there are two
ways to specify it. They can be used either independently or
together.
## The After Clause ##
```
using ::testing::Expectation;
...
Expectation init_x = EXPECT_CALL(foo, InitX());
Expectation init_y = EXPECT_CALL(foo, InitY());
EXPECT_CALL(foo, Bar())
.After(init_x, init_y);
```
says that `Bar()` can be called only after both `InitX()` and
`InitY()` have been called.
If you don't know how many pre-requisites an expectation has when you
write it, you can use an `ExpectationSet` to collect them:
```
using ::testing::ExpectationSet;
...
ExpectationSet all_inits;
for (int i = 0; i < element_count; i++) {
all_inits += EXPECT_CALL(foo, InitElement(i));
}
EXPECT_CALL(foo, Bar())
.After(all_inits);
```
says that `Bar()` can be called only after all elements have been
initialized (but we don't care about which elements get initialized
before the others).
Modifying an `ExpectationSet` after using it in an `.After()` doesn't
affect the meaning of the `.After()`.
## Sequences ##
When you have a long chain of sequential expectations, it's easier to
specify the order using **sequences**, which don't require you to given
each expectation in the chain a different name. <i>All expected<br>
calls</i> in the same sequence must occur in the order they are
specified.
```
using ::testing::Sequence;
Sequence s1, s2;
...
EXPECT_CALL(foo, Reset())
.InSequence(s1, s2)
.WillOnce(Return(true));
EXPECT_CALL(foo, GetSize())
.InSequence(s1)
.WillOnce(Return(1));
EXPECT_CALL(foo, Describe(A<const char*>()))
.InSequence(s2)
.WillOnce(Return("dummy"));
```
says that `Reset()` must be called before _both_ `GetSize()` _and_
`Describe()`, and the latter two can occur in any order.
To put many expectations in a sequence conveniently:
```
using ::testing::InSequence;
{
InSequence dummy;
EXPECT_CALL(...)...;
EXPECT_CALL(...)...;
...
EXPECT_CALL(...)...;
}
```
says that all expected calls in the scope of `dummy` must occur in
strict order. The name `dummy` is irrelevant.)
# Verifying and Resetting a Mock #
Google Mock will verify the expectations on a mock object when it is destructed, or you can do it earlier:
```
using ::testing::Mock;
...
// Verifies and removes the expectations on mock_obj;
// returns true iff successful.
Mock::VerifyAndClearExpectations(&mock_obj);
...
// Verifies and removes the expectations on mock_obj;
// also removes the default actions set by ON_CALL();
// returns true iff successful.
Mock::VerifyAndClear(&mock_obj);
```
You can also tell Google Mock that a mock object can be leaked and doesn't
need to be verified:
```
Mock::AllowLeak(&mock_obj);
```
# Mock Classes #
Google Mock defines a convenient mock class template
```
class MockFunction<R(A1, ..., An)> {
public:
MOCK_METHODn(Call, R(A1, ..., An));
};
```
See this [recipe](CookBook.md#using-check-points) for one application of it.
# Flags #
| `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. |
|:-------------------------------|:----------------------------------------------|
| `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. |

File diff suppressed because it is too large Load Diff

View File

@ -1,280 +0,0 @@
This page discusses the design of new Google Mock features.
# Macros for Defining Actions #
## Problem ##
Due to the lack of closures in C++, it currently requires some
non-trivial effort to define a custom action in Google Mock. For
example, suppose you want to "increment the value pointed to by the
second argument of the mock function and return it", you could write:
```
int IncrementArg1(Unused, int* p, Unused) {
return ++(*p);
}
... WillOnce(Invoke(IncrementArg1));
```
There are several things unsatisfactory about this approach:
* Even though the action only cares about the second argument of the mock function, its definition needs to list other arguments as dummies. This is tedious.
* The defined action is usable only in mock functions that takes exactly 3 arguments - an unnecessary restriction.
* To use the action, one has to say `Invoke(IncrementArg1)`, which isn't as nice as `IncrementArg1()`.
The latter two problems can be overcome using `MakePolymorphicAction()`,
but it requires much more boilerplate code:
```
class IncrementArg1Action {
public:
template <typename Result, typename ArgumentTuple>
Result Perform(const ArgumentTuple& args) const {
return ++(*tr1::get<1>(args));
}
};
PolymorphicAction<IncrementArg1Action> IncrementArg1() {
return MakePolymorphicAction(IncrementArg1Action());
}
... WillOnce(IncrementArg1());
```
Our goal is to allow defining custom actions with the least amount of
boiler-plate C++ requires.
## Solution ##
We propose to introduce a new macro:
```
ACTION(name) { statements; }
```
Using this in a namespace scope will define an action with the given
name that executes the statements. Inside the statements, you can
refer to the K-th (0-based) argument of the mock function as `argK`.
For example:
```
ACTION(IncrementArg1) { return ++(*arg1); }
```
allows you to write
```
... WillOnce(IncrementArg1());
```
Note that you don't need to specify the types of the mock function
arguments, as brevity is a top design goal here. Rest assured that
your code is still type-safe though: you'll get a compiler error if
`*arg1` doesn't support the `++` operator, or if the type of
`++(*arg1)` isn't compatible with the mock function's return type.
Another example:
```
ACTION(Foo) {
(*arg2)(5);
Blah();
*arg1 = 0;
return arg0;
}
```
defines an action `Foo()` that invokes argument #2 (a function pointer)
with 5, calls function `Blah()`, sets the value pointed to by argument
#1 to 0, and returns argument #0.
For more convenience and flexibility, you can also use the following
pre-defined symbols in the body of `ACTION`:
| `argK_type` | The type of the K-th (0-based) argument of the mock function |
|:------------|:-------------------------------------------------------------|
| `args` | All arguments of the mock function as a tuple |
| `args_type` | The type of all arguments of the mock function as a tuple |
| `return_type` | The return type of the mock function |
| `function_type` | The type of the mock function |
For example, when using an `ACTION` as a stub action for mock function:
```
int DoSomething(bool flag, int* ptr);
```
we have:
| **Pre-defined Symbol** | **Is Bound To** |
|:-----------------------|:----------------|
| `arg0` | the value of `flag` |
| `arg0_type` | the type `bool` |
| `arg1` | the value of `ptr` |
| `arg1_type` | the type `int*` |
| `args` | the tuple `(flag, ptr)` |
| `args_type` | the type `std::tr1::tuple<bool, int*>` |
| `return_type` | the type `int` |
| `function_type` | the type `int(bool, int*)` |
## Parameterized actions ##
Sometimes you'll want to parameterize the action. For that we propose
another macro
```
ACTION_P(name, param) { statements; }
```
For example,
```
ACTION_P(Add, n) { return arg0 + n; }
```
will allow you to write
```
// Returns argument #0 + 5.
... WillOnce(Add(5));
```
For convenience, we use the term _arguments_ for the values used to
invoke the mock function, and the term _parameters_ for the values
used to instantiate an action.
Note that you don't need to provide the type of the parameter either.
Suppose the parameter is named `param`, you can also use the
Google-Mock-defined symbol `param_type` to refer to the type of the
parameter as inferred by the compiler.
We will also provide `ACTION_P2`, `ACTION_P3`, and etc to support
multi-parameter actions. For example,
```
ACTION_P2(ReturnDistanceTo, x, y) {
double dx = arg0 - x;
double dy = arg1 - y;
return sqrt(dx*dx + dy*dy);
}
```
lets you write
```
... WillOnce(ReturnDistanceTo(5.0, 26.5));
```
You can view `ACTION` as a degenerated parameterized action where the
number of parameters is 0.
## Advanced Usages ##
### Overloading Actions ###
You can easily define actions overloaded on the number of parameters:
```
ACTION_P(Plus, a) { ... }
ACTION_P2(Plus, a, b) { ... }
```
### Restricting the Type of an Argument or Parameter ###
For maximum brevity and reusability, the `ACTION*` macros don't let
you specify the types of the mock function arguments and the action
parameters. Instead, we let the compiler infer the types for us.
Sometimes, however, we may want to be more explicit about the types.
There are several tricks to do that. For example:
```
ACTION(Foo) {
// Makes sure arg0 can be converted to int.
int n = arg0;
... use n instead of arg0 here ...
}
ACTION_P(Bar, param) {
// Makes sure the type of arg1 is const char*.
::testing::StaticAssertTypeEq<const char*, arg1_type>();
// Makes sure param can be converted to bool.
bool flag = param;
}
```
where `StaticAssertTypeEq` is a compile-time assertion we plan to add to
Google Test (the name is chosen to match `static_assert` in C++0x).
### Using the ACTION Object's Type ###
If you are writing a function that returns an `ACTION` object, you'll
need to know its type. The type depends on the macro used to define
the action and the parameter types. The rule is relatively simple:
| **Given Definition** | **Expression** | **Has Type** |
|:---------------------|:---------------|:-------------|
| `ACTION(Foo)` | `Foo()` | `FooAction` |
| `ACTION_P(Bar, param)` | `Bar(int_value)` | `BarActionP<int>` |
| `ACTION_P2(Baz, p1, p2)` | `Baz(bool_value, int_value)` | `BazActionP2<bool, int>` |
| ... | ... | ... |
Note that we have to pick different suffixes (`Action`, `ActionP`,
`ActionP2`, and etc) for actions with different numbers of parameters,
or the action definitions cannot be overloaded on the number of
parameters.
## When to Use ##
While the new macros are very convenient, please also consider other
means of implementing actions (e.g. via `ActionInterface` or
`MakePolymorphicAction()`), especially if you need to use the defined
action a lot. While the other approaches require more work, they give
you more control on the types of the mock function arguments and the
action parameters, which in general leads to better compiler error
messages that pay off in the long run. They also allow overloading
actions based on parameter types, as opposed to just the number of
parameters.
## Related Work ##
As you may have realized, the `ACTION*` macros resemble closures (also
known as lambda expressions or anonymous functions). Indeed, both of
them seek to lower the syntactic overhead for defining a function.
C++0x will support lambdas, but they are not part of C++ right now.
Some non-standard libraries (most notably BLL or Boost Lambda Library)
try to alleviate this problem. However, they are not a good choice
for defining actions as:
* They are non-standard and not widely installed. Google Mock only depends on standard libraries and `tr1::tuple`, which is part of the new C++ standard and comes with gcc 4+. We want to keep it that way.
* They are not trivial to learn.
* They will become obsolete when C++0x's lambda feature is widely supported. We don't want to make our users use a dying library.
* Since they are based on operators, they are rather ad hoc: you cannot use statements, and you cannot pass the lambda arguments to a function, for example.
* They have subtle semantics that easily confuses new users. For example, in expression `_1++ + foo++`, `foo` will be incremented only once where the expression is evaluated, while `_1` will be incremented every time the unnamed function is invoked. This is far from intuitive.
`ACTION*` avoid all these problems.
## Future Improvements ##
There may be a need for composing `ACTION*` definitions (i.e. invoking
another `ACTION` inside the definition of one `ACTION*`). We are not
sure we want it yet, as one can get a similar effect by putting
`ACTION` definitions in function templates and composing the function
templates. We'll revisit this based on user feedback.
The reason we don't allow `ACTION*()` inside a function body is that
the current C++ standard doesn't allow function-local types to be used
to instantiate templates. The upcoming C++0x standard will lift this
restriction. Once this feature is widely supported by compilers, we
can revisit the implementation and add support for using `ACTION*()`
inside a function.
C++0x will also support lambda expressions. When they become
available, we may want to support using lambdas as actions.
# Macros for Defining Matchers #
Once the macros for defining actions are implemented, we plan to do
the same for matchers:
```
MATCHER(name) { statements; }
```
where you can refer to the value being matched as `arg`. For example,
given:
```
MATCHER(IsPositive) { return arg > 0; }
```
you can use `IsPositive()` as a matcher that matches a value iff it is
greater than 0.
We will also add `MATCHER_P`, `MATCHER_P2`, and etc for parameterized
matchers.

View File

@ -1,132 +0,0 @@
If you are interested in understanding the internals of Google Mock,
building from source, or contributing ideas or modifications to the
project, then this document is for you.
# Introduction #
First, let's give you some background of the project.
## Licensing ##
All Google Mock source and pre-built packages are provided under the [New BSD License](http://www.opensource.org/licenses/bsd-license.php).
## The Google Mock Community ##
The Google Mock community exists primarily through the [discussion group](http://groups.google.com/group/googlemock), the
[issue tracker](https://github.com/google/googletest/issues) and, to a lesser extent, the [source control repository](../). You are definitely encouraged to contribute to the
discussion and you can also help us to keep the effectiveness of the
group high by following and promoting the guidelines listed here.
### Please Be Friendly ###
Showing courtesy and respect to others is a vital part of the Google
culture, and we strongly encourage everyone participating in Google
Mock development to join us in accepting nothing less. Of course,
being courteous is not the same as failing to constructively disagree
with each other, but it does mean that we should be respectful of each
other when enumerating the 42 technical reasons that a particular
proposal may not be the best choice. There's never a reason to be
antagonistic or dismissive toward anyone who is sincerely trying to
contribute to a discussion.
Sure, C++ testing is serious business and all that, but it's also
a lot of fun. Let's keep it that way. Let's strive to be one of the
friendliest communities in all of open source.
### Where to Discuss Google Mock ###
As always, discuss Google Mock in the official [Google C++ Mocking Framework discussion group](http://groups.google.com/group/googlemock). You don't have to actually submit
code in order to sign up. Your participation itself is a valuable
contribution.
# Working with the Code #
If you want to get your hands dirty with the code inside Google Mock,
this is the section for you.
## Checking Out the Source from Subversion ##
Checking out the Google Mock source is most useful if you plan to
tweak it yourself. You check out the source for Google Mock using a
[Subversion](http://subversion.tigris.org/) client as you would for any
other project hosted on Google Code. Please see the instruction on
the [source code access page](../) for how to do it.
## Compiling from Source ##
Once you check out the code, you can find instructions on how to
compile it in the [README](../README.md) file.
## Testing ##
A mocking framework is of no good if itself is not thoroughly tested.
Tests should be written for any new code, and changes should be
verified to not break existing tests before they are submitted for
review. To perform the tests, follow the instructions in [README](http://code.google.com/p/googlemock/source/browse/trunk/README) and
verify that there are no failures.
# Contributing Code #
We are excited that Google Mock is now open source, and hope to get
great patches from the community. Before you fire up your favorite IDE
and begin hammering away at that new feature, though, please take the
time to read this section and understand the process. While it seems
rigorous, we want to keep a high standard of quality in the code
base.
## Contributor License Agreements ##
You must sign a Contributor License Agreement (CLA) before we can
accept any code. The CLA protects you and us.
* If you are an individual writing original source code and you're sure you own the intellectual property, then you'll need to sign an [individual CLA](http://code.google.com/legal/individual-cla-v1.0.html).
* If you work for a company that wants to allow you to contribute your work to Google Mock, then you'll need to sign a [corporate CLA](http://code.google.com/legal/corporate-cla-v1.0.html).
Follow either of the two links above to access the appropriate CLA and
instructions for how to sign and return it.
## Coding Style ##
To keep the source consistent, readable, diffable and easy to merge,
we use a fairly rigid coding style, as defined by the [google-styleguide](https://github.com/google/styleguide) project. All patches will be expected
to conform to the style outlined [here](https://github.com/google/styleguide/blob/gh-pages/cppguide.xml).
## Submitting Patches ##
Please do submit code. Here's what you need to do:
1. Normally you should make your change against the SVN trunk instead of a branch or a tag, as the latter two are for release control and should be treated mostly as read-only.
1. Decide which code you want to submit. A submission should be a set of changes that addresses one issue in the [Google Mock issue tracker](http://code.google.com/p/googlemock/issues/list). Please don't mix more than one logical change per submittal, because it makes the history hard to follow. If you want to make a change that doesn't have a corresponding issue in the issue tracker, please create one.
1. Also, coordinate with team members that are listed on the issue in question. This ensures that work isn't being duplicated and communicating your plan early also generally leads to better patches.
1. Ensure that your code adheres to the [Google Mock source code style](#Coding_Style.md).
1. Ensure that there are unit tests for your code.
1. Sign a Contributor License Agreement.
1. Create a patch file using `svn diff`.
1. We use [Rietveld](http://codereview.appspot.com/) to do web-based code reviews. You can read about the tool [here](https://github.com/rietveld-codereview/rietveld/wiki). When you are ready, upload your patch via Rietveld and notify `googlemock@googlegroups.com` to review it. There are several ways to upload the patch. We recommend using the [upload\_gmock.py](../scripts/upload_gmock.py) script, which you can find in the `scripts/` folder in the SVN trunk.
## Google Mock Committers ##
The current members of the Google Mock engineering team are the only
committers at present. In the great tradition of eating one's own
dogfood, we will be requiring each new Google Mock engineering team
member to earn the right to become a committer by following the
procedures in this document, writing consistently great code, and
demonstrating repeatedly that he or she truly gets the zen of Google
Mock.
# Release Process #
We follow the typical release process for Subversion-based projects:
1. A release branch named `release-X.Y` is created.
1. Bugs are fixed and features are added in trunk; those individual patches are merged into the release branch until it's stable.
1. An individual point release (the `Z` in `X.Y.Z`) is made by creating a tag from the branch.
1. Repeat steps 2 and 3 throughout one release cycle (as determined by features or time).
1. Go back to step 1 to create another release branch and so on.
---
This page is based on the [Making GWT Better](http://code.google.com/webtoolkit/makinggwtbetter.html) guide from the [Google Web Toolkit](http://code.google.com/webtoolkit/) project. Except as otherwise [noted](http://code.google.com/policies.html#restrictions), the content of this page is licensed under the [Creative Commons Attribution 2.5 License](http://creativecommons.org/licenses/by/2.5/).

View File

@ -1,12 +0,0 @@
This page lists all documentation wiki pages for Google Mock **(the SVN trunk version)**
- **if you use a released version of Google Mock, please read the documentation for that specific version instead.**
* [ForDummies](ForDummies.md) -- start here if you are new to Google Mock.
* [CheatSheet](CheatSheet.md) -- a quick reference.
* [CookBook](CookBook.md) -- recipes for doing various tasks using Google Mock.
* [FrequentlyAskedQuestions](FrequentlyAskedQuestions.md) -- check here before asking a question on the mailing list.
To contribute code to Google Mock, read:
* [DevGuide](DevGuide.md) -- read this _before_ writing your first patch.
* [Pump Manual](../googletest/docs/PumpManual.md) -- how we generate some of Google Mock's source files.

View File

@ -1,439 +0,0 @@
(**Note:** If you get compiler errors that you don't understand, be sure to consult [Google Mock Doctor](FrequentlyAskedQuestions.md#how-am-i-supposed-to-make-sense-of-these-horrible-template-errors).)
# What Is Google C++ Mocking Framework? #
When you write a prototype or test, often it's not feasible or wise to rely on real objects entirely. A **mock object** implements the same interface as a real object (so it can be used as one), but lets you specify at run time how it will be used and what it should do (which methods will be called? in which order? how many times? with what arguments? what will they return? etc).
**Note:** It is easy to confuse the term _fake objects_ with mock objects. Fakes and mocks actually mean very different things in the Test-Driven Development (TDD) community:
* **Fake** objects have working implementations, but usually take some shortcut (perhaps to make the operations less expensive), which makes them not suitable for production. An in-memory file system would be an example of a fake.
* **Mocks** are objects pre-programmed with _expectations_, which form a specification of the calls they are expected to receive.
If all this seems too abstract for you, don't worry - the most important thing to remember is that a mock allows you to check the _interaction_ between itself and code that uses it. The difference between fakes and mocks will become much clearer once you start to use mocks.
**Google C++ Mocking Framework** (or **Google Mock** for short) is a library (sometimes we also call it a "framework" to make it sound cool) for creating mock classes and using them. It does to C++ what [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/) do to Java.
Using Google Mock involves three basic steps:
1. Use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class;
1. Create some mock objects and specify its expectations and behavior using an intuitive syntax;
1. Exercise code that uses the mock objects. Google Mock will catch any violation of the expectations as soon as it arises.
# Why Google Mock? #
While mock objects help you remove unnecessary dependencies in tests and make them fast and reliable, using mocks manually in C++ is _hard_:
* Someone has to implement the mocks. The job is usually tedious and error-prone. No wonder people go great distance to avoid it.
* The quality of those manually written mocks is a bit, uh, unpredictable. You may see some really polished ones, but you may also see some that were hacked up in a hurry and have all sorts of ad hoc restrictions.
* The knowledge you gained from using one mock doesn't transfer to the next.
In contrast, Java and Python programmers have some fine mock frameworks, which automate the creation of mocks. As a result, mocking is a proven effective technique and widely adopted practice in those communities. Having the right tool absolutely makes the difference.
Google Mock was built to help C++ programmers. It was inspired by [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/), but designed with C++'s specifics in mind. It is your friend if any of the following problems is bothering you:
* You are stuck with a sub-optimal design and wish you had done more prototyping before it was too late, but prototyping in C++ is by no means "rapid".
* Your tests are slow as they depend on too many libraries or use expensive resources (e.g. a database).
* Your tests are brittle as some resources they use are unreliable (e.g. the network).
* You want to test how your code handles a failure (e.g. a file checksum error), but it's not easy to cause one.
* You need to make sure that your module interacts with other modules in the right way, but it's hard to observe the interaction; therefore you resort to observing the side effects at the end of the action, which is awkward at best.
* You want to "mock out" your dependencies, except that they don't have mock implementations yet; and, frankly, you aren't thrilled by some of those hand-written mocks.
We encourage you to use Google Mock as:
* a _design_ tool, for it lets you experiment with your interface design early and often. More iterations lead to better designs!
* a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators.
# Getting Started #
Using Google Mock is easy! Inside your C++ source file, just `#include` `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go.
# A Case for Mock Turtles #
Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface:
```
class Turtle {
...
virtual ~Turtle() {}
virtual void PenUp() = 0;
virtual void PenDown() = 0;
virtual void Forward(int distance) = 0;
virtual void Turn(int degrees) = 0;
virtual void GoTo(int x, int y) = 0;
virtual int GetX() const = 0;
virtual int GetY() const = 0;
};
```
(Note that the destructor of `Turtle` **must** be virtual, as is the case for **all** classes you intend to inherit from - otherwise the destructor of the derived class will not be called when you delete an object through a base pointer, and you'll get corrupted program states like memory leaks.)
You can control whether the turtle's movement will leave a trace using `PenUp()` and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and `GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the turtle.
Your program will normally use a real implementation of this interface. In tests, you can use a mock implementation instead. This allows you to easily check what drawing primitives your program is calling, with what arguments, and in which order. Tests written this way are much more robust (they won't break because your new machine does anti-aliasing differently), easier to read and maintain (the intent of a test is expressed in the code, not in some binary images), and run _much, much faster_.
# Writing the Mock Class #
If you are lucky, the mocks you need to use have already been implemented by some nice people. If, however, you find yourself in the position to write a mock class, relax - Google Mock turns this task into a fun game! (Well, almost.)
## How to Define It ##
Using the `Turtle` interface as example, here are the simple steps you need to follow:
1. Derive a class `MockTurtle` from `Turtle`.
1. Take a _virtual_ function of `Turtle` (while it's possible to [mock non-virtual methods using templates](CookBook.md#mocking-nonvirtual-methods), it's much more involved). Count how many arguments it has.
1. In the `public:` section of the child class, write `MOCK_METHODn();` (or `MOCK_CONST_METHODn();` if you are mocking a `const` method), where `n` is the number of the arguments; if you counted wrong, shame on you, and a compiler error will tell you so.
1. Now comes the fun part: you take the function signature, cut-and-paste the _function name_ as the _first_ argument to the macro, and leave what's left as the _second_ argument (in case you're curious, this is the _type of the function_).
1. Repeat until all virtual functions you want to mock are done.
After the process, you should have something like:
```
#include "gmock/gmock.h" // Brings in Google Mock.
class MockTurtle : public Turtle {
public:
...
MOCK_METHOD0(PenUp, void());
MOCK_METHOD0(PenDown, void());
MOCK_METHOD1(Forward, void(int distance));
MOCK_METHOD1(Turn, void(int degrees));
MOCK_METHOD2(GoTo, void(int x, int y));
MOCK_CONST_METHOD0(GetX, int());
MOCK_CONST_METHOD0(GetY, int());
};
```
You don't need to define these mock methods somewhere else - the `MOCK_METHOD*` macros will generate the definitions for you. It's that simple! Once you get the hang of it, you can pump out mock classes faster than your source-control system can handle your check-ins.
**Tip:** If even this is too much work for you, you'll find the
`gmock_gen.py` tool in Google Mock's `scripts/generator/` directory (courtesy of the [cppclean](http://code.google.com/p/cppclean/) project) useful. This command-line
tool requires that you have Python 2.4 installed. You give it a C++ file and the name of an abstract class defined in it,
and it will print the definition of the mock class for you. Due to the
complexity of the C++ language, this script may not always work, but
it can be quite handy when it does. For more details, read the [user documentation](../scripts/generator/README).
## Where to Put It ##
When you define a mock class, you need to decide where to put its definition. Some people put it in a `*_test.cc`. This is fine when the interface being mocked (say, `Foo`) is owned by the same person or team. Otherwise, when the owner of `Foo` changes it, your test could break. (You can't really expect `Foo`'s maintainer to fix every test that uses `Foo`, can you?)
So, the rule of thumb is: if you need to mock `Foo` and it's owned by others, define the mock class in `Foo`'s package (better, in a `testing` sub-package such that you can clearly separate production code and testing utilities), and put it in a `mock_foo.h`. Then everyone can reference `mock_foo.h` from their tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and only tests that depend on the changed methods need to be fixed.
Another way to do it: you can introduce a thin layer `FooAdaptor` on top of `Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb changes in `Foo` much more easily. While this is more work initially, carefully choosing the adaptor interface can make your code easier to write and more readable (a net win in the long run), as you can choose `FooAdaptor` to fit your specific domain much better than `Foo` does.
# Using Mocks in Tests #
Once you have a mock class, using it is easy. The typical work flow is:
1. Import the Google Mock names from the `testing` namespace such that you can use them unqualified (You only have to do it once per file. Remember that namespaces are a good idea and good for your health.).
1. Create some mock objects.
1. Specify your expectations on them (How many times will a method be called? With what arguments? What should it do? etc.).
1. Exercise some code that uses the mocks; optionally, check the result using Google Test assertions. If a mock method is called more than expected or with wrong arguments, you'll get an error immediately.
1. When a mock is destructed, Google Mock will automatically check whether all expectations on it have been satisfied.
Here's an example:
```
#include "path/to/mock-turtle.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
using ::testing::AtLeast; // #1
TEST(PainterTest, CanDrawSomething) {
MockTurtle turtle; // #2
EXPECT_CALL(turtle, PenDown()) // #3
.Times(AtLeast(1));
Painter painter(&turtle); // #4
EXPECT_TRUE(painter.DrawCircle(0, 0, 10));
} // #5
int main(int argc, char** argv) {
// The following line must be executed to initialize Google Mock
// (and Google Test) before running the tests.
::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
```
As you might have guessed, this test checks that `PenDown()` is called at least once. If the `painter` object didn't call this method, your test will fail with a message like this:
```
path/to/my_test.cc:119: Failure
Actual function call count doesn't match this expectation:
Actually: never called;
Expected: called at least once.
```
**Tip 1:** If you run the test from an Emacs buffer, you can hit `<Enter>` on the line number displayed in the error message to jump right to the failed expectation.
**Tip 2:** If your mock objects are never deleted, the final verification won't happen. Therefore it's a good idea to use a heap leak checker in your tests when you allocate mocks on the heap.
**Important note:** Google Mock requires expectations to be set **before** the mock functions are called, otherwise the behavior is **undefined**. In particular, you mustn't interleave `EXPECT_CALL()`s and calls to the mock functions.
This means `EXPECT_CALL()` should be read as expecting that a call will occur _in the future_, not that a call has occurred. Why does Google Mock work like that? Well, specifying the expectation beforehand allows Google Mock to report a violation as soon as it arises, when the context (stack trace, etc) is still available. This makes debugging much easier.
Admittedly, this test is contrived and doesn't do much. You can easily achieve the same effect without using Google Mock. However, as we shall reveal soon, Google Mock allows you to do _much more_ with the mocks.
## Using Google Mock with Any Testing Framework ##
If you want to use something other than Google Test (e.g. [CppUnit](http://sourceforge.net/projects/cppunit/) or
[CxxTest](http://cxxtest.tigris.org/)) as your testing framework, just change the `main()` function in the previous section to:
```
int main(int argc, char** argv) {
// The following line causes Google Mock to throw an exception on failure,
// which will be interpreted by your testing framework as a test failure.
::testing::GTEST_FLAG(throw_on_failure) = true;
::testing::InitGoogleMock(&argc, argv);
... whatever your testing framework requires ...
}
```
This approach has a catch: it makes Google Mock throw an exception
from a mock object's destructor sometimes. With some compilers, this
sometimes causes the test program to crash. You'll still be able to
notice that the test has failed, but it's not a graceful failure.
A better solution is to use Google Test's
[event listener API](../../googletest/docs/AdvancedGuide.md#extending-google-test-by-handling-test-events)
to report a test failure to your testing framework properly. You'll need to
implement the `OnTestPartResult()` method of the event listener interface, but it
should be straightforward.
If this turns out to be too much work, we suggest that you stick with
Google Test, which works with Google Mock seamlessly (in fact, it is
technically part of Google Mock.). If there is a reason that you
cannot use Google Test, please let us know.
# Setting Expectations #
The key to using a mock object successfully is to set the _right expectations_ on it. If you set the expectations too strict, your test will fail as the result of unrelated changes. If you set them too loose, bugs can slip through. You want to do it just right such that your test can catch exactly the kind of bugs you intend it to catch. Google Mock provides the necessary means for you to do it "just right."
## General Syntax ##
In Google Mock we use the `EXPECT_CALL()` macro to set an expectation on a mock method. The general syntax is:
```
EXPECT_CALL(mock_object, method(matchers))
.Times(cardinality)
.WillOnce(action)
.WillRepeatedly(action);
```
The macro has two arguments: first the mock object, and then the method and its arguments. Note that the two are separated by a comma (`,`), not a period (`.`). (Why using a comma? The answer is that it was necessary for technical reasons.)
The macro can be followed by some optional _clauses_ that provide more information about the expectation. We'll discuss how each clause works in the coming sections.
This syntax is designed to make an expectation read like English. For example, you can probably guess that
```
using ::testing::Return;...
EXPECT_CALL(turtle, GetX())
.Times(5)
.WillOnce(Return(100))
.WillOnce(Return(150))
.WillRepeatedly(Return(200));
```
says that the `turtle` object's `GetX()` method will be called five times, it will return 100 the first time, 150 the second time, and then 200 every time. Some people like to call this style of syntax a Domain-Specific Language (DSL).
**Note:** Why do we use a macro to do this? It serves two purposes: first it makes expectations easily identifiable (either by `grep` or by a human reader), and second it allows Google Mock to include the source file location of a failed expectation in messages, making debugging easier.
## Matchers: What Arguments Do We Expect? ##
When a mock function takes arguments, we must specify what arguments we are expecting; for example:
```
// Expects the turtle to move forward by 100 units.
EXPECT_CALL(turtle, Forward(100));
```
Sometimes you may not want to be too specific (Remember that talk about tests being too rigid? Over specification leads to brittle tests and obscures the intent of tests. Therefore we encourage you to specify only what's necessary - no more, no less.). If you care to check that `Forward()` will be called but aren't interested in its actual argument, write `_` as the argument, which means "anything goes":
```
using ::testing::_;
...
// Expects the turtle to move forward.
EXPECT_CALL(turtle, Forward(_));
```
`_` is an instance of what we call **matchers**. A matcher is like a predicate and can test whether an argument is what we'd expect. You can use a matcher inside `EXPECT_CALL()` wherever a function argument is expected.
A list of built-in matchers can be found in the [CheatSheet](CheatSheet.md). For example, here's the `Ge` (greater than or equal) matcher:
```
using ::testing::Ge;...
EXPECT_CALL(turtle, Forward(Ge(100)));
```
This checks that the turtle will be told to go forward by at least 100 units.
## Cardinalities: How Many Times Will It Be Called? ##
The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We call its argument a **cardinality** as it tells _how many times_ the call should occur. It allows us to repeat an expectation many times without actually writing it as many times. More importantly, a cardinality can be "fuzzy", just like a matcher can be. This allows a user to express the intent of a test exactly.
An interesting special case is when we say `Times(0)`. You may have guessed - it means that the function shouldn't be called with the given arguments at all, and Google Mock will report a Google Test failure whenever the function is (wrongfully) called.
We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the list of built-in cardinalities you can use, see the [CheatSheet](CheatSheet.md).
The `Times()` clause can be omitted. **If you omit `Times()`, Google Mock will infer the cardinality for you.** The rules are easy to remember:
* If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the `EXPECT_CALL()`, the inferred cardinality is `Times(1)`.
* If there are `n WillOnce()`'s but **no** `WillRepeatedly()`, where `n` >= 1, the cardinality is `Times(n)`.
* If there are `n WillOnce()`'s and **one** `WillRepeatedly()`, where `n` >= 0, the cardinality is `Times(AtLeast(n))`.
**Quick quiz:** what do you think will happen if a function is expected to be called twice but actually called four times?
## Actions: What Should It Do? ##
Remember that a mock object doesn't really have a working implementation? We as users have to tell it what to do when a method is invoked. This is easy in Google Mock.
First, if the return type of a mock function is a built-in type or a pointer, the function has a **default action** (a `void` function will just return, a `bool` function will return `false`, and other functions will return 0). In addition, in C++ 11 and above, a mock function whose return type is default-constructible (i.e. has a default constructor) has a default action of returning a default-constructed value. If you don't say anything, this behavior will be used.
Second, if a mock function doesn't have a default action, or the default action doesn't suit you, you can specify the action to be taken each time the expectation matches using a series of `WillOnce()` clauses followed by an optional `WillRepeatedly()`. For example,
```
using ::testing::Return;...
EXPECT_CALL(turtle, GetX())
.WillOnce(Return(100))
.WillOnce(Return(200))
.WillOnce(Return(300));
```
This says that `turtle.GetX()` will be called _exactly three times_ (Google Mock inferred this from how many `WillOnce()` clauses we've written, since we didn't explicitly write `Times()`), and will return 100, 200, and 300 respectively.
```
using ::testing::Return;...
EXPECT_CALL(turtle, GetY())
.WillOnce(Return(100))
.WillOnce(Return(200))
.WillRepeatedly(Return(300));
```
says that `turtle.GetY()` will be called _at least twice_ (Google Mock knows this as we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no explicit `Times()`), will return 100 the first time, 200 the second time, and 300 from the third time on.
Of course, if you explicitly write a `Times()`, Google Mock will not try to infer the cardinality itself. What if the number you specified is larger than there are `WillOnce()` clauses? Well, after all `WillOnce()`s are used up, Google Mock will do the _default_ action for the function every time (unless, of course, you have a `WillRepeatedly()`.).
What can we do inside `WillOnce()` besides `Return()`? You can return a reference using `ReturnRef(variable)`, or invoke a pre-defined function, among [others](CheatSheet.md#actions).
**Important note:** The `EXPECT_CALL()` statement evaluates the action clause only once, even though the action may be performed many times. Therefore you must be careful about side effects. The following may not do what you want:
```
int n = 100;
EXPECT_CALL(turtle, GetX())
.Times(4)
.WillRepeatedly(Return(n++));
```
Instead of returning 100, 101, 102, ..., consecutively, this mock function will always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will return the same pointer every time. If you want the side effect to happen every time, you need to define a custom action, which we'll teach in the [CookBook](CookBook.md).
Time for another quiz! What do you think the following means?
```
using ::testing::Return;...
EXPECT_CALL(turtle, GetY())
.Times(4)
.WillOnce(Return(100));
```
Obviously `turtle.GetY()` is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that one `WillOnce()` clause will be consumed each time the function is invoked and the default action will be taken afterwards. So the right answer is that `turtle.GetY()` will return 100 the first time, but **return 0 from the second time on**, as returning 0 is the default action for `int` functions.
## Using Multiple Expectations ##
So far we've only shown examples where you have a single expectation. More realistically, you're going to specify expectations on multiple mock methods, which may be from multiple mock objects.
By default, when a mock method is invoked, Google Mock will search the expectations in the **reverse order** they are defined, and stop when an active expectation that matches the arguments is found (you can think of it as "newer rules override older ones."). If the matching expectation cannot take any more calls, you will get an upper-bound-violated failure. Here's an example:
```
using ::testing::_;...
EXPECT_CALL(turtle, Forward(_)); // #1
EXPECT_CALL(turtle, Forward(10)) // #2
.Times(2);
```
If `Forward(10)` is called three times in a row, the third time it will be an error, as the last matching expectation (#2) has been saturated. If, however, the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, as now #1 will be the matching expectation.
**Side note:** Why does Google Mock search for a match in the _reverse_ order of the expectations? The reason is that this allows a user to set up the default expectations in a mock object's constructor or the test fixture's set-up phase and then customize the mock by writing more specific expectations in the test body. So, if you have two expectations on the same method, you want to put the one with more specific matchers **after** the other, or the more specific rule would be shadowed by the more general one that comes after it.
## Ordered vs Unordered Calls ##
By default, an expectation can match a call even though an earlier expectation hasn't been satisfied. In other words, the calls don't have to occur in the order the expectations are specified.
Sometimes, you may want all the expected calls to occur in a strict order. To say this in Google Mock is easy:
```
using ::testing::InSequence;...
TEST(FooTest, DrawsLineSegment) {
...
{
InSequence dummy;
EXPECT_CALL(turtle, PenDown());
EXPECT_CALL(turtle, Forward(100));
EXPECT_CALL(turtle, PenUp());
}
Foo();
}
```
By creating an object of type `InSequence`, all expectations in its scope are put into a _sequence_ and have to occur _sequentially_. Since we are just relying on the constructor and destructor of this object to do the actual work, its name is really irrelevant.
In this example, we test that `Foo()` calls the three expected functions in the order as written. If a call is made out-of-order, it will be an error.
(What if you care about the relative order of some of the calls, but not all of them? Can you specify an arbitrary partial order? The answer is ... yes! If you are impatient, the details can be found in the [CookBook](CookBook#Expecting_Partially_Ordered_Calls.md).)
## All Expectations Are Sticky (Unless Said Otherwise) ##
Now let's do a quick quiz to see how well you can use this mock stuff already. How would you test that the turtle is asked to go to the origin _exactly twice_ (you want to ignore any other instructions it receives)?
After you've come up with your answer, take a look at ours and compare notes (solve it yourself first - don't cheat!):
```
using ::testing::_;...
EXPECT_CALL(turtle, GoTo(_, _)) // #1
.Times(AnyNumber());
EXPECT_CALL(turtle, GoTo(0, 0)) // #2
.Times(2);
```
Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, Google Mock will see that the arguments match expectation #2 (remember that we always pick the last matching expectation). Now, since we said that there should be only two such calls, Google Mock will report an error immediately. This is basically what we've told you in the "Using Multiple Expectations" section above.
This example shows that **expectations in Google Mock are "sticky" by default**, in the sense that they remain active even after we have reached their invocation upper bounds. This is an important rule to remember, as it affects the meaning of the spec, and is **different** to how it's done in many other mocking frameworks (Why'd we do that? Because we think our rule makes the common cases easier to express and understand.).
Simple? Let's see if you've really understood it: what does the following code say?
```
using ::testing::Return;
...
for (int i = n; i > 0; i--) {
EXPECT_CALL(turtle, GetX())
.WillOnce(Return(10*i));
}
```
If you think it says that `turtle.GetX()` will be called `n` times and will return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we said, expectations are sticky. So, the second time `turtle.GetX()` is called, the last (latest) `EXPECT_CALL()` statement will match, and will immediately lead to an "upper bound exceeded" error - this piece of code is not very useful!
One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is to explicitly say that the expectations are _not_ sticky. In other words, they should _retire_ as soon as they are saturated:
```
using ::testing::Return;
...
for (int i = n; i > 0; i--) {
EXPECT_CALL(turtle, GetX())
.WillOnce(Return(10*i))
.RetiresOnSaturation();
}
```
And, there's a better way to do it: in this case, we expect the calls to occur in a specific order, and we line up the actions to match the order. Since the order is important here, we should make it explicit using a sequence:
```
using ::testing::InSequence;
using ::testing::Return;
...
{
InSequence s;
for (int i = 1; i <= n; i++) {
EXPECT_CALL(turtle, GetX())
.WillOnce(Return(10*i))
.RetiresOnSaturation();
}
}
```
By the way, the other situation where an expectation may _not_ be sticky is when it's in a sequence - as soon as another expectation that comes after it in the sequence has been used, it automatically retires (and will never be used to match any call).
## Uninteresting Calls ##
A mock object may have many methods, and not all of them are that interesting. For example, in some tests we may not care about how many times `GetX()` and `GetY()` get called.
In Google Mock, if you are not interested in a method, just don't say anything about it. If a call to this method occurs, you'll see a warning in the test output, but it won't be a failure.
# What Now? #
Congratulations! You've learned enough about Google Mock to start using it. Now, you might want to join the [googlemock](http://groups.google.com/group/googlemock) discussion group and actually write some tests using Google Mock - it will be fun. Hey, it may even be addictive - you've been warned.
Then, if you feel like increasing your mock quotient, you should move on to the [CookBook](CookBook.md). You can learn many advanced features of Google Mock there -- and advance your level of enjoyment and testing bliss.

View File

@ -1,628 +0,0 @@
Please send your questions to the
[googlemock](http://groups.google.com/group/googlemock) discussion
group. If you need help with compiler errors, make sure you have
tried [Google Mock Doctor](#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md) first.
## When I call a method on my mock object, the method for the real object is invoked instead. What's the problem? ##
In order for a method to be mocked, it must be _virtual_, unless you use the [high-perf dependency injection technique](CookBook.md#mocking-nonvirtual-methods).
## I wrote some matchers. After I upgraded to a new version of Google Mock, they no longer compile. What's going on? ##
After version 1.4.0 of Google Mock was released, we had an idea on how
to make it easier to write matchers that can generate informative
messages efficiently. We experimented with this idea and liked what
we saw. Therefore we decided to implement it.
Unfortunately, this means that if you have defined your own matchers
by implementing `MatcherInterface` or using `MakePolymorphicMatcher()`,
your definitions will no longer compile. Matchers defined using the
`MATCHER*` family of macros are not affected.
Sorry for the hassle if your matchers are affected. We believe it's
in everyone's long-term interest to make this change sooner than
later. Fortunately, it's usually not hard to migrate an existing
matcher to the new API. Here's what you need to do:
If you wrote your matcher like this:
```
// Old matcher definition that doesn't work with the latest
// Google Mock.
using ::testing::MatcherInterface;
...
class MyWonderfulMatcher : public MatcherInterface<MyType> {
public:
...
virtual bool Matches(MyType value) const {
// Returns true if value matches.
return value.GetFoo() > 5;
}
...
};
```
you'll need to change it to:
```
// New matcher definition that works with the latest Google Mock.
using ::testing::MatcherInterface;
using ::testing::MatchResultListener;
...
class MyWonderfulMatcher : public MatcherInterface<MyType> {
public:
...
virtual bool MatchAndExplain(MyType value,
MatchResultListener* listener) const {
// Returns true if value matches.
return value.GetFoo() > 5;
}
...
};
```
(i.e. rename `Matches()` to `MatchAndExplain()` and give it a second
argument of type `MatchResultListener*`.)
If you were also using `ExplainMatchResultTo()` to improve the matcher
message:
```
// Old matcher definition that doesn't work with the lastest
// Google Mock.
using ::testing::MatcherInterface;
...
class MyWonderfulMatcher : public MatcherInterface<MyType> {
public:
...
virtual bool Matches(MyType value) const {
// Returns true if value matches.
return value.GetFoo() > 5;
}
virtual void ExplainMatchResultTo(MyType value,
::std::ostream* os) const {
// Prints some helpful information to os to help
// a user understand why value matches (or doesn't match).
*os << "the Foo property is " << value.GetFoo();
}
...
};
```
you should move the logic of `ExplainMatchResultTo()` into
`MatchAndExplain()`, using the `MatchResultListener` argument where
the `::std::ostream` was used:
```
// New matcher definition that works with the latest Google Mock.
using ::testing::MatcherInterface;
using ::testing::MatchResultListener;
...
class MyWonderfulMatcher : public MatcherInterface<MyType> {
public:
...
virtual bool MatchAndExplain(MyType value,
MatchResultListener* listener) const {
// Returns true if value matches.
*listener << "the Foo property is " << value.GetFoo();
return value.GetFoo() > 5;
}
...
};
```
If your matcher is defined using `MakePolymorphicMatcher()`:
```
// Old matcher definition that doesn't work with the latest
// Google Mock.
using ::testing::MakePolymorphicMatcher;
...
class MyGreatMatcher {
public:
...
bool Matches(MyType value) const {
// Returns true if value matches.
return value.GetBar() < 42;
}
...
};
... MakePolymorphicMatcher(MyGreatMatcher()) ...
```
you should rename the `Matches()` method to `MatchAndExplain()` and
add a `MatchResultListener*` argument (the same as what you need to do
for matchers defined by implementing `MatcherInterface`):
```
// New matcher definition that works with the latest Google Mock.
using ::testing::MakePolymorphicMatcher;
using ::testing::MatchResultListener;
...
class MyGreatMatcher {
public:
...
bool MatchAndExplain(MyType value,
MatchResultListener* listener) const {
// Returns true if value matches.
return value.GetBar() < 42;
}
...
};
... MakePolymorphicMatcher(MyGreatMatcher()) ...
```
If your polymorphic matcher uses `ExplainMatchResultTo()` for better
failure messages:
```
// Old matcher definition that doesn't work with the latest
// Google Mock.
using ::testing::MakePolymorphicMatcher;
...
class MyGreatMatcher {
public:
...
bool Matches(MyType value) const {
// Returns true if value matches.
return value.GetBar() < 42;
}
...
};
void ExplainMatchResultTo(const MyGreatMatcher& matcher,
MyType value,
::std::ostream* os) {
// Prints some helpful information to os to help
// a user understand why value matches (or doesn't match).
*os << "the Bar property is " << value.GetBar();
}
... MakePolymorphicMatcher(MyGreatMatcher()) ...
```
you'll need to move the logic inside `ExplainMatchResultTo()` to
`MatchAndExplain()`:
```
// New matcher definition that works with the latest Google Mock.
using ::testing::MakePolymorphicMatcher;
using ::testing::MatchResultListener;
...
class MyGreatMatcher {
public:
...
bool MatchAndExplain(MyType value,
MatchResultListener* listener) const {
// Returns true if value matches.
*listener << "the Bar property is " << value.GetBar();
return value.GetBar() < 42;
}
...
};
... MakePolymorphicMatcher(MyGreatMatcher()) ...
```
For more information, you can read these
[two](CookBook.md#writing-new-monomorphic-matchers)
[recipes](CookBook.md#writing-new-polymorphic-matchers)
from the cookbook. As always, you
are welcome to post questions on `googlemock@googlegroups.com` if you
need any help.
## When using Google Mock, do I have to use Google Test as the testing framework? I have my favorite testing framework and don't want to switch. ##
Google Mock works out of the box with Google Test. However, it's easy
to configure it to work with any testing framework of your choice.
[Here](ForDummies.md#using-google-mock-with-any-testing-framework) is how.
## How am I supposed to make sense of these horrible template errors? ##
If you are confused by the compiler errors gcc threw at you,
try consulting the _Google Mock Doctor_ tool first. What it does is to
scan stdin for gcc error messages, and spit out diagnoses on the
problems (we call them diseases) your code has.
To "install", run command:
```
alias gmd='<path to googlemock>/scripts/gmock_doctor.py'
```
To use it, do:
```
<your-favorite-build-command> <your-test> 2>&1 | gmd
```
For example:
```
make my_test 2>&1 | gmd
```
Or you can run `gmd` and copy-n-paste gcc's error messages to it.
## Can I mock a variadic function? ##
You cannot mock a variadic function (i.e. a function taking ellipsis
(`...`) arguments) directly in Google Mock.
The problem is that in general, there is _no way_ for a mock object to
know how many arguments are passed to the variadic method, and what
the arguments' types are. Only the _author of the base class_ knows
the protocol, and we cannot look into his head.
Therefore, to mock such a function, the _user_ must teach the mock
object how to figure out the number of arguments and their types. One
way to do it is to provide overloaded versions of the function.
Ellipsis arguments are inherited from C and not really a C++ feature.
They are unsafe to use and don't work with arguments that have
constructors or destructors. Therefore we recommend to avoid them in
C++ as much as possible.
## MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? ##
If you compile this using Microsoft Visual C++ 2005 SP1:
```
class Foo {
...
virtual void Bar(const int i) = 0;
};
class MockFoo : public Foo {
...
MOCK_METHOD1(Bar, void(const int i));
};
```
You may get the following warning:
```
warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier
```
This is a MSVC bug. The same code compiles fine with gcc ,for
example. If you use Visual C++ 2008 SP1, you would get the warning:
```
warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers
```
In C++, if you _declare_ a function with a `const` parameter, the
`const` modifier is _ignored_. Therefore, the `Foo` base class above
is equivalent to:
```
class Foo {
...
virtual void Bar(int i) = 0; // int or const int? Makes no difference.
};
```
In fact, you can _declare_ Bar() with an `int` parameter, and _define_
it with a `const int` parameter. The compiler will still match them
up.
Since making a parameter `const` is meaningless in the method
_declaration_, we recommend to remove it in both `Foo` and `MockFoo`.
That should workaround the VC bug.
Note that we are talking about the _top-level_ `const` modifier here.
If the function parameter is passed by pointer or reference, declaring
the _pointee_ or _referee_ as `const` is still meaningful. For
example, the following two declarations are _not_ equivalent:
```
void Bar(int* p); // Neither p nor *p is const.
void Bar(const int* p); // p is not const, but *p is.
```
## I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? ##
We've noticed that when the `/clr` compiler flag is used, Visual C++
uses 5~6 times as much memory when compiling a mock class. We suggest
to avoid `/clr` when compiling native C++ mocks.
## I can't figure out why Google Mock thinks my expectations are not satisfied. What should I do? ##
You might want to run your test with
`--gmock_verbose=info`. This flag lets Google Mock print a trace
of every mock function call it receives. By studying the trace,
you'll gain insights on why the expectations you set are not met.
## How can I assert that a function is NEVER called? ##
```
EXPECT_CALL(foo, Bar(_))
.Times(0);
```
## I have a failed test where Google Mock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? ##
When Google Mock detects a failure, it prints relevant information
(the mock function arguments, the state of relevant expectations, and
etc) to help the user debug. If another failure is detected, Google
Mock will do the same, including printing the state of relevant
expectations.
Sometimes an expectation's state didn't change between two failures,
and you'll see the same description of the state twice. They are
however _not_ redundant, as they refer to _different points in time_.
The fact they are the same _is_ interesting information.
## I get a heap check failure when using a mock object, but using a real object is fine. What can be wrong? ##
Does the class (hopefully a pure interface) you are mocking have a
virtual destructor?
Whenever you derive from a base class, make sure its destructor is
virtual. Otherwise Bad Things will happen. Consider the following
code:
```
class Base {
public:
// Not virtual, but should be.
~Base() { ... }
...
};
class Derived : public Base {
public:
...
private:
std::string value_;
};
...
Base* p = new Derived;
...
delete p; // Surprise! ~Base() will be called, but ~Derived() will not
// - value_ is leaked.
```
By changing `~Base()` to virtual, `~Derived()` will be correctly
called when `delete p` is executed, and the heap checker
will be happy.
## The "newer expectations override older ones" rule makes writing expectations awkward. Why does Google Mock do that? ##
When people complain about this, often they are referring to code like:
```
// foo.Bar() should be called twice, return 1 the first time, and return
// 2 the second time. However, I have to write the expectations in the
// reverse order. This sucks big time!!!
EXPECT_CALL(foo, Bar())
.WillOnce(Return(2))
.RetiresOnSaturation();
EXPECT_CALL(foo, Bar())
.WillOnce(Return(1))
.RetiresOnSaturation();
```
The problem is that they didn't pick the **best** way to express the test's
intent.
By default, expectations don't have to be matched in _any_ particular
order. If you want them to match in a certain order, you need to be
explicit. This is Google Mock's (and jMock's) fundamental philosophy: it's
easy to accidentally over-specify your tests, and we want to make it
harder to do so.
There are two better ways to write the test spec. You could either
put the expectations in sequence:
```
// foo.Bar() should be called twice, return 1 the first time, and return
// 2 the second time. Using a sequence, we can write the expectations
// in their natural order.
{
InSequence s;
EXPECT_CALL(foo, Bar())
.WillOnce(Return(1))
.RetiresOnSaturation();
EXPECT_CALL(foo, Bar())
.WillOnce(Return(2))
.RetiresOnSaturation();
}
```
or you can put the sequence of actions in the same expectation:
```
// foo.Bar() should be called twice, return 1 the first time, and return
// 2 the second time.
EXPECT_CALL(foo, Bar())
.WillOnce(Return(1))
.WillOnce(Return(2))
.RetiresOnSaturation();
```
Back to the original questions: why does Google Mock search the
expectations (and `ON_CALL`s) from back to front? Because this
allows a user to set up a mock's behavior for the common case early
(e.g. in the mock's constructor or the test fixture's set-up phase)
and customize it with more specific rules later. If Google Mock
searches from front to back, this very useful pattern won't be
possible.
## Google Mock prints a warning when a function without EXPECT\_CALL is called, even if I have set its behavior using ON\_CALL. Would it be reasonable not to show the warning in this case? ##
When choosing between being neat and being safe, we lean toward the
latter. So the answer is that we think it's better to show the
warning.
Often people write `ON_CALL`s in the mock object's
constructor or `SetUp()`, as the default behavior rarely changes from
test to test. Then in the test body they set the expectations, which
are often different for each test. Having an `ON_CALL` in the set-up
part of a test doesn't mean that the calls are expected. If there's
no `EXPECT_CALL` and the method is called, it's possibly an error. If
we quietly let the call go through without notifying the user, bugs
may creep in unnoticed.
If, however, you are sure that the calls are OK, you can write
```
EXPECT_CALL(foo, Bar(_))
.WillRepeatedly(...);
```
instead of
```
ON_CALL(foo, Bar(_))
.WillByDefault(...);
```
This tells Google Mock that you do expect the calls and no warning should be
printed.
Also, you can control the verbosity using the `--gmock_verbose` flag.
If you find the output too noisy when debugging, just choose a less
verbose level.
## How can I delete the mock function's argument in an action? ##
If you find yourself needing to perform some action that's not
supported by Google Mock directly, remember that you can define your own
actions using
[MakeAction()](CookBook.md#writing-new-actions) or
[MakePolymorphicAction()](CookBook.md#writing_new_polymorphic_actions),
or you can write a stub function and invoke it using
[Invoke()](CookBook.md#using-functions_methods_functors).
## MOCK\_METHODn()'s second argument looks funny. Why don't you use the MOCK\_METHODn(Method, return\_type, arg\_1, ..., arg\_n) syntax? ##
What?! I think it's beautiful. :-)
While which syntax looks more natural is a subjective matter to some
extent, Google Mock's syntax was chosen for several practical advantages it
has.
Try to mock a function that takes a map as an argument:
```
virtual int GetSize(const map<int, std::string>& m);
```
Using the proposed syntax, it would be:
```
MOCK_METHOD1(GetSize, int, const map<int, std::string>& m);
```
Guess what? You'll get a compiler error as the compiler thinks that
`const map<int, std::string>& m` are **two**, not one, arguments. To work
around this you can use `typedef` to give the map type a name, but
that gets in the way of your work. Google Mock's syntax avoids this
problem as the function's argument types are protected inside a pair
of parentheses:
```
// This compiles fine.
MOCK_METHOD1(GetSize, int(const map<int, std::string>& m));
```
You still need a `typedef` if the return type contains an unprotected
comma, but that's much rarer.
Other advantages include:
1. `MOCK_METHOD1(Foo, int, bool)` can leave a reader wonder whether the method returns `int` or `bool`, while there won't be such confusion using Google Mock's syntax.
1. The way Google Mock describes a function type is nothing new, although many people may not be familiar with it. The same syntax was used in C, and the `function` library in `tr1` uses this syntax extensively. Since `tr1` will become a part of the new version of STL, we feel very comfortable to be consistent with it.
1. The function type syntax is also used in other parts of Google Mock's API (e.g. the action interface) in order to make the implementation tractable. A user needs to learn it anyway in order to utilize Google Mock's more advanced features. We'd as well stick to the same syntax in `MOCK_METHOD*`!
## My code calls a static/global function. Can I mock it? ##
You can, but you need to make some changes.
In general, if you find yourself needing to mock a static function,
it's a sign that your modules are too tightly coupled (and less
flexible, less reusable, less testable, etc). You are probably better
off defining a small interface and call the function through that
interface, which then can be easily mocked. It's a bit of work
initially, but usually pays for itself quickly.
This Google Testing Blog
[post](http://googletesting.blogspot.com/2008/06/defeat-static-cling.html)
says it excellently. Check it out.
## My mock object needs to do complex stuff. It's a lot of pain to specify the actions. Google Mock sucks! ##
I know it's not a question, but you get an answer for free any way. :-)
With Google Mock, you can create mocks in C++ easily. And people might be
tempted to use them everywhere. Sometimes they work great, and
sometimes you may find them, well, a pain to use. So, what's wrong in
the latter case?
When you write a test without using mocks, you exercise the code and
assert that it returns the correct value or that the system is in an
expected state. This is sometimes called "state-based testing".
Mocks are great for what some call "interaction-based" testing:
instead of checking the system state at the very end, mock objects
verify that they are invoked the right way and report an error as soon
as it arises, giving you a handle on the precise context in which the
error was triggered. This is often more effective and economical to
do than state-based testing.
If you are doing state-based testing and using a test double just to
simulate the real object, you are probably better off using a fake.
Using a mock in this case causes pain, as it's not a strong point for
mocks to perform complex actions. If you experience this and think
that mocks suck, you are just not using the right tool for your
problem. Or, you might be trying to solve the wrong problem. :-)
## I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? ##
By all means, NO! It's just an FYI.
What it means is that you have a mock function, you haven't set any
expectations on it (by Google Mock's rule this means that you are not
interested in calls to this function and therefore it can be called
any number of times), and it is called. That's OK - you didn't say
it's not OK to call the function!
What if you actually meant to disallow this function to be called, but
forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`? While
one can argue that it's the user's fault, Google Mock tries to be nice and
prints you a note.
So, when you see the message and believe that there shouldn't be any
uninteresting calls, you should investigate what's going on. To make
your life easier, Google Mock prints the function name and arguments
when an uninteresting call is encountered.
## I want to define a custom action. Should I use Invoke() or implement the action interface? ##
Either way is fine - you want to choose the one that's more convenient
for your circumstance.
Usually, if your action is for a particular function type, defining it
using `Invoke()` should be easier; if your action can be used in
functions of different types (e.g. if you are defining
`Return(value)`), `MakePolymorphicAction()` is
easiest. Sometimes you want precise control on what types of
functions the action can be used in, and implementing
`ActionInterface` is the way to go here. See the implementation of
`Return()` in `include/gmock/gmock-actions.h` for an example.
## I'm using the set-argument-pointee action, and the compiler complains about "conflicting return type specified". What does it mean? ##
You got this error as Google Mock has no idea what value it should return
when the mock method is called. `SetArgPointee()` says what the
side effect is, but doesn't say what the return value should be. You
need `DoAll()` to chain a `SetArgPointee()` with a `Return()`.
See this [recipe](CookBook.md#mocking_side_effects) for more details and an example.
## My question is not in your FAQ! ##
If you cannot find the answer to your question in this FAQ, there are
some other resources you can use:
1. read other [documentation](Documentation.md),
1. search the mailing list [archive](http://groups.google.com/group/googlemock/topics),
1. ask it on [googlemock@googlegroups.com](mailto:googlemock@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googlemock) before you can post.).
Please note that creating an issue in the
[issue tracker](https://github.com/google/googletest/issues) is _not_
a good way to get your answer, as it is monitored infrequently by a
very small number of people.
When asking a question, it's helpful to provide as much of the
following information as possible (people cannot help you if there's
not enough information in your question):
* the version (or the revision number if you check out from SVN directly) of Google Mock you use (Google Mock is under active development, so it's possible that your problem has been solved in a later version),
* your operating system,
* the name and version of your compiler,
* the complete command line flags you give to your compiler,
* the complete compiler error messages (if the question is about compilation),
* the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter.

View File

@ -1,19 +0,0 @@
As any non-trivial software system, Google Mock has some known limitations and problems. We are working on improving it, and welcome your help! The follow is a list of issues we know about.
## README contains outdated information on Google Mock's compatibility with other testing frameworks ##
The `README` file in release 1.1.0 still says that Google Mock only works with Google Test. Actually, you can configure Google Mock to work with any testing framework you choose.
## Tests failing on machines using Power PC CPUs (e.g. some Macs) ##
`gmock_output_test` and `gmock-printers_test` are known to fail with Power PC CPUs. This is due to portability issues with these tests, and is not an indication of problems in Google Mock itself. You can safely ignore them.
## Failed to resolve libgtest.so.0 in tests when built against installed Google Test ##
This only applies if you manually built and installed Google Test, and then built a Google Mock against it (either explicitly, or because gtest-config was in your path post-install). In this situation, Libtool has a known issue with certain systems' ldconfig setup:
http://article.gmane.org/gmane.comp.sysutils.automake.general/9025
This requires a manual run of "sudo ldconfig" after the "sudo make install" for Google Test before any binaries which link against it can be executed. This isn't a bug in our install, but we should at least have documented it or hacked a work-around into our install. We should have one of these solutions in our next release.

View File

@ -0,0 +1,4 @@
# Content Moved
We are working on updates to the GoogleTest documentation, which has moved to
the top-level [docs](../../docs) directory.

View File

@ -1,525 +0,0 @@
# Defining a Mock Class #
## Mocking a Normal Class ##
Given
```
class Foo {
...
virtual ~Foo();
virtual int GetSize() const = 0;
virtual string Describe(const char* name) = 0;
virtual string Describe(int type) = 0;
virtual bool Process(Bar elem, int count) = 0;
};
```
(note that `~Foo()` **must** be virtual) we can define its mock as
```
#include <gmock/gmock.h>
class MockFoo : public Foo {
MOCK_CONST_METHOD0(GetSize, int());
MOCK_METHOD1(Describe, string(const char* name));
MOCK_METHOD1(Describe, string(int type));
MOCK_METHOD2(Process, bool(Bar elem, int count));
};
```
To create a "nice" mock object which ignores all uninteresting calls,
or a "strict" mock object, which treats them as failures:
```
NiceMock<MockFoo> nice_foo; // The type is a subclass of MockFoo.
StrictMock<MockFoo> strict_foo; // The type is a subclass of MockFoo.
```
## Mocking a Class Template ##
To mock
```
template <typename Elem>
class StackInterface {
public:
...
virtual ~StackInterface();
virtual int GetSize() const = 0;
virtual void Push(const Elem& x) = 0;
};
```
(note that `~StackInterface()` **must** be virtual) just append `_T` to the `MOCK_*` macros:
```
template <typename Elem>
class MockStack : public StackInterface<Elem> {
public:
...
MOCK_CONST_METHOD0_T(GetSize, int());
MOCK_METHOD1_T(Push, void(const Elem& x));
};
```
## Specifying Calling Conventions for Mock Functions ##
If your mock function doesn't use the default calling convention, you
can specify it by appending `_WITH_CALLTYPE` to any of the macros
described in the previous two sections and supplying the calling
convention as the first argument to the macro. For example,
```
MOCK_METHOD_1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int n));
MOCK_CONST_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, Bar, int(double x, double y));
```
where `STDMETHODCALLTYPE` is defined by `<objbase.h>` on Windows.
# Using Mocks in Tests #
The typical flow is:
1. Import the Google Mock names you need to use. All Google Mock names are in the `testing` namespace unless they are macros or otherwise noted.
1. Create the mock objects.
1. Optionally, set the default actions of the mock objects.
1. Set your expectations on the mock objects (How will they be called? What wil they do?).
1. Exercise code that uses the mock objects; if necessary, check the result using [Google Test](http://code.google.com/p/googletest/) assertions.
1. When a mock objects is destructed, Google Mock automatically verifies that all expectations on it have been satisfied.
Here is an example:
```
using ::testing::Return; // #1
TEST(BarTest, DoesThis) {
MockFoo foo; // #2
ON_CALL(foo, GetSize()) // #3
.WillByDefault(Return(1));
// ... other default actions ...
EXPECT_CALL(foo, Describe(5)) // #4
.Times(3)
.WillRepeatedly(Return("Category 5"));
// ... other expectations ...
EXPECT_EQ("good", MyProductionFunction(&foo)); // #5
} // #6
```
# Setting Default Actions #
Google Mock has a **built-in default action** for any function that
returns `void`, `bool`, a numeric value, or a pointer.
To customize the default action for functions with return type `T` globally:
```
using ::testing::DefaultValue;
DefaultValue<T>::Set(value); // Sets the default value to be returned.
// ... use the mocks ...
DefaultValue<T>::Clear(); // Resets the default value.
```
To customize the default action for a particular method, use `ON_CALL()`:
```
ON_CALL(mock_object, method(matchers))
.With(multi_argument_matcher) ?
.WillByDefault(action);
```
# Setting Expectations #
`EXPECT_CALL()` sets **expectations** on a mock method (How will it be
called? What will it do?):
```
EXPECT_CALL(mock_object, method(matchers))
.With(multi_argument_matcher) ?
.Times(cardinality) ?
.InSequence(sequences) *
.After(expectations) *
.WillOnce(action) *
.WillRepeatedly(action) ?
.RetiresOnSaturation(); ?
```
If `Times()` is omitted, the cardinality is assumed to be:
* `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`;
* `Times(n)` when there are `n WillOnce()`s but no `WillRepeatedly()`, where `n` >= 1; or
* `Times(AtLeast(n))` when there are `n WillOnce()`s and a `WillRepeatedly()`, where `n` >= 0.
A method with no `EXPECT_CALL()` is free to be invoked _any number of times_, and the default action will be taken each time.
# Matchers #
A **matcher** matches a _single_ argument. You can use it inside
`ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value
directly:
| `EXPECT_THAT(value, matcher)` | Asserts that `value` matches `matcher`. |
|:------------------------------|:----------------------------------------|
| `ASSERT_THAT(value, matcher)` | The same as `EXPECT_THAT(value, matcher)`, except that it generates a **fatal** failure. |
Built-in matchers (where `argument` is the function argument) are
divided into several categories:
## Wildcard ##
|`_`|`argument` can be any value of the correct type.|
|:--|:-----------------------------------------------|
|`A<type>()` or `An<type>()`|`argument` can be any value of type `type`. |
## Generic Comparison ##
|`Eq(value)` or `value`|`argument == value`|
|:---------------------|:------------------|
|`Ge(value)` |`argument >= value`|
|`Gt(value)` |`argument > value` |
|`Le(value)` |`argument <= value`|
|`Lt(value)` |`argument < value` |
|`Ne(value)` |`argument != value`|
|`IsNull()` |`argument` is a `NULL` pointer (raw or smart).|
|`NotNull()` |`argument` is a non-null pointer (raw or smart).|
|`Ref(variable)` |`argument` is a reference to `variable`.|
|`TypedEq<type>(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.|
Except `Ref()`, these matchers make a _copy_ of `value` in case it's
modified or destructed later. If the compiler complains that `value`
doesn't have a public copy constructor, try wrap it in `ByRef()`,
e.g. `Eq(ByRef(non_copyable_value))`. If you do that, make sure
`non_copyable_value` is not changed afterwards, or the meaning of your
matcher will be changed.
## Floating-Point Matchers ##
|`DoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal.|
|:-------------------|:----------------------------------------------------------------------------------------------|
|`FloatEq(a_float)` |`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. |
|`NanSensitiveDoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. |
|`NanSensitiveFloatEq(a_float)`|`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. |
The above matchers use ULP-based comparison (the same as used in
[Google Test](http://code.google.com/p/googletest/)). They
automatically pick a reasonable error bound based on the absolute
value of the expected value. `DoubleEq()` and `FloatEq()` conform to
the IEEE standard, which requires comparing two NaNs for equality to
return false. The `NanSensitive*` version instead treats two NaNs as
equal, which is often what a user wants.
## String Matchers ##
The `argument` can be either a C string or a C++ string object:
|`ContainsRegex(string)`|`argument` matches the given regular expression.|
|:----------------------|:-----------------------------------------------|
|`EndsWith(suffix)` |`argument` ends with string `suffix`. |
|`HasSubstr(string)` |`argument` contains `string` as a sub-string. |
|`MatchesRegex(string)` |`argument` matches the given regular expression with the match starting at the first character and ending at the last character.|
|`StartsWith(prefix)` |`argument` starts with string `prefix`. |
|`StrCaseEq(string)` |`argument` is equal to `string`, ignoring case. |
|`StrCaseNe(string)` |`argument` is not equal to `string`, ignoring case.|
|`StrEq(string)` |`argument` is equal to `string`. |
|`StrNe(string)` |`argument` is not equal to `string`. |
`StrCaseEq()`, `StrCaseNe()`, `StrEq()`, and `StrNe()` work for wide
strings as well.
## Container Matchers ##
Most STL-style containers support `==`, so you can use
`Eq(expected_container)` or simply `expected_container` to match a
container exactly. If you want to write the elements in-line,
match them more flexibly, or get more informative messages, you can use:
| `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. |
|:--------------|:-------------------------------------------------------------------------------------------|
|`ElementsAre(e0, e1, ..., en)`|`argument` has `n + 1` elements, where the i-th element matches `ei`, which can be a value or a matcher. 0 to 10 arguments are allowed.|
|`ElementsAreArray(array)` or `ElementsAreArray(array, count)`|The same as `ElementsAre()` except that the expected element values/matchers come from a C-style array.|
| `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. |
These matchers can also match:
1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and
1. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#Multiargument_Matchers.md)).
where the array may be multi-dimensional (i.e. its elements can be arrays).
## Member Matchers ##
|`Field(&class::field, m)`|`argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.|
|:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------|
|`Key(e)` |`argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`.|
|`Pair(m1, m2)` |`argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. |
|`Property(&class::property, m)`|`argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.|
## Matching the Result of a Function or Functor ##
|`ResultOf(f, m)`|`f(argument)` matches matcher `m`, where `f` is a function or functor.|
|:---------------|:---------------------------------------------------------------------|
## Pointer Matchers ##
|`Pointee(m)`|`argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`.|
|:-----------|:-----------------------------------------------------------------------------------------------|
## Multiargument Matchers ##
These are matchers on tuple types. They can be used in
`.With()`. The following can be used on functions with <i>two<br>
arguments</i> `x` and `y`:
|`Eq()`|`x == y`|
|:-----|:-------|
|`Ge()`|`x >= y`|
|`Gt()`|`x > y` |
|`Le()`|`x <= y`|
|`Lt()`|`x < y` |
|`Ne()`|`x != y`|
You can use the following selectors to pick a subset of the arguments
(or reorder them) to participate in the matching:
|`AllArgs(m)`|Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`.|
|:-----------|:-------------------------------------------------------------------|
|`Args<N1, N2, ..., Nk>(m)`|The `k` selected (using 0-based indices) arguments match `m`, e.g. `Args<1, 2>(Contains(5))`.|
## Composite Matchers ##
You can make a matcher from one or more other matchers:
|`AllOf(m1, m2, ..., mn)`|`argument` matches all of the matchers `m1` to `mn`.|
|:-----------------------|:---------------------------------------------------|
|`AnyOf(m1, m2, ..., mn)`|`argument` matches at least one of the matchers `m1` to `mn`.|
|`Not(m)` |`argument` doesn't match matcher `m`. |
## Adapters for Matchers ##
|`MatcherCast<T>(m)`|casts matcher `m` to type `Matcher<T>`.|
|:------------------|:--------------------------------------|
|`SafeMatcherCast<T>(m)`| [safely casts](V1_5_CookBook#Casting_Matchers.md) matcher `m` to type `Matcher<T>`. |
|`Truly(predicate)` |`predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor.|
## Matchers as Predicates ##
|`Matches(m)`|a unary functor that returns `true` if the argument matches `m`.|
|:-----------|:---------------------------------------------------------------|
|`ExplainMatchResult(m, value, result_listener)`|returns `true` if `value` matches `m`, explaining the result to `result_listener`.|
|`Value(x, m)`|returns `true` if the value of `x` matches `m`. |
## Defining Matchers ##
| `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. |
|:-------------------------------------------------|:------------------------------------------------------|
| `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a macher `IsDivisibleBy(n)` to match a number divisible by `n`. |
| `MATCHER_P2(IsBetween, a, b, "is between %(a)s and %(b)s") { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. |
**Notes:**
1. The `MATCHER*` macros cannot be used inside a function or class.
1. The matcher body must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters).
1. You can use `PrintToString(x)` to convert a value `x` of any type to a string.
## Matchers as Test Assertions ##
|`ASSERT_THAT(expression, m)`|Generates a [fatal failure](http://code.google.com/p/googletest/wiki/GoogleTestPrimer#Assertions) if the value of `expression` doesn't match matcher `m`.|
|:---------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------|
|`EXPECT_THAT(expression, m)`|Generates a non-fatal failure if the value of `expression` doesn't match matcher `m`. |
# Actions #
**Actions** specify what a mock function should do when invoked.
## Returning a Value ##
|`Return()`|Return from a `void` mock function.|
|:---------|:----------------------------------|
|`Return(value)`|Return `value`. |
|`ReturnArg<N>()`|Return the `N`-th (0-based) argument.|
|`ReturnNew<T>(a1, ..., ak)`|Return `new T(a1, ..., ak)`; a different object is created each time.|
|`ReturnNull()`|Return a null pointer. |
|`ReturnRef(variable)`|Return a reference to `variable`. |
## Side Effects ##
|`Assign(&variable, value)`|Assign `value` to variable.|
|:-------------------------|:--------------------------|
| `DeleteArg<N>()` | Delete the `N`-th (0-based) argument, which must be a pointer. |
| `SaveArg<N>(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. |
| `SetArgReferee<N>(value)` | Assign value to the variable referenced by the `N`-th (0-based) argument. |
|`SetArgumentPointee<N>(value)`|Assign `value` to the variable pointed by the `N`-th (0-based) argument.|
|`SetArrayArgument<N>(first, last)`|Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.|
|`SetErrnoAndReturn(error, value)`|Set `errno` to `error` and return `value`.|
|`Throw(exception)` |Throws the given exception, which can be any copyable value. Available since v1.1.0.|
## Using a Function or a Functor as an Action ##
|`Invoke(f)`|Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor.|
|:----------|:-----------------------------------------------------------------------------------------------------------------|
|`Invoke(object_pointer, &class::method)`|Invoke the {method on the object with the arguments passed to the mock function. |
|`InvokeWithoutArgs(f)`|Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. |
|`InvokeWithoutArgs(object_pointer, &class::method)`|Invoke the method on the object, which takes no arguments. |
|`InvokeArgument<N>(arg1, arg2, ..., argk)`|Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments.|
The return value of the invoked function is used as the return value
of the action.
When defining a function or functor to be used with `Invoke*()`, you can declare any unused parameters as `Unused`:
```
double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); }
...
EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance));
```
In `InvokeArgument<N>(...)`, if an argument needs to be passed by reference, wrap it inside `ByRef()`. For example,
```
InvokeArgument<2>(5, string("Hi"), ByRef(foo))
```
calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference.
## Default Action ##
|`DoDefault()`|Do the default action (specified by `ON_CALL()` or the built-in one).|
|:------------|:--------------------------------------------------------------------|
**Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error.
## Composite Actions ##
|`DoAll(a1, a2, ..., an)`|Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. |
|:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------|
|`IgnoreResult(a)` |Perform action `a` and ignore its result. `a` must not return void. |
|`WithArg<N>(a)` |Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. |
|`WithArgs<N1, N2, ..., Nk>(a)`|Pass the selected (0-based) arguments of the mock function to action `a` and perform it. |
|`WithoutArgs(a)` |Perform action `a` without any arguments. |
## Defining Actions ##
| `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. |
|:--------------------------------------|:---------------------------------------------------------------------------------------|
| `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. |
| `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. |
The `ACTION*` macros cannot be used inside a function or class.
# Cardinalities #
These are used in `Times()` to specify how many times a mock function will be called:
|`AnyNumber()`|The function can be called any number of times.|
|:------------|:----------------------------------------------|
|`AtLeast(n)` |The call is expected at least `n` times. |
|`AtMost(n)` |The call is expected at most `n` times. |
|`Between(m, n)`|The call is expected between `m` and `n` (inclusive) times.|
|`Exactly(n) or n`|The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0.|
# Expectation Order #
By default, the expectations can be matched in _any_ order. If some
or all expectations must be matched in a given order, there are two
ways to specify it. They can be used either independently or
together.
## The After Clause ##
```
using ::testing::Expectation;
...
Expectation init_x = EXPECT_CALL(foo, InitX());
Expectation init_y = EXPECT_CALL(foo, InitY());
EXPECT_CALL(foo, Bar())
.After(init_x, init_y);
```
says that `Bar()` can be called only after both `InitX()` and
`InitY()` have been called.
If you don't know how many pre-requisites an expectation has when you
write it, you can use an `ExpectationSet` to collect them:
```
using ::testing::ExpectationSet;
...
ExpectationSet all_inits;
for (int i = 0; i < element_count; i++) {
all_inits += EXPECT_CALL(foo, InitElement(i));
}
EXPECT_CALL(foo, Bar())
.After(all_inits);
```
says that `Bar()` can be called only after all elements have been
initialized (but we don't care about which elements get initialized
before the others).
Modifying an `ExpectationSet` after using it in an `.After()` doesn't
affect the meaning of the `.After()`.
## Sequences ##
When you have a long chain of sequential expectations, it's easier to
specify the order using **sequences**, which don't require you to given
each expectation in the chain a different name. <i>All expected<br>
calls</i> in the same sequence must occur in the order they are
specified.
```
using ::testing::Sequence;
Sequence s1, s2;
...
EXPECT_CALL(foo, Reset())
.InSequence(s1, s2)
.WillOnce(Return(true));
EXPECT_CALL(foo, GetSize())
.InSequence(s1)
.WillOnce(Return(1));
EXPECT_CALL(foo, Describe(A<const char*>()))
.InSequence(s2)
.WillOnce(Return("dummy"));
```
says that `Reset()` must be called before _both_ `GetSize()` _and_
`Describe()`, and the latter two can occur in any order.
To put many expectations in a sequence conveniently:
```
using ::testing::InSequence;
{
InSequence dummy;
EXPECT_CALL(...)...;
EXPECT_CALL(...)...;
...
EXPECT_CALL(...)...;
}
```
says that all expected calls in the scope of `dummy` must occur in
strict order. The name `dummy` is irrelevant.)
# Verifying and Resetting a Mock #
Google Mock will verify the expectations on a mock object when it is destructed, or you can do it earlier:
```
using ::testing::Mock;
...
// Verifies and removes the expectations on mock_obj;
// returns true iff successful.
Mock::VerifyAndClearExpectations(&mock_obj);
...
// Verifies and removes the expectations on mock_obj;
// also removes the default actions set by ON_CALL();
// returns true iff successful.
Mock::VerifyAndClear(&mock_obj);
```
You can also tell Google Mock that a mock object can be leaked and doesn't
need to be verified:
```
Mock::AllowLeak(&mock_obj);
```
# Mock Classes #
Google Mock defines a convenient mock class template
```
class MockFunction<R(A1, ..., An)> {
public:
MOCK_METHODn(Call, R(A1, ..., An));
};
```
See this [recipe](V1_5_CookBook#Using_Check_Points.md) for one application of it.
# Flags #
| `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. |
|:-------------------------------|:----------------------------------------------|
| `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. |

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +0,0 @@
This page lists all documentation wiki pages for Google Mock **version 1.5.0** -- **if you use a different version of Google Mock, please read the documentation for that specific version instead.**
* [ForDummies](V1_5_ForDummies.md) -- start here if you are new to Google Mock.
* [CheatSheet](V1_5_CheatSheet.md) -- a quick reference.
* [CookBook](V1_5_CookBook.md) -- recipes for doing various tasks using Google Mock.
* [FrequentlyAskedQuestions](V1_5_FrequentlyAskedQuestions.md) -- check here before asking a question on the mailing list.
To contribute code to Google Mock, read:
* DevGuide -- read this _before_ writing your first patch.
* [Pump Manual](http://code.google.com/p/googletest/wiki/PumpManual) -- how we generate some of Google Mock's source files.

View File

@ -1,439 +0,0 @@
(**Note:** If you get compiler errors that you don't understand, be sure to consult [Google Mock Doctor](V1_5_FrequentlyAskedQuestions#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md).)
# What Is Google C++ Mocking Framework? #
When you write a prototype or test, often it's not feasible or wise to rely on real objects entirely. A **mock object** implements the same interface as a real object (so it can be used as one), but lets you specify at run time how it will be used and what it should do (which methods will be called? in which order? how many times? with what arguments? what will they return? etc).
**Note:** It is easy to confuse the term _fake objects_ with mock objects. Fakes and mocks actually mean very different things in the Test-Driven Development (TDD) community:
* **Fake** objects have working implementations, but usually take some shortcut (perhaps to make the operations less expensive), which makes them not suitable for production. An in-memory file system would be an example of a fake.
* **Mocks** are objects pre-programmed with _expectations_, which form a specification of the calls they are expected to receive.
If all this seems too abstract for you, don't worry - the most important thing to remember is that a mock allows you to check the _interaction_ between itself and code that uses it. The difference between fakes and mocks will become much clearer once you start to use mocks.
**Google C++ Mocking Framework** (or **Google Mock** for short) is a library (sometimes we also call it a "framework" to make it sound cool) for creating mock classes and using them. It does to C++ what [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/) do to Java.
Using Google Mock involves three basic steps:
1. Use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class;
1. Create some mock objects and specify its expectations and behavior using an intuitive syntax;
1. Exercise code that uses the mock objects. Google Mock will catch any violation of the expectations as soon as it arises.
# Why Google Mock? #
While mock objects help you remove unnecessary dependencies in tests and make them fast and reliable, using mocks manually in C++ is _hard_:
* Someone has to implement the mocks. The job is usually tedious and error-prone. No wonder people go great distance to avoid it.
* The quality of those manually written mocks is a bit, uh, unpredictable. You may see some really polished ones, but you may also see some that were hacked up in a hurry and have all sorts of ad hoc restrictions.
* The knowledge you gained from using one mock doesn't transfer to the next.
In contrast, Java and Python programmers have some fine mock frameworks, which automate the creation of mocks. As a result, mocking is a proven effective technique and widely adopted practice in those communities. Having the right tool absolutely makes the difference.
Google Mock was built to help C++ programmers. It was inspired by [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/), but designed with C++'s specifics in mind. It is your friend if any of the following problems is bothering you:
* You are stuck with a sub-optimal design and wish you had done more prototyping before it was too late, but prototyping in C++ is by no means "rapid".
* Your tests are slow as they depend on too many libraries or use expensive resources (e.g. a database).
* Your tests are brittle as some resources they use are unreliable (e.g. the network).
* You want to test how your code handles a failure (e.g. a file checksum error), but it's not easy to cause one.
* You need to make sure that your module interacts with other modules in the right way, but it's hard to observe the interaction; therefore you resort to observing the side effects at the end of the action, which is awkward at best.
* You want to "mock out" your dependencies, except that they don't have mock implementations yet; and, frankly, you aren't thrilled by some of those hand-written mocks.
We encourage you to use Google Mock as:
* a _design_ tool, for it lets you experiment with your interface design early and often. More iterations lead to better designs!
* a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators.
# Getting Started #
Using Google Mock is easy! Inside your C++ source file, just `#include` `<gtest/gtest.h>` and `<gmock/gmock.h>`, and you are ready to go.
# A Case for Mock Turtles #
Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface:
```
class Turtle {
...
virtual ~Turtle() {}
virtual void PenUp() = 0;
virtual void PenDown() = 0;
virtual void Forward(int distance) = 0;
virtual void Turn(int degrees) = 0;
virtual void GoTo(int x, int y) = 0;
virtual int GetX() const = 0;
virtual int GetY() const = 0;
};
```
(Note that the destructor of `Turtle` **must** be virtual, as is the case for **all** classes you intend to inherit from - otherwise the destructor of the derived class will not be called when you delete an object through a base pointer, and you'll get corrupted program states like memory leaks.)
You can control whether the turtle's movement will leave a trace using `PenUp()` and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and `GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the turtle.
Your program will normally use a real implementation of this interface. In tests, you can use a mock implementation instead. This allows you to easily check what drawing primitives your program is calling, with what arguments, and in which order. Tests written this way are much more robust (they won't break because your new machine does anti-aliasing differently), easier to read and maintain (the intent of a test is expressed in the code, not in some binary images), and run _much, much faster_.
# Writing the Mock Class #
If you are lucky, the mocks you need to use have already been implemented by some nice people. If, however, you find yourself in the position to write a mock class, relax - Google Mock turns this task into a fun game! (Well, almost.)
## How to Define It ##
Using the `Turtle` interface as example, here are the simple steps you need to follow:
1. Derive a class `MockTurtle` from `Turtle`.
1. Take a virtual function of `Turtle`. Count how many arguments it has.
1. In the `public:` section of the child class, write `MOCK_METHODn();` (or `MOCK_CONST_METHODn();` if you are mocking a `const` method), where `n` is the number of the arguments; if you counted wrong, shame on you, and a compiler error will tell you so.
1. Now comes the fun part: you take the function signature, cut-and-paste the _function name_ as the _first_ argument to the macro, and leave what's left as the _second_ argument (in case you're curious, this is the _type of the function_).
1. Repeat until all virtual functions you want to mock are done.
After the process, you should have something like:
```
#include <gmock/gmock.h> // Brings in Google Mock.
class MockTurtle : public Turtle {
public:
...
MOCK_METHOD0(PenUp, void());
MOCK_METHOD0(PenDown, void());
MOCK_METHOD1(Forward, void(int distance));
MOCK_METHOD1(Turn, void(int degrees));
MOCK_METHOD2(GoTo, void(int x, int y));
MOCK_CONST_METHOD0(GetX, int());
MOCK_CONST_METHOD0(GetY, int());
};
```
You don't need to define these mock methods somewhere else - the `MOCK_METHOD*` macros will generate the definitions for you. It's that simple! Once you get the hang of it, you can pump out mock classes faster than your source-control system can handle your check-ins.
**Tip:** If even this is too much work for you, you'll find the
`gmock_gen.py` tool in Google Mock's `scripts/generator/` directory (courtesy of the [cppclean](http://code.google.com/p/cppclean/) project) useful. This command-line
tool requires that you have Python 2.4 installed. You give it a C++ file and the name of an abstract class defined in it,
and it will print the definition of the mock class for you. Due to the
complexity of the C++ language, this script may not always work, but
it can be quite handy when it does. For more details, read the [user documentation](http://code.google.com/p/googlemock/source/browse/trunk/scripts/generator/README).
## Where to Put It ##
When you define a mock class, you need to decide where to put its definition. Some people put it in a `*_test.cc`. This is fine when the interface being mocked (say, `Foo`) is owned by the same person or team. Otherwise, when the owner of `Foo` changes it, your test could break. (You can't really expect `Foo`'s maintainer to fix every test that uses `Foo`, can you?)
So, the rule of thumb is: if you need to mock `Foo` and it's owned by others, define the mock class in `Foo`'s package (better, in a `testing` sub-package such that you can clearly separate production code and testing utilities), and put it in a `mock_foo.h`. Then everyone can reference `mock_foo.h` from their tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and only tests that depend on the changed methods need to be fixed.
Another way to do it: you can introduce a thin layer `FooAdaptor` on top of `Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb changes in `Foo` much more easily. While this is more work initially, carefully choosing the adaptor interface can make your code easier to write and more readable (a net win in the long run), as you can choose `FooAdaptor` to fit your specific domain much better than `Foo` does.
# Using Mocks in Tests #
Once you have a mock class, using it is easy. The typical work flow is:
1. Import the Google Mock names from the `testing` namespace such that you can use them unqualified (You only have to do it once per file. Remember that namespaces are a good idea and good for your health.).
1. Create some mock objects.
1. Specify your expectations on them (How many times will a method be called? With what arguments? What should it do? etc.).
1. Exercise some code that uses the mocks; optionally, check the result using Google Test assertions. If a mock method is called more than expected or with wrong arguments, you'll get an error immediately.
1. When a mock is destructed, Google Mock will automatically check whether all expectations on it have been satisfied.
Here's an example:
```
#include "path/to/mock-turtle.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using ::testing::AtLeast; // #1
TEST(PainterTest, CanDrawSomething) {
MockTurtle turtle; // #2
EXPECT_CALL(turtle, PenDown()) // #3
.Times(AtLeast(1));
Painter painter(&turtle); // #4
EXPECT_TRUE(painter.DrawCircle(0, 0, 10));
} // #5
int main(int argc, char** argv) {
// The following line must be executed to initialize Google Mock
// (and Google Test) before running the tests.
::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
```
As you might have guessed, this test checks that `PenDown()` is called at least once. If the `painter` object didn't call this method, your test will fail with a message like this:
```
path/to/my_test.cc:119: Failure
Actual function call count doesn't match this expectation:
Actually: never called;
Expected: called at least once.
```
**Tip 1:** If you run the test from an Emacs buffer, you can hit `<Enter>` on the line number displayed in the error message to jump right to the failed expectation.
**Tip 2:** If your mock objects are never deleted, the final verification won't happen. Therefore it's a good idea to use a heap leak checker in your tests when you allocate mocks on the heap.
**Important note:** Google Mock requires expectations to be set **before** the mock functions are called, otherwise the behavior is **undefined**. In particular, you mustn't interleave `EXPECT_CALL()`s and calls to the mock functions.
This means `EXPECT_CALL()` should be read as expecting that a call will occur _in the future_, not that a call has occurred. Why does Google Mock work like that? Well, specifying the expectation beforehand allows Google Mock to report a violation as soon as it arises, when the context (stack trace, etc) is still available. This makes debugging much easier.
Admittedly, this test is contrived and doesn't do much. You can easily achieve the same effect without using Google Mock. However, as we shall reveal soon, Google Mock allows you to do _much more_ with the mocks.
## Using Google Mock with Any Testing Framework ##
If you want to use something other than Google Test (e.g. [CppUnit](http://apps.sourceforge.net/mediawiki/cppunit/index.php?title=Main_Page) or
[CxxTest](http://cxxtest.tigris.org/)) as your testing framework, just change the `main()` function in the previous section to:
```
int main(int argc, char** argv) {
// The following line causes Google Mock to throw an exception on failure,
// which will be interpreted by your testing framework as a test failure.
::testing::GTEST_FLAG(throw_on_failure) = true;
::testing::InitGoogleMock(&argc, argv);
... whatever your testing framework requires ...
}
```
This approach has a catch: it makes Google Mock throw an exception
from a mock object's destructor sometimes. With some compilers, this
sometimes causes the test program to crash. You'll still be able to
notice that the test has failed, but it's not a graceful failure.
A better solution is to use Google Test's
[event listener API](http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide#Extending_Google_Test_by_Handling_Test_Events)
to report a test failure to your testing framework properly. You'll need to
implement the `OnTestPartResult()` method of the event listener interface, but it
should be straightforward.
If this turns out to be too much work, we suggest that you stick with
Google Test, which works with Google Mock seamlessly (in fact, it is
technically part of Google Mock.). If there is a reason that you
cannot use Google Test, please let us know.
# Setting Expectations #
The key to using a mock object successfully is to set the _right expectations_ on it. If you set the expectations too strict, your test will fail as the result of unrelated changes. If you set them too loose, bugs can slip through. You want to do it just right such that your test can catch exactly the kind of bugs you intend it to catch. Google Mock provides the necessary means for you to do it "just right."
## General Syntax ##
In Google Mock we use the `EXPECT_CALL()` macro to set an expectation on a mock method. The general syntax is:
```
EXPECT_CALL(mock_object, method(matchers))
.Times(cardinality)
.WillOnce(action)
.WillRepeatedly(action);
```
The macro has two arguments: first the mock object, and then the method and its arguments. Note that the two are separated by a comma (`,`), not a period (`.`). (Why using a comma? The answer is that it was necessary for technical reasons.)
The macro can be followed by some optional _clauses_ that provide more information about the expectation. We'll discuss how each clause works in the coming sections.
This syntax is designed to make an expectation read like English. For example, you can probably guess that
```
using ::testing::Return;...
EXPECT_CALL(turtle, GetX())
.Times(5)
.WillOnce(Return(100))
.WillOnce(Return(150))
.WillRepeatedly(Return(200));
```
says that the `turtle` object's `GetX()` method will be called five times, it will return 100 the first time, 150 the second time, and then 200 every time. Some people like to call this style of syntax a Domain-Specific Language (DSL).
**Note:** Why do we use a macro to do this? It serves two purposes: first it makes expectations easily identifiable (either by `grep` or by a human reader), and second it allows Google Mock to include the source file location of a failed expectation in messages, making debugging easier.
## Matchers: What Arguments Do We Expect? ##
When a mock function takes arguments, we must specify what arguments we are expecting; for example:
```
// Expects the turtle to move forward by 100 units.
EXPECT_CALL(turtle, Forward(100));
```
Sometimes you may not want to be too specific (Remember that talk about tests being too rigid? Over specification leads to brittle tests and obscures the intent of tests. Therefore we encourage you to specify only what's necessary - no more, no less.). If you care to check that `Forward()` will be called but aren't interested in its actual argument, write `_` as the argument, which means "anything goes":
```
using ::testing::_;
...
// Expects the turtle to move forward.
EXPECT_CALL(turtle, Forward(_));
```
`_` is an instance of what we call **matchers**. A matcher is like a predicate and can test whether an argument is what we'd expect. You can use a matcher inside `EXPECT_CALL()` wherever a function argument is expected.
A list of built-in matchers can be found in the [CheatSheet](V1_5_CheatSheet.md). For example, here's the `Ge` (greater than or equal) matcher:
```
using ::testing::Ge;...
EXPECT_CALL(turtle, Forward(Ge(100)));
```
This checks that the turtle will be told to go forward by at least 100 units.
## Cardinalities: How Many Times Will It Be Called? ##
The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We call its argument a **cardinality** as it tells _how many times_ the call should occur. It allows us to repeat an expectation many times without actually writing it as many times. More importantly, a cardinality can be "fuzzy", just like a matcher can be. This allows a user to express the intent of a test exactly.
An interesting special case is when we say `Times(0)`. You may have guessed - it means that the function shouldn't be called with the given arguments at all, and Google Mock will report a Google Test failure whenever the function is (wrongfully) called.
We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the list of built-in cardinalities you can use, see the [CheatSheet](V1_5_CheatSheet.md).
The `Times()` clause can be omitted. **If you omit `Times()`, Google Mock will infer the cardinality for you.** The rules are easy to remember:
* If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the `EXPECT_CALL()`, the inferred cardinality is `Times(1)`.
* If there are `n WillOnce()`'s but **no** `WillRepeatedly()`, where `n` >= 1, the cardinality is `Times(n)`.
* If there are `n WillOnce()`'s and **one** `WillRepeatedly()`, where `n` >= 0, the cardinality is `Times(AtLeast(n))`.
**Quick quiz:** what do you think will happen if a function is expected to be called twice but actually called four times?
## Actions: What Should It Do? ##
Remember that a mock object doesn't really have a working implementation? We as users have to tell it what to do when a method is invoked. This is easy in Google Mock.
First, if the return type of a mock function is a built-in type or a pointer, the function has a **default action** (a `void` function will just return, a `bool` function will return `false`, and other functions will return 0). If you don't say anything, this behavior will be used.
Second, if a mock function doesn't have a default action, or the default action doesn't suit you, you can specify the action to be taken each time the expectation matches using a series of `WillOnce()` clauses followed by an optional `WillRepeatedly()`. For example,
```
using ::testing::Return;...
EXPECT_CALL(turtle, GetX())
.WillOnce(Return(100))
.WillOnce(Return(200))
.WillOnce(Return(300));
```
This says that `turtle.GetX()` will be called _exactly three times_ (Google Mock inferred this from how many `WillOnce()` clauses we've written, since we didn't explicitly write `Times()`), and will return 100, 200, and 300 respectively.
```
using ::testing::Return;...
EXPECT_CALL(turtle, GetY())
.WillOnce(Return(100))
.WillOnce(Return(200))
.WillRepeatedly(Return(300));
```
says that `turtle.GetY()` will be called _at least twice_ (Google Mock knows this as we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no explicit `Times()`), will return 100 the first time, 200 the second time, and 300 from the third time on.
Of course, if you explicitly write a `Times()`, Google Mock will not try to infer the cardinality itself. What if the number you specified is larger than there are `WillOnce()` clauses? Well, after all `WillOnce()`s are used up, Google Mock will do the _default_ action for the function every time (unless, of course, you have a `WillRepeatedly()`.).
What can we do inside `WillOnce()` besides `Return()`? You can return a reference using `ReturnRef(variable)`, or invoke a pre-defined function, among [others](V1_5_CheatSheet#Actions.md).
**Important note:** The `EXPECT_CALL()` statement evaluates the action clause only once, even though the action may be performed many times. Therefore you must be careful about side effects. The following may not do what you want:
```
int n = 100;
EXPECT_CALL(turtle, GetX())
.Times(4)
.WillOnce(Return(n++));
```
Instead of returning 100, 101, 102, ..., consecutively, this mock function will always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will return the same pointer every time. If you want the side effect to happen every time, you need to define a custom action, which we'll teach in the [CookBook](V1_5_CookBook.md).
Time for another quiz! What do you think the following means?
```
using ::testing::Return;...
EXPECT_CALL(turtle, GetY())
.Times(4)
.WillOnce(Return(100));
```
Obviously `turtle.GetY()` is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that one `WillOnce()` clause will be consumed each time the function is invoked and the default action will be taken afterwards. So the right answer is that `turtle.GetY()` will return 100 the first time, but **return 0 from the second time on**, as returning 0 is the default action for `int` functions.
## Using Multiple Expectations ##
So far we've only shown examples where you have a single expectation. More realistically, you're going to specify expectations on multiple mock methods, which may be from multiple mock objects.
By default, when a mock method is invoked, Google Mock will search the expectations in the **reverse order** they are defined, and stop when an active expectation that matches the arguments is found (you can think of it as "newer rules override older ones."). If the matching expectation cannot take any more calls, you will get an upper-bound-violated failure. Here's an example:
```
using ::testing::_;...
EXPECT_CALL(turtle, Forward(_)); // #1
EXPECT_CALL(turtle, Forward(10)) // #2
.Times(2);
```
If `Forward(10)` is called three times in a row, the third time it will be an error, as the last matching expectation (#2) has been saturated. If, however, the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, as now #1 will be the matching expectation.
**Side note:** Why does Google Mock search for a match in the _reverse_ order of the expectations? The reason is that this allows a user to set up the default expectations in a mock object's constructor or the test fixture's set-up phase and then customize the mock by writing more specific expectations in the test body. So, if you have two expectations on the same method, you want to put the one with more specific matchers **after** the other, or the more specific rule would be shadowed by the more general one that comes after it.
## Ordered vs Unordered Calls ##
By default, an expectation can match a call even though an earlier expectation hasn't been satisfied. In other words, the calls don't have to occur in the order the expectations are specified.
Sometimes, you may want all the expected calls to occur in a strict order. To say this in Google Mock is easy:
```
using ::testing::InSequence;...
TEST(FooTest, DrawsLineSegment) {
...
{
InSequence dummy;
EXPECT_CALL(turtle, PenDown());
EXPECT_CALL(turtle, Forward(100));
EXPECT_CALL(turtle, PenUp());
}
Foo();
}
```
By creating an object of type `InSequence`, all expectations in its scope are put into a _sequence_ and have to occur _sequentially_. Since we are just relying on the constructor and destructor of this object to do the actual work, its name is really irrelevant.
In this example, we test that `Foo()` calls the three expected functions in the order as written. If a call is made out-of-order, it will be an error.
(What if you care about the relative order of some of the calls, but not all of them? Can you specify an arbitrary partial order? The answer is ... yes! If you are impatient, the details can be found in the [CookBook](V1_5_CookBook.md).)
## All Expectations Are Sticky (Unless Said Otherwise) ##
Now let's do a quick quiz to see how well you can use this mock stuff already. How would you test that the turtle is asked to go to the origin _exactly twice_ (you want to ignore any other instructions it receives)?
After you've come up with your answer, take a look at ours and compare notes (solve it yourself first - don't cheat!):
```
using ::testing::_;...
EXPECT_CALL(turtle, GoTo(_, _)) // #1
.Times(AnyNumber());
EXPECT_CALL(turtle, GoTo(0, 0)) // #2
.Times(2);
```
Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, Google Mock will see that the arguments match expectation #2 (remember that we always pick the last matching expectation). Now, since we said that there should be only two such calls, Google Mock will report an error immediately. This is basically what we've told you in the "Using Multiple Expectations" section above.
This example shows that **expectations in Google Mock are "sticky" by default**, in the sense that they remain active even after we have reached their invocation upper bounds. This is an important rule to remember, as it affects the meaning of the spec, and is **different** to how it's done in many other mocking frameworks (Why'd we do that? Because we think our rule makes the common cases easier to express and understand.).
Simple? Let's see if you've really understood it: what does the following code say?
```
using ::testing::Return;
...
for (int i = n; i > 0; i--) {
EXPECT_CALL(turtle, GetX())
.WillOnce(Return(10*i));
}
```
If you think it says that `turtle.GetX()` will be called `n` times and will return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we said, expectations are sticky. So, the second time `turtle.GetX()` is called, the last (latest) `EXPECT_CALL()` statement will match, and will immediately lead to an "upper bound exceeded" error - this piece of code is not very useful!
One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is to explicitly say that the expectations are _not_ sticky. In other words, they should _retire_ as soon as they are saturated:
```
using ::testing::Return;
...
for (int i = n; i > 0; i--) {
EXPECT_CALL(turtle, GetX())
.WillOnce(Return(10*i))
.RetiresOnSaturation();
}
```
And, there's a better way to do it: in this case, we expect the calls to occur in a specific order, and we line up the actions to match the order. Since the order is important here, we should make it explicit using a sequence:
```
using ::testing::InSequence;
using ::testing::Return;
...
{
InSequence s;
for (int i = 1; i <= n; i++) {
EXPECT_CALL(turtle, GetX())
.WillOnce(Return(10*i))
.RetiresOnSaturation();
}
}
```
By the way, the other situation where an expectation may _not_ be sticky is when it's in a sequence - as soon as another expectation that comes after it in the sequence has been used, it automatically retires (and will never be used to match any call).
## Uninteresting Calls ##
A mock object may have many methods, and not all of them are that interesting. For example, in some tests we may not care about how many times `GetX()` and `GetY()` get called.
In Google Mock, if you are not interested in a method, just don't say anything about it. If a call to this method occurs, you'll see a warning in the test output, but it won't be a failure.
# What Now? #
Congratulations! You've learned enough about Google Mock to start using it. Now, you might want to join the [googlemock](http://groups.google.com/group/googlemock) discussion group and actually write some tests using Google Mock - it will be fun. Hey, it may even be addictive - you've been warned.
Then, if you feel like increasing your mock quotient, you should move on to the [CookBook](V1_5_CookBook.md). You can learn many advanced features of Google Mock there -- and advance your level of enjoyment and testing bliss.

View File

@ -1,624 +0,0 @@
Please send your questions to the
[googlemock](http://groups.google.com/group/googlemock) discussion
group. If you need help with compiler errors, make sure you have
tried [Google Mock Doctor](#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md) first.
## I wrote some matchers. After I upgraded to a new version of Google Mock, they no longer compile. What's going on? ##
After version 1.4.0 of Google Mock was released, we had an idea on how
to make it easier to write matchers that can generate informative
messages efficiently. We experimented with this idea and liked what
we saw. Therefore we decided to implement it.
Unfortunately, this means that if you have defined your own matchers
by implementing `MatcherInterface` or using `MakePolymorphicMatcher()`,
your definitions will no longer compile. Matchers defined using the
`MATCHER*` family of macros are not affected.
Sorry for the hassle if your matchers are affected. We believe it's
in everyone's long-term interest to make this change sooner than
later. Fortunately, it's usually not hard to migrate an existing
matcher to the new API. Here's what you need to do:
If you wrote your matcher like this:
```
// Old matcher definition that doesn't work with the latest
// Google Mock.
using ::testing::MatcherInterface;
...
class MyWonderfulMatcher : public MatcherInterface<MyType> {
public:
...
virtual bool Matches(MyType value) const {
// Returns true if value matches.
return value.GetFoo() > 5;
}
...
};
```
you'll need to change it to:
```
// New matcher definition that works with the latest Google Mock.
using ::testing::MatcherInterface;
using ::testing::MatchResultListener;
...
class MyWonderfulMatcher : public MatcherInterface<MyType> {
public:
...
virtual bool MatchAndExplain(MyType value,
MatchResultListener* listener) const {
// Returns true if value matches.
return value.GetFoo() > 5;
}
...
};
```
(i.e. rename `Matches()` to `MatchAndExplain()` and give it a second
argument of type `MatchResultListener*`.)
If you were also using `ExplainMatchResultTo()` to improve the matcher
message:
```
// Old matcher definition that doesn't work with the lastest
// Google Mock.
using ::testing::MatcherInterface;
...
class MyWonderfulMatcher : public MatcherInterface<MyType> {
public:
...
virtual bool Matches(MyType value) const {
// Returns true if value matches.
return value.GetFoo() > 5;
}
virtual void ExplainMatchResultTo(MyType value,
::std::ostream* os) const {
// Prints some helpful information to os to help
// a user understand why value matches (or doesn't match).
*os << "the Foo property is " << value.GetFoo();
}
...
};
```
you should move the logic of `ExplainMatchResultTo()` into
`MatchAndExplain()`, using the `MatchResultListener` argument where
the `::std::ostream` was used:
```
// New matcher definition that works with the latest Google Mock.
using ::testing::MatcherInterface;
using ::testing::MatchResultListener;
...
class MyWonderfulMatcher : public MatcherInterface<MyType> {
public:
...
virtual bool MatchAndExplain(MyType value,
MatchResultListener* listener) const {
// Returns true if value matches.
*listener << "the Foo property is " << value.GetFoo();
return value.GetFoo() > 5;
}
...
};
```
If your matcher is defined using `MakePolymorphicMatcher()`:
```
// Old matcher definition that doesn't work with the latest
// Google Mock.
using ::testing::MakePolymorphicMatcher;
...
class MyGreatMatcher {
public:
...
bool Matches(MyType value) const {
// Returns true if value matches.
return value.GetBar() < 42;
}
...
};
... MakePolymorphicMatcher(MyGreatMatcher()) ...
```
you should rename the `Matches()` method to `MatchAndExplain()` and
add a `MatchResultListener*` argument (the same as what you need to do
for matchers defined by implementing `MatcherInterface`):
```
// New matcher definition that works with the latest Google Mock.
using ::testing::MakePolymorphicMatcher;
using ::testing::MatchResultListener;
...
class MyGreatMatcher {
public:
...
bool MatchAndExplain(MyType value,
MatchResultListener* listener) const {
// Returns true if value matches.
return value.GetBar() < 42;
}
...
};
... MakePolymorphicMatcher(MyGreatMatcher()) ...
```
If your polymorphic matcher uses `ExplainMatchResultTo()` for better
failure messages:
```
// Old matcher definition that doesn't work with the latest
// Google Mock.
using ::testing::MakePolymorphicMatcher;
...
class MyGreatMatcher {
public:
...
bool Matches(MyType value) const {
// Returns true if value matches.
return value.GetBar() < 42;
}
...
};
void ExplainMatchResultTo(const MyGreatMatcher& matcher,
MyType value,
::std::ostream* os) {
// Prints some helpful information to os to help
// a user understand why value matches (or doesn't match).
*os << "the Bar property is " << value.GetBar();
}
... MakePolymorphicMatcher(MyGreatMatcher()) ...
```
you'll need to move the logic inside `ExplainMatchResultTo()` to
`MatchAndExplain()`:
```
// New matcher definition that works with the latest Google Mock.
using ::testing::MakePolymorphicMatcher;
using ::testing::MatchResultListener;
...
class MyGreatMatcher {
public:
...
bool MatchAndExplain(MyType value,
MatchResultListener* listener) const {
// Returns true if value matches.
*listener << "the Bar property is " << value.GetBar();
return value.GetBar() < 42;
}
...
};
... MakePolymorphicMatcher(MyGreatMatcher()) ...
```
For more information, you can read these
[two](V1_5_CookBook#Writing_New_Monomorphic_Matchers.md)
[recipes](V1_5_CookBook#Writing_New_Polymorphic_Matchers.md)
from the cookbook. As always, you
are welcome to post questions on `googlemock@googlegroups.com` if you
need any help.
## When using Google Mock, do I have to use Google Test as the testing framework? I have my favorite testing framework and don't want to switch. ##
Google Mock works out of the box with Google Test. However, it's easy
to configure it to work with any testing framework of your choice.
[Here](V1_5_ForDummies#Using_Google_Mock_with_Any_Testing_Framework.md) is how.
## How am I supposed to make sense of these horrible template errors? ##
If you are confused by the compiler errors gcc threw at you,
try consulting the _Google Mock Doctor_ tool first. What it does is to
scan stdin for gcc error messages, and spit out diagnoses on the
problems (we call them diseases) your code has.
To "install", run command:
```
alias gmd='<path to googlemock>/scripts/gmock_doctor.py'
```
To use it, do:
```
<your-favorite-build-command> <your-test> 2>&1 | gmd
```
For example:
```
make my_test 2>&1 | gmd
```
Or you can run `gmd` and copy-n-paste gcc's error messages to it.
## Can I mock a variadic function? ##
You cannot mock a variadic function (i.e. a function taking ellipsis
(`...`) arguments) directly in Google Mock.
The problem is that in general, there is _no way_ for a mock object to
know how many arguments are passed to the variadic method, and what
the arguments' types are. Only the _author of the base class_ knows
the protocol, and we cannot look into his head.
Therefore, to mock such a function, the _user_ must teach the mock
object how to figure out the number of arguments and their types. One
way to do it is to provide overloaded versions of the function.
Ellipsis arguments are inherited from C and not really a C++ feature.
They are unsafe to use and don't work with arguments that have
constructors or destructors. Therefore we recommend to avoid them in
C++ as much as possible.
## MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? ##
If you compile this using Microsoft Visual C++ 2005 SP1:
```
class Foo {
...
virtual void Bar(const int i) = 0;
};
class MockFoo : public Foo {
...
MOCK_METHOD1(Bar, void(const int i));
};
```
You may get the following warning:
```
warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier
```
This is a MSVC bug. The same code compiles fine with gcc ,for
example. If you use Visual C++ 2008 SP1, you would get the warning:
```
warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers
```
In C++, if you _declare_ a function with a `const` parameter, the
`const` modifier is _ignored_. Therefore, the `Foo` base class above
is equivalent to:
```
class Foo {
...
virtual void Bar(int i) = 0; // int or const int? Makes no difference.
};
```
In fact, you can _declare_ Bar() with an `int` parameter, and _define_
it with a `const int` parameter. The compiler will still match them
up.
Since making a parameter `const` is meaningless in the method
_declaration_, we recommend to remove it in both `Foo` and `MockFoo`.
That should workaround the VC bug.
Note that we are talking about the _top-level_ `const` modifier here.
If the function parameter is passed by pointer or reference, declaring
the _pointee_ or _referee_ as `const` is still meaningful. For
example, the following two declarations are _not_ equivalent:
```
void Bar(int* p); // Neither p nor *p is const.
void Bar(const int* p); // p is not const, but *p is.
```
## I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? ##
We've noticed that when the `/clr` compiler flag is used, Visual C++
uses 5~6 times as much memory when compiling a mock class. We suggest
to avoid `/clr` when compiling native C++ mocks.
## I can't figure out why Google Mock thinks my expectations are not satisfied. What should I do? ##
You might want to run your test with
`--gmock_verbose=info`. This flag lets Google Mock print a trace
of every mock function call it receives. By studying the trace,
you'll gain insights on why the expectations you set are not met.
## How can I assert that a function is NEVER called? ##
```
EXPECT_CALL(foo, Bar(_))
.Times(0);
```
## I have a failed test where Google Mock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? ##
When Google Mock detects a failure, it prints relevant information
(the mock function arguments, the state of relevant expectations, and
etc) to help the user debug. If another failure is detected, Google
Mock will do the same, including printing the state of relevant
expectations.
Sometimes an expectation's state didn't change between two failures,
and you'll see the same description of the state twice. They are
however _not_ redundant, as they refer to _different points in time_.
The fact they are the same _is_ interesting information.
## I get a heap check failure when using a mock object, but using a real object is fine. What can be wrong? ##
Does the class (hopefully a pure interface) you are mocking have a
virtual destructor?
Whenever you derive from a base class, make sure its destructor is
virtual. Otherwise Bad Things will happen. Consider the following
code:
```
class Base {
public:
// Not virtual, but should be.
~Base() { ... }
...
};
class Derived : public Base {
public:
...
private:
std::string value_;
};
...
Base* p = new Derived;
...
delete p; // Surprise! ~Base() will be called, but ~Derived() will not
// - value_ is leaked.
```
By changing `~Base()` to virtual, `~Derived()` will be correctly
called when `delete p` is executed, and the heap checker
will be happy.
## The "newer expectations override older ones" rule makes writing expectations awkward. Why does Google Mock do that? ##
When people complain about this, often they are referring to code like:
```
// foo.Bar() should be called twice, return 1 the first time, and return
// 2 the second time. However, I have to write the expectations in the
// reverse order. This sucks big time!!!
EXPECT_CALL(foo, Bar())
.WillOnce(Return(2))
.RetiresOnSaturation();
EXPECT_CALL(foo, Bar())
.WillOnce(Return(1))
.RetiresOnSaturation();
```
The problem is that they didn't pick the **best** way to express the test's
intent.
By default, expectations don't have to be matched in _any_ particular
order. If you want them to match in a certain order, you need to be
explicit. This is Google Mock's (and jMock's) fundamental philosophy: it's
easy to accidentally over-specify your tests, and we want to make it
harder to do so.
There are two better ways to write the test spec. You could either
put the expectations in sequence:
```
// foo.Bar() should be called twice, return 1 the first time, and return
// 2 the second time. Using a sequence, we can write the expectations
// in their natural order.
{
InSequence s;
EXPECT_CALL(foo, Bar())
.WillOnce(Return(1))
.RetiresOnSaturation();
EXPECT_CALL(foo, Bar())
.WillOnce(Return(2))
.RetiresOnSaturation();
}
```
or you can put the sequence of actions in the same expectation:
```
// foo.Bar() should be called twice, return 1 the first time, and return
// 2 the second time.
EXPECT_CALL(foo, Bar())
.WillOnce(Return(1))
.WillOnce(Return(2))
.RetiresOnSaturation();
```
Back to the original questions: why does Google Mock search the
expectations (and `ON_CALL`s) from back to front? Because this
allows a user to set up a mock's behavior for the common case early
(e.g. in the mock's constructor or the test fixture's set-up phase)
and customize it with more specific rules later. If Google Mock
searches from front to back, this very useful pattern won't be
possible.
## Google Mock prints a warning when a function without EXPECT\_CALL is called, even if I have set its behavior using ON\_CALL. Would it be reasonable not to show the warning in this case? ##
When choosing between being neat and being safe, we lean toward the
latter. So the answer is that we think it's better to show the
warning.
Often people write `ON_CALL`s in the mock object's
constructor or `SetUp()`, as the default behavior rarely changes from
test to test. Then in the test body they set the expectations, which
are often different for each test. Having an `ON_CALL` in the set-up
part of a test doesn't mean that the calls are expected. If there's
no `EXPECT_CALL` and the method is called, it's possibly an error. If
we quietly let the call go through without notifying the user, bugs
may creep in unnoticed.
If, however, you are sure that the calls are OK, you can write
```
EXPECT_CALL(foo, Bar(_))
.WillRepeatedly(...);
```
instead of
```
ON_CALL(foo, Bar(_))
.WillByDefault(...);
```
This tells Google Mock that you do expect the calls and no warning should be
printed.
Also, you can control the verbosity using the `--gmock_verbose` flag.
If you find the output too noisy when debugging, just choose a less
verbose level.
## How can I delete the mock function's argument in an action? ##
If you find yourself needing to perform some action that's not
supported by Google Mock directly, remember that you can define your own
actions using
[MakeAction()](V1_5_CookBook#Writing_New_Actions.md) or
[MakePolymorphicAction()](V1_5_CookBook#Writing_New_Polymorphic_Actions.md),
or you can write a stub function and invoke it using
[Invoke()](V1_5_CookBook#Using_Functions_Methods_Functors.md).
## MOCK\_METHODn()'s second argument looks funny. Why don't you use the MOCK\_METHODn(Method, return\_type, arg\_1, ..., arg\_n) syntax? ##
What?! I think it's beautiful. :-)
While which syntax looks more natural is a subjective matter to some
extent, Google Mock's syntax was chosen for several practical advantages it
has.
Try to mock a function that takes a map as an argument:
```
virtual int GetSize(const map<int, std::string>& m);
```
Using the proposed syntax, it would be:
```
MOCK_METHOD1(GetSize, int, const map<int, std::string>& m);
```
Guess what? You'll get a compiler error as the compiler thinks that
`const map<int, std::string>& m` are **two**, not one, arguments. To work
around this you can use `typedef` to give the map type a name, but
that gets in the way of your work. Google Mock's syntax avoids this
problem as the function's argument types are protected inside a pair
of parentheses:
```
// This compiles fine.
MOCK_METHOD1(GetSize, int(const map<int, std::string>& m));
```
You still need a `typedef` if the return type contains an unprotected
comma, but that's much rarer.
Other advantages include:
1. `MOCK_METHOD1(Foo, int, bool)` can leave a reader wonder whether the method returns `int` or `bool`, while there won't be such confusion using Google Mock's syntax.
1. The way Google Mock describes a function type is nothing new, although many people may not be familiar with it. The same syntax was used in C, and the `function` library in `tr1` uses this syntax extensively. Since `tr1` will become a part of the new version of STL, we feel very comfortable to be consistent with it.
1. The function type syntax is also used in other parts of Google Mock's API (e.g. the action interface) in order to make the implementation tractable. A user needs to learn it anyway in order to utilize Google Mock's more advanced features. We'd as well stick to the same syntax in `MOCK_METHOD*`!
## My code calls a static/global function. Can I mock it? ##
You can, but you need to make some changes.
In general, if you find yourself needing to mock a static function,
it's a sign that your modules are too tightly coupled (and less
flexible, less reusable, less testable, etc). You are probably better
off defining a small interface and call the function through that
interface, which then can be easily mocked. It's a bit of work
initially, but usually pays for itself quickly.
This Google Testing Blog
[post](http://googletesting.blogspot.com/2008/06/defeat-static-cling.html)
says it excellently. Check it out.
## My mock object needs to do complex stuff. It's a lot of pain to specify the actions. Google Mock sucks! ##
I know it's not a question, but you get an answer for free any way. :-)
With Google Mock, you can create mocks in C++ easily. And people might be
tempted to use them everywhere. Sometimes they work great, and
sometimes you may find them, well, a pain to use. So, what's wrong in
the latter case?
When you write a test without using mocks, you exercise the code and
assert that it returns the correct value or that the system is in an
expected state. This is sometimes called "state-based testing".
Mocks are great for what some call "interaction-based" testing:
instead of checking the system state at the very end, mock objects
verify that they are invoked the right way and report an error as soon
as it arises, giving you a handle on the precise context in which the
error was triggered. This is often more effective and economical to
do than state-based testing.
If you are doing state-based testing and using a test double just to
simulate the real object, you are probably better off using a fake.
Using a mock in this case causes pain, as it's not a strong point for
mocks to perform complex actions. If you experience this and think
that mocks suck, you are just not using the right tool for your
problem. Or, you might be trying to solve the wrong problem. :-)
## I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? ##
By all means, NO! It's just an FYI.
What it means is that you have a mock function, you haven't set any
expectations on it (by Google Mock's rule this means that you are not
interested in calls to this function and therefore it can be called
any number of times), and it is called. That's OK - you didn't say
it's not OK to call the function!
What if you actually meant to disallow this function to be called, but
forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`? While
one can argue that it's the user's fault, Google Mock tries to be nice and
prints you a note.
So, when you see the message and believe that there shouldn't be any
uninteresting calls, you should investigate what's going on. To make
your life easier, Google Mock prints the function name and arguments
when an uninteresting call is encountered.
## I want to define a custom action. Should I use Invoke() or implement the action interface? ##
Either way is fine - you want to choose the one that's more convenient
for your circumstance.
Usually, if your action is for a particular function type, defining it
using `Invoke()` should be easier; if your action can be used in
functions of different types (e.g. if you are defining
`Return(value)`), `MakePolymorphicAction()` is
easiest. Sometimes you want precise control on what types of
functions the action can be used in, and implementing
`ActionInterface` is the way to go here. See the implementation of
`Return()` in `include/gmock/gmock-actions.h` for an example.
## I'm using the set-argument-pointee action, and the compiler complains about "conflicting return type specified". What does it mean? ##
You got this error as Google Mock has no idea what value it should return
when the mock method is called. `SetArgumentPointee()` says what the
side effect is, but doesn't say what the return value should be. You
need `DoAll()` to chain a `SetArgumentPointee()` with a `Return()`.
See this [recipe](V1_5_CookBook#Mocking_Side_Effects.md) for more details and an example.
## My question is not in your FAQ! ##
If you cannot find the answer to your question in this FAQ, there are
some other resources you can use:
1. read other [wiki pages](http://code.google.com/p/googlemock/w/list),
1. search the mailing list [archive](http://groups.google.com/group/googlemock/topics),
1. ask it on [googlemock@googlegroups.com](mailto:googlemock@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googlemock) before you can post.).
Please note that creating an issue in the
[issue tracker](http://code.google.com/p/googlemock/issues/list) is _not_
a good way to get your answer, as it is monitored infrequently by a
very small number of people.
When asking a question, it's helpful to provide as much of the
following information as possible (people cannot help you if there's
not enough information in your question):
* the version (or the revision number if you check out from SVN directly) of Google Mock you use (Google Mock is under active development, so it's possible that your problem has been solved in a later version),
* your operating system,
* the name and version of your compiler,
* the complete command line flags you give to your compiler,
* the complete compiler error messages (if the question is about compilation),
* the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter.

View File

@ -1,534 +0,0 @@
# Defining a Mock Class #
## Mocking a Normal Class ##
Given
```
class Foo {
...
virtual ~Foo();
virtual int GetSize() const = 0;
virtual string Describe(const char* name) = 0;
virtual string Describe(int type) = 0;
virtual bool Process(Bar elem, int count) = 0;
};
```
(note that `~Foo()` **must** be virtual) we can define its mock as
```
#include "gmock/gmock.h"
class MockFoo : public Foo {
MOCK_CONST_METHOD0(GetSize, int());
MOCK_METHOD1(Describe, string(const char* name));
MOCK_METHOD1(Describe, string(int type));
MOCK_METHOD2(Process, bool(Bar elem, int count));
};
```
To create a "nice" mock object which ignores all uninteresting calls,
or a "strict" mock object, which treats them as failures:
```
NiceMock<MockFoo> nice_foo; // The type is a subclass of MockFoo.
StrictMock<MockFoo> strict_foo; // The type is a subclass of MockFoo.
```
## Mocking a Class Template ##
To mock
```
template <typename Elem>
class StackInterface {
public:
...
virtual ~StackInterface();
virtual int GetSize() const = 0;
virtual void Push(const Elem& x) = 0;
};
```
(note that `~StackInterface()` **must** be virtual) just append `_T` to the `MOCK_*` macros:
```
template <typename Elem>
class MockStack : public StackInterface<Elem> {
public:
...
MOCK_CONST_METHOD0_T(GetSize, int());
MOCK_METHOD1_T(Push, void(const Elem& x));
};
```
## Specifying Calling Conventions for Mock Functions ##
If your mock function doesn't use the default calling convention, you
can specify it by appending `_WITH_CALLTYPE` to any of the macros
described in the previous two sections and supplying the calling
convention as the first argument to the macro. For example,
```
MOCK_METHOD_1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int n));
MOCK_CONST_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, Bar, int(double x, double y));
```
where `STDMETHODCALLTYPE` is defined by `<objbase.h>` on Windows.
# Using Mocks in Tests #
The typical flow is:
1. Import the Google Mock names you need to use. All Google Mock names are in the `testing` namespace unless they are macros or otherwise noted.
1. Create the mock objects.
1. Optionally, set the default actions of the mock objects.
1. Set your expectations on the mock objects (How will they be called? What wil they do?).
1. Exercise code that uses the mock objects; if necessary, check the result using [Google Test](http://code.google.com/p/googletest/) assertions.
1. When a mock objects is destructed, Google Mock automatically verifies that all expectations on it have been satisfied.
Here is an example:
```
using ::testing::Return; // #1
TEST(BarTest, DoesThis) {
MockFoo foo; // #2
ON_CALL(foo, GetSize()) // #3
.WillByDefault(Return(1));
// ... other default actions ...
EXPECT_CALL(foo, Describe(5)) // #4
.Times(3)
.WillRepeatedly(Return("Category 5"));
// ... other expectations ...
EXPECT_EQ("good", MyProductionFunction(&foo)); // #5
} // #6
```
# Setting Default Actions #
Google Mock has a **built-in default action** for any function that
returns `void`, `bool`, a numeric value, or a pointer.
To customize the default action for functions with return type `T` globally:
```
using ::testing::DefaultValue;
DefaultValue<T>::Set(value); // Sets the default value to be returned.
// ... use the mocks ...
DefaultValue<T>::Clear(); // Resets the default value.
```
To customize the default action for a particular method, use `ON_CALL()`:
```
ON_CALL(mock_object, method(matchers))
.With(multi_argument_matcher) ?
.WillByDefault(action);
```
# Setting Expectations #
`EXPECT_CALL()` sets **expectations** on a mock method (How will it be
called? What will it do?):
```
EXPECT_CALL(mock_object, method(matchers))
.With(multi_argument_matcher) ?
.Times(cardinality) ?
.InSequence(sequences) *
.After(expectations) *
.WillOnce(action) *
.WillRepeatedly(action) ?
.RetiresOnSaturation(); ?
```
If `Times()` is omitted, the cardinality is assumed to be:
* `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`;
* `Times(n)` when there are `n WillOnce()`s but no `WillRepeatedly()`, where `n` >= 1; or
* `Times(AtLeast(n))` when there are `n WillOnce()`s and a `WillRepeatedly()`, where `n` >= 0.
A method with no `EXPECT_CALL()` is free to be invoked _any number of times_, and the default action will be taken each time.
# Matchers #
A **matcher** matches a _single_ argument. You can use it inside
`ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value
directly:
| `EXPECT_THAT(value, matcher)` | Asserts that `value` matches `matcher`. |
|:------------------------------|:----------------------------------------|
| `ASSERT_THAT(value, matcher)` | The same as `EXPECT_THAT(value, matcher)`, except that it generates a **fatal** failure. |
Built-in matchers (where `argument` is the function argument) are
divided into several categories:
## Wildcard ##
|`_`|`argument` can be any value of the correct type.|
|:--|:-----------------------------------------------|
|`A<type>()` or `An<type>()`|`argument` can be any value of type `type`. |
## Generic Comparison ##
|`Eq(value)` or `value`|`argument == value`|
|:---------------------|:------------------|
|`Ge(value)` |`argument >= value`|
|`Gt(value)` |`argument > value` |
|`Le(value)` |`argument <= value`|
|`Lt(value)` |`argument < value` |
|`Ne(value)` |`argument != value`|
|`IsNull()` |`argument` is a `NULL` pointer (raw or smart).|
|`NotNull()` |`argument` is a non-null pointer (raw or smart).|
|`Ref(variable)` |`argument` is a reference to `variable`.|
|`TypedEq<type>(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.|
Except `Ref()`, these matchers make a _copy_ of `value` in case it's
modified or destructed later. If the compiler complains that `value`
doesn't have a public copy constructor, try wrap it in `ByRef()`,
e.g. `Eq(ByRef(non_copyable_value))`. If you do that, make sure
`non_copyable_value` is not changed afterwards, or the meaning of your
matcher will be changed.
## Floating-Point Matchers ##
|`DoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal.|
|:-------------------|:----------------------------------------------------------------------------------------------|
|`FloatEq(a_float)` |`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. |
|`NanSensitiveDoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. |
|`NanSensitiveFloatEq(a_float)`|`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. |
These matchers use ULP-based comparison (the same as used in
[Google Test](http://code.google.com/p/googletest/)). They
automatically pick a reasonable error bound based on the absolute
value of the expected value. `DoubleEq()` and `FloatEq()` conform to
the IEEE standard, which requires comparing two NaNs for equality to
return false. The `NanSensitive*` version instead treats two NaNs as
equal, which is often what a user wants.
## String Matchers ##
The `argument` can be either a C string or a C++ string object:
|`ContainsRegex(string)`|`argument` matches the given regular expression.|
|:----------------------|:-----------------------------------------------|
|`EndsWith(suffix)` |`argument` ends with string `suffix`. |
|`HasSubstr(string)` |`argument` contains `string` as a sub-string. |
|`MatchesRegex(string)` |`argument` matches the given regular expression with the match starting at the first character and ending at the last character.|
|`StartsWith(prefix)` |`argument` starts with string `prefix`. |
|`StrCaseEq(string)` |`argument` is equal to `string`, ignoring case. |
|`StrCaseNe(string)` |`argument` is not equal to `string`, ignoring case.|
|`StrEq(string)` |`argument` is equal to `string`. |
|`StrNe(string)` |`argument` is not equal to `string`. |
`ContainsRegex()` and `MatchesRegex()` use the regular expression
syntax defined
[here](http://code.google.com/p/googletest/wiki/V1_6_AdvancedGuide#Regular_Expression_Syntax).
`StrCaseEq()`, `StrCaseNe()`, `StrEq()`, and `StrNe()` work for wide
strings as well.
## Container Matchers ##
Most STL-style containers support `==`, so you can use
`Eq(expected_container)` or simply `expected_container` to match a
container exactly. If you want to write the elements in-line,
match them more flexibly, or get more informative messages, you can use:
| `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. |
|:--------------|:-------------------------------------------------------------------------------------------|
| `Each(e)` | `argument` is a container where _every_ element matches `e`, which can be either a value or a matcher. |
| `ElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, where the i-th element matches `ei`, which can be a value or a matcher. 0 to 10 arguments are allowed. |
| `ElementsAreArray(array)` or `ElementsAreArray(array, count)` | The same as `ElementsAre()` except that the expected element values/matchers come from a C-style array. |
| `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. |
| `Pointwise(m, container)` | `argument` contains the same number of elements as in `container`, and for all i, (the i-th element in `argument`, the i-th element in `container`) match `m`, which is a matcher on 2-tuples. E.g. `Pointwise(Le(), upper_bounds)` verifies that each element in `argument` doesn't exceed the corresponding element in `upper_bounds`. |
These matchers can also match:
1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and
1. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#Multiargument_Matchers.md)).
where the array may be multi-dimensional (i.e. its elements can be arrays).
## Member Matchers ##
|`Field(&class::field, m)`|`argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.|
|:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------|
|`Key(e)` |`argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`.|
|`Pair(m1, m2)` |`argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. |
|`Property(&class::property, m)`|`argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.|
## Matching the Result of a Function or Functor ##
|`ResultOf(f, m)`|`f(argument)` matches matcher `m`, where `f` is a function or functor.|
|:---------------|:---------------------------------------------------------------------|
## Pointer Matchers ##
|`Pointee(m)`|`argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`.|
|:-----------|:-----------------------------------------------------------------------------------------------|
## Multiargument Matchers ##
Technically, all matchers match a _single_ value. A "multi-argument"
matcher is just one that matches a _tuple_. The following matchers can
be used to match a tuple `(x, y)`:
|`Eq()`|`x == y`|
|:-----|:-------|
|`Ge()`|`x >= y`|
|`Gt()`|`x > y` |
|`Le()`|`x <= y`|
|`Lt()`|`x < y` |
|`Ne()`|`x != y`|
You can use the following selectors to pick a subset of the arguments
(or reorder them) to participate in the matching:
|`AllArgs(m)`|Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`.|
|:-----------|:-------------------------------------------------------------------|
|`Args<N1, N2, ..., Nk>(m)`|The tuple of the `k` selected (using 0-based indices) arguments matches `m`, e.g. `Args<1, 2>(Eq())`.|
## Composite Matchers ##
You can make a matcher from one or more other matchers:
|`AllOf(m1, m2, ..., mn)`|`argument` matches all of the matchers `m1` to `mn`.|
|:-----------------------|:---------------------------------------------------|
|`AnyOf(m1, m2, ..., mn)`|`argument` matches at least one of the matchers `m1` to `mn`.|
|`Not(m)` |`argument` doesn't match matcher `m`. |
## Adapters for Matchers ##
|`MatcherCast<T>(m)`|casts matcher `m` to type `Matcher<T>`.|
|:------------------|:--------------------------------------|
|`SafeMatcherCast<T>(m)`| [safely casts](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Casting_Matchers) matcher `m` to type `Matcher<T>`. |
|`Truly(predicate)` |`predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor.|
## Matchers as Predicates ##
|`Matches(m)(value)`|evaluates to `true` if `value` matches `m`. You can use `Matches(m)` alone as a unary functor.|
|:------------------|:---------------------------------------------------------------------------------------------|
|`ExplainMatchResult(m, value, result_listener)`|evaluates to `true` if `value` matches `m`, explaining the result to `result_listener`. |
|`Value(value, m)` |evaluates to `true` if `value` matches `m`. |
## Defining Matchers ##
| `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. |
|:-------------------------------------------------|:------------------------------------------------------|
| `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a macher `IsDivisibleBy(n)` to match a number divisible by `n`. |
| `MATCHER_P2(IsBetween, a, b, std::string(negation ? "isn't" : "is") + " between " + PrintToString(a) + " and " + PrintToString(b)) { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. |
**Notes:**
1. The `MATCHER*` macros cannot be used inside a function or class.
1. The matcher body must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters).
1. You can use `PrintToString(x)` to convert a value `x` of any type to a string.
## Matchers as Test Assertions ##
|`ASSERT_THAT(expression, m)`|Generates a [fatal failure](http://code.google.com/p/googletest/wiki/V1_6_Primer#Assertions) if the value of `expression` doesn't match matcher `m`.|
|:---------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------|
|`EXPECT_THAT(expression, m)`|Generates a non-fatal failure if the value of `expression` doesn't match matcher `m`. |
# Actions #
**Actions** specify what a mock function should do when invoked.
## Returning a Value ##
|`Return()`|Return from a `void` mock function.|
|:---------|:----------------------------------|
|`Return(value)`|Return `value`. If the type of `value` is different to the mock function's return type, `value` is converted to the latter type <i>at the time the expectation is set</i>, not when the action is executed.|
|`ReturnArg<N>()`|Return the `N`-th (0-based) argument.|
|`ReturnNew<T>(a1, ..., ak)`|Return `new T(a1, ..., ak)`; a different object is created each time.|
|`ReturnNull()`|Return a null pointer. |
|`ReturnPointee(ptr)`|Return the value pointed to by `ptr`.|
|`ReturnRef(variable)`|Return a reference to `variable`. |
|`ReturnRefOfCopy(value)`|Return a reference to a copy of `value`; the copy lives as long as the action.|
## Side Effects ##
|`Assign(&variable, value)`|Assign `value` to variable.|
|:-------------------------|:--------------------------|
| `DeleteArg<N>()` | Delete the `N`-th (0-based) argument, which must be a pointer. |
| `SaveArg<N>(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. |
| `SaveArgPointee<N>(pointer)` | Save the value pointed to by the `N`-th (0-based) argument to `*pointer`. |
| `SetArgReferee<N>(value)` | Assign value to the variable referenced by the `N`-th (0-based) argument. |
|`SetArgPointee<N>(value)` |Assign `value` to the variable pointed by the `N`-th (0-based) argument.|
|`SetArgumentPointee<N>(value)`|Same as `SetArgPointee<N>(value)`. Deprecated. Will be removed in v1.7.0.|
|`SetArrayArgument<N>(first, last)`|Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.|
|`SetErrnoAndReturn(error, value)`|Set `errno` to `error` and return `value`.|
|`Throw(exception)` |Throws the given exception, which can be any copyable value. Available since v1.1.0.|
## Using a Function or a Functor as an Action ##
|`Invoke(f)`|Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor.|
|:----------|:-----------------------------------------------------------------------------------------------------------------|
|`Invoke(object_pointer, &class::method)`|Invoke the {method on the object with the arguments passed to the mock function. |
|`InvokeWithoutArgs(f)`|Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. |
|`InvokeWithoutArgs(object_pointer, &class::method)`|Invoke the method on the object, which takes no arguments. |
|`InvokeArgument<N>(arg1, arg2, ..., argk)`|Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments.|
The return value of the invoked function is used as the return value
of the action.
When defining a function or functor to be used with `Invoke*()`, you can declare any unused parameters as `Unused`:
```
double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); }
...
EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance));
```
In `InvokeArgument<N>(...)`, if an argument needs to be passed by reference, wrap it inside `ByRef()`. For example,
```
InvokeArgument<2>(5, string("Hi"), ByRef(foo))
```
calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference.
## Default Action ##
|`DoDefault()`|Do the default action (specified by `ON_CALL()` or the built-in one).|
|:------------|:--------------------------------------------------------------------|
**Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error.
## Composite Actions ##
|`DoAll(a1, a2, ..., an)`|Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. |
|:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------|
|`IgnoreResult(a)` |Perform action `a` and ignore its result. `a` must not return void. |
|`WithArg<N>(a)` |Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. |
|`WithArgs<N1, N2, ..., Nk>(a)`|Pass the selected (0-based) arguments of the mock function to action `a` and perform it. |
|`WithoutArgs(a)` |Perform action `a` without any arguments. |
## Defining Actions ##
| `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. |
|:--------------------------------------|:---------------------------------------------------------------------------------------|
| `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. |
| `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. |
The `ACTION*` macros cannot be used inside a function or class.
# Cardinalities #
These are used in `Times()` to specify how many times a mock function will be called:
|`AnyNumber()`|The function can be called any number of times.|
|:------------|:----------------------------------------------|
|`AtLeast(n)` |The call is expected at least `n` times. |
|`AtMost(n)` |The call is expected at most `n` times. |
|`Between(m, n)`|The call is expected between `m` and `n` (inclusive) times.|
|`Exactly(n) or n`|The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0.|
# Expectation Order #
By default, the expectations can be matched in _any_ order. If some
or all expectations must be matched in a given order, there are two
ways to specify it. They can be used either independently or
together.
## The After Clause ##
```
using ::testing::Expectation;
...
Expectation init_x = EXPECT_CALL(foo, InitX());
Expectation init_y = EXPECT_CALL(foo, InitY());
EXPECT_CALL(foo, Bar())
.After(init_x, init_y);
```
says that `Bar()` can be called only after both `InitX()` and
`InitY()` have been called.
If you don't know how many pre-requisites an expectation has when you
write it, you can use an `ExpectationSet` to collect them:
```
using ::testing::ExpectationSet;
...
ExpectationSet all_inits;
for (int i = 0; i < element_count; i++) {
all_inits += EXPECT_CALL(foo, InitElement(i));
}
EXPECT_CALL(foo, Bar())
.After(all_inits);
```
says that `Bar()` can be called only after all elements have been
initialized (but we don't care about which elements get initialized
before the others).
Modifying an `ExpectationSet` after using it in an `.After()` doesn't
affect the meaning of the `.After()`.
## Sequences ##
When you have a long chain of sequential expectations, it's easier to
specify the order using **sequences**, which don't require you to given
each expectation in the chain a different name. <i>All expected<br>
calls</i> in the same sequence must occur in the order they are
specified.
```
using ::testing::Sequence;
Sequence s1, s2;
...
EXPECT_CALL(foo, Reset())
.InSequence(s1, s2)
.WillOnce(Return(true));
EXPECT_CALL(foo, GetSize())
.InSequence(s1)
.WillOnce(Return(1));
EXPECT_CALL(foo, Describe(A<const char*>()))
.InSequence(s2)
.WillOnce(Return("dummy"));
```
says that `Reset()` must be called before _both_ `GetSize()` _and_
`Describe()`, and the latter two can occur in any order.
To put many expectations in a sequence conveniently:
```
using ::testing::InSequence;
{
InSequence dummy;
EXPECT_CALL(...)...;
EXPECT_CALL(...)...;
...
EXPECT_CALL(...)...;
}
```
says that all expected calls in the scope of `dummy` must occur in
strict order. The name `dummy` is irrelevant.)
# Verifying and Resetting a Mock #
Google Mock will verify the expectations on a mock object when it is destructed, or you can do it earlier:
```
using ::testing::Mock;
...
// Verifies and removes the expectations on mock_obj;
// returns true iff successful.
Mock::VerifyAndClearExpectations(&mock_obj);
...
// Verifies and removes the expectations on mock_obj;
// also removes the default actions set by ON_CALL();
// returns true iff successful.
Mock::VerifyAndClear(&mock_obj);
```
You can also tell Google Mock that a mock object can be leaked and doesn't
need to be verified:
```
Mock::AllowLeak(&mock_obj);
```
# Mock Classes #
Google Mock defines a convenient mock class template
```
class MockFunction<R(A1, ..., An)> {
public:
MOCK_METHODn(Call, R(A1, ..., An));
};
```
See this [recipe](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Using_Check_Points) for one application of it.
# Flags #
| `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. |
|:-------------------------------|:----------------------------------------------|
| `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. |

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
This page lists all documentation wiki pages for Google Mock **1.6**
- **if you use a released version of Google Mock, please read the documentation for that specific version instead.**
* [ForDummies](V1_6_ForDummies.md) -- start here if you are new to Google Mock.
* [CheatSheet](V1_6_CheatSheet.md) -- a quick reference.
* [CookBook](V1_6_CookBook.md) -- recipes for doing various tasks using Google Mock.
* [FrequentlyAskedQuestions](V1_6_FrequentlyAskedQuestions.md) -- check here before asking a question on the mailing list.
To contribute code to Google Mock, read:
* [DevGuide](DevGuide.md) -- read this _before_ writing your first patch.
* [Pump Manual](http://code.google.com/p/googletest/wiki/V1_6_PumpManual) -- how we generate some of Google Mock's source files.

View File

@ -1,439 +0,0 @@
(**Note:** If you get compiler errors that you don't understand, be sure to consult [Google Mock Doctor](http://code.google.com/p/googlemock/wiki/V1_6_FrequentlyAskedQuestions#How_am_I_supposed_to_make_sense_of_these_horrible_template_error).)
# What Is Google C++ Mocking Framework? #
When you write a prototype or test, often it's not feasible or wise to rely on real objects entirely. A **mock object** implements the same interface as a real object (so it can be used as one), but lets you specify at run time how it will be used and what it should do (which methods will be called? in which order? how many times? with what arguments? what will they return? etc).
**Note:** It is easy to confuse the term _fake objects_ with mock objects. Fakes and mocks actually mean very different things in the Test-Driven Development (TDD) community:
* **Fake** objects have working implementations, but usually take some shortcut (perhaps to make the operations less expensive), which makes them not suitable for production. An in-memory file system would be an example of a fake.
* **Mocks** are objects pre-programmed with _expectations_, which form a specification of the calls they are expected to receive.
If all this seems too abstract for you, don't worry - the most important thing to remember is that a mock allows you to check the _interaction_ between itself and code that uses it. The difference between fakes and mocks will become much clearer once you start to use mocks.
**Google C++ Mocking Framework** (or **Google Mock** for short) is a library (sometimes we also call it a "framework" to make it sound cool) for creating mock classes and using them. It does to C++ what [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/) do to Java.
Using Google Mock involves three basic steps:
1. Use some simple macros to describe the interface you want to mock, and they will expand to the implementation of your mock class;
1. Create some mock objects and specify its expectations and behavior using an intuitive syntax;
1. Exercise code that uses the mock objects. Google Mock will catch any violation of the expectations as soon as it arises.
# Why Google Mock? #
While mock objects help you remove unnecessary dependencies in tests and make them fast and reliable, using mocks manually in C++ is _hard_:
* Someone has to implement the mocks. The job is usually tedious and error-prone. No wonder people go great distance to avoid it.
* The quality of those manually written mocks is a bit, uh, unpredictable. You may see some really polished ones, but you may also see some that were hacked up in a hurry and have all sorts of ad hoc restrictions.
* The knowledge you gained from using one mock doesn't transfer to the next.
In contrast, Java and Python programmers have some fine mock frameworks, which automate the creation of mocks. As a result, mocking is a proven effective technique and widely adopted practice in those communities. Having the right tool absolutely makes the difference.
Google Mock was built to help C++ programmers. It was inspired by [jMock](http://www.jmock.org/) and [EasyMock](http://www.easymock.org/), but designed with C++'s specifics in mind. It is your friend if any of the following problems is bothering you:
* You are stuck with a sub-optimal design and wish you had done more prototyping before it was too late, but prototyping in C++ is by no means "rapid".
* Your tests are slow as they depend on too many libraries or use expensive resources (e.g. a database).
* Your tests are brittle as some resources they use are unreliable (e.g. the network).
* You want to test how your code handles a failure (e.g. a file checksum error), but it's not easy to cause one.
* You need to make sure that your module interacts with other modules in the right way, but it's hard to observe the interaction; therefore you resort to observing the side effects at the end of the action, which is awkward at best.
* You want to "mock out" your dependencies, except that they don't have mock implementations yet; and, frankly, you aren't thrilled by some of those hand-written mocks.
We encourage you to use Google Mock as:
* a _design_ tool, for it lets you experiment with your interface design early and often. More iterations lead to better designs!
* a _testing_ tool to cut your tests' outbound dependencies and probe the interaction between your module and its collaborators.
# Getting Started #
Using Google Mock is easy! Inside your C++ source file, just `#include` `"gtest/gtest.h"` and `"gmock/gmock.h"`, and you are ready to go.
# A Case for Mock Turtles #
Let's look at an example. Suppose you are developing a graphics program that relies on a LOGO-like API for drawing. How would you test that it does the right thing? Well, you can run it and compare the screen with a golden screen snapshot, but let's admit it: tests like this are expensive to run and fragile (What if you just upgraded to a shiny new graphics card that has better anti-aliasing? Suddenly you have to update all your golden images.). It would be too painful if all your tests are like this. Fortunately, you learned about Dependency Injection and know the right thing to do: instead of having your application talk to the drawing API directly, wrap the API in an interface (say, `Turtle`) and code to that interface:
```
class Turtle {
...
virtual ~Turtle() {}
virtual void PenUp() = 0;
virtual void PenDown() = 0;
virtual void Forward(int distance) = 0;
virtual void Turn(int degrees) = 0;
virtual void GoTo(int x, int y) = 0;
virtual int GetX() const = 0;
virtual int GetY() const = 0;
};
```
(Note that the destructor of `Turtle` **must** be virtual, as is the case for **all** classes you intend to inherit from - otherwise the destructor of the derived class will not be called when you delete an object through a base pointer, and you'll get corrupted program states like memory leaks.)
You can control whether the turtle's movement will leave a trace using `PenUp()` and `PenDown()`, and control its movement using `Forward()`, `Turn()`, and `GoTo()`. Finally, `GetX()` and `GetY()` tell you the current position of the turtle.
Your program will normally use a real implementation of this interface. In tests, you can use a mock implementation instead. This allows you to easily check what drawing primitives your program is calling, with what arguments, and in which order. Tests written this way are much more robust (they won't break because your new machine does anti-aliasing differently), easier to read and maintain (the intent of a test is expressed in the code, not in some binary images), and run _much, much faster_.
# Writing the Mock Class #
If you are lucky, the mocks you need to use have already been implemented by some nice people. If, however, you find yourself in the position to write a mock class, relax - Google Mock turns this task into a fun game! (Well, almost.)
## How to Define It ##
Using the `Turtle` interface as example, here are the simple steps you need to follow:
1. Derive a class `MockTurtle` from `Turtle`.
1. Take a _virtual_ function of `Turtle` (while it's possible to [mock non-virtual methods using templates](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Mocking_Nonvirtual_Methods), it's much more involved). Count how many arguments it has.
1. In the `public:` section of the child class, write `MOCK_METHODn();` (or `MOCK_CONST_METHODn();` if you are mocking a `const` method), where `n` is the number of the arguments; if you counted wrong, shame on you, and a compiler error will tell you so.
1. Now comes the fun part: you take the function signature, cut-and-paste the _function name_ as the _first_ argument to the macro, and leave what's left as the _second_ argument (in case you're curious, this is the _type of the function_).
1. Repeat until all virtual functions you want to mock are done.
After the process, you should have something like:
```
#include "gmock/gmock.h" // Brings in Google Mock.
class MockTurtle : public Turtle {
public:
...
MOCK_METHOD0(PenUp, void());
MOCK_METHOD0(PenDown, void());
MOCK_METHOD1(Forward, void(int distance));
MOCK_METHOD1(Turn, void(int degrees));
MOCK_METHOD2(GoTo, void(int x, int y));
MOCK_CONST_METHOD0(GetX, int());
MOCK_CONST_METHOD0(GetY, int());
};
```
You don't need to define these mock methods somewhere else - the `MOCK_METHOD*` macros will generate the definitions for you. It's that simple! Once you get the hang of it, you can pump out mock classes faster than your source-control system can handle your check-ins.
**Tip:** If even this is too much work for you, you'll find the
`gmock_gen.py` tool in Google Mock's `scripts/generator/` directory (courtesy of the [cppclean](http://code.google.com/p/cppclean/) project) useful. This command-line
tool requires that you have Python 2.4 installed. You give it a C++ file and the name of an abstract class defined in it,
and it will print the definition of the mock class for you. Due to the
complexity of the C++ language, this script may not always work, but
it can be quite handy when it does. For more details, read the [user documentation](http://code.google.com/p/googlemock/source/browse/trunk/scripts/generator/README).
## Where to Put It ##
When you define a mock class, you need to decide where to put its definition. Some people put it in a `*_test.cc`. This is fine when the interface being mocked (say, `Foo`) is owned by the same person or team. Otherwise, when the owner of `Foo` changes it, your test could break. (You can't really expect `Foo`'s maintainer to fix every test that uses `Foo`, can you?)
So, the rule of thumb is: if you need to mock `Foo` and it's owned by others, define the mock class in `Foo`'s package (better, in a `testing` sub-package such that you can clearly separate production code and testing utilities), and put it in a `mock_foo.h`. Then everyone can reference `mock_foo.h` from their tests. If `Foo` ever changes, there is only one copy of `MockFoo` to change, and only tests that depend on the changed methods need to be fixed.
Another way to do it: you can introduce a thin layer `FooAdaptor` on top of `Foo` and code to this new interface. Since you own `FooAdaptor`, you can absorb changes in `Foo` much more easily. While this is more work initially, carefully choosing the adaptor interface can make your code easier to write and more readable (a net win in the long run), as you can choose `FooAdaptor` to fit your specific domain much better than `Foo` does.
# Using Mocks in Tests #
Once you have a mock class, using it is easy. The typical work flow is:
1. Import the Google Mock names from the `testing` namespace such that you can use them unqualified (You only have to do it once per file. Remember that namespaces are a good idea and good for your health.).
1. Create some mock objects.
1. Specify your expectations on them (How many times will a method be called? With what arguments? What should it do? etc.).
1. Exercise some code that uses the mocks; optionally, check the result using Google Test assertions. If a mock method is called more than expected or with wrong arguments, you'll get an error immediately.
1. When a mock is destructed, Google Mock will automatically check whether all expectations on it have been satisfied.
Here's an example:
```
#include "path/to/mock-turtle.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
using ::testing::AtLeast; // #1
TEST(PainterTest, CanDrawSomething) {
MockTurtle turtle; // #2
EXPECT_CALL(turtle, PenDown()) // #3
.Times(AtLeast(1));
Painter painter(&turtle); // #4
EXPECT_TRUE(painter.DrawCircle(0, 0, 10));
} // #5
int main(int argc, char** argv) {
// The following line must be executed to initialize Google Mock
// (and Google Test) before running the tests.
::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
```
As you might have guessed, this test checks that `PenDown()` is called at least once. If the `painter` object didn't call this method, your test will fail with a message like this:
```
path/to/my_test.cc:119: Failure
Actual function call count doesn't match this expectation:
Actually: never called;
Expected: called at least once.
```
**Tip 1:** If you run the test from an Emacs buffer, you can hit `<Enter>` on the line number displayed in the error message to jump right to the failed expectation.
**Tip 2:** If your mock objects are never deleted, the final verification won't happen. Therefore it's a good idea to use a heap leak checker in your tests when you allocate mocks on the heap.
**Important note:** Google Mock requires expectations to be set **before** the mock functions are called, otherwise the behavior is **undefined**. In particular, you mustn't interleave `EXPECT_CALL()`s and calls to the mock functions.
This means `EXPECT_CALL()` should be read as expecting that a call will occur _in the future_, not that a call has occurred. Why does Google Mock work like that? Well, specifying the expectation beforehand allows Google Mock to report a violation as soon as it arises, when the context (stack trace, etc) is still available. This makes debugging much easier.
Admittedly, this test is contrived and doesn't do much. You can easily achieve the same effect without using Google Mock. However, as we shall reveal soon, Google Mock allows you to do _much more_ with the mocks.
## Using Google Mock with Any Testing Framework ##
If you want to use something other than Google Test (e.g. [CppUnit](http://apps.sourceforge.net/mediawiki/cppunit/index.php?title=Main_Page) or
[CxxTest](http://cxxtest.tigris.org/)) as your testing framework, just change the `main()` function in the previous section to:
```
int main(int argc, char** argv) {
// The following line causes Google Mock to throw an exception on failure,
// which will be interpreted by your testing framework as a test failure.
::testing::GTEST_FLAG(throw_on_failure) = true;
::testing::InitGoogleMock(&argc, argv);
... whatever your testing framework requires ...
}
```
This approach has a catch: it makes Google Mock throw an exception
from a mock object's destructor sometimes. With some compilers, this
sometimes causes the test program to crash. You'll still be able to
notice that the test has failed, but it's not a graceful failure.
A better solution is to use Google Test's
[event listener API](http://code.google.com/p/googletest/wiki/V1_6_AdvancedGuide#Extending_Google_Test_by_Handling_Test_Events)
to report a test failure to your testing framework properly. You'll need to
implement the `OnTestPartResult()` method of the event listener interface, but it
should be straightforward.
If this turns out to be too much work, we suggest that you stick with
Google Test, which works with Google Mock seamlessly (in fact, it is
technically part of Google Mock.). If there is a reason that you
cannot use Google Test, please let us know.
# Setting Expectations #
The key to using a mock object successfully is to set the _right expectations_ on it. If you set the expectations too strict, your test will fail as the result of unrelated changes. If you set them too loose, bugs can slip through. You want to do it just right such that your test can catch exactly the kind of bugs you intend it to catch. Google Mock provides the necessary means for you to do it "just right."
## General Syntax ##
In Google Mock we use the `EXPECT_CALL()` macro to set an expectation on a mock method. The general syntax is:
```
EXPECT_CALL(mock_object, method(matchers))
.Times(cardinality)
.WillOnce(action)
.WillRepeatedly(action);
```
The macro has two arguments: first the mock object, and then the method and its arguments. Note that the two are separated by a comma (`,`), not a period (`.`). (Why using a comma? The answer is that it was necessary for technical reasons.)
The macro can be followed by some optional _clauses_ that provide more information about the expectation. We'll discuss how each clause works in the coming sections.
This syntax is designed to make an expectation read like English. For example, you can probably guess that
```
using ::testing::Return;...
EXPECT_CALL(turtle, GetX())
.Times(5)
.WillOnce(Return(100))
.WillOnce(Return(150))
.WillRepeatedly(Return(200));
```
says that the `turtle` object's `GetX()` method will be called five times, it will return 100 the first time, 150 the second time, and then 200 every time. Some people like to call this style of syntax a Domain-Specific Language (DSL).
**Note:** Why do we use a macro to do this? It serves two purposes: first it makes expectations easily identifiable (either by `grep` or by a human reader), and second it allows Google Mock to include the source file location of a failed expectation in messages, making debugging easier.
## Matchers: What Arguments Do We Expect? ##
When a mock function takes arguments, we must specify what arguments we are expecting; for example:
```
// Expects the turtle to move forward by 100 units.
EXPECT_CALL(turtle, Forward(100));
```
Sometimes you may not want to be too specific (Remember that talk about tests being too rigid? Over specification leads to brittle tests and obscures the intent of tests. Therefore we encourage you to specify only what's necessary - no more, no less.). If you care to check that `Forward()` will be called but aren't interested in its actual argument, write `_` as the argument, which means "anything goes":
```
using ::testing::_;
...
// Expects the turtle to move forward.
EXPECT_CALL(turtle, Forward(_));
```
`_` is an instance of what we call **matchers**. A matcher is like a predicate and can test whether an argument is what we'd expect. You can use a matcher inside `EXPECT_CALL()` wherever a function argument is expected.
A list of built-in matchers can be found in the [CheatSheet](V1_6_CheatSheet.md). For example, here's the `Ge` (greater than or equal) matcher:
```
using ::testing::Ge;...
EXPECT_CALL(turtle, Forward(Ge(100)));
```
This checks that the turtle will be told to go forward by at least 100 units.
## Cardinalities: How Many Times Will It Be Called? ##
The first clause we can specify following an `EXPECT_CALL()` is `Times()`. We call its argument a **cardinality** as it tells _how many times_ the call should occur. It allows us to repeat an expectation many times without actually writing it as many times. More importantly, a cardinality can be "fuzzy", just like a matcher can be. This allows a user to express the intent of a test exactly.
An interesting special case is when we say `Times(0)`. You may have guessed - it means that the function shouldn't be called with the given arguments at all, and Google Mock will report a Google Test failure whenever the function is (wrongfully) called.
We've seen `AtLeast(n)` as an example of fuzzy cardinalities earlier. For the list of built-in cardinalities you can use, see the [CheatSheet](V1_6_CheatSheet.md).
The `Times()` clause can be omitted. **If you omit `Times()`, Google Mock will infer the cardinality for you.** The rules are easy to remember:
* If **neither** `WillOnce()` **nor** `WillRepeatedly()` is in the `EXPECT_CALL()`, the inferred cardinality is `Times(1)`.
* If there are `n WillOnce()`'s but **no** `WillRepeatedly()`, where `n` >= 1, the cardinality is `Times(n)`.
* If there are `n WillOnce()`'s and **one** `WillRepeatedly()`, where `n` >= 0, the cardinality is `Times(AtLeast(n))`.
**Quick quiz:** what do you think will happen if a function is expected to be called twice but actually called four times?
## Actions: What Should It Do? ##
Remember that a mock object doesn't really have a working implementation? We as users have to tell it what to do when a method is invoked. This is easy in Google Mock.
First, if the return type of a mock function is a built-in type or a pointer, the function has a **default action** (a `void` function will just return, a `bool` function will return `false`, and other functions will return 0). If you don't say anything, this behavior will be used.
Second, if a mock function doesn't have a default action, or the default action doesn't suit you, you can specify the action to be taken each time the expectation matches using a series of `WillOnce()` clauses followed by an optional `WillRepeatedly()`. For example,
```
using ::testing::Return;...
EXPECT_CALL(turtle, GetX())
.WillOnce(Return(100))
.WillOnce(Return(200))
.WillOnce(Return(300));
```
This says that `turtle.GetX()` will be called _exactly three times_ (Google Mock inferred this from how many `WillOnce()` clauses we've written, since we didn't explicitly write `Times()`), and will return 100, 200, and 300 respectively.
```
using ::testing::Return;...
EXPECT_CALL(turtle, GetY())
.WillOnce(Return(100))
.WillOnce(Return(200))
.WillRepeatedly(Return(300));
```
says that `turtle.GetY()` will be called _at least twice_ (Google Mock knows this as we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no explicit `Times()`), will return 100 the first time, 200 the second time, and 300 from the third time on.
Of course, if you explicitly write a `Times()`, Google Mock will not try to infer the cardinality itself. What if the number you specified is larger than there are `WillOnce()` clauses? Well, after all `WillOnce()`s are used up, Google Mock will do the _default_ action for the function every time (unless, of course, you have a `WillRepeatedly()`.).
What can we do inside `WillOnce()` besides `Return()`? You can return a reference using `ReturnRef(variable)`, or invoke a pre-defined function, among [others](http://code.google.com/p/googlemock/wiki/V1_6_CheatSheet#Actions).
**Important note:** The `EXPECT_CALL()` statement evaluates the action clause only once, even though the action may be performed many times. Therefore you must be careful about side effects. The following may not do what you want:
```
int n = 100;
EXPECT_CALL(turtle, GetX())
.Times(4)
.WillRepeatedly(Return(n++));
```
Instead of returning 100, 101, 102, ..., consecutively, this mock function will always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)` will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will return the same pointer every time. If you want the side effect to happen every time, you need to define a custom action, which we'll teach in the [CookBook](V1_6_CookBook.md).
Time for another quiz! What do you think the following means?
```
using ::testing::Return;...
EXPECT_CALL(turtle, GetY())
.Times(4)
.WillOnce(Return(100));
```
Obviously `turtle.GetY()` is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that one `WillOnce()` clause will be consumed each time the function is invoked and the default action will be taken afterwards. So the right answer is that `turtle.GetY()` will return 100 the first time, but **return 0 from the second time on**, as returning 0 is the default action for `int` functions.
## Using Multiple Expectations ##
So far we've only shown examples where you have a single expectation. More realistically, you're going to specify expectations on multiple mock methods, which may be from multiple mock objects.
By default, when a mock method is invoked, Google Mock will search the expectations in the **reverse order** they are defined, and stop when an active expectation that matches the arguments is found (you can think of it as "newer rules override older ones."). If the matching expectation cannot take any more calls, you will get an upper-bound-violated failure. Here's an example:
```
using ::testing::_;...
EXPECT_CALL(turtle, Forward(_)); // #1
EXPECT_CALL(turtle, Forward(10)) // #2
.Times(2);
```
If `Forward(10)` is called three times in a row, the third time it will be an error, as the last matching expectation (#2) has been saturated. If, however, the third `Forward(10)` call is replaced by `Forward(20)`, then it would be OK, as now #1 will be the matching expectation.
**Side note:** Why does Google Mock search for a match in the _reverse_ order of the expectations? The reason is that this allows a user to set up the default expectations in a mock object's constructor or the test fixture's set-up phase and then customize the mock by writing more specific expectations in the test body. So, if you have two expectations on the same method, you want to put the one with more specific matchers **after** the other, or the more specific rule would be shadowed by the more general one that comes after it.
## Ordered vs Unordered Calls ##
By default, an expectation can match a call even though an earlier expectation hasn't been satisfied. In other words, the calls don't have to occur in the order the expectations are specified.
Sometimes, you may want all the expected calls to occur in a strict order. To say this in Google Mock is easy:
```
using ::testing::InSequence;...
TEST(FooTest, DrawsLineSegment) {
...
{
InSequence dummy;
EXPECT_CALL(turtle, PenDown());
EXPECT_CALL(turtle, Forward(100));
EXPECT_CALL(turtle, PenUp());
}
Foo();
}
```
By creating an object of type `InSequence`, all expectations in its scope are put into a _sequence_ and have to occur _sequentially_. Since we are just relying on the constructor and destructor of this object to do the actual work, its name is really irrelevant.
In this example, we test that `Foo()` calls the three expected functions in the order as written. If a call is made out-of-order, it will be an error.
(What if you care about the relative order of some of the calls, but not all of them? Can you specify an arbitrary partial order? The answer is ... yes! If you are impatient, the details can be found in the [CookBook](V1_6_CookBook.md).)
## All Expectations Are Sticky (Unless Said Otherwise) ##
Now let's do a quick quiz to see how well you can use this mock stuff already. How would you test that the turtle is asked to go to the origin _exactly twice_ (you want to ignore any other instructions it receives)?
After you've come up with your answer, take a look at ours and compare notes (solve it yourself first - don't cheat!):
```
using ::testing::_;...
EXPECT_CALL(turtle, GoTo(_, _)) // #1
.Times(AnyNumber());
EXPECT_CALL(turtle, GoTo(0, 0)) // #2
.Times(2);
```
Suppose `turtle.GoTo(0, 0)` is called three times. In the third time, Google Mock will see that the arguments match expectation #2 (remember that we always pick the last matching expectation). Now, since we said that there should be only two such calls, Google Mock will report an error immediately. This is basically what we've told you in the "Using Multiple Expectations" section above.
This example shows that **expectations in Google Mock are "sticky" by default**, in the sense that they remain active even after we have reached their invocation upper bounds. This is an important rule to remember, as it affects the meaning of the spec, and is **different** to how it's done in many other mocking frameworks (Why'd we do that? Because we think our rule makes the common cases easier to express and understand.).
Simple? Let's see if you've really understood it: what does the following code say?
```
using ::testing::Return;
...
for (int i = n; i > 0; i--) {
EXPECT_CALL(turtle, GetX())
.WillOnce(Return(10*i));
}
```
If you think it says that `turtle.GetX()` will be called `n` times and will return 10, 20, 30, ..., consecutively, think twice! The problem is that, as we said, expectations are sticky. So, the second time `turtle.GetX()` is called, the last (latest) `EXPECT_CALL()` statement will match, and will immediately lead to an "upper bound exceeded" error - this piece of code is not very useful!
One correct way of saying that `turtle.GetX()` will return 10, 20, 30, ..., is to explicitly say that the expectations are _not_ sticky. In other words, they should _retire_ as soon as they are saturated:
```
using ::testing::Return;
...
for (int i = n; i > 0; i--) {
EXPECT_CALL(turtle, GetX())
.WillOnce(Return(10*i))
.RetiresOnSaturation();
}
```
And, there's a better way to do it: in this case, we expect the calls to occur in a specific order, and we line up the actions to match the order. Since the order is important here, we should make it explicit using a sequence:
```
using ::testing::InSequence;
using ::testing::Return;
...
{
InSequence s;
for (int i = 1; i <= n; i++) {
EXPECT_CALL(turtle, GetX())
.WillOnce(Return(10*i))
.RetiresOnSaturation();
}
}
```
By the way, the other situation where an expectation may _not_ be sticky is when it's in a sequence - as soon as another expectation that comes after it in the sequence has been used, it automatically retires (and will never be used to match any call).
## Uninteresting Calls ##
A mock object may have many methods, and not all of them are that interesting. For example, in some tests we may not care about how many times `GetX()` and `GetY()` get called.
In Google Mock, if you are not interested in a method, just don't say anything about it. If a call to this method occurs, you'll see a warning in the test output, but it won't be a failure.
# What Now? #
Congratulations! You've learned enough about Google Mock to start using it. Now, you might want to join the [googlemock](http://groups.google.com/group/googlemock) discussion group and actually write some tests using Google Mock - it will be fun. Hey, it may even be addictive - you've been warned.
Then, if you feel like increasing your mock quotient, you should move on to the [CookBook](V1_6_CookBook.md). You can learn many advanced features of Google Mock there -- and advance your level of enjoyment and testing bliss.

View File

@ -1,628 +0,0 @@
Please send your questions to the
[googlemock](http://groups.google.com/group/googlemock) discussion
group. If you need help with compiler errors, make sure you have
tried [Google Mock Doctor](#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md) first.
## When I call a method on my mock object, the method for the real object is invoked instead. What's the problem? ##
In order for a method to be mocked, it must be _virtual_, unless you use the [high-perf dependency injection technique](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Mocking_Nonvirtual_Methods).
## I wrote some matchers. After I upgraded to a new version of Google Mock, they no longer compile. What's going on? ##
After version 1.4.0 of Google Mock was released, we had an idea on how
to make it easier to write matchers that can generate informative
messages efficiently. We experimented with this idea and liked what
we saw. Therefore we decided to implement it.
Unfortunately, this means that if you have defined your own matchers
by implementing `MatcherInterface` or using `MakePolymorphicMatcher()`,
your definitions will no longer compile. Matchers defined using the
`MATCHER*` family of macros are not affected.
Sorry for the hassle if your matchers are affected. We believe it's
in everyone's long-term interest to make this change sooner than
later. Fortunately, it's usually not hard to migrate an existing
matcher to the new API. Here's what you need to do:
If you wrote your matcher like this:
```
// Old matcher definition that doesn't work with the latest
// Google Mock.
using ::testing::MatcherInterface;
...
class MyWonderfulMatcher : public MatcherInterface<MyType> {
public:
...
virtual bool Matches(MyType value) const {
// Returns true if value matches.
return value.GetFoo() > 5;
}
...
};
```
you'll need to change it to:
```
// New matcher definition that works with the latest Google Mock.
using ::testing::MatcherInterface;
using ::testing::MatchResultListener;
...
class MyWonderfulMatcher : public MatcherInterface<MyType> {
public:
...
virtual bool MatchAndExplain(MyType value,
MatchResultListener* listener) const {
// Returns true if value matches.
return value.GetFoo() > 5;
}
...
};
```
(i.e. rename `Matches()` to `MatchAndExplain()` and give it a second
argument of type `MatchResultListener*`.)
If you were also using `ExplainMatchResultTo()` to improve the matcher
message:
```
// Old matcher definition that doesn't work with the lastest
// Google Mock.
using ::testing::MatcherInterface;
...
class MyWonderfulMatcher : public MatcherInterface<MyType> {
public:
...
virtual bool Matches(MyType value) const {
// Returns true if value matches.
return value.GetFoo() > 5;
}
virtual void ExplainMatchResultTo(MyType value,
::std::ostream* os) const {
// Prints some helpful information to os to help
// a user understand why value matches (or doesn't match).
*os << "the Foo property is " << value.GetFoo();
}
...
};
```
you should move the logic of `ExplainMatchResultTo()` into
`MatchAndExplain()`, using the `MatchResultListener` argument where
the `::std::ostream` was used:
```
// New matcher definition that works with the latest Google Mock.
using ::testing::MatcherInterface;
using ::testing::MatchResultListener;
...
class MyWonderfulMatcher : public MatcherInterface<MyType> {
public:
...
virtual bool MatchAndExplain(MyType value,
MatchResultListener* listener) const {
// Returns true if value matches.
*listener << "the Foo property is " << value.GetFoo();
return value.GetFoo() > 5;
}
...
};
```
If your matcher is defined using `MakePolymorphicMatcher()`:
```
// Old matcher definition that doesn't work with the latest
// Google Mock.
using ::testing::MakePolymorphicMatcher;
...
class MyGreatMatcher {
public:
...
bool Matches(MyType value) const {
// Returns true if value matches.
return value.GetBar() < 42;
}
...
};
... MakePolymorphicMatcher(MyGreatMatcher()) ...
```
you should rename the `Matches()` method to `MatchAndExplain()` and
add a `MatchResultListener*` argument (the same as what you need to do
for matchers defined by implementing `MatcherInterface`):
```
// New matcher definition that works with the latest Google Mock.
using ::testing::MakePolymorphicMatcher;
using ::testing::MatchResultListener;
...
class MyGreatMatcher {
public:
...
bool MatchAndExplain(MyType value,
MatchResultListener* listener) const {
// Returns true if value matches.
return value.GetBar() < 42;
}
...
};
... MakePolymorphicMatcher(MyGreatMatcher()) ...
```
If your polymorphic matcher uses `ExplainMatchResultTo()` for better
failure messages:
```
// Old matcher definition that doesn't work with the latest
// Google Mock.
using ::testing::MakePolymorphicMatcher;
...
class MyGreatMatcher {
public:
...
bool Matches(MyType value) const {
// Returns true if value matches.
return value.GetBar() < 42;
}
...
};
void ExplainMatchResultTo(const MyGreatMatcher& matcher,
MyType value,
::std::ostream* os) {
// Prints some helpful information to os to help
// a user understand why value matches (or doesn't match).
*os << "the Bar property is " << value.GetBar();
}
... MakePolymorphicMatcher(MyGreatMatcher()) ...
```
you'll need to move the logic inside `ExplainMatchResultTo()` to
`MatchAndExplain()`:
```
// New matcher definition that works with the latest Google Mock.
using ::testing::MakePolymorphicMatcher;
using ::testing::MatchResultListener;
...
class MyGreatMatcher {
public:
...
bool MatchAndExplain(MyType value,
MatchResultListener* listener) const {
// Returns true if value matches.
*listener << "the Bar property is " << value.GetBar();
return value.GetBar() < 42;
}
...
};
... MakePolymorphicMatcher(MyGreatMatcher()) ...
```
For more information, you can read these
[two](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Writing_New_Monomorphic_Matchers)
[recipes](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Writing_New_Polymorphic_Matchers)
from the cookbook. As always, you
are welcome to post questions on `googlemock@googlegroups.com` if you
need any help.
## When using Google Mock, do I have to use Google Test as the testing framework? I have my favorite testing framework and don't want to switch. ##
Google Mock works out of the box with Google Test. However, it's easy
to configure it to work with any testing framework of your choice.
[Here](http://code.google.com/p/googlemock/wiki/V1_6_ForDummies#Using_Google_Mock_with_Any_Testing_Framework) is how.
## How am I supposed to make sense of these horrible template errors? ##
If you are confused by the compiler errors gcc threw at you,
try consulting the _Google Mock Doctor_ tool first. What it does is to
scan stdin for gcc error messages, and spit out diagnoses on the
problems (we call them diseases) your code has.
To "install", run command:
```
alias gmd='<path to googlemock>/scripts/gmock_doctor.py'
```
To use it, do:
```
<your-favorite-build-command> <your-test> 2>&1 | gmd
```
For example:
```
make my_test 2>&1 | gmd
```
Or you can run `gmd` and copy-n-paste gcc's error messages to it.
## Can I mock a variadic function? ##
You cannot mock a variadic function (i.e. a function taking ellipsis
(`...`) arguments) directly in Google Mock.
The problem is that in general, there is _no way_ for a mock object to
know how many arguments are passed to the variadic method, and what
the arguments' types are. Only the _author of the base class_ knows
the protocol, and we cannot look into his head.
Therefore, to mock such a function, the _user_ must teach the mock
object how to figure out the number of arguments and their types. One
way to do it is to provide overloaded versions of the function.
Ellipsis arguments are inherited from C and not really a C++ feature.
They are unsafe to use and don't work with arguments that have
constructors or destructors. Therefore we recommend to avoid them in
C++ as much as possible.
## MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter. Why? ##
If you compile this using Microsoft Visual C++ 2005 SP1:
```
class Foo {
...
virtual void Bar(const int i) = 0;
};
class MockFoo : public Foo {
...
MOCK_METHOD1(Bar, void(const int i));
};
```
You may get the following warning:
```
warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier
```
This is a MSVC bug. The same code compiles fine with gcc ,for
example. If you use Visual C++ 2008 SP1, you would get the warning:
```
warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers
```
In C++, if you _declare_ a function with a `const` parameter, the
`const` modifier is _ignored_. Therefore, the `Foo` base class above
is equivalent to:
```
class Foo {
...
virtual void Bar(int i) = 0; // int or const int? Makes no difference.
};
```
In fact, you can _declare_ Bar() with an `int` parameter, and _define_
it with a `const int` parameter. The compiler will still match them
up.
Since making a parameter `const` is meaningless in the method
_declaration_, we recommend to remove it in both `Foo` and `MockFoo`.
That should workaround the VC bug.
Note that we are talking about the _top-level_ `const` modifier here.
If the function parameter is passed by pointer or reference, declaring
the _pointee_ or _referee_ as `const` is still meaningful. For
example, the following two declarations are _not_ equivalent:
```
void Bar(int* p); // Neither p nor *p is const.
void Bar(const int* p); // p is not const, but *p is.
```
## I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it. What can I do? ##
We've noticed that when the `/clr` compiler flag is used, Visual C++
uses 5~6 times as much memory when compiling a mock class. We suggest
to avoid `/clr` when compiling native C++ mocks.
## I can't figure out why Google Mock thinks my expectations are not satisfied. What should I do? ##
You might want to run your test with
`--gmock_verbose=info`. This flag lets Google Mock print a trace
of every mock function call it receives. By studying the trace,
you'll gain insights on why the expectations you set are not met.
## How can I assert that a function is NEVER called? ##
```
EXPECT_CALL(foo, Bar(_))
.Times(0);
```
## I have a failed test where Google Mock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant? ##
When Google Mock detects a failure, it prints relevant information
(the mock function arguments, the state of relevant expectations, and
etc) to help the user debug. If another failure is detected, Google
Mock will do the same, including printing the state of relevant
expectations.
Sometimes an expectation's state didn't change between two failures,
and you'll see the same description of the state twice. They are
however _not_ redundant, as they refer to _different points in time_.
The fact they are the same _is_ interesting information.
## I get a heap check failure when using a mock object, but using a real object is fine. What can be wrong? ##
Does the class (hopefully a pure interface) you are mocking have a
virtual destructor?
Whenever you derive from a base class, make sure its destructor is
virtual. Otherwise Bad Things will happen. Consider the following
code:
```
class Base {
public:
// Not virtual, but should be.
~Base() { ... }
...
};
class Derived : public Base {
public:
...
private:
std::string value_;
};
...
Base* p = new Derived;
...
delete p; // Surprise! ~Base() will be called, but ~Derived() will not
// - value_ is leaked.
```
By changing `~Base()` to virtual, `~Derived()` will be correctly
called when `delete p` is executed, and the heap checker
will be happy.
## The "newer expectations override older ones" rule makes writing expectations awkward. Why does Google Mock do that? ##
When people complain about this, often they are referring to code like:
```
// foo.Bar() should be called twice, return 1 the first time, and return
// 2 the second time. However, I have to write the expectations in the
// reverse order. This sucks big time!!!
EXPECT_CALL(foo, Bar())
.WillOnce(Return(2))
.RetiresOnSaturation();
EXPECT_CALL(foo, Bar())
.WillOnce(Return(1))
.RetiresOnSaturation();
```
The problem is that they didn't pick the **best** way to express the test's
intent.
By default, expectations don't have to be matched in _any_ particular
order. If you want them to match in a certain order, you need to be
explicit. This is Google Mock's (and jMock's) fundamental philosophy: it's
easy to accidentally over-specify your tests, and we want to make it
harder to do so.
There are two better ways to write the test spec. You could either
put the expectations in sequence:
```
// foo.Bar() should be called twice, return 1 the first time, and return
// 2 the second time. Using a sequence, we can write the expectations
// in their natural order.
{
InSequence s;
EXPECT_CALL(foo, Bar())
.WillOnce(Return(1))
.RetiresOnSaturation();
EXPECT_CALL(foo, Bar())
.WillOnce(Return(2))
.RetiresOnSaturation();
}
```
or you can put the sequence of actions in the same expectation:
```
// foo.Bar() should be called twice, return 1 the first time, and return
// 2 the second time.
EXPECT_CALL(foo, Bar())
.WillOnce(Return(1))
.WillOnce(Return(2))
.RetiresOnSaturation();
```
Back to the original questions: why does Google Mock search the
expectations (and `ON_CALL`s) from back to front? Because this
allows a user to set up a mock's behavior for the common case early
(e.g. in the mock's constructor or the test fixture's set-up phase)
and customize it with more specific rules later. If Google Mock
searches from front to back, this very useful pattern won't be
possible.
## Google Mock prints a warning when a function without EXPECT\_CALL is called, even if I have set its behavior using ON\_CALL. Would it be reasonable not to show the warning in this case? ##
When choosing between being neat and being safe, we lean toward the
latter. So the answer is that we think it's better to show the
warning.
Often people write `ON_CALL`s in the mock object's
constructor or `SetUp()`, as the default behavior rarely changes from
test to test. Then in the test body they set the expectations, which
are often different for each test. Having an `ON_CALL` in the set-up
part of a test doesn't mean that the calls are expected. If there's
no `EXPECT_CALL` and the method is called, it's possibly an error. If
we quietly let the call go through without notifying the user, bugs
may creep in unnoticed.
If, however, you are sure that the calls are OK, you can write
```
EXPECT_CALL(foo, Bar(_))
.WillRepeatedly(...);
```
instead of
```
ON_CALL(foo, Bar(_))
.WillByDefault(...);
```
This tells Google Mock that you do expect the calls and no warning should be
printed.
Also, you can control the verbosity using the `--gmock_verbose` flag.
If you find the output too noisy when debugging, just choose a less
verbose level.
## How can I delete the mock function's argument in an action? ##
If you find yourself needing to perform some action that's not
supported by Google Mock directly, remember that you can define your own
actions using
[MakeAction()](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Writing_New_Actions) or
[MakePolymorphicAction()](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Writing_New_Polymorphic_Actions),
or you can write a stub function and invoke it using
[Invoke()](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Using_Functions_Methods_Functors).
## MOCK\_METHODn()'s second argument looks funny. Why don't you use the MOCK\_METHODn(Method, return\_type, arg\_1, ..., arg\_n) syntax? ##
What?! I think it's beautiful. :-)
While which syntax looks more natural is a subjective matter to some
extent, Google Mock's syntax was chosen for several practical advantages it
has.
Try to mock a function that takes a map as an argument:
```
virtual int GetSize(const map<int, std::string>& m);
```
Using the proposed syntax, it would be:
```
MOCK_METHOD1(GetSize, int, const map<int, std::string>& m);
```
Guess what? You'll get a compiler error as the compiler thinks that
`const map<int, std::string>& m` are **two**, not one, arguments. To work
around this you can use `typedef` to give the map type a name, but
that gets in the way of your work. Google Mock's syntax avoids this
problem as the function's argument types are protected inside a pair
of parentheses:
```
// This compiles fine.
MOCK_METHOD1(GetSize, int(const map<int, std::string>& m));
```
You still need a `typedef` if the return type contains an unprotected
comma, but that's much rarer.
Other advantages include:
1. `MOCK_METHOD1(Foo, int, bool)` can leave a reader wonder whether the method returns `int` or `bool`, while there won't be such confusion using Google Mock's syntax.
1. The way Google Mock describes a function type is nothing new, although many people may not be familiar with it. The same syntax was used in C, and the `function` library in `tr1` uses this syntax extensively. Since `tr1` will become a part of the new version of STL, we feel very comfortable to be consistent with it.
1. The function type syntax is also used in other parts of Google Mock's API (e.g. the action interface) in order to make the implementation tractable. A user needs to learn it anyway in order to utilize Google Mock's more advanced features. We'd as well stick to the same syntax in `MOCK_METHOD*`!
## My code calls a static/global function. Can I mock it? ##
You can, but you need to make some changes.
In general, if you find yourself needing to mock a static function,
it's a sign that your modules are too tightly coupled (and less
flexible, less reusable, less testable, etc). You are probably better
off defining a small interface and call the function through that
interface, which then can be easily mocked. It's a bit of work
initially, but usually pays for itself quickly.
This Google Testing Blog
[post](http://googletesting.blogspot.com/2008/06/defeat-static-cling.html)
says it excellently. Check it out.
## My mock object needs to do complex stuff. It's a lot of pain to specify the actions. Google Mock sucks! ##
I know it's not a question, but you get an answer for free any way. :-)
With Google Mock, you can create mocks in C++ easily. And people might be
tempted to use them everywhere. Sometimes they work great, and
sometimes you may find them, well, a pain to use. So, what's wrong in
the latter case?
When you write a test without using mocks, you exercise the code and
assert that it returns the correct value or that the system is in an
expected state. This is sometimes called "state-based testing".
Mocks are great for what some call "interaction-based" testing:
instead of checking the system state at the very end, mock objects
verify that they are invoked the right way and report an error as soon
as it arises, giving you a handle on the precise context in which the
error was triggered. This is often more effective and economical to
do than state-based testing.
If you are doing state-based testing and using a test double just to
simulate the real object, you are probably better off using a fake.
Using a mock in this case causes pain, as it's not a strong point for
mocks to perform complex actions. If you experience this and think
that mocks suck, you are just not using the right tool for your
problem. Or, you might be trying to solve the wrong problem. :-)
## I got a warning "Uninteresting function call encountered - default action taken.." Should I panic? ##
By all means, NO! It's just an FYI.
What it means is that you have a mock function, you haven't set any
expectations on it (by Google Mock's rule this means that you are not
interested in calls to this function and therefore it can be called
any number of times), and it is called. That's OK - you didn't say
it's not OK to call the function!
What if you actually meant to disallow this function to be called, but
forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`? While
one can argue that it's the user's fault, Google Mock tries to be nice and
prints you a note.
So, when you see the message and believe that there shouldn't be any
uninteresting calls, you should investigate what's going on. To make
your life easier, Google Mock prints the function name and arguments
when an uninteresting call is encountered.
## I want to define a custom action. Should I use Invoke() or implement the action interface? ##
Either way is fine - you want to choose the one that's more convenient
for your circumstance.
Usually, if your action is for a particular function type, defining it
using `Invoke()` should be easier; if your action can be used in
functions of different types (e.g. if you are defining
`Return(value)`), `MakePolymorphicAction()` is
easiest. Sometimes you want precise control on what types of
functions the action can be used in, and implementing
`ActionInterface` is the way to go here. See the implementation of
`Return()` in `include/gmock/gmock-actions.h` for an example.
## I'm using the set-argument-pointee action, and the compiler complains about "conflicting return type specified". What does it mean? ##
You got this error as Google Mock has no idea what value it should return
when the mock method is called. `SetArgPointee()` says what the
side effect is, but doesn't say what the return value should be. You
need `DoAll()` to chain a `SetArgPointee()` with a `Return()`.
See this [recipe](http://code.google.com/p/googlemock/wiki/V1_6_CookBook#Mocking_Side_Effects) for more details and an example.
## My question is not in your FAQ! ##
If you cannot find the answer to your question in this FAQ, there are
some other resources you can use:
1. read other [wiki pages](http://code.google.com/p/googlemock/w/list),
1. search the mailing list [archive](http://groups.google.com/group/googlemock/topics),
1. ask it on [googlemock@googlegroups.com](mailto:googlemock@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googlemock) before you can post.).
Please note that creating an issue in the
[issue tracker](http://code.google.com/p/googlemock/issues/list) is _not_
a good way to get your answer, as it is monitored infrequently by a
very small number of people.
When asking a question, it's helpful to provide as much of the
following information as possible (people cannot help you if there's
not enough information in your question):
* the version (or the revision number if you check out from SVN directly) of Google Mock you use (Google Mock is under active development, so it's possible that your problem has been solved in a later version),
* your operating system,
* the name and version of your compiler,
* the complete command line flags you give to your compiler,
* the complete compiler error messages (if the question is about compilation),
* the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter.

View File

@ -1,556 +0,0 @@
# Defining a Mock Class #
## Mocking a Normal Class ##
Given
```
class Foo {
...
virtual ~Foo();
virtual int GetSize() const = 0;
virtual string Describe(const char* name) = 0;
virtual string Describe(int type) = 0;
virtual bool Process(Bar elem, int count) = 0;
};
```
(note that `~Foo()` **must** be virtual) we can define its mock as
```
#include "gmock/gmock.h"
class MockFoo : public Foo {
MOCK_CONST_METHOD0(GetSize, int());
MOCK_METHOD1(Describe, string(const char* name));
MOCK_METHOD1(Describe, string(int type));
MOCK_METHOD2(Process, bool(Bar elem, int count));
};
```
To create a "nice" mock object which ignores all uninteresting calls,
or a "strict" mock object, which treats them as failures:
```
NiceMock<MockFoo> nice_foo; // The type is a subclass of MockFoo.
StrictMock<MockFoo> strict_foo; // The type is a subclass of MockFoo.
```
## Mocking a Class Template ##
To mock
```
template <typename Elem>
class StackInterface {
public:
...
virtual ~StackInterface();
virtual int GetSize() const = 0;
virtual void Push(const Elem& x) = 0;
};
```
(note that `~StackInterface()` **must** be virtual) just append `_T` to the `MOCK_*` macros:
```
template <typename Elem>
class MockStack : public StackInterface<Elem> {
public:
...
MOCK_CONST_METHOD0_T(GetSize, int());
MOCK_METHOD1_T(Push, void(const Elem& x));
};
```
## Specifying Calling Conventions for Mock Functions ##
If your mock function doesn't use the default calling convention, you
can specify it by appending `_WITH_CALLTYPE` to any of the macros
described in the previous two sections and supplying the calling
convention as the first argument to the macro. For example,
```
MOCK_METHOD_1_WITH_CALLTYPE(STDMETHODCALLTYPE, Foo, bool(int n));
MOCK_CONST_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, Bar, int(double x, double y));
```
where `STDMETHODCALLTYPE` is defined by `<objbase.h>` on Windows.
# Using Mocks in Tests #
The typical flow is:
1. Import the Google Mock names you need to use. All Google Mock names are in the `testing` namespace unless they are macros or otherwise noted.
1. Create the mock objects.
1. Optionally, set the default actions of the mock objects.
1. Set your expectations on the mock objects (How will they be called? What wil they do?).
1. Exercise code that uses the mock objects; if necessary, check the result using [Google Test](http://code.google.com/p/googletest/) assertions.
1. When a mock objects is destructed, Google Mock automatically verifies that all expectations on it have been satisfied.
Here is an example:
```
using ::testing::Return; // #1
TEST(BarTest, DoesThis) {
MockFoo foo; // #2
ON_CALL(foo, GetSize()) // #3
.WillByDefault(Return(1));
// ... other default actions ...
EXPECT_CALL(foo, Describe(5)) // #4
.Times(3)
.WillRepeatedly(Return("Category 5"));
// ... other expectations ...
EXPECT_EQ("good", MyProductionFunction(&foo)); // #5
} // #6
```
# Setting Default Actions #
Google Mock has a **built-in default action** for any function that
returns `void`, `bool`, a numeric value, or a pointer.
To customize the default action for functions with return type `T` globally:
```
using ::testing::DefaultValue;
DefaultValue<T>::Set(value); // Sets the default value to be returned.
// ... use the mocks ...
DefaultValue<T>::Clear(); // Resets the default value.
```
To customize the default action for a particular method, use `ON_CALL()`:
```
ON_CALL(mock_object, method(matchers))
.With(multi_argument_matcher) ?
.WillByDefault(action);
```
# Setting Expectations #
`EXPECT_CALL()` sets **expectations** on a mock method (How will it be
called? What will it do?):
```
EXPECT_CALL(mock_object, method(matchers))
.With(multi_argument_matcher) ?
.Times(cardinality) ?
.InSequence(sequences) *
.After(expectations) *
.WillOnce(action) *
.WillRepeatedly(action) ?
.RetiresOnSaturation(); ?
```
If `Times()` is omitted, the cardinality is assumed to be:
* `Times(1)` when there is neither `WillOnce()` nor `WillRepeatedly()`;
* `Times(n)` when there are `n WillOnce()`s but no `WillRepeatedly()`, where `n` >= 1; or
* `Times(AtLeast(n))` when there are `n WillOnce()`s and a `WillRepeatedly()`, where `n` >= 0.
A method with no `EXPECT_CALL()` is free to be invoked _any number of times_, and the default action will be taken each time.
# Matchers #
A **matcher** matches a _single_ argument. You can use it inside
`ON_CALL()` or `EXPECT_CALL()`, or use it to validate a value
directly:
| `EXPECT_THAT(value, matcher)` | Asserts that `value` matches `matcher`. |
|:------------------------------|:----------------------------------------|
| `ASSERT_THAT(value, matcher)` | The same as `EXPECT_THAT(value, matcher)`, except that it generates a **fatal** failure. |
Built-in matchers (where `argument` is the function argument) are
divided into several categories:
## Wildcard ##
|`_`|`argument` can be any value of the correct type.|
|:--|:-----------------------------------------------|
|`A<type>()` or `An<type>()`|`argument` can be any value of type `type`. |
## Generic Comparison ##
|`Eq(value)` or `value`|`argument == value`|
|:---------------------|:------------------|
|`Ge(value)` |`argument >= value`|
|`Gt(value)` |`argument > value` |
|`Le(value)` |`argument <= value`|
|`Lt(value)` |`argument < value` |
|`Ne(value)` |`argument != value`|
|`IsNull()` |`argument` is a `NULL` pointer (raw or smart).|
|`NotNull()` |`argument` is a non-null pointer (raw or smart).|
|`Ref(variable)` |`argument` is a reference to `variable`.|
|`TypedEq<type>(value)`|`argument` has type `type` and is equal to `value`. You may need to use this instead of `Eq(value)` when the mock function is overloaded.|
Except `Ref()`, these matchers make a _copy_ of `value` in case it's
modified or destructed later. If the compiler complains that `value`
doesn't have a public copy constructor, try wrap it in `ByRef()`,
e.g. `Eq(ByRef(non_copyable_value))`. If you do that, make sure
`non_copyable_value` is not changed afterwards, or the meaning of your
matcher will be changed.
## Floating-Point Matchers ##
|`DoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as unequal.|
|:-------------------|:----------------------------------------------------------------------------------------------|
|`FloatEq(a_float)` |`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as unequal. |
|`NanSensitiveDoubleEq(a_double)`|`argument` is a `double` value approximately equal to `a_double`, treating two NaNs as equal. |
|`NanSensitiveFloatEq(a_float)`|`argument` is a `float` value approximately equal to `a_float`, treating two NaNs as equal. |
The above matchers use ULP-based comparison (the same as used in
[Google Test](http://code.google.com/p/googletest/)). They
automatically pick a reasonable error bound based on the absolute
value of the expected value. `DoubleEq()` and `FloatEq()` conform to
the IEEE standard, which requires comparing two NaNs for equality to
return false. The `NanSensitive*` version instead treats two NaNs as
equal, which is often what a user wants.
|`DoubleNear(a_double, max_abs_error)`|`argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as unequal.|
|:------------------------------------|:--------------------------------------------------------------------------------------------------------------------|
|`FloatNear(a_float, max_abs_error)` |`argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as unequal. |
|`NanSensitiveDoubleNear(a_double, max_abs_error)`|`argument` is a `double` value close to `a_double` (absolute error <= `max_abs_error`), treating two NaNs as equal. |
|`NanSensitiveFloatNear(a_float, max_abs_error)`|`argument` is a `float` value close to `a_float` (absolute error <= `max_abs_error`), treating two NaNs as equal. |
## String Matchers ##
The `argument` can be either a C string or a C++ string object:
|`ContainsRegex(string)`|`argument` matches the given regular expression.|
|:----------------------|:-----------------------------------------------|
|`EndsWith(suffix)` |`argument` ends with string `suffix`. |
|`HasSubstr(string)` |`argument` contains `string` as a sub-string. |
|`MatchesRegex(string)` |`argument` matches the given regular expression with the match starting at the first character and ending at the last character.|
|`StartsWith(prefix)` |`argument` starts with string `prefix`. |
|`StrCaseEq(string)` |`argument` is equal to `string`, ignoring case. |
|`StrCaseNe(string)` |`argument` is not equal to `string`, ignoring case.|
|`StrEq(string)` |`argument` is equal to `string`. |
|`StrNe(string)` |`argument` is not equal to `string`. |
`ContainsRegex()` and `MatchesRegex()` use the regular expression
syntax defined
[here](http://code.google.com/p/googletest/wiki/AdvancedGuide#Regular_Expression_Syntax).
`StrCaseEq()`, `StrCaseNe()`, `StrEq()`, and `StrNe()` work for wide
strings as well.
## Container Matchers ##
Most STL-style containers support `==`, so you can use
`Eq(expected_container)` or simply `expected_container` to match a
container exactly. If you want to write the elements in-line,
match them more flexibly, or get more informative messages, you can use:
| `ContainerEq(container)` | The same as `Eq(container)` except that the failure message also includes which elements are in one container but not the other. |
|:-------------------------|:---------------------------------------------------------------------------------------------------------------------------------|
| `Contains(e)` | `argument` contains an element that matches `e`, which can be either a value or a matcher. |
| `Each(e)` | `argument` is a container where _every_ element matches `e`, which can be either a value or a matcher. |
| `ElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, where the i-th element matches `ei`, which can be a value or a matcher. 0 to 10 arguments are allowed. |
| `ElementsAreArray({ e0, e1, ..., en })`, `ElementsAreArray(array)`, or `ElementsAreArray(array, count)` | The same as `ElementsAre()` except that the expected element values/matchers come from an initializer list, vector, or C-style array. |
| `IsEmpty()` | `argument` is an empty container (`container.empty()`). |
| `Pointwise(m, container)` | `argument` contains the same number of elements as in `container`, and for all i, (the i-th element in `argument`, the i-th element in `container`) match `m`, which is a matcher on 2-tuples. E.g. `Pointwise(Le(), upper_bounds)` verifies that each element in `argument` doesn't exceed the corresponding element in `upper_bounds`. See more detail below. |
| `SizeIs(m)` | `argument` is a container whose size matches `m`. E.g. `SizeIs(2)` or `SizeIs(Lt(2))`. |
| `UnorderedElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, and under some permutation each element matches an `ei` (for a different `i`), which can be a value or a matcher. 0 to 10 arguments are allowed. |
| `UnorderedElementsAreArray({ e0, e1, ..., en })`, `UnorderedElementsAreArray(array)`, or `UnorderedElementsAreArray(array, count)` | The same as `UnorderedElementsAre()` except that the expected element values/matchers come from an initializer list, vector, or C-style array. |
| `WhenSorted(m)` | When `argument` is sorted using the `<` operator, it matches container matcher `m`. E.g. `WhenSorted(UnorderedElementsAre(1, 2, 3))` verifies that `argument` contains elements `1`, `2`, and `3`, ignoring order. |
| `WhenSortedBy(comparator, m)` | The same as `WhenSorted(m)`, except that the given comparator instead of `<` is used to sort `argument`. E.g. `WhenSortedBy(std::greater<int>(), ElementsAre(3, 2, 1))`. |
Notes:
* These matchers can also match:
1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`), and
1. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer, int len)` -- see [Multi-argument Matchers](#Multiargument_Matchers.md)).
* The array being matched may be multi-dimensional (i.e. its elements can be arrays).
* `m` in `Pointwise(m, ...)` should be a matcher for `std::tr1::tuple<T, U>` where `T` and `U` are the element type of the actual container and the expected container, respectively. For example, to compare two `Foo` containers where `Foo` doesn't support `operator==` but has an `Equals()` method, one might write:
```
using ::std::tr1::get;
MATCHER(FooEq, "") {
return get<0>(arg).Equals(get<1>(arg));
}
...
EXPECT_THAT(actual_foos, Pointwise(FooEq(), expected_foos));
```
## Member Matchers ##
|`Field(&class::field, m)`|`argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.|
|:------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------|
|`Key(e)` |`argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`.|
|`Pair(m1, m2)` |`argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. |
|`Property(&class::property, m)`|`argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_.|
## Matching the Result of a Function or Functor ##
|`ResultOf(f, m)`|`f(argument)` matches matcher `m`, where `f` is a function or functor.|
|:---------------|:---------------------------------------------------------------------|
## Pointer Matchers ##
|`Pointee(m)`|`argument` (either a smart pointer or a raw pointer) points to a value that matches matcher `m`.|
|:-----------|:-----------------------------------------------------------------------------------------------|
## Multiargument Matchers ##
Technically, all matchers match a _single_ value. A "multi-argument"
matcher is just one that matches a _tuple_. The following matchers can
be used to match a tuple `(x, y)`:
|`Eq()`|`x == y`|
|:-----|:-------|
|`Ge()`|`x >= y`|
|`Gt()`|`x > y` |
|`Le()`|`x <= y`|
|`Lt()`|`x < y` |
|`Ne()`|`x != y`|
You can use the following selectors to pick a subset of the arguments
(or reorder them) to participate in the matching:
|`AllArgs(m)`|Equivalent to `m`. Useful as syntactic sugar in `.With(AllArgs(m))`.|
|:-----------|:-------------------------------------------------------------------|
|`Args<N1, N2, ..., Nk>(m)`|The tuple of the `k` selected (using 0-based indices) arguments matches `m`, e.g. `Args<1, 2>(Eq())`.|
## Composite Matchers ##
You can make a matcher from one or more other matchers:
|`AllOf(m1, m2, ..., mn)`|`argument` matches all of the matchers `m1` to `mn`.|
|:-----------------------|:---------------------------------------------------|
|`AnyOf(m1, m2, ..., mn)`|`argument` matches at least one of the matchers `m1` to `mn`.|
|`Not(m)` |`argument` doesn't match matcher `m`. |
## Adapters for Matchers ##
|`MatcherCast<T>(m)`|casts matcher `m` to type `Matcher<T>`.|
|:------------------|:--------------------------------------|
|`SafeMatcherCast<T>(m)`| [safely casts](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Casting_Matchers) matcher `m` to type `Matcher<T>`. |
|`Truly(predicate)` |`predicate(argument)` returns something considered by C++ to be true, where `predicate` is a function or functor.|
## Matchers as Predicates ##
|`Matches(m)(value)`|evaluates to `true` if `value` matches `m`. You can use `Matches(m)` alone as a unary functor.|
|:------------------|:---------------------------------------------------------------------------------------------|
|`ExplainMatchResult(m, value, result_listener)`|evaluates to `true` if `value` matches `m`, explaining the result to `result_listener`. |
|`Value(value, m)` |evaluates to `true` if `value` matches `m`. |
## Defining Matchers ##
| `MATCHER(IsEven, "") { return (arg % 2) == 0; }` | Defines a matcher `IsEven()` to match an even number. |
|:-------------------------------------------------|:------------------------------------------------------|
| `MATCHER_P(IsDivisibleBy, n, "") { *result_listener << "where the remainder is " << (arg % n); return (arg % n) == 0; }` | Defines a macher `IsDivisibleBy(n)` to match a number divisible by `n`. |
| `MATCHER_P2(IsBetween, a, b, std::string(negation ? "isn't" : "is") + " between " + PrintToString(a) + " and " + PrintToString(b)) { return a <= arg && arg <= b; }` | Defines a matcher `IsBetween(a, b)` to match a value in the range [`a`, `b`]. |
**Notes:**
1. The `MATCHER*` macros cannot be used inside a function or class.
1. The matcher body must be _purely functional_ (i.e. it cannot have any side effect, and the result must not depend on anything other than the value being matched and the matcher parameters).
1. You can use `PrintToString(x)` to convert a value `x` of any type to a string.
## Matchers as Test Assertions ##
|`ASSERT_THAT(expression, m)`|Generates a [fatal failure](http://code.google.com/p/googletest/wiki/Primer#Assertions) if the value of `expression` doesn't match matcher `m`.|
|:---------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------|
|`EXPECT_THAT(expression, m)`|Generates a non-fatal failure if the value of `expression` doesn't match matcher `m`. |
# Actions #
**Actions** specify what a mock function should do when invoked.
## Returning a Value ##
|`Return()`|Return from a `void` mock function.|
|:---------|:----------------------------------|
|`Return(value)`|Return `value`. If the type of `value` is different to the mock function's return type, `value` is converted to the latter type <i>at the time the expectation is set</i>, not when the action is executed.|
|`ReturnArg<N>()`|Return the `N`-th (0-based) argument.|
|`ReturnNew<T>(a1, ..., ak)`|Return `new T(a1, ..., ak)`; a different object is created each time.|
|`ReturnNull()`|Return a null pointer. |
|`ReturnPointee(ptr)`|Return the value pointed to by `ptr`.|
|`ReturnRef(variable)`|Return a reference to `variable`. |
|`ReturnRefOfCopy(value)`|Return a reference to a copy of `value`; the copy lives as long as the action.|
## Side Effects ##
|`Assign(&variable, value)`|Assign `value` to variable.|
|:-------------------------|:--------------------------|
| `DeleteArg<N>()` | Delete the `N`-th (0-based) argument, which must be a pointer. |
| `SaveArg<N>(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. |
| `SaveArgPointee<N>(pointer)` | Save the value pointed to by the `N`-th (0-based) argument to `*pointer`. |
| `SetArgReferee<N>(value)` | Assign value to the variable referenced by the `N`-th (0-based) argument. |
|`SetArgPointee<N>(value)` |Assign `value` to the variable pointed by the `N`-th (0-based) argument.|
|`SetArgumentPointee<N>(value)`|Same as `SetArgPointee<N>(value)`. Deprecated. Will be removed in v1.7.0.|
|`SetArrayArgument<N>(first, last)`|Copies the elements in source range [`first`, `last`) to the array pointed to by the `N`-th (0-based) argument, which can be either a pointer or an iterator. The action does not take ownership of the elements in the source range.|
|`SetErrnoAndReturn(error, value)`|Set `errno` to `error` and return `value`.|
|`Throw(exception)` |Throws the given exception, which can be any copyable value. Available since v1.1.0.|
## Using a Function or a Functor as an Action ##
|`Invoke(f)`|Invoke `f` with the arguments passed to the mock function, where `f` can be a global/static function or a functor.|
|:----------|:-----------------------------------------------------------------------------------------------------------------|
|`Invoke(object_pointer, &class::method)`|Invoke the {method on the object with the arguments passed to the mock function. |
|`InvokeWithoutArgs(f)`|Invoke `f`, which can be a global/static function or a functor. `f` must take no arguments. |
|`InvokeWithoutArgs(object_pointer, &class::method)`|Invoke the method on the object, which takes no arguments. |
|`InvokeArgument<N>(arg1, arg2, ..., argk)`|Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments.|
The return value of the invoked function is used as the return value
of the action.
When defining a function or functor to be used with `Invoke*()`, you can declare any unused parameters as `Unused`:
```
double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); }
...
EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance));
```
In `InvokeArgument<N>(...)`, if an argument needs to be passed by reference, wrap it inside `ByRef()`. For example,
```
InvokeArgument<2>(5, string("Hi"), ByRef(foo))
```
calls the mock function's #2 argument, passing to it `5` and `string("Hi")` by value, and `foo` by reference.
## Default Action ##
|`DoDefault()`|Do the default action (specified by `ON_CALL()` or the built-in one).|
|:------------|:--------------------------------------------------------------------|
**Note:** due to technical reasons, `DoDefault()` cannot be used inside a composite action - trying to do so will result in a run-time error.
## Composite Actions ##
|`DoAll(a1, a2, ..., an)`|Do all actions `a1` to `an` and return the result of `an` in each invocation. The first `n - 1` sub-actions must return void. |
|:-----------------------|:-----------------------------------------------------------------------------------------------------------------------------|
|`IgnoreResult(a)` |Perform action `a` and ignore its result. `a` must not return void. |
|`WithArg<N>(a)` |Pass the `N`-th (0-based) argument of the mock function to action `a` and perform it. |
|`WithArgs<N1, N2, ..., Nk>(a)`|Pass the selected (0-based) arguments of the mock function to action `a` and perform it. |
|`WithoutArgs(a)` |Perform action `a` without any arguments. |
## Defining Actions ##
| `ACTION(Sum) { return arg0 + arg1; }` | Defines an action `Sum()` to return the sum of the mock function's argument #0 and #1. |
|:--------------------------------------|:---------------------------------------------------------------------------------------|
| `ACTION_P(Plus, n) { return arg0 + n; }` | Defines an action `Plus(n)` to return the sum of the mock function's argument #0 and `n`. |
| `ACTION_Pk(Foo, p1, ..., pk) { statements; }` | Defines a parameterized action `Foo(p1, ..., pk)` to execute the given `statements`. |
The `ACTION*` macros cannot be used inside a function or class.
# Cardinalities #
These are used in `Times()` to specify how many times a mock function will be called:
|`AnyNumber()`|The function can be called any number of times.|
|:------------|:----------------------------------------------|
|`AtLeast(n)` |The call is expected at least `n` times. |
|`AtMost(n)` |The call is expected at most `n` times. |
|`Between(m, n)`|The call is expected between `m` and `n` (inclusive) times.|
|`Exactly(n) or n`|The call is expected exactly `n` times. In particular, the call should never happen when `n` is 0.|
# Expectation Order #
By default, the expectations can be matched in _any_ order. If some
or all expectations must be matched in a given order, there are two
ways to specify it. They can be used either independently or
together.
## The After Clause ##
```
using ::testing::Expectation;
...
Expectation init_x = EXPECT_CALL(foo, InitX());
Expectation init_y = EXPECT_CALL(foo, InitY());
EXPECT_CALL(foo, Bar())
.After(init_x, init_y);
```
says that `Bar()` can be called only after both `InitX()` and
`InitY()` have been called.
If you don't know how many pre-requisites an expectation has when you
write it, you can use an `ExpectationSet` to collect them:
```
using ::testing::ExpectationSet;
...
ExpectationSet all_inits;
for (int i = 0; i < element_count; i++) {
all_inits += EXPECT_CALL(foo, InitElement(i));
}
EXPECT_CALL(foo, Bar())
.After(all_inits);
```
says that `Bar()` can be called only after all elements have been
initialized (but we don't care about which elements get initialized
before the others).
Modifying an `ExpectationSet` after using it in an `.After()` doesn't
affect the meaning of the `.After()`.
## Sequences ##
When you have a long chain of sequential expectations, it's easier to
specify the order using **sequences**, which don't require you to given
each expectation in the chain a different name. <i>All expected<br>
calls</i> in the same sequence must occur in the order they are
specified.
```
using ::testing::Sequence;
Sequence s1, s2;
...
EXPECT_CALL(foo, Reset())
.InSequence(s1, s2)
.WillOnce(Return(true));
EXPECT_CALL(foo, GetSize())
.InSequence(s1)
.WillOnce(Return(1));
EXPECT_CALL(foo, Describe(A<const char*>()))
.InSequence(s2)
.WillOnce(Return("dummy"));
```
says that `Reset()` must be called before _both_ `GetSize()` _and_
`Describe()`, and the latter two can occur in any order.
To put many expectations in a sequence conveniently:
```
using ::testing::InSequence;
{
InSequence dummy;
EXPECT_CALL(...)...;
EXPECT_CALL(...)...;
...
EXPECT_CALL(...)...;
}
```
says that all expected calls in the scope of `dummy` must occur in
strict order. The name `dummy` is irrelevant.)
# Verifying and Resetting a Mock #
Google Mock will verify the expectations on a mock object when it is destructed, or you can do it earlier:
```
using ::testing::Mock;
...
// Verifies and removes the expectations on mock_obj;
// returns true iff successful.
Mock::VerifyAndClearExpectations(&mock_obj);
...
// Verifies and removes the expectations on mock_obj;
// also removes the default actions set by ON_CALL();
// returns true iff successful.
Mock::VerifyAndClear(&mock_obj);
```
You can also tell Google Mock that a mock object can be leaked and doesn't
need to be verified:
```
Mock::AllowLeak(&mock_obj);
```
# Mock Classes #
Google Mock defines a convenient mock class template
```
class MockFunction<R(A1, ..., An)> {
public:
MOCK_METHODn(Call, R(A1, ..., An));
};
```
See this [recipe](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Using_Check_Points) for one application of it.
# Flags #
| `--gmock_catch_leaked_mocks=0` | Don't report leaked mock objects as failures. |
|:-------------------------------|:----------------------------------------------|
| `--gmock_verbose=LEVEL` | Sets the default verbosity level (`info`, `warning`, or `error`) of Google Mock messages. |

Some files were not shown because too many files have changed in this diff Show More