This adds a googletest-based test harness (with googletest pulled into `testing/googletest`, so we have a fixed state of it), and a few test cases that demonstrate its use. Original work by Eric Paniagua in #898, with minor cleanups by Gergely Nagy. Signed-off-by: Eric Paniagua <epaniagua@google.com> Signed-off-by: Gergely Nagy <algernon@keyboard.io>pull/908/head
parent
57814671a5
commit
fad1b7e051
@ -0,0 +1,56 @@
|
|||||||
|
# Automated Testing
|
||||||
|
|
||||||
|
## Testing with gtest/gmock
|
||||||
|
|
||||||
|
Before feature requests or bug fixes can be merged into master, the folowing
|
||||||
|
steps should be taken:
|
||||||
|
|
||||||
|
- Create a new test suite named after the issue, e.g. `Issue840`.
|
||||||
|
- Add a test case named `Reproduces` that reproduces the bug. It should fail if
|
||||||
|
the bug is present and pass if the bug is fixed.
|
||||||
|
- Merge the proposed fix into a temporary testing branch.
|
||||||
|
- The reproduction test should fail.
|
||||||
|
- Add a test called "HasNotRegresed" that detects a potential regression.
|
||||||
|
It should pass with the fix and fail before the fix.
|
||||||
|
- Comment out and keep the `Reproduces` test case as documentation.
|
||||||
|
|
||||||
|
For an example, see keyboardio:Kaleidoscope/tests/issue_840.
|
||||||
|
|
||||||
|
### Adding a New Test Case
|
||||||
|
|
||||||
|
For general information on writing test with gtest/gmock see [gtest
|
||||||
|
docs](https://github.com/google/googletest/tree/master/googletest/docs) and
|
||||||
|
[gmock docs](https://github.com/google/googletest/tree/master/googlemock/docs).
|
||||||
|
|
||||||
|
1. Create a new test file, if appropriate.
|
||||||
|
1. Choose a new test suite name and create a new test fixture, if appropriate.
|
||||||
|
1. Write your test case.
|
||||||
|
|
||||||
|
The final include in any test file should be `#include
|
||||||
|
"testing/setup-googletest.h"` which should be followed by the macro
|
||||||
|
invocation `SETUP_GOOGLETEST()`. This will take care of including headers
|
||||||
|
commonly used in tests in addtion to gtest and gmock headers.
|
||||||
|
|
||||||
|
Any test fixtures should inherit from `VirtualDeviceTest` which wraps the test
|
||||||
|
sim APIs and provides common setup and teardown functionality. The appropriate
|
||||||
|
header is already imported by `setup-googletest.h`
|
||||||
|
|
||||||
|
### Test Infrastructure
|
||||||
|
|
||||||
|
If you need to modify or extend test infrastructure to support your use case,
|
||||||
|
it can currently be found under `keyboardio:Kaleidoscope/testing`.
|
||||||
|
|
||||||
|
### Style
|
||||||
|
|
||||||
|
TODO(obra): Fill out this section to your liking.
|
||||||
|
|
||||||
|
You can see samples of the desired test style in the [example tests](#examples).
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
All existing tests are examples and may be found under
|
||||||
|
`keyboardio:Kaleidoscope/tests`.
|
||||||
|
|
||||||
|
## Testing with Aglais/Papilio
|
||||||
|
|
||||||
|
TODO(obra): Write (or delegate the writing of) this section.
|
@ -0,0 +1,99 @@
|
|||||||
|
# Release testing
|
||||||
|
|
||||||
|
Before a new release of Kaleidoscope, the following test process should be run through on all supported operating systems.
|
||||||
|
|
||||||
|
Always run all of the [automated tests](automated-testing.md) to verify there are no regressions.
|
||||||
|
|
||||||
|
(As of August 2017, this whole thing really applies to Model01-Firmware, but we hope to generalize it to Kaleidoscope)
|
||||||
|
|
||||||
|
# Tested operating systems
|
||||||
|
|
||||||
|
* The latest stable Ubuntu Linux release running X11. (We _should_ eventually be testing both X11 and Wayland)
|
||||||
|
* The latest stable release of macOS
|
||||||
|
* An older Mac OS X release TBD. (There were major USB stack changes in 10.9 or so)
|
||||||
|
* Windows 10
|
||||||
|
* Windows 7
|
||||||
|
* The current release of ChromeOS
|
||||||
|
* A currentish android tablet that supports USB Host
|
||||||
|
* an iOS device (once we fix the usb connection issue to limit power draw)
|
||||||
|
|
||||||
|
# Test process
|
||||||
|
|
||||||
|
## Basic testing
|
||||||
|
1. Plug the keyboard in
|
||||||
|
1. Make sure the host OS doesn't throw an error
|
||||||
|
1. Make sure the LED in the top left doesn't glow red
|
||||||
|
1. Make sure the LED in the top-right corner of the left side breathes blue for ~10s
|
||||||
|
1. Bring up some sort of notepad app or text editor
|
||||||
|
|
||||||
|
## Basic testing, part 2
|
||||||
|
|
||||||
|
1. Test typing of shifted and unshifted letters and numbers with and without key repeat
|
||||||
|
1. Test typing of fn-shifted characters: []{}|\ with and without key repeat
|
||||||
|
1. Test that 'Any' key generates a random letter or number and that key repeat works
|
||||||
|
1. Test fn-hjkl to move the cursor
|
||||||
|
1. Test Fn-WASD to move the mouse
|
||||||
|
1. Test Fn-RFV for the three mouse buttons
|
||||||
|
1. Test Fn-BGTabEsc for mouse warp
|
||||||
|
1. Test that LeftFn+RightFn + hjkl move the cursor
|
||||||
|
1. Verify that leftfn+rightfn do not light up the numpad
|
||||||
|
|
||||||
|
## NKRO
|
||||||
|
|
||||||
|
1. Open the platform's native key event viewer
|
||||||
|
(If not available, visit https://www.microsoft.com/appliedsciences/KeyboardGhostingDemo.mspx in a browser)
|
||||||
|
1. Press as many keys as your fingers will let you
|
||||||
|
1. Verify that the keymap reports all the keys you're pressing
|
||||||
|
|
||||||
|
|
||||||
|
## Test media keys
|
||||||
|
|
||||||
|
1. Fn-Any: previous track
|
||||||
|
1. Fn-Y: next-track
|
||||||
|
1. Fn-Enter: play/pause
|
||||||
|
1. Fn-Butterfly: Windows 'menu' key
|
||||||
|
1. Fn-n: mute
|
||||||
|
1. Fn-m: volume down
|
||||||
|
1. Fn-,: volume up
|
||||||
|
|
||||||
|
## Test numlock
|
||||||
|
|
||||||
|
1. Tap "Num"
|
||||||
|
1. Verify that the numpad lights up red
|
||||||
|
1. Verify that the num key is breathing blue
|
||||||
|
1. Verify that numpad keys generate numbers
|
||||||
|
1. Tap the Num key
|
||||||
|
1. Verify that the numpad keys stop being lit up
|
||||||
|
1 Verify that 'jkl' don't generate numbers.
|
||||||
|
|
||||||
|
## Test LED Effects
|
||||||
|
|
||||||
|
1. Tap the LED key
|
||||||
|
1. Verify that there is a rainbow effect
|
||||||
|
1. Tap the LED key a few more times and verify that other LED effects show up
|
||||||
|
1. Verify that you can still type.
|
||||||
|
|
||||||
|
## Second connection
|
||||||
|
1. Unplug the keyboard
|
||||||
|
1. Plug the keyboard back in
|
||||||
|
1. Make sure you can still type
|
||||||
|
|
||||||
|
## Programming
|
||||||
|
1. If the OS has a way to show serial port devices, verify that the keyboard's serial port shows up.
|
||||||
|
1. If you can run stty, as you can on linux and macos, make sure you can tickle the serial port at 1200 bps.
|
||||||
|
Linux: stty -F /dev/ttyACM0 1200
|
||||||
|
Mac:
|
||||||
|
1. If you tickle the serial port without holding down the prog key, verify that the Prog key does not light up red
|
||||||
|
1. If you hold down the prog key before tickling the serial port, verify that the Prog key's LED lights up red.
|
||||||
|
1. Unplug the keyboard
|
||||||
|
1. While holding down prog, plug the keyboard in
|
||||||
|
1. Verify that the prog key is glowing red.
|
||||||
|
1. Unplug the keyboard
|
||||||
|
1. Plug the keyboard in
|
||||||
|
1. Verify that the prog key is not glowing red.
|
||||||
|
|
||||||
|
# If the current platform supports the Arduino IDE (Win/Lin/Mac)
|
||||||
|
1. use the Arduino IDE to reflash the current version of the software.
|
||||||
|
1. Verify that you can type a few keys
|
||||||
|
1. Verify that the LED key toggles between LED effects
|
||||||
|
|
@ -0,0 +1,3 @@
|
|||||||
|
**/bin/
|
||||||
|
**/lib/
|
||||||
|
**/obj/
|
@ -0,0 +1,56 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Copyright (C) 2020 Eric Paniagua (epaniagua@google.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "testing/AbsoluteMouseReport.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "MouseButtons.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
AbsoluteMouseReport::AbsoluteMouseReport(const void* data) {
|
||||||
|
const ReportData& report_data =
|
||||||
|
*static_cast<const ReportData*>(data);
|
||||||
|
memcpy(&report_data_, &report_data, sizeof(report_data_));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> AbsoluteMouseReport::Buttons() const {
|
||||||
|
std::vector<uint8_t> buttons;
|
||||||
|
const uint8_t bs = report_data_.buttons;
|
||||||
|
if (bs & MOUSE_LEFT) buttons.push_back(MOUSE_LEFT);
|
||||||
|
if (bs & MOUSE_RIGHT) buttons.push_back(MOUSE_RIGHT);
|
||||||
|
if (bs & MOUSE_MIDDLE) buttons.push_back(MOUSE_MIDDLE);
|
||||||
|
if (bs & MOUSE_PREV) buttons.push_back(MOUSE_PREV);
|
||||||
|
if (bs & MOUSE_NEXT) buttons.push_back(MOUSE_NEXT);
|
||||||
|
return buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t AbsoluteMouseReport::XAxis() const {
|
||||||
|
return report_data_.xAxis;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t AbsoluteMouseReport::YAxis() const {
|
||||||
|
return report_data_.yAxis;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t AbsoluteMouseReport::Wheel() const {
|
||||||
|
return report_data_.wheel;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace kaleidoscope
|
@ -0,0 +1,46 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Copyright (C) 2020 Eric Paniagua (epaniagua@google.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "DeviceAPIs/AbsoluteMouseAPI.h"
|
||||||
|
#include "HID-Settings.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
class AbsoluteMouseReport {
|
||||||
|
public:
|
||||||
|
typedef HID_MouseAbsoluteReport_Data_t ReportData;
|
||||||
|
|
||||||
|
static constexpr uint8_t kHidReportType = HID_REPORTID_MOUSE_ABSOLUTE;
|
||||||
|
|
||||||
|
AbsoluteMouseReport(const void* data);
|
||||||
|
|
||||||
|
std::vector<uint8_t> Buttons() const;
|
||||||
|
uint16_t XAxis() const;
|
||||||
|
uint16_t YAxis() const;
|
||||||
|
int8_t Wheel() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ReportData report_data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
} // namespce kaleidoscope
|
@ -0,0 +1,40 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Copyright (C) 2020 Eric Paniagua (epaniagua@google.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "testing/ConsumerControlReport.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
ConsumerControlReport::ConsumerControlReport(const void *data) {
|
||||||
|
const ReportData& report_data =
|
||||||
|
*static_cast<const ReportData*>(data);
|
||||||
|
memcpy(&report_data_, &report_data, sizeof(report_data_));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint16_t> ConsumerControlReport::Keys() const {
|
||||||
|
std::vector<uint16_t> keys;
|
||||||
|
if (report_data_.key1) keys.push_back(report_data_.key1);
|
||||||
|
if (report_data_.key2) keys.push_back(report_data_.key2);
|
||||||
|
if (report_data_.key3) keys.push_back(report_data_.key3);
|
||||||
|
if (report_data_.key4) keys.push_back(report_data_.key4);
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace kaleidoscope
|
@ -0,0 +1,43 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Copyright (C) 2020 Eric Paniagua (epaniagua@google.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "HID-Settings.h"
|
||||||
|
#include "MultiReport/ConsumerControl.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
class ConsumerControlReport {
|
||||||
|
public:
|
||||||
|
typedef HID_ConsumerControlReport_Data_t ReportData;
|
||||||
|
|
||||||
|
static constexpr uint8_t kHidReportType = HID_REPORTID_CONSUMERCONTROL;
|
||||||
|
|
||||||
|
ConsumerControlReport(const void *data);
|
||||||
|
|
||||||
|
std::vector<uint16_t> Keys() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ReportData report_data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace kaleidoscope
|
@ -0,0 +1,155 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Copyright (C) 2020 Eric Paniagua (epaniagua@google.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "testing/HIDState.h"
|
||||||
|
|
||||||
|
#include "HID-Settings.h"
|
||||||
|
|
||||||
|
#include "testing/fix-macros.h"
|
||||||
|
|
||||||
|
// TODO(epan): Add proper logging.
|
||||||
|
#include <iostream>
|
||||||
|
#define LOG(x) std::cout
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
const std::vector<AbsoluteMouseReport>& HIDState::AbsoluteMouse() const {
|
||||||
|
return absolute_mouse_reports_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AbsoluteMouseReport& HIDState::AbsoluteMouse(size_t i) const {
|
||||||
|
return absolute_mouse_reports_.at(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<ConsumerControlReport>& HIDState::ConsumerControl() const {
|
||||||
|
return consumer_control_reports_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ConsumerControlReport& HIDState::ConsumerControl(size_t i) const {
|
||||||
|
return consumer_control_reports_.at(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<KeyboardReport>& HIDState::Keyboard() const {
|
||||||
|
return keyboard_reports_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const KeyboardReport& HIDState::Keyboard(size_t i) const {
|
||||||
|
return keyboard_reports_.at(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<SystemControlReport>& HIDState::SystemControl() const {
|
||||||
|
return system_control_reports_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SystemControlReport& HIDState::SystemControl(size_t i) const {
|
||||||
|
return system_control_reports_.at(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// static
|
||||||
|
void HIDStateBuilder::ProcessHidReport(
|
||||||
|
uint8_t id, const void* data, int len, int result) {
|
||||||
|
switch (id) {
|
||||||
|
case HID_REPORTID_MOUSE: {
|
||||||
|
LOG(ERROR) << "Dropped MouseReport: unimplemented";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HID_REPORTID_KEYBOARD: {
|
||||||
|
LOG(ERROR) << "Dropped BootKeyboardReport: unimplemented";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HID_REPORTID_GAMEPAD: {
|
||||||
|
LOG(ERROR) << "Dropped GamePadReport: unimplemented";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HID_REPORTID_CONSUMERCONTROL: {
|
||||||
|
ProcessConsumerControlReport(ConsumerControlReport{data});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HID_REPORTID_SYSTEMCONTROL: {
|
||||||
|
ProcessSystemControlReport(SystemControlReport{data});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HID_REPORTID_MOUSE_ABSOLUTE: {
|
||||||
|
ProcessAbsoluteMouseReport(AbsoluteMouseReport{data});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HID_REPORTID_NKRO_KEYBOARD: {
|
||||||
|
ProcessKeyboardReport(KeyboardReport{data});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
LOG(ERROR) << "Encountered unknown HID report with id = " << id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
std::unique_ptr<HIDState> HIDStateBuilder::Snapshot() {
|
||||||
|
auto hid_state = std::make_unique<HIDState>();
|
||||||
|
// Populate state.
|
||||||
|
// TODO: Grab a copy of current instantaneous state, like:
|
||||||
|
// key states, layer stack, led states
|
||||||
|
hid_state->absolute_mouse_reports_ = std::move(absolute_mouse_reports_);
|
||||||
|
hid_state->consumer_control_reports_ = std::move(consumer_control_reports_);
|
||||||
|
hid_state->keyboard_reports_ = std::move(keyboard_reports_);
|
||||||
|
hid_state->system_control_reports_ = std::move(system_control_reports_);
|
||||||
|
|
||||||
|
Clear(); // Clear global state.
|
||||||
|
return hid_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void HIDStateBuilder::Clear() {
|
||||||
|
absolute_mouse_reports_.clear();
|
||||||
|
consumer_control_reports_.clear();
|
||||||
|
keyboard_reports_.clear();
|
||||||
|
system_control_reports_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void HIDStateBuilder::ProcessAbsoluteMouseReport(const AbsoluteMouseReport& report) {
|
||||||
|
absolute_mouse_reports_.push_back(report);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void HIDStateBuilder::ProcessConsumerControlReport(const ConsumerControlReport& report) {
|
||||||
|
consumer_control_reports_.push_back(report);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void HIDStateBuilder::ProcessKeyboardReport(const KeyboardReport& report) {
|
||||||
|
keyboard_reports_.push_back(report);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void HIDStateBuilder::ProcessSystemControlReport(const SystemControlReport& report) {
|
||||||
|
system_control_reports_.push_back(report);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
std::vector<AbsoluteMouseReport> HIDStateBuilder::absolute_mouse_reports_;
|
||||||
|
// static
|
||||||
|
std::vector<ConsumerControlReport> HIDStateBuilder::consumer_control_reports_;
|
||||||
|
// static
|
||||||
|
std::vector<KeyboardReport> HIDStateBuilder::keyboard_reports_;
|
||||||
|
// static
|
||||||
|
std::vector<SystemControlReport> HIDStateBuilder::system_control_reports_;
|
||||||
|
|
||||||
|
} // namesapce internal
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace kaleidoscope
|
@ -0,0 +1,81 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Copyright (C) 2020 Eric Paniagua (epaniagua@google.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "testing/AbsoluteMouseReport.h"
|
||||||
|
#include "testing/ConsumerControlReport.h"
|
||||||
|
#include "testing/KeyboardReport.h"
|
||||||
|
#include "testing/SystemControlReport.h"
|
||||||
|
|
||||||
|
// Out of order due to macro conflicts.
|
||||||
|
#include "testing/fix-macros.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace testing {
|
||||||
|
namespace internal {
|
||||||
|
class HIDStateBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
class HIDState {
|
||||||
|
public:
|
||||||
|
const std::vector<AbsoluteMouseReport>& AbsoluteMouse() const;
|
||||||
|
const AbsoluteMouseReport& AbsoluteMouse(size_t i) const;
|
||||||
|
|
||||||
|
const std::vector<ConsumerControlReport>& ConsumerControl() const;
|
||||||
|
const ConsumerControlReport& ConsumerControl(size_t i) const;
|
||||||
|
|
||||||
|
const std::vector<KeyboardReport>& Keyboard() const;
|
||||||
|
const KeyboardReport& Keyboard(size_t i) const;
|
||||||
|
|
||||||
|
const std::vector<SystemControlReport>& SystemControl() const;
|
||||||
|
const SystemControlReport& SystemControl(size_t i) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class internal::HIDStateBuilder;
|
||||||
|
|
||||||
|
std::vector<AbsoluteMouseReport> absolute_mouse_reports_;
|
||||||
|
std::vector<ConsumerControlReport> consumer_control_reports_;
|
||||||
|
std::vector<KeyboardReport> keyboard_reports_;
|
||||||
|
std::vector<SystemControlReport> system_control_reports_;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class HIDStateBuilder {
|
||||||
|
public:
|
||||||
|
static void ProcessHidReport(
|
||||||
|
uint8_t id, const void* data, int len, int result);
|
||||||
|
|
||||||
|
static std::unique_ptr<HIDState> Snapshot();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void Clear();
|
||||||
|
static void ProcessAbsoluteMouseReport(const AbsoluteMouseReport& report);
|
||||||
|
static void ProcessConsumerControlReport(const ConsumerControlReport& report);
|
||||||
|
static void ProcessKeyboardReport(const KeyboardReport& report);
|
||||||
|
static void ProcessSystemControlReport(const SystemControlReport& report);
|
||||||
|
|
||||||
|
static std::vector<AbsoluteMouseReport> absolute_mouse_reports_;
|
||||||
|
static std::vector<ConsumerControlReport> consumer_control_reports_;
|
||||||
|
static std::vector<KeyboardReport> keyboard_reports_;
|
||||||
|
static std::vector<SystemControlReport> system_control_reports_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace kaleidoscope
|
@ -0,0 +1,41 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Copyright (C) 2020 Eric Paniagua (epaniagua@google.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "testing/KeyboardReport.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
KeyboardReport::KeyboardReport(const void* data) {
|
||||||
|
const ReportData& report_data =
|
||||||
|
*static_cast<const ReportData*>(data);
|
||||||
|
memcpy(&report_data_, &report_data, sizeof(report_data_));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> KeyboardReport::ActiveKeycodes() const {
|
||||||
|
std::vector<uint8_t> active_keys;
|
||||||
|
for (uint8_t i = 0; i < HID_LAST_KEY; ++i) {
|
||||||
|
uint8_t bit = 1 << (uint8_t(i) % 8);
|
||||||
|
uint8_t key_code = report_data_.keys[i / 8] & bit;
|
||||||
|
if (key_code) active_keys.push_back(i);
|
||||||
|
}
|
||||||
|
return active_keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace kaleidoscope
|
@ -0,0 +1,43 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Copyright (C) 2020 Eric Paniagua (epaniagua@google.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "HID-Settings.h"
|
||||||
|
#include "MultiReport/Keyboard.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
class KeyboardReport {
|
||||||
|
public:
|
||||||
|
typedef HID_KeyboardReport_Data_t ReportData;
|
||||||
|
|
||||||
|
static constexpr uint8_t kHidReportType = HID_REPORTID_NKRO_KEYBOARD;
|
||||||
|
|
||||||
|
KeyboardReport(const void* data);
|
||||||
|
|
||||||
|
std::vector<uint8_t> ActiveKeycodes() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ReportData report_data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace kaleidoscope
|
@ -0,0 +1,47 @@
|
|||||||
|
/* kailedoscope::sim - Harness for Unit Testing Kaleidoscope
|
||||||
|
* Copyright (C) 2020 Eric Paniagua <epaniagua@google.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Kaleidoscope.h"
|
||||||
|
#include "testing/SimHarness.h"
|
||||||
|
|
||||||
|
#include "testing/fix-macros.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
void SimHarness::RunCycle() {
|
||||||
|
Kaleidoscope.loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimHarness::RunCycles(size_t n) {
|
||||||
|
for (size_t i = 0; i < n; ++i) RunCycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimHarness::Press(uint8_t row, uint8_t col) {
|
||||||
|
Kaleidoscope.device().keyScanner().setKeystate(
|
||||||
|
KeyAddr{row, col},
|
||||||
|
kaleidoscope::Device::Props::KeyScanner::KeyState::Pressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimHarness::Release(uint8_t row, uint8_t col) {
|
||||||
|
Kaleidoscope.device().keyScanner().setKeystate(
|
||||||
|
KeyAddr{row, col},
|
||||||
|
kaleidoscope::Device::Props::KeyScanner::KeyState::NotPressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace kaleidoscope
|
@ -0,0 +1,35 @@
|
|||||||
|
/* kailedoscope::sim - Simulator for Unit Testing Kaleidoscope
|
||||||
|
* Copyright (C) 2020 Eric Paniagua <epaniagua@google.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
class SimHarness {
|
||||||
|
public:
|
||||||
|
void RunCycle();
|
||||||
|
void RunCycles(size_t n);
|
||||||
|
|
||||||
|
void Press(uint8_t row, uint8_t col);
|
||||||
|
void Release(uint8_t row, uint8_t col);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace kaleidoscope
|
@ -0,0 +1,34 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Copyright (C) 2020 Eric Paniagua (epaniagua@google.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "testing/State.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
// static
|
||||||
|
std::unique_ptr<State> State::Snapshot() {
|
||||||
|
auto state = std::make_unique<State>();
|
||||||
|
state->hid_state_ = internal::HIDStateBuilder::Snapshot();
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
const HIDState* State::HIDReports() const {
|
||||||
|
return hid_state_.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace kaleidoscope
|
@ -0,0 +1,43 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Copyright (C) 2020 Eric Paniagua (epaniagua@google.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "testing/HIDState.h"
|
||||||
|
|
||||||
|
// Out of order due to macro conflicts.
|
||||||
|
#include "testing/fix-macros.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
class State {
|
||||||
|
public:
|
||||||
|
static std::unique_ptr<State> Snapshot();
|
||||||
|
|
||||||
|
const HIDState* HIDReports() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<HIDState> hid_state_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace kaleidoscope
|
@ -0,0 +1,38 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Copyright (C) 2020 Eric Paniagua (epaniagua@google.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "testing/SystemControlReport.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
SystemControlReport::SystemControlReport(const void* data) {
|
||||||
|
const ReportData& report_data =
|
||||||
|
*static_cast<const ReportData*>(data);
|
||||||
|
memcpy(&report_data_, &report_data, sizeof(report_data_));
|
||||||
|
if (report_data_.key != 0) {
|
||||||
|
this->push_back(report_data_.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t SystemControlReport::Key() const {
|
||||||
|
return report_data_.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace kaleidoscope
|
@ -0,0 +1,43 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Copyright (C) 2020 Eric Paniagua (epaniagua@google.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "HID-Settings.h"
|
||||||
|
#include "MultiReport/SystemControl.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
class SystemControlReport : public std::vector<uint8_t> {
|
||||||
|
public:
|
||||||
|
typedef HID_SystemControlReport_Data_t ReportData;
|
||||||
|
|
||||||
|
static constexpr uint8_t kHidReportType = HID_REPORTID_SYSTEMCONTROL;
|
||||||
|
|
||||||
|
SystemControlReport(const void* data);
|
||||||
|
|
||||||
|
uint8_t Key() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ReportData report_data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace kaleidoscope
|
@ -0,0 +1,87 @@
|
|||||||
|
Build System
|
||||||
|
============
|
||||||
|
Directory structure
|
||||||
|
- Test infrastructure should be able to be hierarchically organized
|
||||||
|
|
||||||
|
Future Work
|
||||||
|
===========
|
||||||
|
Issue 867
|
||||||
|
- Infra changes: none needed
|
||||||
|
- Testing 867
|
||||||
|
- Design a set of layers that allows all the test cases you would like, and configure them in a sketch.
|
||||||
|
- If you need multiple sets of layers, the current build mechanism requires splitting
|
||||||
|
the test code in two, each with its corresponding sketch.
|
||||||
|
- Navigate between layers using sim_.Press(row, col) and sim_.Release(row, col) as a user
|
||||||
|
would with the test sketch loaded.
|
||||||
|
- Verify that the right keys are pressed (based on the current layer) using
|
||||||
|
EXPECT_THAT(state->HidReports()->Keyboard(0), Contains(Key_A))
|
||||||
|
- See issue_840 for example usage.
|
||||||
|
Testing LED activation
|
||||||
|
- Infra changes
|
||||||
|
- Create an LedState class to hold a snapshot of LED activations.
|
||||||
|
- Add an led_state_ member to State together with whatever accessors are convenient.
|
||||||
|
- If the accessors are complicated or you just want to namespace that part of the global state,
|
||||||
|
create a state module for LEDs following the pattern implemented for HIDState.
|
||||||
|
- Of course, the HIDReportObserver stuff doesn't apply here.
|
||||||
|
- Modify State::Snapshot to copy the current LED state into led_state_
|
||||||
|
- This must be a copy, not a reference, as it may be desirable to compare state objects
|
||||||
|
generated at different times.
|
||||||
|
- Consider whether there are any sensible LED-specific "matchers" (in the gmock sense) that could
|
||||||
|
be added to make LED tests more readable.
|
||||||
|
- See https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md for instructions
|
||||||
|
and examples on writing new matchers
|
||||||
|
- Add USB simulation, eg to test Focus and FocusSerial
|
||||||
|
- It would be nice if there were a way to specify the test firmware configuration directly in the test
|
||||||
|
(ie *_test.cpp) files
|
||||||
|
|
||||||
|
Design of the Testing Simulator
|
||||||
|
===============================
|
||||||
|
Two halves of the simulator, each an abstraction to isolate tests from firmware implementation details
|
||||||
|
and thereby decrease the maintence cost of tests.
|
||||||
|
- SimHarness
|
||||||
|
- This is what lets you prod the firmware, e.g. with a change in keyswitch state
|
||||||
|
- Any new ways of feeding input to the simulated firmware should do so through this abstraction
|
||||||
|
- State
|
||||||
|
- This is a snapshot of the global firmware state. It is currently only intended to be accessible via
|
||||||
|
the snapshot returned by RunCycle.
|
||||||
|
- Should always be a copy of firmware state, never a reference or pointer to it.
|
||||||
|
- In general it is desirable to be able to compare aspects of state from two different "times" in
|
||||||
|
the simulation.
|
||||||
|
Both halves may end up with modular structure as complexity grows. This is fine as long as the basic
|
||||||
|
abstractions and division of responsibilities are maintained.
|
||||||
|
|
||||||
|
BEFORE MERGING
|
||||||
|
==============
|
||||||
|
- The bundle repo should merge branch `epan/build/justlib`. The test infra depends on the changes in
|
||||||
|
that branch.
|
||||||
|
- Consider whether you want to add the following before or after merging (and delay merging if appropriate):
|
||||||
|
- Fleshing out the coverage of HID reports by HID state.
|
||||||
|
- Adding LED output capture to State.
|
||||||
|
- Please impement a proper logging solution (rather than dumping almost everything to stdout/stderr and
|
||||||
|
needing to sort through it manually at fixed verbosity)
|
||||||
|
- Some desirable properties of a logging system
|
||||||
|
- Global verbosity levels (e.g. INFO, WARNING, ERROR, FATAL)
|
||||||
|
- Custom verbosity levels
|
||||||
|
- Local verbosity levels, eg per file, ideally configurable in a central and obvious location like the command line
|
||||||
|
- See parseCommandLine in virtual/cores/main.cpp for the hook that would need to be overridden
|
||||||
|
- Logging macros that compile away to nothing in production builds (ie where NDEBUG is defined)
|
||||||
|
- This allows logging directly from the firmware code at no space or time cost to the real firmware
|
||||||
|
- glog is a good example of some desirable capabilities in a logging system, if not a good system to adopt.
|
||||||
|
For portability for developers, please get the test build system to play well with Docker
|
||||||
|
- (right now, cmake isn't playing well with Docker)
|
||||||
|
Update testing documentation as appropriate to relfect changes to test infra or to directory structures.
|
||||||
|
- See docs/codebase/testing/automated-testing.md
|
||||||
|
- Add links into the codebase as appropriate
|
||||||
|
|
||||||
|
What I'd do with Another Solid Week
|
||||||
|
===================================
|
||||||
|
- Add coverage of remaining HID report types
|
||||||
|
- Add capture of LED state
|
||||||
|
- Pick several reported bugs and write up tests to reproduce them and then regression tests once they've been fixed
|
||||||
|
- My main goal here would be to exercise the framwork to identify pain points or other areas for improvement
|
||||||
|
- Write a test-specific plugin that supports snapshotting state each time one of its event handlers is called
|
||||||
|
- More formally document the test simulator's design and usage
|
||||||
|
- If there were time left and earlier steps were to bear out the need...
|
||||||
|
- Add the ability to inject synthetic events or events at a given delay into the future
|
||||||
|
- Improve the simulator's concept of time and trigger events against the firmware, interleaving them in the right
|
||||||
|
order with a time-based priority queue
|
@ -0,0 +1,35 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Copyright (C) 2020 Eric Paniagua (epaniagua@google.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "testing/VirtualDeviceTest.h"
|
||||||
|
|
||||||
|
#include "HIDReportObserver.h"
|
||||||
|
#include "testing/HIDState.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
void VirtualDeviceTest::SetUp() {
|
||||||
|
HIDReportObserver::resetHook(&internal::HIDStateBuilder::ProcessHidReport);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<State> VirtualDeviceTest::RunCycle() {
|
||||||
|
sim_.RunCycle();
|
||||||
|
return State::Snapshot();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace kaleidoscope
|
@ -0,0 +1,42 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Copyright (C) 2020 Eric Paniagua (epaniagua@google.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include "testing/SimHarness.h"
|
||||||
|
#include "testing/State.h"
|
||||||
|
|
||||||
|
// Out of order due to macro conflicts.
|
||||||
|
#include "testing/fix-macros.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
class VirtualDeviceTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
void SetUp();
|
||||||
|
|
||||||
|
std::unique_ptr<State> RunCycle();
|
||||||
|
|
||||||
|
SimHarness sim_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace kaleidoscope
|
@ -0,0 +1,26 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Copyright (C) 2020 Eric Paniagua (epaniagua@google.com)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// No `#pragma once` since these undefs need to have every time a Kaleidoscope/
|
||||||
|
// Arduino header is included before non-Kaleidoscope/Arduino header.
|
||||||
|
// #pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
|
#undef T
|
||||||
|
#undef U
|
||||||
|
#undef TEST
|
@ -0,0 +1,4 @@
|
|||||||
|
# Run manually to reformat a file:
|
||||||
|
# clang-format -i --style=file <file>
|
||||||
|
Language: Cpp
|
||||||
|
BasedOnStyle: Google
|
@ -0,0 +1,84 @@
|
|||||||
|
# Ignore CI build directory
|
||||||
|
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
|
@ -0,0 +1,73 @@
|
|||||||
|
# Build matrix / environment variable are explained on:
|
||||||
|
# https://docs.travis-ci.com/user/customizing-the-build/
|
||||||
|
# This file can be validated on:
|
||||||
|
# http://lint.travis-ci.org/
|
||||||
|
|
||||||
|
language: cpp
|
||||||
|
|
||||||
|
# Define the matrix explicitly, manually expanding the combinations of (os, compiler, env).
|
||||||
|
# It is more tedious, but grants us far more flexibility.
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: linux
|
||||||
|
before_install: chmod -R +x ./ci/*platformio.sh
|
||||||
|
install: ./ci/install-platformio.sh
|
||||||
|
script: ./ci/build-platformio.sh
|
||||||
|
- os: linux
|
||||||
|
dist: xenial
|
||||||
|
compiler: gcc
|
||||||
|
install: ./ci/install-linux.sh && ./ci/log-config.sh
|
||||||
|
script: ./ci/build-linux-bazel.sh
|
||||||
|
- os: linux
|
||||||
|
dist: xenial
|
||||||
|
compiler: clang
|
||||||
|
install: ./ci/install-linux.sh && ./ci/log-config.sh
|
||||||
|
script: ./ci/build-linux-bazel.sh
|
||||||
|
- os: linux
|
||||||
|
compiler: gcc
|
||||||
|
env: BUILD_TYPE=Debug VERBOSE=1 CXX_FLAGS=-std=c++11
|
||||||
|
- os: linux
|
||||||
|
compiler: clang
|
||||||
|
env: BUILD_TYPE=Release VERBOSE=1 CXX_FLAGS=-std=c++11 -Wgnu-zero-variadic-macro-arguments
|
||||||
|
- os: linux
|
||||||
|
compiler: clang
|
||||||
|
env: BUILD_TYPE=Release VERBOSE=1 CXX_FLAGS=-std=c++11 NO_EXCEPTION=ON NO_RTTI=ON COMPILER_IS_GNUCXX=ON
|
||||||
|
- os: osx
|
||||||
|
compiler: gcc
|
||||||
|
env: BUILD_TYPE=Release VERBOSE=1 CXX_FLAGS=-std=c++11 HOMEBREW_LOGS=~/homebrew-logs HOMEBREW_TEMP=~/homebrew-temp
|
||||||
|
- os: osx
|
||||||
|
compiler: clang
|
||||||
|
env: BUILD_TYPE=Release VERBOSE=1 CXX_FLAGS=-std=c++11 HOMEBREW_LOGS=~/homebrew-logs HOMEBREW_TEMP=~/homebrew-temp
|
||||||
|
|
||||||
|
# These are the install and build (script) phases for the most common entries in the matrix. They could be included
|
||||||
|
# in each entry in the matrix, but that is just repetitive.
|
||||||
|
install:
|
||||||
|
- ./ci/install-${TRAVIS_OS_NAME}.sh
|
||||||
|
- . ./ci/env-${TRAVIS_OS_NAME}.sh
|
||||||
|
- ./ci/log-config.sh
|
||||||
|
|
||||||
|
script: ./ci/travis.sh
|
||||||
|
|
||||||
|
# This section installs the necessary dependencies.
|
||||||
|
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.9
|
||||||
|
packages:
|
||||||
|
- g++-4.9
|
||||||
|
- clang-3.9
|
||||||
|
update: true
|
||||||
|
homebrew:
|
||||||
|
packages:
|
||||||
|
- ccache
|
||||||
|
- gcc@4.9
|
||||||
|
- llvm@4
|
||||||
|
update: true
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email: false
|
@ -0,0 +1,179 @@
|
|||||||
|
# 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)
|
||||||
|
|
||||||
|
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
|
||||||
|
|
||||||
|
package(default_visibility = ["//visibility:public"])
|
||||||
|
|
||||||
|
licenses(["notice"])
|
||||||
|
|
||||||
|
config_setting(
|
||||||
|
name = "windows",
|
||||||
|
constraint_values = ["@bazel_tools//platforms:windows"],
|
||||||
|
)
|
||||||
|
|
||||||
|
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({
|
||||||
|
":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({
|
||||||
|
":windows": [],
|
||||||
|
"//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/strings",
|
||||||
|
"@com_google_absl//absl/types:optional",
|
||||||
|
"@com_google_absl//absl/types:variant",
|
||||||
|
],
|
||||||
|
"//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"],
|
||||||
|
)
|
@ -0,0 +1,36 @@
|
|||||||
|
# Note: CMake support is community-based. The maintainers do not use CMake
|
||||||
|
# internally.
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 2.8.8)
|
||||||
|
|
||||||
|
if (POLICY CMP0048)
|
||||||
|
cmake_policy(SET CMP0048 NEW)
|
||||||
|
endif (POLICY CMP0048)
|
||||||
|
|
||||||
|
project(googletest-distribution)
|
||||||
|
set(GOOGLETEST_VERSION 1.10.0)
|
||||||
|
|
||||||
|
if (CMAKE_VERSION VERSION_LESS "3.1")
|
||||||
|
add_definitions(-std=c++11)
|
||||||
|
else()
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
if(NOT CYGWIN)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
include(CMakeDependentOption)
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
||||||
|
if(BUILD_GMOCK)
|
||||||
|
add_subdirectory( googlemock )
|
||||||
|
else()
|
||||||
|
add_subdirectory( googletest )
|
||||||
|
endif()
|
@ -0,0 +1,142 @@
|
|||||||
|
# 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 change rather
|
||||||
|
than a GitHub Pull Request. If you are not able to submit an internal change 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).
|
||||||
|
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).
|
||||||
|
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.6.4 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.
|
||||||
|
|
||||||
|
### 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/pump_manual.md).
|
@ -0,0 +1,28 @@
|
|||||||
|
Copyright 2008, 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.
|
@ -0,0 +1,134 @@
|
|||||||
|
# Google Test
|
||||||
|
|
||||||
|
#### OSS Builds Status:
|
||||||
|
|
||||||
|
[![Build Status](https://api.travis-ci.org/google/googletest.svg?branch=master)](https://travis-ci.org/google/googletest)
|
||||||
|
[![Build status](https://ci.appveyor.com/api/projects/status/4o38plt0xbo1ubc8/branch/master?svg=true)](https://ci.appveyor.com/project/GoogleTestAppVeyor/googletest/branch/master)
|
||||||
|
|
||||||
|
### Future Plans
|
||||||
|
|
||||||
|
#### 1.8.x Release:
|
||||||
|
|
||||||
|
[the 1.8.x](https://github.com/google/googletest/releases/tag/release-1.8.1) is
|
||||||
|
the last release that works with pre-C++11 compilers. The 1.8.x will not accept
|
||||||
|
any requests for any new features and any bugfix requests will only be accepted
|
||||||
|
if proven "critical"
|
||||||
|
|
||||||
|
#### Post 1.8.x:
|
||||||
|
|
||||||
|
On-going work to improve/cleanup/pay technical debt. When this work is completed
|
||||||
|
there will be a 1.9.x tagged release
|
||||||
|
|
||||||
|
#### Post 1.9.x
|
||||||
|
|
||||||
|
Post 1.9.x googletest will follow
|
||||||
|
[Abseil Live at Head philosophy](https://abseil.io/about/philosophy)
|
||||||
|
|
||||||
|
## Welcome to **Google Test**, 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.
|
||||||
|
|
||||||
|
Please subscribe to the mailing list at googletestframework@googlegroups.com for
|
||||||
|
questions, discussions, and development.
|
||||||
|
|
||||||
|
### Getting started:
|
||||||
|
|
||||||
|
The information for **Google Test** is available in the
|
||||||
|
[Google Test Primer](googletest/docs/primer.md) documentation.
|
||||||
|
|
||||||
|
**Google Mock** is an extension to Google Test for writing and using C++ mock
|
||||||
|
classes. See the separate [Google Mock documentation](googlemock/README.md).
|
||||||
|
|
||||||
|
More detailed documentation for googletest is in its interior
|
||||||
|
[googletest/README.md](googletest/README.md) file.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* An [xUnit](https://en.wikipedia.org/wiki/XUnit) test framework.
|
||||||
|
* Test discovery.
|
||||||
|
* A rich set of assertions.
|
||||||
|
* User-defined assertions.
|
||||||
|
* Death tests.
|
||||||
|
* Fatal and non-fatal failures.
|
||||||
|
* Value-parameterized tests.
|
||||||
|
* Type-parameterized tests.
|
||||||
|
* Various options for running the tests.
|
||||||
|
* XML test report generation.
|
||||||
|
|
||||||
|
## Platforms
|
||||||
|
|
||||||
|
Google test has been used on a variety of platforms:
|
||||||
|
|
||||||
|
* Linux
|
||||||
|
* Mac OS X
|
||||||
|
* Windows
|
||||||
|
* Cygwin
|
||||||
|
* MinGW
|
||||||
|
* Windows Mobile
|
||||||
|
* Symbian
|
||||||
|
* PlatformIO
|
||||||
|
|
||||||
|
## Who Is Using Google Test?
|
||||||
|
|
||||||
|
In addition to many internal projects at Google, Google Test 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.
|
||||||
|
* [Protocol Buffers](https://github.com/google/protobuf), Google's data
|
||||||
|
interchange format.
|
||||||
|
* The [OpenCV](http://opencv.org/) computer vision library.
|
||||||
|
* [tiny-dnn](https://github.com/tiny-dnn/tiny-dnn): header only,
|
||||||
|
dependency-free deep learning framework in C++11.
|
||||||
|
|
||||||
|
## Related Open Source Projects
|
||||||
|
|
||||||
|
[GTest Runner](https://github.com/nholthaus/gtest-runner) is a Qt5 based
|
||||||
|
automated test-runner and Graphical User Interface with powerful features for
|
||||||
|
Windows and Linux platforms.
|
||||||
|
|
||||||
|
[Google Test UI](https://github.com/ospector/gtest-gbar) is 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. Google
|
||||||
|
Test UI is written in C#.
|
||||||
|
|
||||||
|
[GTest TAP Listener](https://github.com/kinow/gtest-tap-listener) is an event
|
||||||
|
listener for Google Test that implements the
|
||||||
|
[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.
|
||||||
|
|
||||||
|
[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.
|
||||||
|
|
||||||
|
[GoogleTest Adapter](https://marketplace.visualstudio.com/items?itemName=DavidSchuldenfrei.gtest-adapter)
|
||||||
|
is a VS Code extension allowing to view Google Tests in a tree view, and
|
||||||
|
run/debug your tests.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
Google Test is designed to have fairly minimal requirements to build and use
|
||||||
|
with your projects, but there are some. If you notice any problems on your
|
||||||
|
platform, please notify
|
||||||
|
[googletestframework@googlegroups.com](https://groups.google.com/forum/#!forum/googletestframework).
|
||||||
|
Patches for fixing them are welcome!
|
||||||
|
|
||||||
|
### Build Requirements
|
||||||
|
|
||||||
|
These are the base requirements to build and use Google Test from a source
|
||||||
|
package:
|
||||||
|
|
||||||
|
* [Bazel](https://bazel.build/) or [CMake](https://cmake.org/). NOTE: Bazel is
|
||||||
|
the build system that googletest is using internally and tests against.
|
||||||
|
CMake is community-supported.
|
||||||
|
|
||||||
|
* a C++11-standard-compliant compiler
|
||||||
|
|
||||||
|
## Contributing change
|
||||||
|
|
||||||
|
Please read the [`CONTRIBUTING.md`](CONTRIBUTING.md) for details on how to
|
||||||
|
contribute to this project.
|
||||||
|
|
||||||
|
Happy testing!
|
@ -0,0 +1,23 @@
|
|||||||
|
workspace(name = "com_google_googletest")
|
||||||
|
|
||||||
|
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||||
|
|
||||||
|
# Abseil
|
||||||
|
http_archive(
|
||||||
|
name = "com_google_absl",
|
||||||
|
urls = ["https://github.com/abseil/abseil-cpp/archive/master.zip"],
|
||||||
|
strip_prefix = "abseil-cpp-master",
|
||||||
|
)
|
||||||
|
|
||||||
|
http_archive(
|
||||||
|
name = "rules_cc",
|
||||||
|
strip_prefix = "rules_cc-master",
|
||||||
|
urls = ["https://github.com/bazelbuild/rules_cc/archive/master.zip"],
|
||||||
|
)
|
||||||
|
|
||||||
|
http_archive(
|
||||||
|
name = "rules_python",
|
||||||
|
strip_prefix = "rules_python-master",
|
||||||
|
urls = ["https://github.com/bazelbuild/rules_python/archive/master.zip"],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,154 @@
|
|||||||
|
version: '{build}'
|
||||||
|
|
||||||
|
os: Visual Studio 2015
|
||||||
|
|
||||||
|
environment:
|
||||||
|
matrix:
|
||||||
|
- compiler: msvc-15-seh
|
||||||
|
generator: "Visual Studio 15 2017"
|
||||||
|
build_system: cmake
|
||||||
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||||
|
|
||||||
|
- compiler: msvc-15-seh
|
||||||
|
generator: "Visual Studio 15 2017 Win64"
|
||||||
|
build_system: cmake
|
||||||
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||||
|
enabled_on_pr: yes
|
||||||
|
|
||||||
|
- compiler: msvc-15-seh
|
||||||
|
build_system: bazel
|
||||||
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||||
|
enabled_on_pr: yes
|
||||||
|
|
||||||
|
- compiler: msvc-14-seh
|
||||||
|
build_system: cmake
|
||||||
|
generator: "Visual Studio 14 2015"
|
||||||
|
enabled_on_pr: yes
|
||||||
|
|
||||||
|
- compiler: msvc-14-seh
|
||||||
|
build_system: cmake
|
||||||
|
generator: "Visual Studio 14 2015 Win64"
|
||||||
|
|
||||||
|
- compiler: gcc-6.3.0-posix
|
||||||
|
build_system: cmake
|
||||||
|
generator: "MinGW Makefiles"
|
||||||
|
cxx_path: 'C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin'
|
||||||
|
enabled_on_pr: yes
|
||||||
|
|
||||||
|
configuration:
|
||||||
|
- Debug
|
||||||
|
|
||||||
|
build:
|
||||||
|
verbosity: minimal
|
||||||
|
|
||||||
|
install:
|
||||||
|
- ps: |
|
||||||
|
Write-Output "Compiler: $env:compiler"
|
||||||
|
Write-Output "Generator: $env:generator"
|
||||||
|
Write-Output "Env:Configuation: $env:configuration"
|
||||||
|
Write-Output "Env: $env"
|
||||||
|
if (-not (Test-Path env:APPVEYOR_PULL_REQUEST_NUMBER)) {
|
||||||
|
Write-Output "This is *NOT* a pull request build"
|
||||||
|
} else {
|
||||||
|
Write-Output "This is a pull request build"
|
||||||
|
if (-not (Test-Path env:enabled_on_pr) -or $env:enabled_on_pr -ne "yes") {
|
||||||
|
Write-Output "PR builds are *NOT* explicitly enabled"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# install Bazel
|
||||||
|
if ($env:build_system -eq "bazel") {
|
||||||
|
appveyor DownloadFile https://github.com/bazelbuild/bazel/releases/download/0.28.1/bazel-0.28.1-windows-x86_64.exe -FileName bazel.exe
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($env:build_system -eq "cmake") {
|
||||||
|
# git bash conflicts with MinGW makefiles
|
||||||
|
if ($env:generator -eq "MinGW Makefiles") {
|
||||||
|
$env:path = $env:path.replace("C:\Program Files\Git\usr\bin;", "")
|
||||||
|
if ($env:cxx_path -ne "") {
|
||||||
|
$env:path += ";$env:cxx_path"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
before_build:
|
||||||
|
- ps: |
|
||||||
|
$env:root=$env:APPVEYOR_BUILD_FOLDER
|
||||||
|
Write-Output "env:root: $env:root"
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
- ps: |
|
||||||
|
# Only enable some builds for pull requests, the AppVeyor queue is too long.
|
||||||
|
if ((Test-Path env:APPVEYOR_PULL_REQUEST_NUMBER) -And (-not (Test-Path env:enabled_on_pr) -or $env:enabled_on_pr -ne "yes")) {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
# special case - build with Bazel
|
||||||
|
if ($env:build_system -eq "bazel") {
|
||||||
|
& $env:root\bazel.exe build -c opt //:gtest_samples
|
||||||
|
if ($LastExitCode -eq 0) { # bazel writes to StdErr and PowerShell interprets it as an error
|
||||||
|
$host.SetShouldExit(0)
|
||||||
|
} else { # a real error
|
||||||
|
throw "Exec: $ErrorMessage"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# by default build with CMake
|
||||||
|
md _build -Force | Out-Null
|
||||||
|
cd _build
|
||||||
|
|
||||||
|
$conf = if ($env:generator -eq "MinGW Makefiles") {"-DCMAKE_BUILD_TYPE=$env:configuration"} else {"-DCMAKE_CONFIGURATION_TYPES=Debug;Release"}
|
||||||
|
# Disable test for MinGW (gtest tests fail, gmock tests can not build)
|
||||||
|
$gtest_build_tests = if ($env:generator -eq "MinGW Makefiles") {"-Dgtest_build_tests=OFF"} else {"-Dgtest_build_tests=ON"}
|
||||||
|
$gmock_build_tests = if ($env:generator -eq "MinGW Makefiles") {"-Dgmock_build_tests=OFF"} else {"-Dgmock_build_tests=ON"}
|
||||||
|
& cmake -G "$env:generator" $conf -Dgtest_build_samples=ON $gtest_build_tests $gmock_build_tests ..
|
||||||
|
if ($LastExitCode -ne 0) {
|
||||||
|
throw "Exec: $ErrorMessage"
|
||||||
|
}
|
||||||
|
$cmake_parallel = if ($env:generator -eq "MinGW Makefiles") {"-j2"} else {"/m"}
|
||||||
|
& cmake --build . --config $env:configuration -- $cmake_parallel
|
||||||
|
if ($LastExitCode -ne 0) {
|
||||||
|
throw "Exec: $ErrorMessage"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
skip_commits:
|
||||||
|
files:
|
||||||
|
- '**/*.md'
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
- ps: |
|
||||||
|
# Only enable some builds for pull requests, the AppVeyor queue is too long.
|
||||||
|
if ((Test-Path env:APPVEYOR_PULL_REQUEST_NUMBER) -And (-not (Test-Path env:enabled_on_pr) -or $env:enabled_on_pr -ne "yes")) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ($env:build_system -eq "bazel") {
|
||||||
|
# special case - testing with Bazel
|
||||||
|
& $env:root\bazel.exe test //:gtest_samples
|
||||||
|
if ($LastExitCode -eq 0) { # bazel writes to StdErr and PowerShell interprets it as an error
|
||||||
|
$host.SetShouldExit(0)
|
||||||
|
} else { # a real error
|
||||||
|
throw "Exec: $ErrorMessage"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($env:build_system -eq "cmake") {
|
||||||
|
# built with CMake - test with CTest
|
||||||
|
if ($env:generator -eq "MinGW Makefiles") {
|
||||||
|
return # No test available for MinGW
|
||||||
|
}
|
||||||
|
|
||||||
|
& ctest -C $env:configuration --timeout 600 --output-on-failure
|
||||||
|
if ($LastExitCode -ne 0) {
|
||||||
|
throw "Exec: $ErrorMessage"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
- path: '_build/CMakeFiles/*.log'
|
||||||
|
name: logs
|
||||||
|
- path: '_build/Testing/**/*.xml'
|
||||||
|
name: test_results
|
||||||
|
- path: 'bazel-testlogs/**/test.log'
|
||||||
|
name: test_logs
|
||||||
|
- path: 'bazel-testlogs/**/test.xml'
|
||||||
|
name: test_results
|
@ -0,0 +1,37 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
bazel version
|
||||||
|
bazel build --curses=no //...:all
|
||||||
|
bazel test --curses=no //...:all
|
||||||
|
bazel test --curses=no //...:all --define absl=1
|
@ -0,0 +1,2 @@
|
|||||||
|
# run PlatformIO builds
|
||||||
|
platformio run
|
@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file should be sourced, and not executed as a standalone script.
|
||||||
|
#
|
||||||
|
|
||||||
|
# TODO() - we can check if this is being sourced using $BASH_VERSION and $BASH_SOURCE[0] != ${0}.
|
||||||
|
|
||||||
|
if [ "${TRAVIS_OS_NAME}" = "linux" ]; then
|
||||||
|
if [ "$CXX" = "g++" ]; then export CXX="g++-4.9" CC="gcc-4.9"; fi
|
||||||
|
if [ "$CXX" = "clang++" ]; then export CXX="clang++-3.9" CC="clang-3.9"; fi
|
||||||
|
fi
|
@ -0,0 +1,47 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file should be sourced, and not executed as a standalone script.
|
||||||
|
#
|
||||||
|
|
||||||
|
# TODO() - we can check if this is being sourced using $BASH_VERSION and $BASH_SOURCE[0] != ${0}.
|
||||||
|
#
|
||||||
|
|
||||||
|
if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
|
||||||
|
if [ "$CXX" = "clang++" ]; then
|
||||||
|
# $PATH needs to be adjusted because the llvm tap doesn't install the
|
||||||
|
# package to /usr/local/bin, etc, like the gcc tap does.
|
||||||
|
# See: https://github.com/Homebrew/legacy-homebrew/issues/29733
|
||||||
|
clang_version=3.9
|
||||||
|
export PATH="/usr/local/opt/llvm@${clang_version}/bin:$PATH";
|
||||||
|
fi
|
||||||
|
fi
|
@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# This file is typically sourced by another script.
|
||||||
|
# if possible, ask for the precise number of processors,
|
||||||
|
# otherwise take 2 processors as reasonable default; see
|
||||||
|
# https://docs.travis-ci.com/user/speeding-up-the-build/#Makefile-optimization
|
||||||
|
if [ -x /usr/bin/getconf ]; then
|
||||||
|
NPROCESSORS=$(/usr/bin/getconf _NPROCESSORS_ONLN)
|
||||||
|
else
|
||||||
|
NPROCESSORS=2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# as of 2017-09-04 Travis CI reports 32 processors, but GCC build
|
||||||
|
# crashes if parallelized too much (maybe memory consumption problem),
|
||||||
|
# so limit to 4 processors for the time being.
|
||||||
|
if [ $NPROCESSORS -gt 4 ] ; then
|
||||||
|
echo "$0:Note: Limiting processors to use by make from $NPROCESSORS to 4."
|
||||||
|
NPROCESSORS=4
|
||||||
|
fi
|
@ -0,0 +1,49 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
if [ "${TRAVIS_OS_NAME}" != linux ]; then
|
||||||
|
echo "Not a Linux build; skipping installation"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [ "${TRAVIS_SUDO}" = "true" ]; then
|
||||||
|
echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | \
|
||||||
|
sudo tee /etc/apt/sources.list.d/bazel.list
|
||||||
|
curl https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -
|
||||||
|
sudo apt-get update && sudo apt-get install -y bazel gcc-4.9 g++-4.9 clang-3.9
|
||||||
|
elif [ "${CXX}" = "clang++" ]; then
|
||||||
|
# Use ccache, assuming $HOME/bin is in the path, which is true in the Travis build environment.
|
||||||
|
ln -sf /usr/bin/ccache $HOME/bin/${CXX};
|
||||||
|
ln -sf /usr/bin/ccache $HOME/bin/${CC};
|
||||||
|
fi
|
@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
if [ "${TRAVIS_OS_NAME}" != "osx" ]; then
|
||||||
|
echo "Not a macOS build; skipping installation"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
brew update
|
||||||
|
brew install ccache gcc@4.9
|
@ -0,0 +1,5 @@
|
|||||||
|
# install PlatformIO
|
||||||
|
sudo pip install -U platformio
|
||||||
|
|
||||||
|
# update PlatformIO
|
||||||
|
platformio update
|
@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# ccache on OS X needs installation first
|
||||||
|
# reset ccache statistics
|
||||||
|
ccache --zero-stats
|
||||||
|
|
||||||
|
echo PATH=${PATH}
|
||||||
|
|
||||||
|
echo "Compiler configuration:"
|
||||||
|
echo CXX=${CXX}
|
||||||
|
echo CC=${CC}
|
||||||
|
echo CXXFLAGS=${CXXFLAGS}
|
||||||
|
|
||||||
|
echo "C++ compiler version:"
|
||||||
|
${CXX} --version || echo "${CXX} does not seem to support the --version flag"
|
||||||
|
${CXX} -v || echo "${CXX} does not seem to support the -v flag"
|
||||||
|
|
||||||
|
echo "C compiler version:"
|
||||||
|
${CC} --version || echo "${CXX} does not seem to support the --version flag"
|
||||||
|
${CC} -v || echo "${CXX} does not seem to support the -v flag"
|
@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
set -evx
|
||||||
|
|
||||||
|
. ci/get-nprocessors.sh
|
||||||
|
|
||||||
|
# if possible, ask for the precise number of processors,
|
||||||
|
# otherwise take 2 processors as reasonable default; see
|
||||||
|
# https://docs.travis-ci.com/user/speeding-up-the-build/#Makefile-optimization
|
||||||
|
if [ -x /usr/bin/getconf ]; then
|
||||||
|
NPROCESSORS=$(/usr/bin/getconf _NPROCESSORS_ONLN)
|
||||||
|
else
|
||||||
|
NPROCESSORS=2
|
||||||
|
fi
|
||||||
|
# as of 2017-09-04 Travis CI reports 32 processors, but GCC build
|
||||||
|
# crashes if parallelized too much (maybe memory consumption problem),
|
||||||
|
# so limit to 4 processors for the time being.
|
||||||
|
if [ $NPROCESSORS -gt 4 ] ; then
|
||||||
|
echo "$0:Note: Limiting processors to use by make from $NPROCESSORS to 4."
|
||||||
|
NPROCESSORS=4
|
||||||
|
fi
|
||||||
|
# Tell make to use the processors. No preceding '-' required.
|
||||||
|
MAKEFLAGS="j${NPROCESSORS}"
|
||||||
|
export MAKEFLAGS
|
||||||
|
|
||||||
|
env | sort
|
||||||
|
|
||||||
|
# Set default values to OFF for these variables if not specified.
|
||||||
|
: "${NO_EXCEPTION:=OFF}"
|
||||||
|
: "${NO_RTTI:=OFF}"
|
||||||
|
: "${COMPILER_IS_GNUCXX:=OFF}"
|
||||||
|
|
||||||
|
mkdir build || true
|
||||||
|
cd build
|
||||||
|
cmake -Dgtest_build_samples=ON \
|
||||||
|
-Dgtest_build_tests=ON \
|
||||||
|
-Dgmock_build_tests=ON \
|
||||||
|
-Dcxx_no_exception=$NO_EXCEPTION \
|
||||||
|
-Dcxx_no_rtti=$NO_RTTI \
|
||||||
|
-DCMAKE_COMPILER_IS_GNUCXX=$COMPILER_IS_GNUCXX \
|
||||||
|
-DCMAKE_CXX_FLAGS=$CXX_FLAGS \
|
||||||
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
|
..
|
||||||
|
make
|
||||||
|
CTEST_OUTPUT_ON_FAILURE=1 make test
|
@ -0,0 +1,233 @@
|
|||||||
|
########################################################################
|
||||||
|
# Note: CMake support is community-based. The maintainers do not use CMake
|
||||||
|
# internally.
|
||||||
|
#
|
||||||
|
# CMake build script for Google Mock.
|
||||||
|
#
|
||||||
|
# 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'.
|
||||||
|
# For more options, run 'ctest --help'.
|
||||||
|
|
||||||
|
option(gmock_build_tests "Build all of Google Mock's own tests." OFF)
|
||||||
|
|
||||||
|
# A directory to find Google Test sources.
|
||||||
|
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/gtest/CMakeLists.txt")
|
||||||
|
set(gtest_dir gtest)
|
||||||
|
else()
|
||||||
|
set(gtest_dir ../googletest)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Defines pre_project_set_up_hermetic_build() and set_up_hermetic_build().
|
||||||
|
include("${gtest_dir}/cmake/hermetic_build.cmake" OPTIONAL)
|
||||||
|
|
||||||
|
if (COMMAND pre_project_set_up_hermetic_build)
|
||||||
|
# Google Test also calls hermetic setup functions from add_subdirectory,
|
||||||
|
# although its changes will not affect things at the current scope.
|
||||||
|
pre_project_set_up_hermetic_build()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
#
|
||||||
|
# Project-wide settings
|
||||||
|
|
||||||
|
# Name of the project.
|
||||||
|
#
|
||||||
|
# CMake files in this project can refer to the root source directory
|
||||||
|
# as ${gmock_SOURCE_DIR} and to the root binary directory as
|
||||||
|
# ${gmock_BINARY_DIR}.
|
||||||
|
# Language "C" is required for find_package(Threads).
|
||||||
|
if (CMAKE_VERSION VERSION_LESS 3.0)
|
||||||
|
project(gmock CXX C)
|
||||||
|
else()
|
||||||
|
cmake_policy(SET CMP0048 NEW)
|
||||||
|
project(gmock VERSION ${GOOGLETEST_VERSION} LANGUAGES CXX C)
|
||||||
|
endif()
|
||||||
|
cmake_minimum_required(VERSION 2.6.4)
|
||||||
|
|
||||||
|
if (COMMAND set_up_hermetic_build)
|
||||||
|
set_up_hermetic_build()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Instructs CMake to process Google Test's CMakeLists.txt and add its
|
||||||
|
# targets to the current scope. We are placing Google Test's binary
|
||||||
|
# directory in a subdirectory of our own as VC compilation may break
|
||||||
|
# if they are the same (the default).
|
||||||
|
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
|
||||||
|
# changes there don't affect the current scope. Therefore we have to
|
||||||
|
# call it again here.
|
||||||
|
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.
|
||||||
|
set(gmock_build_include_dirs
|
||||||
|
"${gmock_SOURCE_DIR}/include"
|
||||||
|
"${gmock_SOURCE_DIR}"
|
||||||
|
"${gtest_SOURCE_DIR}/include"
|
||||||
|
# This directory is needed to build directly from Google Test sources.
|
||||||
|
"${gtest_SOURCE_DIR}")
|
||||||
|
include_directories(${gmock_build_include_dirs})
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
#
|
||||||
|
# Defines the gmock & gmock_main libraries. User tests should link
|
||||||
|
# with one of them.
|
||||||
|
|
||||||
|
# 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
|
||||||
|
# a user aggressive about warnings.
|
||||||
|
if (MSVC)
|
||||||
|
cxx_library(gmock
|
||||||
|
"${cxx_strict}"
|
||||||
|
"${gtest_dir}/src/gtest-all.cc"
|
||||||
|
src/gmock-all.cc)
|
||||||
|
|
||||||
|
cxx_library(gmock_main
|
||||||
|
"${cxx_strict}"
|
||||||
|
"${gtest_dir}/src/gtest-all.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)
|
||||||
|
cxx_library(gmock_main "${cxx_strict}" src/gmock_main.cc)
|
||||||
|
target_link_libraries(gmock_main PUBLIC gmock)
|
||||||
|
endif()
|
||||||
|
# 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
|
||||||
|
# in via add_subdirectory() rather than being a standalone build).
|
||||||
|
if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")
|
||||||
|
target_include_directories(gmock SYSTEM INTERFACE
|
||||||
|
"$<BUILD_INTERFACE:${gmock_build_include_dirs}>"
|
||||||
|
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>")
|
||||||
|
target_include_directories(gmock_main SYSTEM INTERFACE
|
||||||
|
"$<BUILD_INTERFACE:${gmock_build_include_dirs}>"
|
||||||
|
"$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
#
|
||||||
|
# Install rules
|
||||||
|
install_project(gmock gmock_main)
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
#
|
||||||
|
# Google Mock's own tests.
|
||||||
|
#
|
||||||
|
# You can skip this section if you aren't interested in testing
|
||||||
|
# Google Mock itself.
|
||||||
|
#
|
||||||
|
# The tests are not built by default. To build them, set the
|
||||||
|
# gmock_build_tests option to ON. You can do it by running ccmake
|
||||||
|
# or specifying the -Dgmock_build_tests=ON flag when running cmake.
|
||||||
|
|
||||||
|
if (gmock_build_tests)
|
||||||
|
# This must be set in the root directory for the tests to be run by
|
||||||
|
# 'make test' or ctest.
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/RunTest.ps1"
|
||||||
|
CONTENT
|
||||||
|
"$project_bin = \"${CMAKE_BINARY_DIR}/bin/$<CONFIG>\"
|
||||||
|
$env:Path = \"$project_bin;$env:Path\"
|
||||||
|
& $args")
|
||||||
|
elseif (MINGW OR CYGWIN)
|
||||||
|
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/RunTest.ps1"
|
||||||
|
CONTENT
|
||||||
|
"$project_bin = (cygpath --windows ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
$env:Path = \"$project_bin;$env:Path\"
|
||||||
|
& $args")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
cxx_test(gmock-actions_test gmock_main)
|
||||||
|
cxx_test(gmock-cardinalities_test gmock_main)
|
||||||
|
cxx_test(gmock_ex_test gmock_main)
|
||||||
|
cxx_test(gmock-function-mocker_test gmock_main)
|
||||||
|
cxx_test(gmock-generated-actions_test gmock_main)
|
||||||
|
cxx_test(gmock-generated-function-mockers_test gmock_main)
|
||||||
|
cxx_test(gmock-generated-matchers_test gmock_main)
|
||||||
|
cxx_test(gmock-internal-utils_test gmock_main)
|
||||||
|
cxx_test(gmock-matchers_test gmock_main)
|
||||||
|
cxx_test(gmock-more-actions_test gmock_main)
|
||||||
|
cxx_test(gmock-nice-strict_test gmock_main)
|
||||||
|
cxx_test(gmock-port_test gmock_main)
|
||||||
|
cxx_test(gmock-spec-builders_test gmock_main)
|
||||||
|
cxx_test(gmock_link_test gmock_main test/gmock_link2_test.cc)
|
||||||
|
cxx_test(gmock_test gmock_main)
|
||||||
|
|
||||||
|
if (DEFINED GTEST_HAS_PTHREAD)
|
||||||
|
cxx_test(gmock_stress_test gmock)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# gmock_all_test is commented to save time building and running tests.
|
||||||
|
# Uncomment if necessary.
|
||||||
|
# cxx_test(gmock_all_test gmock_main)
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# C++ tests built with non-standard compiler flags.
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
cxx_library(gmock_main_no_exception "${cxx_no_exception}"
|
||||||
|
"${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc)
|
||||||
|
|
||||||
|
cxx_library(gmock_main_no_rtti "${cxx_no_rtti}"
|
||||||
|
"${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc)
|
||||||
|
|
||||||
|
else()
|
||||||
|
cxx_library(gmock_main_no_exception "${cxx_no_exception}" src/gmock_main.cc)
|
||||||
|
target_link_libraries(gmock_main_no_exception PUBLIC gmock)
|
||||||
|
|
||||||
|
cxx_library(gmock_main_no_rtti "${cxx_no_rtti}" src/gmock_main.cc)
|
||||||
|
target_link_libraries(gmock_main_no_rtti PUBLIC gmock)
|
||||||
|
endif()
|
||||||
|
cxx_test_with_flags(gmock-more-actions_no_exception_test "${cxx_no_exception}"
|
||||||
|
gmock_main_no_exception test/gmock-more-actions_test.cc)
|
||||||
|
|
||||||
|
cxx_test_with_flags(gmock_no_rtti_test "${cxx_no_rtti}"
|
||||||
|
gmock_main_no_rtti test/gmock-spec-builders_test.cc)
|
||||||
|
|
||||||
|
cxx_shared_library(shared_gmock_main "${cxx_default}"
|
||||||
|
"${gtest_dir}/src/gtest-all.cc" src/gmock-all.cc src/gmock_main.cc)
|
||||||
|
|
||||||
|
# Tests that a binary can be built with Google Mock as a shared library. On
|
||||||
|
# some system configurations, it may not possible to run the binary without
|
||||||
|
# knowing more details about the system configurations. We do not try to run
|
||||||
|
# this binary. To get a more robust shared library coverage, configure with
|
||||||
|
# -DBUILD_SHARED_LIBS=ON.
|
||||||
|
cxx_executable_with_flags(shared_gmock_test_ "${cxx_default}"
|
||||||
|
shared_gmock_main test/gmock-spec-builders_test.cc)
|
||||||
|
set_target_properties(shared_gmock_test_
|
||||||
|
PROPERTIES
|
||||||
|
COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Python tests.
|
||||||
|
|
||||||
|
cxx_executable(gmock_leak_test_ test gmock_main)
|
||||||
|
py_test(gmock_leak_test)
|
||||||
|
|
||||||
|
cxx_executable(gmock_output_test_ test gmock)
|
||||||
|
py_test(gmock_output_test)
|
||||||
|
endif()
|
@ -0,0 +1,40 @@
|
|||||||
|
# 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>
|
@ -0,0 +1,28 @@
|
|||||||
|
Copyright 2008, 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.
|
@ -0,0 +1,44 @@
|
|||||||
|
# Googletest Mocking (gMock) Framework
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
It is inspired by:
|
||||||
|
|
||||||
|
* [jMock](http://www.jmock.org/),
|
||||||
|
* [EasyMock](http://www.easymock.org/), and
|
||||||
|
* [Hamcrest](http://code.google.com/p/hamcrest/),
|
||||||
|
|
||||||
|
and designed with C++'s specifics in mind.
|
||||||
|
|
||||||
|
gMock:
|
||||||
|
|
||||||
|
- provides a declarative syntax for defining mocks,
|
||||||
|
- can define partial (hybrid) mocks, which are a cross of real and mock
|
||||||
|
objects,
|
||||||
|
- handles functions of arbitrary types and overloaded functions,
|
||||||
|
- comes with a rich set of matchers for validating function arguments,
|
||||||
|
- uses an intuitive syntax for controlling the behavior of a mock,
|
||||||
|
- does automatic verification of expectations (no record-and-replay needed),
|
||||||
|
- allows arbitrary (partial) ordering constraints on function calls to be
|
||||||
|
expressed,
|
||||||
|
- lets a user extend it by defining new matchers and actions.
|
||||||
|
- does not use exceptions, and
|
||||||
|
- is easy to learn and use.
|
||||||
|
|
||||||
|
Details and examples can be found here:
|
||||||
|
|
||||||
|
* [gMock for Dummies](docs/for_dummies.md)
|
||||||
|
* [Legacy gMock FAQ](docs/gmock_faq.md)
|
||||||
|
* [gMock Cookbook](docs/cook_book.md)
|
||||||
|
* [gMock Cheat Sheet](docs/cheat_sheet.md)
|
||||||
|
|
||||||
|
Please note that code under scripts/generator/ is from the [cppclean
|
||||||
|
project](http://code.google.com/p/cppclean/) and under the Apache
|
||||||
|
License, which is different from Google Mock's license.
|
||||||
|
|
||||||
|
Google Mock is a part of
|
||||||
|
[Google Test C++ testing framework](http://github.com/google/googletest/) and a
|
||||||
|
subject to the same requirements.
|
@ -0,0 +1,11 @@
|
|||||||
|
prefix=${pcfiledir}/../..
|
||||||
|
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||||
|
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||||
|
|
||||||
|
Name: gmock
|
||||||
|
Description: GoogleMock (without main() function)
|
||||||
|
Version: @PROJECT_VERSION@
|
||||||
|
URL: https://github.com/google/googletest
|
||||||
|
Requires: gtest
|
||||||
|
Libs: -L${libdir} -lgmock @CMAKE_THREAD_LIBS_INIT@
|
||||||
|
Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@ @CMAKE_THREAD_LIBS_INIT@
|
@ -0,0 +1,11 @@
|
|||||||
|
prefix=${pcfiledir}/../..
|
||||||
|
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||||
|
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||||
|
|
||||||
|
Name: gmock_main
|
||||||
|
Description: GoogleMock (with main() function)
|
||||||
|
Version: @PROJECT_VERSION@
|
||||||
|
URL: https://github.com/google/googletest
|
||||||
|
Requires: gmock
|
||||||
|
Libs: -L${libdir} -lgmock_main @CMAKE_THREAD_LIBS_INIT@
|
||||||
|
Cflags: -I${includedir} @GTEST_HAS_PTHREAD_MACRO@ @CMAKE_THREAD_LIBS_INIT@
|
@ -0,0 +1,781 @@
|
|||||||
|
## gMock Cheat Sheet
|
||||||
|
|
||||||
|
<!-- GOOGLETEST_CM0019 DO NOT DELETE -->
|
||||||
|
|
||||||
|
<!-- GOOGLETEST_CM0033 DO NOT DELETE -->
|
||||||
|
|
||||||
|
### Defining a Mock Class
|
||||||
|
|
||||||
|
#### Mocking a Normal Class {#MockClass}
|
||||||
|
|
||||||
|
Given
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
|
||||||
|
class MockFoo : public Foo {
|
||||||
|
...
|
||||||
|
MOCK_METHOD(int, GetSize, (), (const, override));
|
||||||
|
MOCK_METHOD(string, Describe, (const char* name), (override));
|
||||||
|
MOCK_METHOD(string, Describe, (int type), (override));
|
||||||
|
MOCK_METHOD(bool, Process, (Bar elem, int count), (override));
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
To create a "nice" mock, which ignores all uninteresting calls, a "naggy" mock,
|
||||||
|
which warns on all uninteresting calls, or a "strict" mock, which treats them as
|
||||||
|
failures:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::NiceMock;
|
||||||
|
using ::testing::NaggyMock;
|
||||||
|
using ::testing::StrictMock;
|
||||||
|
|
||||||
|
NiceMock<MockFoo> nice_foo; // The type is a subclass of MockFoo.
|
||||||
|
NaggyMock<MockFoo> naggy_foo; // The type is a subclass of MockFoo.
|
||||||
|
StrictMock<MockFoo> strict_foo; // The type is a subclass of MockFoo.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** A mock object is currently naggy by default. We may make it nice by
|
||||||
|
default in the future.
|
||||||
|
|
||||||
|
#### Mocking a Class Template {#MockTemplate}
|
||||||
|
|
||||||
|
Class templates can be mocked just like any class.
|
||||||
|
|
||||||
|
To mock
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template <typename Elem>
|
||||||
|
class StackInterface {
|
||||||
|
...
|
||||||
|
virtual ~StackInterface();
|
||||||
|
virtual int GetSize() const = 0;
|
||||||
|
virtual void Push(const Elem& x) = 0;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
(note that all member functions that are mocked, including `~StackInterface()`
|
||||||
|
**must** be virtual).
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template <typename Elem>
|
||||||
|
class MockStack : public StackInterface<Elem> {
|
||||||
|
...
|
||||||
|
MOCK_METHOD(int, GetSize, (), (const, override));
|
||||||
|
MOCK_METHOD(void, Push, (const Elem& x), (override));
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Specifying Calling Conventions for Mock Functions
|
||||||
|
|
||||||
|
If your mock function doesn't use the default calling convention, you can
|
||||||
|
specify it by adding `Calltype(convention)` to `MOCK_METHOD`'s 4th parameter.
|
||||||
|
For example,
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
MOCK_METHOD(bool, Foo, (int n), (Calltype(STDMETHODCALLTYPE)));
|
||||||
|
MOCK_METHOD(int, Bar, (double x, double y),
|
||||||
|
(const, Calltype(STDMETHODCALLTYPE)));
|
||||||
|
```
|
||||||
|
|
||||||
|
where `STDMETHODCALLTYPE` is defined by `<objbase.h>` on Windows.
|
||||||
|
|
||||||
|
### Using Mocks in Tests {#UsingMocks}
|
||||||
|
|
||||||
|
The typical work flow is:
|
||||||
|
|
||||||
|
1. Import the gMock names you need to use. All gMock symbols are in the
|
||||||
|
`testing` namespace unless they are macros or otherwise noted.
|
||||||
|
2. Create the mock objects.
|
||||||
|
3. Optionally, set the default actions of the mock objects.
|
||||||
|
4. Set your expectations on the mock objects (How will they be called? What
|
||||||
|
will they do?).
|
||||||
|
5. Exercise code that uses the mock objects; if necessary, check the result
|
||||||
|
using googletest assertions.
|
||||||
|
6. When a mock object is destructed, gMock automatically verifies that all
|
||||||
|
expectations on it have been satisfied.
|
||||||
|
|
||||||
|
Here's an example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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 {#OnCall}
|
||||||
|
|
||||||
|
gMock has a **built-in default action** for any function that returns `void`,
|
||||||
|
`bool`, a numeric value, or a pointer. In C++11, it will additionally returns
|
||||||
|
the default-constructed value, if one exists for the given type.
|
||||||
|
|
||||||
|
To customize the default action for functions with return type *`T`*:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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();
|
||||||
|
```
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Sets the default action for return type std::unique_ptr<Buzz> to
|
||||||
|
// creating a new Buzz every time.
|
||||||
|
DefaultValue<std::unique_ptr<Buzz>>::SetFactory(
|
||||||
|
[] { return MakeUnique<Buzz>(AccessLevel::kInternal); });
|
||||||
|
|
||||||
|
// When this fires, the default action of MakeBuzz() will run, which
|
||||||
|
// will return a new Buzz object.
|
||||||
|
EXPECT_CALL(mock_buzzer_, MakeBuzz("hello")).Times(AnyNumber());
|
||||||
|
|
||||||
|
auto buzz1 = mock_buzzer_.MakeBuzz("hello");
|
||||||
|
auto buzz2 = mock_buzzer_.MakeBuzz("hello");
|
||||||
|
EXPECT_NE(nullptr, buzz1);
|
||||||
|
EXPECT_NE(nullptr, buzz2);
|
||||||
|
EXPECT_NE(buzz1, buzz2);
|
||||||
|
|
||||||
|
// Resets the default action for return type std::unique_ptr<Buzz>,
|
||||||
|
// to avoid interfere with other tests.
|
||||||
|
DefaultValue<std::unique_ptr<Buzz>>::Clear();
|
||||||
|
```
|
||||||
|
|
||||||
|
To customize the default action for a particular method of a specific mock
|
||||||
|
object, use `ON_CALL()`. `ON_CALL()` has a similar syntax to `EXPECT_CALL()`,
|
||||||
|
but it is used for setting default behaviors (when you do not require that the
|
||||||
|
mock method is called). See [here](cook_book.md#UseOnCall) for a more detailed
|
||||||
|
discussion.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
ON_CALL(mock-object, method(matchers))
|
||||||
|
.With(multi-argument-matcher) ?
|
||||||
|
.WillByDefault(action);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Setting Expectations {#ExpectCall}
|
||||||
|
|
||||||
|
`EXPECT_CALL()` sets **expectations** on a mock method (How will it be called?
|
||||||
|
What will it do?):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
EXPECT_CALL(mock-object, method (matchers)?)
|
||||||
|
.With(multi-argument-matcher) ?
|
||||||
|
.Times(cardinality) ?
|
||||||
|
.InSequence(sequences) *
|
||||||
|
.After(expectations) *
|
||||||
|
.WillOnce(action) *
|
||||||
|
.WillRepeatedly(action) ?
|
||||||
|
.RetiresOnSaturation(); ?
|
||||||
|
```
|
||||||
|
|
||||||
|
For each item above, `?` means it can be used at most once, while `*` means it
|
||||||
|
can be used any number of times.
|
||||||
|
|
||||||
|
In order to pass, `EXPECT_CALL` must be used before the calls are actually made.
|
||||||
|
|
||||||
|
The `(matchers)` is a comma-separated list of matchers that correspond to each
|
||||||
|
of the arguments of `method`, and sets the expectation only for calls of
|
||||||
|
`method` that matches all of the matchers.
|
||||||
|
|
||||||
|
If `(matchers)` is omitted, the expectation is the same as if the matchers were
|
||||||
|
set to anything matchers (for example, `(_, _, _, _)` for a four-arg method).
|
||||||
|
|
||||||
|
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 {#MatcherList}
|
||||||
|
|
||||||
|
<!-- GOOGLETEST_CM0020 DO NOT DELETE -->
|
||||||
|
|
||||||
|
A **matcher** matches a *single* argument. You can use it inside `ON_CALL()` or
|
||||||
|
`EXPECT_CALL()`, or use it to validate a value directly using two macros:
|
||||||
|
|
||||||
|
<!-- mdformat off(github rendering does not support multiline tables) -->
|
||||||
|
| Macro | Description |
|
||||||
|
| :----------------------------------- | :------------------------------------ |
|
||||||
|
| `EXPECT_THAT(actual_value, matcher)` | Asserts that `actual_value` matches `matcher`. |
|
||||||
|
| `ASSERT_THAT(actual_value, matcher)` | The same as `EXPECT_THAT(actual_value, matcher)`, except that it generates a **fatal** failure. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
Built-in matchers (where `argument` is the function argument, e.g.
|
||||||
|
`actual_value` in the example above, or when used in the context of
|
||||||
|
`EXPECT_CALL(mock_object, method(matchers))`, the arguments of `method`) are
|
||||||
|
divided into several categories:
|
||||||
|
|
||||||
|
#### Wildcard
|
||||||
|
|
||||||
|
Matcher | Description
|
||||||
|
:-------------------------- | :-----------------------------------------------
|
||||||
|
`_` | `argument` can be any value of the correct type.
|
||||||
|
`A<type>()` or `An<type>()` | `argument` can be any value of type `type`.
|
||||||
|
|
||||||
|
#### Generic Comparison
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| Matcher | Description |
|
||||||
|
| :--------------------- | :-------------------------------------------------- |
|
||||||
|
| `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` |
|
||||||
|
| `IsFalse()` | `argument` evaluates to `false` in a Boolean context. |
|
||||||
|
| `IsTrue()` | `argument` evaluates to `true` in a Boolean context. |
|
||||||
|
| `IsNull()` | `argument` is a `NULL` pointer (raw or smart). |
|
||||||
|
| `NotNull()` | `argument` is a non-null pointer (raw or smart). |
|
||||||
|
| `Optional(m)` | `argument` is `optional<>` that contains a value matching `m`. |
|
||||||
|
| `VariantWith<T>(m)` | `argument` is `variant<>` that holds the alternative of type T with a value matching `m`. |
|
||||||
|
| `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. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
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 {#FpMatchers}
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| Matcher | Description |
|
||||||
|
| :------------------------------- | :--------------------------------- |
|
||||||
|
| `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. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
The above matchers use ULP-based comparison (the same as used in 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.
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| Matcher | Description |
|
||||||
|
| :------------------------------------------------ | :----------------------- |
|
||||||
|
| `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. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
#### String Matchers
|
||||||
|
|
||||||
|
The `argument` can be either a C string or a C++ string object:
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| Matcher | Description |
|
||||||
|
| :---------------------- | :------------------------------------------------- |
|
||||||
|
| `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`. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
`ContainsRegex()` and `MatchesRegex()` take ownership of the `RE` object. They
|
||||||
|
use the regular expression syntax defined
|
||||||
|
[here](../../googletest/docs/advanced.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:
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| Matcher | Description |
|
||||||
|
| :---------------------------------------- | :------------------------------- |
|
||||||
|
| `BeginEndDistanceIs(m)` | `argument` is a container whose `begin()` and `end()` iterators are separated by a number of increments matching `m`. E.g. `BeginEndDistanceIs(2)` or `BeginEndDistanceIs(Lt(2))`. For containers that define a `size()` method, `SizeIs(m)` may be more efficient. |
|
||||||
|
| `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. |
|
||||||
|
| `ElementsAreArray({e0, e1, ..., en})`, `ElementsAreArray(a_container)`, `ElementsAreArray(begin, end)`, `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, iterator range, or C-style array. |
|
||||||
|
| `IsEmpty()` | `argument` is an empty container (`container.empty()`). |
|
||||||
|
| `IsSubsetOf({e0, e1, ..., en})`, `IsSubsetOf(a_container)`, `IsSubsetOf(begin, end)`, `IsSubsetOf(array)`, or `IsSubsetOf(array, count)` | `argument` matches `UnorderedElementsAre(x0, x1, ..., xk)` for some subset `{x0, x1, ..., xk}` of the expected matchers. |
|
||||||
|
| `IsSupersetOf({e0, e1, ..., en})`, `IsSupersetOf(a_container)`, `IsSupersetOf(begin, end)`, `IsSupersetOf(array)`, or `IsSupersetOf(array, count)` | Some subset of `argument` matches `UnorderedElementsAre(`expected matchers`)`. |
|
||||||
|
| `Pointwise(m, container)`, `Pointwise(m, {e0, e1, ..., en})` | `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 of the elements, each element matches an `ei` (for a different `i`), which can be a value or a matcher. |
|
||||||
|
| `UnorderedElementsAreArray({e0, e1, ..., en})`, `UnorderedElementsAreArray(a_container)`, `UnorderedElementsAreArray(begin, end)`, `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, iterator range, or C-style array. |
|
||||||
|
| `UnorderedPointwise(m, container)`, `UnorderedPointwise(m, {e0, e1, ..., en})` | Like `Pointwise(m, container)`, but ignores the order of elements. |
|
||||||
|
| `WhenSorted(m)` | When `argument` is sorted using the `<` operator, it matches container matcher `m`. E.g. `WhenSorted(ElementsAre(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(), ElementsAre(3, 2, 1))`. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
|
||||||
|
* These matchers can also match:
|
||||||
|
1. a native array passed by reference (e.g. in `Foo(const int (&a)[5])`),
|
||||||
|
and
|
||||||
|
2. an array passed as a pointer and a count (e.g. in `Bar(const T* buffer,
|
||||||
|
int len)` -- see [Multi-argument Matchers](#MultiArgMatchers)).
|
||||||
|
* 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::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==`, one might write:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::std::get;
|
||||||
|
MATCHER(FooEq, "") {
|
||||||
|
return std::get<0>(arg).Equals(std::get<1>(arg));
|
||||||
|
}
|
||||||
|
...
|
||||||
|
EXPECT_THAT(actual_foos, Pointwise(FooEq(), expected_foos));
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Member Matchers
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| Matcher | Description |
|
||||||
|
| :------------------------------ | :----------------------------------------- |
|
||||||
|
| `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_. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
#### Matching the Result of a Function, Functor, or Callback
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| Matcher | Description |
|
||||||
|
| :--------------- | :------------------------------------------------ |
|
||||||
|
| `ResultOf(f, m)` | `f(argument)` matches matcher `m`, where `f` is a function or functor. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
#### Pointer Matchers
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| Matcher | Description |
|
||||||
|
| :------------------------ | :---------------------------------------------- |
|
||||||
|
| `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`. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
<!-- GOOGLETEST_CM0026 DO NOT DELETE -->
|
||||||
|
|
||||||
|
<!-- GOOGLETEST_CM0027 DO NOT DELETE -->
|
||||||
|
|
||||||
|
#### Multi-argument Matchers {#MultiArgMatchers}
|
||||||
|
|
||||||
|
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)`:
|
||||||
|
|
||||||
|
Matcher | Description
|
||||||
|
:------ | :----------
|
||||||
|
`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:
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| Matcher | Description |
|
||||||
|
| :------------------------- | :---------------------------------------------- |
|
||||||
|
| `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())`. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
#### Composite Matchers
|
||||||
|
|
||||||
|
You can make a matcher from one or more other matchers:
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| Matcher | Description |
|
||||||
|
| :------------------------------- | :-------------------------------------- |
|
||||||
|
| `AllOf(m1, m2, ..., mn)` | `argument` matches all of the matchers `m1` to `mn`. |
|
||||||
|
| `AllOfArray({m0, m1, ..., mn})`, `AllOfArray(a_container)`, `AllOfArray(begin, end)`, `AllOfArray(array)`, or `AllOfArray(array, count)` | The same as `AllOf()` except that the matchers come from an initializer list, STL-style container, iterator range, or C-style array. |
|
||||||
|
| `AnyOf(m1, m2, ..., mn)` | `argument` matches at least one of the matchers `m1` to `mn`. |
|
||||||
|
| `AnyOfArray({m0, m1, ..., mn})`, `AnyOfArray(a_container)`, `AnyOfArray(begin, end)`, `AnyOfArray(array)`, or `AnyOfArray(array, count)` | The same as `AnyOf()` except that the matchers come from an initializer list, STL-style container, iterator range, or C-style array. |
|
||||||
|
| `Not(m)` | `argument` doesn't match matcher `m`. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
<!-- GOOGLETEST_CM0028 DO NOT DELETE -->
|
||||||
|
|
||||||
|
#### Adapters for Matchers
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| Matcher | Description |
|
||||||
|
| :---------------------- | :------------------------------------ |
|
||||||
|
| `MatcherCast<T>(m)` | casts matcher `m` to type `Matcher<T>`. |
|
||||||
|
| `SafeMatcherCast<T>(m)` | [safely casts](cook_book.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. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
`AddressSatisfies(callback)` and `Truly(callback)` take ownership of `callback`,
|
||||||
|
which must be a permanent callback.
|
||||||
|
|
||||||
|
#### Using Matchers as Predicates {#MatchersAsPredicatesCheat}
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| Matcher | Description |
|
||||||
|
| :---------------------------- | :------------------------------------------ |
|
||||||
|
| `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`. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
#### Defining Matchers
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| Matcher | Description |
|
||||||
|
| :----------------------------------- | :------------------------------------ |
|
||||||
|
| `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`]. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
|
||||||
|
1. The `MATCHER*` macros cannot be used inside a function or class.
|
||||||
|
2. 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).
|
||||||
|
3. You can use `PrintToString(x)` to convert a value `x` of any type to a
|
||||||
|
string.
|
||||||
|
|
||||||
|
### Actions {#ActionList}
|
||||||
|
|
||||||
|
**Actions** specify what a mock function should do when invoked.
|
||||||
|
|
||||||
|
#### Returning a Value
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| | |
|
||||||
|
| :-------------------------- | :-------------------------------------------- |
|
||||||
|
| `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. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
#### Side Effects
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| | |
|
||||||
|
| :--------------------------------- | :-------------------------------------- |
|
||||||
|
| `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. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
#### Using a Function, Functor, or Lambda as an Action
|
||||||
|
|
||||||
|
In the following, by "callable" we mean a free function, `std::function`,
|
||||||
|
functor, or lambda.
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| | |
|
||||||
|
| :---------------------------------- | :------------------------------------- |
|
||||||
|
| `f` | Invoke f with the arguments passed to the mock function, where f is a callable. |
|
||||||
|
| `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. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
The return value of the invoked function is used as the return value of the
|
||||||
|
action.
|
||||||
|
|
||||||
|
When defining a callable to be used with `Invoke*()`, you can declare any unused
|
||||||
|
parameters as `Unused`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::Invoke;
|
||||||
|
double Distance(Unused, double x, double y) { return sqrt(x*x + y*y); }
|
||||||
|
...
|
||||||
|
EXPECT_CALL(mock, Foo("Hi", _, _)).WillOnce(Invoke(Distance));
|
||||||
|
```
|
||||||
|
|
||||||
|
`Invoke(callback)` and `InvokeWithoutArgs(callback)` take ownership of
|
||||||
|
`callback`, which must be permanent. The type of `callback` must be a base
|
||||||
|
callback type instead of a derived one, e.g.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
BlockingClosure* done = new BlockingClosure;
|
||||||
|
... Invoke(done) ...; // This won't compile!
|
||||||
|
|
||||||
|
Closure* done2 = new BlockingClosure;
|
||||||
|
... Invoke(done2) ...; // This works.
|
||||||
|
```
|
||||||
|
|
||||||
|
In `InvokeArgument<N>(...)`, if an argument needs to be passed by reference,
|
||||||
|
wrap it inside `ByRef()`. For example,
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::ByRef;
|
||||||
|
using ::testing::InvokeArgument;
|
||||||
|
...
|
||||||
|
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
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| Matcher | Description |
|
||||||
|
| :------------ | :----------------------------------------------------- |
|
||||||
|
| `DoDefault()` | Do the default action (specified by `ON_CALL()` or the built-in one). |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
**Note:** due to technical reasons, `DoDefault()` cannot be used inside a
|
||||||
|
composite action - trying to do so will result in a run-time error.
|
||||||
|
|
||||||
|
<!-- GOOGLETEST_CM0032 DO NOT DELETE -->
|
||||||
|
|
||||||
|
#### Composite Actions
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| | |
|
||||||
|
| :----------------------------- | :------------------------------------------ |
|
||||||
|
| `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. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
#### Defining Actions
|
||||||
|
|
||||||
|
<table border="1" cellspacing="0" cellpadding="1">
|
||||||
|
<tr>
|
||||||
|
<td>`struct SumAction {` <br>
|
||||||
|
 `template <typename T>` <br>
|
||||||
|
 `T operator()(T x, Ty) { return x + y; }` <br>
|
||||||
|
`};`
|
||||||
|
</td>
|
||||||
|
<td> Defines a generic functor that can be used as an action summing its
|
||||||
|
arguments. </td> </tr>
|
||||||
|
<tr>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| | |
|
||||||
|
| :--------------------------------- | :-------------------------------------- |
|
||||||
|
| `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`. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
The `ACTION*` macros cannot be used inside a function or class.
|
||||||
|
|
||||||
|
### Cardinalities {#CardinalityList}
|
||||||
|
|
||||||
|
These are used in `Times()` to specify how many times a mock function will be
|
||||||
|
called:
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| | |
|
||||||
|
| :---------------- | :----------------------------------------------------- |
|
||||||
|
| `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. |
|
||||||
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
### 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 {#AfterClause}
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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 {#UsingSequences}
|
||||||
|
|
||||||
|
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. *All expected calls* in the same sequence must
|
||||||
|
occur in the order they are specified.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::Return;
|
||||||
|
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:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::InSequence;
|
||||||
|
{
|
||||||
|
InSequence seq;
|
||||||
|
|
||||||
|
EXPECT_CALL(...)...;
|
||||||
|
EXPECT_CALL(...)...;
|
||||||
|
...
|
||||||
|
EXPECT_CALL(...)...;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
says that all expected calls in the scope of `seq` must occur in strict order.
|
||||||
|
The name `seq` is irrelevant.
|
||||||
|
|
||||||
|
### Verifying and Resetting a Mock
|
||||||
|
|
||||||
|
gMock will verify the expectations on a mock object when it is destructed, or
|
||||||
|
you can do it earlier:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::Mock;
|
||||||
|
...
|
||||||
|
// Verifies and removes the expectations on mock_obj;
|
||||||
|
// returns true if and only if successful.
|
||||||
|
Mock::VerifyAndClearExpectations(&mock_obj);
|
||||||
|
...
|
||||||
|
// Verifies and removes the expectations on mock_obj;
|
||||||
|
// also removes the default actions set by ON_CALL();
|
||||||
|
// returns true if and only if successful.
|
||||||
|
Mock::VerifyAndClear(&mock_obj);
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also tell gMock that a mock object can be leaked and doesn't need to be
|
||||||
|
verified:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
Mock::AllowLeak(&mock_obj);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mock Classes
|
||||||
|
|
||||||
|
gMock defines a convenient mock class template
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class MockFunction<R(A1, ..., An)> {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD(R, Call, (A1, ..., An));
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
See this [recipe](cook_book.md#using-check-points) for one application of it.
|
||||||
|
|
||||||
|
### Flags
|
||||||
|
|
||||||
|
<!-- mdformat off(no multiline tables) -->
|
||||||
|
| Flag | Description |
|
||||||
|
| :----------------------------- | :---------------------------------------- |
|
||||||
|
| `--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. |
|
||||||
|
<!-- mdformat on -->
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,700 @@
|
|||||||
|
## gMock for Dummies {#GMockForDummies}
|
||||||
|
|
||||||
|
<!-- GOOGLETEST_CM0013 DO NOT DELETE -->
|
||||||
|
|
||||||
|
### What Is gMock?
|
||||||
|
|
||||||
|
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 shall become much
|
||||||
|
clearer once you start to use mocks.
|
||||||
|
|
||||||
|
**gMock** 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/EasyMock does to Java (well, more or less).
|
||||||
|
|
||||||
|
When using gMock,
|
||||||
|
|
||||||
|
1. first, you use some simple macros to describe the interface you want to
|
||||||
|
mock, and they will expand to the implementation of your mock class;
|
||||||
|
2. next, you create some mock objects and specify its expectations and behavior
|
||||||
|
using an intuitive syntax;
|
||||||
|
3. then you exercise code that uses the mock objects. gMock will catch any
|
||||||
|
violation to the expectations as soon as it arises.
|
||||||
|
|
||||||
|
### Why gMock?
|
||||||
|
|
||||||
|
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
|
||||||
|
one.
|
||||||
|
|
||||||
|
In contrast, Java and Python programmers have some fine mock frameworks (jMock,
|
||||||
|
EasyMock, [Mox](http://wtf/mox), etc), 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.
|
||||||
|
|
||||||
|
gMock was built to help C++ programmers. It was inspired by jMock and EasyMock,
|
||||||
|
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, but it's 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 gMock 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
|
||||||
|
|
||||||
|
gMock is bundled with googletest.
|
||||||
|
|
||||||
|
### A Case for Mock Turtles
|
||||||
|
|
||||||
|
Let's look at an example. Suppose you are developing a graphics program that
|
||||||
|
relies on a [LOGO](http://en.wikipedia.org/wiki/Logo_programming_language)-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](http://en.wikipedia.org/wiki/Dependency_injection) and know the right thing
|
||||||
|
to do: instead of having your application talk to the system API directly, wrap
|
||||||
|
the API in an interface (say, `Turtle`) and code to that interface:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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 - gMock 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:
|
||||||
|
|
||||||
|
* Derive a class `MockTurtle` from `Turtle`.
|
||||||
|
* Take a *virtual* function of `Turtle` (while it's possible to
|
||||||
|
[mock non-virtual methods using templates](cook_book.md#MockingNonVirtualMethods),
|
||||||
|
it's much more involved).
|
||||||
|
* In the `public:` section of the child class, write `MOCK_METHOD();`
|
||||||
|
* Now comes the fun part: you take the function signature, cut-and-paste it
|
||||||
|
into the macro, and add two commas - one between the return type and the
|
||||||
|
name, another between the name and the argument list.
|
||||||
|
* If you're mocking a const method, add a 4th parameter containing `(const)`
|
||||||
|
(the parentheses are required).
|
||||||
|
* Since you're overriding a virtual method, we suggest adding the `override`
|
||||||
|
keyword. For const methods the 4th parameter becomes `(const, override)`,
|
||||||
|
for non-const methods just `(override)`. This isn't mandatory.
|
||||||
|
* Repeat until all virtual functions you want to mock are done. (It goes
|
||||||
|
without saying that *all* pure virtual methods in your abstract class must
|
||||||
|
be either mocked or overridden.)
|
||||||
|
|
||||||
|
After the process, you should have something like:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "gmock/gmock.h" // Brings in gMock.
|
||||||
|
|
||||||
|
class MockTurtle : public Turtle {
|
||||||
|
public:
|
||||||
|
...
|
||||||
|
MOCK_METHOD(void, PenUp, (), (override));
|
||||||
|
MOCK_METHOD(void, PenDown, (), (override));
|
||||||
|
MOCK_METHOD(void, Forward, (int distance), (override));
|
||||||
|
MOCK_METHOD(void, Turn, (int degrees), (override));
|
||||||
|
MOCK_METHOD(void, GoTo, (int x, int y), (override));
|
||||||
|
MOCK_METHOD(int, GetX, (), (const, override));
|
||||||
|
MOCK_METHOD(int, GetY, (), (const, override));
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
You don't need to define these mock methods somewhere else - the `MOCK_METHOD`
|
||||||
|
macro will generate the definitions for you. It's that simple!
|
||||||
|
|
||||||
|
#### 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), put
|
||||||
|
it in a `.h` and a `cc_library`. Then everyone can reference them 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.
|
||||||
|
|
||||||
|
<!-- GOOGLETEST_CM0029 DO NOT DELETE -->
|
||||||
|
|
||||||
|
### Using Mocks in Tests
|
||||||
|
|
||||||
|
Once you have a mock class, using it is easy. The typical work flow is:
|
||||||
|
|
||||||
|
1. Import the gMock 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.
|
||||||
|
2. Create some mock objects.
|
||||||
|
3. Specify your expectations on them (How many times will a method be called?
|
||||||
|
With what arguments? What should it do? etc.).
|
||||||
|
4. Exercise some code that uses the mocks; optionally, check the result using
|
||||||
|
googletest assertions. If a mock method is called more than expected or with
|
||||||
|
wrong arguments, you'll get an error immediately.
|
||||||
|
5. When a mock is destructed, gMock will automatically check whether all
|
||||||
|
expectations on it have been satisfied.
|
||||||
|
|
||||||
|
Here's an example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#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
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
```text
|
||||||
|
path/to/my_test.cc:119: Failure
|
||||||
|
Actual function call count doesn't match this expectation:
|
||||||
|
Actually: never called;
|
||||||
|
Expected: called at least once.
|
||||||
|
Stack trace:
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Tip 1:** If you run the test from an Emacs buffer, you can hit <Enter> on the
|
||||||
|
line number 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 turn on the heap checker in your tests
|
||||||
|
when you allocate mocks on the heap. You get that automatically if you use the
|
||||||
|
`gtest_main` library already.
|
||||||
|
|
||||||
|
**Important note:** gMock 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 gMock work like that?
|
||||||
|
Well, specifying the expectation beforehand allows gMock to report a violation
|
||||||
|
as soon as it rises, 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 gMock. However, as we shall reveal soon, gMock
|
||||||
|
allows you to do *so much more* with the mocks.
|
||||||
|
|
||||||
|
### 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. gMock provides the necessary means for you to do it "just
|
||||||
|
right."
|
||||||
|
|
||||||
|
#### General Syntax
|
||||||
|
|
||||||
|
In gMock we use the `EXPECT_CALL()` macro to set an expectation on a mock
|
||||||
|
method. The general syntax is:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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.)
|
||||||
|
If the method is not overloaded, the macro can also be called without matchers:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
EXPECT_CALL(mock_object, non-overloaded-method)
|
||||||
|
.Times(cardinality)
|
||||||
|
.WillOnce(action)
|
||||||
|
.WillRepeatedly(action);
|
||||||
|
```
|
||||||
|
|
||||||
|
This syntax allows the test writer to specify "called with any arguments"
|
||||||
|
without explicitly specifying the number or types of arguments. To avoid
|
||||||
|
unintended ambiguity, this syntax may only be used for methods which are not
|
||||||
|
overloaded
|
||||||
|
|
||||||
|
Either form of 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
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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? Well it serves two purposes: first
|
||||||
|
it makes expectations easily identifiable (either by `gsearch` or by a human
|
||||||
|
reader), and second it allows gMock 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 may specify what arguments we are
|
||||||
|
expecting, for example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Expects the turtle to move forward by 100 units.
|
||||||
|
EXPECT_CALL(turtle, Forward(100));
|
||||||
|
```
|
||||||
|
|
||||||
|
Oftentimes you do 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 aren't interested in the value of an argument, write `_`
|
||||||
|
as the argument, which means "anything goes":
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::_;
|
||||||
|
...
|
||||||
|
// Expects that the turtle jumps to somewhere on the x=50 line.
|
||||||
|
EXPECT_CALL(turtle, GoTo(50, _));
|
||||||
|
```
|
||||||
|
|
||||||
|
`_` 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. `_` is a
|
||||||
|
convenient way of saying "any value".
|
||||||
|
|
||||||
|
In the above examples, `100` and `50` are also matchers; implicitly, they are
|
||||||
|
the same as `Eq(100)` and `Eq(50)`, which specify that the argument must be
|
||||||
|
equal (using `operator==`) to the matcher argument. There are many
|
||||||
|
[built-in matchers](#MatcherList) for common types (as well as
|
||||||
|
[custom matchers](cook_book.md#NewMatchers)); for example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::Ge;
|
||||||
|
...
|
||||||
|
// Expects the turtle moves forward by at least 100.
|
||||||
|
EXPECT_CALL(turtle, Forward(Ge(100)));
|
||||||
|
```
|
||||||
|
|
||||||
|
If you don't care about *any* arguments, rather than specify `_` for each of
|
||||||
|
them you may instead omit the parameter list:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Expects the turtle to move forward.
|
||||||
|
EXPECT_CALL(turtle, Forward);
|
||||||
|
// Expects the turtle to jump somewhere.
|
||||||
|
EXPECT_CALL(turtle, GoTo);
|
||||||
|
```
|
||||||
|
|
||||||
|
This works for all non-overloaded methods; if a method is overloaded, you need
|
||||||
|
to help gMock resolve which overload is expected by specifying the number of
|
||||||
|
arguments and possibly also the
|
||||||
|
[types of the arguments](cook_book.md#SelectOverload).
|
||||||
|
|
||||||
|
#### 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
|
||||||
|
gMock will report a googletest 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
|
||||||
|
[here](cheat_sheet.md#CardinalityList).
|
||||||
|
|
||||||
|
The `Times()` clause can be omitted. **If you omit `Times()`, gMock 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
|
||||||
|
gMock.
|
||||||
|
|
||||||
|
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,
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::Return;
|
||||||
|
...
|
||||||
|
EXPECT_CALL(turtle, GetX())
|
||||||
|
.WillOnce(Return(100))
|
||||||
|
.WillOnce(Return(200))
|
||||||
|
.WillOnce(Return(300));
|
||||||
|
```
|
||||||
|
|
||||||
|
says that `turtle.GetX()` will be called *exactly three times* (gMock 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.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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* (gMock knows this as
|
||||||
|
we've written two `WillOnce()` clauses and a `WillRepeatedly()` while having no
|
||||||
|
explicit `Times()`), will return 100 and 200 respectively the first two times,
|
||||||
|
and 300 from the third time on.
|
||||||
|
|
||||||
|
Of course, if you explicitly write a `Times()`, gMock 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, gMock 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](cook_book.md#using-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:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::Return;
|
||||||
|
...
|
||||||
|
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
|
||||||
|
[cook book](http://<!-- GOOGLETEST_CM0012 DO NOT DELETE -->).
|
||||||
|
|
||||||
|
Time for another quiz! What do you think the following means?
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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 {#MultiExpectations}
|
||||||
|
|
||||||
|
So far we've only shown examples where you have a single expectation. More
|
||||||
|
realistically, you'll specify expectations on multiple mock methods which may be
|
||||||
|
from multiple mock objects.
|
||||||
|
|
||||||
|
By default, when a mock method is invoked, gMock 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:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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.
|
||||||
|
|
||||||
|
**Note:** Why does gMock 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.
|
||||||
|
|
||||||
|
**Tip:** It is very common to start with a catch-all expectation for a method
|
||||||
|
and `Times(AnyNumber())` (omitting arguments, or with `_` for all arguments, if
|
||||||
|
overloaded). This makes any calls to the method expected. This is not necessary
|
||||||
|
for methods that are not mentioned at all (these are "uninteresting"), but is
|
||||||
|
useful for methods that have some expectations, but for which other calls are
|
||||||
|
ok. See
|
||||||
|
[Understanding Uninteresting vs Unexpected Calls](cook_book.md#uninteresting-vs-unexpected).
|
||||||
|
|
||||||
|
#### Ordered vs Unordered Calls {#OrderedCalls}
|
||||||
|
|
||||||
|
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 gMock is easy:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::InSequence;
|
||||||
|
...
|
||||||
|
TEST(FooTest, DrawsLineSegment) {
|
||||||
|
...
|
||||||
|
{
|
||||||
|
InSequence seq;
|
||||||
|
|
||||||
|
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! The
|
||||||
|
details can be found [here](cook_book.md#OrderedCalls).)
|
||||||
|
|
||||||
|
#### All Expectations Are Sticky (Unless Said Otherwise) {#StickyExpectations}
|
||||||
|
|
||||||
|
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!):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::_;
|
||||||
|
using ::testing::AnyNumber;
|
||||||
|
...
|
||||||
|
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, gMock 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, gMock will report an error immediately. This is basically what we've
|
||||||
|
told you in the [Using Multiple Expectations](#MultiExpectations) section above.
|
||||||
|
|
||||||
|
This example shows that **expectations in gMock 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?
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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 violated" 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:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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 gMock, 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. This is called "naggy" behavior; to change, see
|
||||||
|
[The Nice, the Strict, and the Naggy](cook_book.md#NiceStrictNaggy).
|
@ -0,0 +1,396 @@
|
|||||||
|
## Legacy gMock FAQ {#GMockFaq}
|
||||||
|
|
||||||
|
<!-- GOOGLETEST_CM0021 DO NOT DELETE -->
|
||||||
|
|
||||||
|
### 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](#MockingNonVirtualMethods).
|
||||||
|
|
||||||
|
### Can I mock a variadic function?
|
||||||
|
|
||||||
|
You cannot mock a variadic function (i.e. a function taking ellipsis (`...`)
|
||||||
|
arguments) directly in gMock.
|
||||||
|
|
||||||
|
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 or her 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:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class Foo {
|
||||||
|
...
|
||||||
|
virtual void Bar(const int i) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MockFoo : public Foo {
|
||||||
|
...
|
||||||
|
MOCK_METHOD(void, Bar, (const int i), (override));
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
You may get the following warning:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
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:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
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:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void Bar(int* p); // Neither p nor *p is const.
|
||||||
|
void Bar(const int* p); // p is not const, but *p is.
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- GOOGLETEST_CM0030 DO NOT DELETE -->
|
||||||
|
|
||||||
|
### I can't figure out why gMock thinks my expectations are not satisfied. What should I do?
|
||||||
|
|
||||||
|
You might want to run your test with `--gmock_verbose=info`. This flag lets
|
||||||
|
gMock 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.
|
||||||
|
|
||||||
|
If you see the message "The mock function has no default action set, and its
|
||||||
|
return type has no default value set.", then try
|
||||||
|
[adding a default action](for_dummies.md#DefaultValue). Due to a known issue,
|
||||||
|
unexpected calls on mocks without default actions don't print out a detailed
|
||||||
|
comparison between the actual arguments and the expected arguments.
|
||||||
|
|
||||||
|
### My program crashed and `ScopedMockLog` spit out tons of messages. Is it a gMock bug?
|
||||||
|
|
||||||
|
gMock and `ScopedMockLog` are likely doing the right thing here.
|
||||||
|
|
||||||
|
When a test crashes, the failure signal handler will try to log a lot of
|
||||||
|
information (the stack trace, and the address map, for example). The messages
|
||||||
|
are compounded if you have many threads with depth stacks. When `ScopedMockLog`
|
||||||
|
intercepts these messages and finds that they don't match any expectations, it
|
||||||
|
prints an error for each of them.
|
||||||
|
|
||||||
|
You can learn to ignore the errors, or you can rewrite your expectations to make
|
||||||
|
your test more robust, for example, by adding something like:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::AnyNumber;
|
||||||
|
using ::testing::Not;
|
||||||
|
...
|
||||||
|
// Ignores any log not done by us.
|
||||||
|
EXPECT_CALL(log, Log(_, Not(EndsWith("/my_file.cc")), _))
|
||||||
|
.Times(AnyNumber());
|
||||||
|
```
|
||||||
|
|
||||||
|
### How can I assert that a function is NEVER called?
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::_;
|
||||||
|
...
|
||||||
|
EXPECT_CALL(foo, Bar(_))
|
||||||
|
.Times(0);
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- GOOGLETEST_CM0031 DO NOT DELETE -->
|
||||||
|
|
||||||
|
### I have a failed test where gMock tells me TWICE that a particular expectation is not satisfied. Isn't this redundant?
|
||||||
|
|
||||||
|
When gMock 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, gMock 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 heapcheck 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:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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 gMock do that?
|
||||||
|
|
||||||
|
When people complain about this, often they are referring to code like:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::Return;
|
||||||
|
...
|
||||||
|
// 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
|
||||||
|
gMock'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:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::Return;
|
||||||
|
...
|
||||||
|
// 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:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::Return;
|
||||||
|
...
|
||||||
|
// 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 gMock 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
|
||||||
|
gMock searches from front to back, this very useful pattern won't be possible.
|
||||||
|
|
||||||
|
### gMock 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
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::_;
|
||||||
|
...
|
||||||
|
EXPECT_CALL(foo, Bar(_))
|
||||||
|
.WillRepeatedly(...);
|
||||||
|
```
|
||||||
|
|
||||||
|
instead of
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::_;
|
||||||
|
...
|
||||||
|
ON_CALL(foo, Bar(_))
|
||||||
|
.WillByDefault(...);
|
||||||
|
```
|
||||||
|
|
||||||
|
This tells gMock that you do expect the calls and no warning should be printed.
|
||||||
|
|
||||||
|
Also, you can control the verbosity by specifying `--gmock_verbose=error`. Other
|
||||||
|
values are `info` and `warning`. 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 your mock function takes a pointer argument and you want to delete that
|
||||||
|
argument, you can use testing::DeleteArg<N>() to delete the N'th (zero-indexed)
|
||||||
|
argument:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::_;
|
||||||
|
...
|
||||||
|
MOCK_METHOD(void, Bar, (X* x, const Y& y));
|
||||||
|
...
|
||||||
|
EXPECT_CALL(mock_foo_, Bar(_, _))
|
||||||
|
.WillOnce(testing::DeleteArg<0>()));
|
||||||
|
```
|
||||||
|
|
||||||
|
### How can I perform an arbitrary action on a mock function's argument?
|
||||||
|
|
||||||
|
If you find yourself needing to perform some action that's not supported by
|
||||||
|
gMock directly, remember that you can define your own actions using
|
||||||
|
[`MakeAction()`](#NewMonoActions) or
|
||||||
|
[`MakePolymorphicAction()`](#NewPolyActions), or you can write a stub function
|
||||||
|
and invoke it using [`Invoke()`](#FunctionsAsActions).
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using ::testing::_;
|
||||||
|
using ::testing::Invoke;
|
||||||
|
...
|
||||||
|
MOCK_METHOD(void, Bar, (X* p));
|
||||||
|
...
|
||||||
|
EXPECT_CALL(mock_foo_, Bar(_))
|
||||||
|
.WillOnce(Invoke(MyAction(...)));
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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](https://testing.googleblog.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. gMock sucks!
|
||||||
|
|
||||||
|
I know it's not a question, but you get an answer for free any way. :-)
|
||||||
|
|
||||||
|
With gMock, 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 gMock'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, gMock 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, gMock dumps the stack trace when an uninteresting call is encountered.
|
||||||
|
From that you can figure out which mock function it is, and how it is called.
|
||||||
|
|
||||||
|
### I want to define a custom action. Should I use Invoke() or implement the ActionInterface 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
|
||||||
|
`testing/base/public/gmock-actions.h` for an example.
|
||||||
|
|
||||||
|
### I use SetArgPointee() in WillOnce(), but gcc complains about "conflicting return type specified". What does it mean?
|
||||||
|
|
||||||
|
You got this error as gMock 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()` that provides a value appropriate to the API
|
||||||
|
being mocked.
|
||||||
|
|
||||||
|
See this [recipe](cook_book.md#mocking-side-effects) for more details and an
|
||||||
|
example.
|
||||||
|
|
||||||
|
### 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.
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,157 @@
|
|||||||
|
// Copyright 2007, 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.
|
||||||
|
|
||||||
|
|
||||||
|
// Google Mock - a framework for writing C++ mock classes.
|
||||||
|
//
|
||||||
|
// This file implements some commonly used cardinalities. More
|
||||||
|
// cardinalities can be defined by the user implementing the
|
||||||
|
// CardinalityInterface interface if necessary.
|
||||||
|
|
||||||
|
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||||
|
|
||||||
|
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_
|
||||||
|
#define GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <ostream> // NOLINT
|
||||||
|
#include "gmock/internal/gmock-port.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
|
||||||
|
/* class A needs to have dll-interface to be used by clients of class B */)
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
// To implement a cardinality Foo, define:
|
||||||
|
// 1. a class FooCardinality that implements the
|
||||||
|
// CardinalityInterface interface, and
|
||||||
|
// 2. a factory function that creates a Cardinality object from a
|
||||||
|
// const FooCardinality*.
|
||||||
|
//
|
||||||
|
// The two-level delegation design follows that of Matcher, providing
|
||||||
|
// consistency for extension developers. It also eases ownership
|
||||||
|
// management as Cardinality objects can now be copied like plain values.
|
||||||
|
|
||||||
|
// The implementation of a cardinality.
|
||||||
|
class CardinalityInterface {
|
||||||
|
public:
|
||||||
|
virtual ~CardinalityInterface() {}
|
||||||
|
|
||||||
|
// Conservative estimate on the lower/upper bound of the number of
|
||||||
|
// calls allowed.
|
||||||
|
virtual int ConservativeLowerBound() const { return 0; }
|
||||||
|
virtual int ConservativeUpperBound() const { return INT_MAX; }
|
||||||
|
|
||||||
|
// Returns true if and only if call_count calls will satisfy this
|
||||||
|
// cardinality.
|
||||||
|
virtual bool IsSatisfiedByCallCount(int call_count) const = 0;
|
||||||
|
|
||||||
|
// Returns true if and only if call_count calls will saturate this
|
||||||
|
// cardinality.
|
||||||
|
virtual bool IsSaturatedByCallCount(int call_count) const = 0;
|
||||||
|
|
||||||
|
// Describes self to an ostream.
|
||||||
|
virtual void DescribeTo(::std::ostream* os) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A Cardinality is a copyable and IMMUTABLE (except by assignment)
|
||||||
|
// object that specifies how many times a mock function is expected to
|
||||||
|
// be called. The implementation of Cardinality is just a std::shared_ptr
|
||||||
|
// to const CardinalityInterface. Don't inherit from Cardinality!
|
||||||
|
class GTEST_API_ Cardinality {
|
||||||
|
public:
|
||||||
|
// Constructs a null cardinality. Needed for storing Cardinality
|
||||||
|
// objects in STL containers.
|
||||||
|
Cardinality() {}
|
||||||
|
|
||||||
|
// Constructs a Cardinality from its implementation.
|
||||||
|
explicit Cardinality(const CardinalityInterface* impl) : impl_(impl) {}
|
||||||
|
|
||||||
|
// Conservative estimate on the lower/upper bound of the number of
|
||||||
|
// calls allowed.
|
||||||
|
int ConservativeLowerBound() const { return impl_->ConservativeLowerBound(); }
|
||||||
|
int ConservativeUpperBound() const { return impl_->ConservativeUpperBound(); }
|
||||||
|
|
||||||
|
// Returns true if and only if call_count calls will satisfy this
|
||||||
|
// cardinality.
|
||||||
|
bool IsSatisfiedByCallCount(int call_count) const {
|
||||||
|
return impl_->IsSatisfiedByCallCount(call_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if and only if call_count calls will saturate this
|
||||||
|
// cardinality.
|
||||||
|
bool IsSaturatedByCallCount(int call_count) const {
|
||||||
|
return impl_->IsSaturatedByCallCount(call_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if and only if call_count calls will over-saturate this
|
||||||
|
// cardinality, i.e. exceed the maximum number of allowed calls.
|
||||||
|
bool IsOverSaturatedByCallCount(int call_count) const {
|
||||||
|
return impl_->IsSaturatedByCallCount(call_count) &&
|
||||||
|
!impl_->IsSatisfiedByCallCount(call_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describes self to an ostream
|
||||||
|
void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); }
|
||||||
|
|
||||||
|
// Describes the given actual call count to an ostream.
|
||||||
|
static void DescribeActualCallCountTo(int actual_call_count,
|
||||||
|
::std::ostream* os);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<const CardinalityInterface> impl_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Creates a cardinality that allows at least n calls.
|
||||||
|
GTEST_API_ Cardinality AtLeast(int n);
|
||||||
|
|
||||||
|
// Creates a cardinality that allows at most n calls.
|
||||||
|
GTEST_API_ Cardinality AtMost(int n);
|
||||||
|
|
||||||
|
// Creates a cardinality that allows any number of calls.
|
||||||
|
GTEST_API_ Cardinality AnyNumber();
|
||||||
|
|
||||||
|
// Creates a cardinality that allows between min and max calls.
|
||||||
|
GTEST_API_ Cardinality Between(int min, int max);
|
||||||
|
|
||||||
|
// Creates a cardinality that allows exactly n calls.
|
||||||
|
GTEST_API_ Cardinality Exactly(int n);
|
||||||
|
|
||||||
|
// Creates a cardinality from its implementation.
|
||||||
|
inline Cardinality MakeCardinality(const CardinalityInterface* c) {
|
||||||
|
return Cardinality(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
|
||||||
|
|
||||||
|
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_
|
@ -0,0 +1,253 @@
|
|||||||
|
// Copyright 2007, 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.
|
||||||
|
|
||||||
|
// Google Mock - a framework for writing C++ mock classes.
|
||||||
|
//
|
||||||
|
// This file implements MOCK_METHOD.
|
||||||
|
|
||||||
|
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||||
|
|
||||||
|
#ifndef THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_ // NOLINT
|
||||||
|
#define THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_ // NOLINT
|
||||||
|
|
||||||
|
#include "gmock/gmock-generated-function-mockers.h" // NOLINT
|
||||||
|
#include "gmock/internal/gmock-pp.h"
|
||||||
|
|
||||||
|
#define MOCK_METHOD(...) \
|
||||||
|
GMOCK_PP_VARIADIC_CALL(GMOCK_INTERNAL_MOCK_METHOD_ARG_, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_MOCK_METHOD_ARG_1(...) \
|
||||||
|
GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_MOCK_METHOD_ARG_2(...) \
|
||||||
|
GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_MOCK_METHOD_ARG_3(_Ret, _MethodName, _Args) \
|
||||||
|
GMOCK_INTERNAL_MOCK_METHOD_ARG_4(_Ret, _MethodName, _Args, ())
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_MOCK_METHOD_ARG_4(_Ret, _MethodName, _Args, _Spec) \
|
||||||
|
GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Args); \
|
||||||
|
GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Spec); \
|
||||||
|
GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE( \
|
||||||
|
GMOCK_PP_NARG0 _Args, GMOCK_INTERNAL_SIGNATURE(_Ret, _Args)); \
|
||||||
|
GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \
|
||||||
|
GMOCK_INTERNAL_MOCK_METHOD_IMPL( \
|
||||||
|
GMOCK_PP_NARG0 _Args, _MethodName, GMOCK_INTERNAL_HAS_CONST(_Spec), \
|
||||||
|
GMOCK_INTERNAL_HAS_OVERRIDE(_Spec), GMOCK_INTERNAL_HAS_FINAL(_Spec), \
|
||||||
|
GMOCK_INTERNAL_HAS_NOEXCEPT(_Spec), GMOCK_INTERNAL_GET_CALLTYPE(_Spec), \
|
||||||
|
(GMOCK_INTERNAL_SIGNATURE(_Ret, _Args)))
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_MOCK_METHOD_ARG_5(...) \
|
||||||
|
GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_MOCK_METHOD_ARG_6(...) \
|
||||||
|
GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_MOCK_METHOD_ARG_7(...) \
|
||||||
|
GMOCK_INTERNAL_WRONG_ARITY(__VA_ARGS__)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_WRONG_ARITY(...) \
|
||||||
|
static_assert( \
|
||||||
|
false, \
|
||||||
|
"MOCK_METHOD must be called with 3 or 4 arguments. _Ret, " \
|
||||||
|
"_MethodName, _Args and optionally _Spec. _Args and _Spec must be " \
|
||||||
|
"enclosed in parentheses. If _Ret is a type with unprotected commas, " \
|
||||||
|
"it must also be enclosed in parentheses.")
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_ASSERT_PARENTHESIS(_Tuple) \
|
||||||
|
static_assert( \
|
||||||
|
GMOCK_PP_IS_ENCLOSED_PARENS(_Tuple), \
|
||||||
|
GMOCK_PP_STRINGIZE(_Tuple) " should be enclosed in parentheses.")
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE(_N, ...) \
|
||||||
|
static_assert( \
|
||||||
|
std::is_function<__VA_ARGS__>::value, \
|
||||||
|
"Signature must be a function type, maybe return type contains " \
|
||||||
|
"unprotected comma."); \
|
||||||
|
static_assert( \
|
||||||
|
::testing::tuple_size<typename ::testing::internal::Function< \
|
||||||
|
__VA_ARGS__>::ArgumentTuple>::value == _N, \
|
||||||
|
"This method does not take " GMOCK_PP_STRINGIZE( \
|
||||||
|
_N) " arguments. Parenthesize all types with unproctected commas.")
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \
|
||||||
|
GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT, ~, _Spec)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_MOCK_METHOD_IMPL(_N, _MethodName, _Constness, \
|
||||||
|
_Override, _Final, _Noexcept, \
|
||||||
|
_CallType, _Signature) \
|
||||||
|
typename ::testing::internal::Function<GMOCK_PP_REMOVE_PARENS( \
|
||||||
|
_Signature)>::Result \
|
||||||
|
GMOCK_INTERNAL_EXPAND(_CallType) \
|
||||||
|
_MethodName(GMOCK_PP_REPEAT(GMOCK_INTERNAL_PARAMETER, _Signature, _N)) \
|
||||||
|
GMOCK_PP_IF(_Constness, const, ) GMOCK_PP_IF(_Noexcept, noexcept, ) \
|
||||||
|
GMOCK_PP_IF(_Override, override, ) \
|
||||||
|
GMOCK_PP_IF(_Final, final, ) { \
|
||||||
|
GMOCK_MOCKER_(_N, _Constness, _MethodName) \
|
||||||
|
.SetOwnerAndName(this, #_MethodName); \
|
||||||
|
return GMOCK_MOCKER_(_N, _Constness, _MethodName) \
|
||||||
|
.Invoke(GMOCK_PP_REPEAT(GMOCK_INTERNAL_FORWARD_ARG, _Signature, _N)); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<GMOCK_PP_REMOVE_PARENS(_Signature)> gmock_##_MethodName( \
|
||||||
|
GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_PARAMETER, _Signature, _N)) \
|
||||||
|
GMOCK_PP_IF(_Constness, const, ) { \
|
||||||
|
GMOCK_MOCKER_(_N, _Constness, _MethodName).RegisterOwner(this); \
|
||||||
|
return GMOCK_MOCKER_(_N, _Constness, _MethodName) \
|
||||||
|
.With(GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_ARGUMENT, , _N)); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<GMOCK_PP_REMOVE_PARENS(_Signature)> gmock_##_MethodName( \
|
||||||
|
const ::testing::internal::WithoutMatchers&, \
|
||||||
|
GMOCK_PP_IF(_Constness, const, )::testing::internal::Function< \
|
||||||
|
GMOCK_PP_REMOVE_PARENS(_Signature)>*) \
|
||||||
|
const GMOCK_PP_IF(_Noexcept, noexcept, ) { \
|
||||||
|
return GMOCK_PP_CAT(::testing::internal::AdjustConstness_, \
|
||||||
|
GMOCK_PP_IF(_Constness, const, ))(this) \
|
||||||
|
->gmock_##_MethodName(GMOCK_PP_REPEAT( \
|
||||||
|
GMOCK_INTERNAL_A_MATCHER_ARGUMENT, _Signature, _N)); \
|
||||||
|
} \
|
||||||
|
mutable ::testing::FunctionMocker<GMOCK_PP_REMOVE_PARENS(_Signature)> \
|
||||||
|
GMOCK_MOCKER_(_N, _Constness, _MethodName)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_EXPAND(...) __VA_ARGS__
|
||||||
|
|
||||||
|
// Five Valid modifiers.
|
||||||
|
#define GMOCK_INTERNAL_HAS_CONST(_Tuple) \
|
||||||
|
GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_CONST, ~, _Tuple))
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_HAS_OVERRIDE(_Tuple) \
|
||||||
|
GMOCK_PP_HAS_COMMA( \
|
||||||
|
GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_OVERRIDE, ~, _Tuple))
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_HAS_FINAL(_Tuple) \
|
||||||
|
GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_FINAL, ~, _Tuple))
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_HAS_NOEXCEPT(_Tuple) \
|
||||||
|
GMOCK_PP_HAS_COMMA( \
|
||||||
|
GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_NOEXCEPT, ~, _Tuple))
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_GET_CALLTYPE(_Tuple) \
|
||||||
|
GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GET_CALLTYPE_IMPL, ~, _Tuple)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT(_i, _, _elem) \
|
||||||
|
static_assert( \
|
||||||
|
(GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_CONST(_i, _, _elem)) + \
|
||||||
|
GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_OVERRIDE(_i, _, _elem)) + \
|
||||||
|
GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_FINAL(_i, _, _elem)) + \
|
||||||
|
GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem)) + \
|
||||||
|
GMOCK_INTERNAL_IS_CALLTYPE(_elem)) == 1, \
|
||||||
|
GMOCK_PP_STRINGIZE( \
|
||||||
|
_elem) " cannot be recognized as a valid specification modifier.");
|
||||||
|
|
||||||
|
// Modifiers implementation.
|
||||||
|
#define GMOCK_INTERNAL_DETECT_CONST(_i, _, _elem) \
|
||||||
|
GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_CONST_I_, _elem)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_DETECT_CONST_I_const ,
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_DETECT_OVERRIDE(_i, _, _elem) \
|
||||||
|
GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_OVERRIDE_I_, _elem)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_DETECT_OVERRIDE_I_override ,
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_DETECT_FINAL(_i, _, _elem) \
|
||||||
|
GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_FINAL_I_, _elem)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_DETECT_FINAL_I_final ,
|
||||||
|
|
||||||
|
// TODO(iserna): Maybe noexcept should accept an argument here as well.
|
||||||
|
#define GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem) \
|
||||||
|
GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_NOEXCEPT_I_, _elem)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_DETECT_NOEXCEPT_I_noexcept ,
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_GET_CALLTYPE_IMPL(_i, _, _elem) \
|
||||||
|
GMOCK_PP_IF(GMOCK_INTERNAL_IS_CALLTYPE(_elem), \
|
||||||
|
GMOCK_INTERNAL_GET_VALUE_CALLTYPE, GMOCK_PP_EMPTY) \
|
||||||
|
(_elem)
|
||||||
|
|
||||||
|
// TODO(iserna): GMOCK_INTERNAL_IS_CALLTYPE and
|
||||||
|
// GMOCK_INTERNAL_GET_VALUE_CALLTYPE needed more expansions to work on windows
|
||||||
|
// maybe they can be simplified somehow.
|
||||||
|
#define GMOCK_INTERNAL_IS_CALLTYPE(_arg) \
|
||||||
|
GMOCK_INTERNAL_IS_CALLTYPE_I( \
|
||||||
|
GMOCK_PP_CAT(GMOCK_INTERNAL_IS_CALLTYPE_HELPER_, _arg))
|
||||||
|
#define GMOCK_INTERNAL_IS_CALLTYPE_I(_arg) GMOCK_PP_IS_ENCLOSED_PARENS(_arg)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_GET_VALUE_CALLTYPE(_arg) \
|
||||||
|
GMOCK_INTERNAL_GET_VALUE_CALLTYPE_I( \
|
||||||
|
GMOCK_PP_CAT(GMOCK_INTERNAL_IS_CALLTYPE_HELPER_, _arg))
|
||||||
|
#define GMOCK_INTERNAL_GET_VALUE_CALLTYPE_I(_arg) \
|
||||||
|
GMOCK_PP_CAT(GMOCK_PP_IDENTITY, _arg)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_IS_CALLTYPE_HELPER_Calltype
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_SIGNATURE(_Ret, _Args) \
|
||||||
|
GMOCK_PP_IF(GMOCK_PP_IS_BEGIN_PARENS(_Ret), GMOCK_PP_REMOVE_PARENS, \
|
||||||
|
GMOCK_PP_IDENTITY) \
|
||||||
|
(_Ret)(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GET_TYPE, _, _Args))
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_GET_TYPE(_i, _, _elem) \
|
||||||
|
GMOCK_PP_COMMA_IF(_i) \
|
||||||
|
GMOCK_PP_IF(GMOCK_PP_IS_BEGIN_PARENS(_elem), GMOCK_PP_REMOVE_PARENS, \
|
||||||
|
GMOCK_PP_IDENTITY) \
|
||||||
|
(_elem)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_PARAMETER(_i, _Signature, _) \
|
||||||
|
GMOCK_PP_COMMA_IF(_i) \
|
||||||
|
GMOCK_INTERNAL_ARG_O(typename, GMOCK_PP_INC(_i), \
|
||||||
|
GMOCK_PP_REMOVE_PARENS(_Signature)) \
|
||||||
|
gmock_a##_i
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_FORWARD_ARG(_i, _Signature, _) \
|
||||||
|
GMOCK_PP_COMMA_IF(_i) \
|
||||||
|
::std::forward<GMOCK_INTERNAL_ARG_O(typename, GMOCK_PP_INC(_i), \
|
||||||
|
GMOCK_PP_REMOVE_PARENS(_Signature))>( \
|
||||||
|
gmock_a##_i)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_MATCHER_PARAMETER(_i, _Signature, _) \
|
||||||
|
GMOCK_PP_COMMA_IF(_i) \
|
||||||
|
GMOCK_INTERNAL_MATCHER_O(typename, GMOCK_PP_INC(_i), \
|
||||||
|
GMOCK_PP_REMOVE_PARENS(_Signature)) \
|
||||||
|
gmock_a##_i
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_MATCHER_ARGUMENT(_i, _1, _2) \
|
||||||
|
GMOCK_PP_COMMA_IF(_i) \
|
||||||
|
gmock_a##_i
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_A_MATCHER_ARGUMENT(_i, _Signature, _) \
|
||||||
|
GMOCK_PP_COMMA_IF(_i) \
|
||||||
|
::testing::A<GMOCK_INTERNAL_ARG_O(typename, GMOCK_PP_INC(_i), \
|
||||||
|
GMOCK_PP_REMOVE_PARENS(_Signature))>()
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_ARG_O(_tn, _i, ...) GMOCK_ARG_(_tn, _i, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define GMOCK_INTERNAL_MATCHER_O(_tn, _i, ...) \
|
||||||
|
GMOCK_MATCHER_(_tn, _i, __VA_ARGS__)
|
||||||
|
|
||||||
|
#endif // THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,627 @@
|
|||||||
|
$$ -*- mode: c++; -*-
|
||||||
|
$$ This is a Pump source file. Please use Pump to convert it to
|
||||||
|
$$ gmock-generated-actions.h.
|
||||||
|
$$
|
||||||
|
$var n = 10 $$ The maximum arity we support.
|
||||||
|
$$}} This meta comment fixes auto-indentation in editors.
|
||||||
|
// Copyright 2007, 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.
|
||||||
|
|
||||||
|
|
||||||
|
// Google Mock - a framework for writing C++ mock classes.
|
||||||
|
//
|
||||||
|
// This file implements some commonly used variadic actions.
|
||||||
|
|
||||||
|
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||||
|
|
||||||
|
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
|
||||||
|
#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "gmock/gmock-actions.h"
|
||||||
|
#include "gmock/internal/gmock-port.h"
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// A macro from the ACTION* family (defined later in this file)
|
||||||
|
// defines an action that can be used in a mock function. Typically,
|
||||||
|
// these actions only care about a subset of the arguments of the mock
|
||||||
|
// function. For example, if such an action only uses the second
|
||||||
|
// argument, it can be used in any mock function that takes >= 2
|
||||||
|
// arguments where the type of the second argument is compatible.
|
||||||
|
//
|
||||||
|
// Therefore, the action implementation must be prepared to take more
|
||||||
|
// arguments than it needs. The ExcessiveArg type is used to
|
||||||
|
// represent those excessive arguments. In order to keep the compiler
|
||||||
|
// error messages tractable, we define it in the testing namespace
|
||||||
|
// instead of testing::internal. However, this is an INTERNAL TYPE
|
||||||
|
// and subject to change without notice, so a user MUST NOT USE THIS
|
||||||
|
// TYPE DIRECTLY.
|
||||||
|
struct ExcessiveArg {};
|
||||||
|
|
||||||
|
// A helper class needed for implementing the ACTION* macros.
|
||||||
|
template <typename Result, class Impl>
|
||||||
|
class ActionHelper {
|
||||||
|
public:
|
||||||
|
$range i 0..n
|
||||||
|
$for i
|
||||||
|
|
||||||
|
[[
|
||||||
|
$var template = [[$if i==0 [[]] $else [[
|
||||||
|
$range j 0..i-1
|
||||||
|
template <$for j, [[typename A$j]]>
|
||||||
|
]]]]
|
||||||
|
$range j 0..i-1
|
||||||
|
$var As = [[$for j, [[A$j]]]]
|
||||||
|
$var as = [[$for j, [[std::get<$j>(args)]]]]
|
||||||
|
$range k 1..n-i
|
||||||
|
$var eas = [[$for k, [[ExcessiveArg()]]]]
|
||||||
|
$var arg_list = [[$if (i==0) | (i==n) [[$as$eas]] $else [[$as, $eas]]]]
|
||||||
|
$template
|
||||||
|
static Result Perform(Impl* impl, const ::std::tuple<$As>& args) {
|
||||||
|
return impl->template gmock_PerformImpl<$As>(args, $arg_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
]]
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
// The ACTION* family of macros can be used in a namespace scope to
|
||||||
|
// define custom actions easily. The syntax:
|
||||||
|
//
|
||||||
|
// ACTION(name) { statements; }
|
||||||
|
//
|
||||||
|
// will define an action with the given name that executes the
|
||||||
|
// statements. The value returned by the statements will be used as
|
||||||
|
// the return value of the action. Inside the statements, you can
|
||||||
|
// refer to the K-th (0-based) argument of the mock function by
|
||||||
|
// 'argK', and refer to its type by 'argK_type'. For example:
|
||||||
|
//
|
||||||
|
// ACTION(IncrementArg1) {
|
||||||
|
// arg1_type temp = arg1;
|
||||||
|
// return ++(*temp);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// allows you to write
|
||||||
|
//
|
||||||
|
// ...WillOnce(IncrementArg1());
|
||||||
|
//
|
||||||
|
// You can also refer to the entire argument tuple and its type by
|
||||||
|
// 'args' and 'args_type', and refer to the mock function type and its
|
||||||
|
// return type by 'function_type' and 'return_type'.
|
||||||
|
//
|
||||||
|
// Note that you don't need to specify the types of the mock function
|
||||||
|
// arguments. However rest assured that your code is still type-safe:
|
||||||
|
// 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, for example.
|
||||||
|
//
|
||||||
|
// Sometimes you'll want to parameterize the action. For that you can use
|
||||||
|
// another macro:
|
||||||
|
//
|
||||||
|
// ACTION_P(name, param_name) { statements; }
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
//
|
||||||
|
// ACTION_P(Add, n) { return arg0 + n; }
|
||||||
|
//
|
||||||
|
// will allow you to write:
|
||||||
|
//
|
||||||
|
// ...WillOnce(Add(5));
|
||||||
|
//
|
||||||
|
// Note that you don't need to provide the type of the parameter
|
||||||
|
// either. If you need to reference the type of a parameter named
|
||||||
|
// 'foo', you can write 'foo_type'. For example, in the body of
|
||||||
|
// ACTION_P(Add, n) above, you can write 'n_type' to refer to the type
|
||||||
|
// of 'n'.
|
||||||
|
//
|
||||||
|
// We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P$n to support
|
||||||
|
// multi-parameter actions.
|
||||||
|
//
|
||||||
|
// For the purpose of typing, you can view
|
||||||
|
//
|
||||||
|
// ACTION_Pk(Foo, p1, ..., pk) { ... }
|
||||||
|
//
|
||||||
|
// as shorthand for
|
||||||
|
//
|
||||||
|
// template <typename p1_type, ..., typename pk_type>
|
||||||
|
// FooActionPk<p1_type, ..., pk_type> Foo(p1_type p1, ..., pk_type pk) { ... }
|
||||||
|
//
|
||||||
|
// In particular, you can provide the template type arguments
|
||||||
|
// explicitly when invoking Foo(), as in Foo<long, bool>(5, false);
|
||||||
|
// although usually you can rely on the compiler to infer the types
|
||||||
|
// for you automatically. You can assign the result of expression
|
||||||
|
// Foo(p1, ..., pk) to a variable of type FooActionPk<p1_type, ...,
|
||||||
|
// pk_type>. This can be useful when composing actions.
|
||||||
|
//
|
||||||
|
// You can also overload actions with different numbers of parameters:
|
||||||
|
//
|
||||||
|
// ACTION_P(Plus, a) { ... }
|
||||||
|
// ACTION_P2(Plus, a, b) { ... }
|
||||||
|
//
|
||||||
|
// While it's tempting to always use the ACTION* macros when defining
|
||||||
|
// a new action, you should also consider implementing ActionInterface
|
||||||
|
// or using MakePolymorphicAction() instead, especially if you need to
|
||||||
|
// use the action a lot. While these 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 based on the number of parameters).
|
||||||
|
//
|
||||||
|
// CAVEAT:
|
||||||
|
//
|
||||||
|
// ACTION*() can only be used in a namespace scope as templates cannot be
|
||||||
|
// declared inside of a local class.
|
||||||
|
// Users can, however, define any local functors (e.g. a lambda) that
|
||||||
|
// can be used as actions.
|
||||||
|
//
|
||||||
|
// MORE INFORMATION:
|
||||||
|
//
|
||||||
|
// To learn more about using these macros, please search for 'ACTION' on
|
||||||
|
// https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md
|
||||||
|
|
||||||
|
$range i 0..n
|
||||||
|
$range k 0..n-1
|
||||||
|
|
||||||
|
// An internal macro needed for implementing ACTION*().
|
||||||
|
#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_\
|
||||||
|
const args_type& args GTEST_ATTRIBUTE_UNUSED_
|
||||||
|
$for k [[, \
|
||||||
|
const arg$k[[]]_type& arg$k GTEST_ATTRIBUTE_UNUSED_]]
|
||||||
|
|
||||||
|
|
||||||
|
// Sometimes you want to give an action explicit template parameters
|
||||||
|
// that cannot be inferred from its value parameters. ACTION() and
|
||||||
|
// ACTION_P*() don't support that. ACTION_TEMPLATE() remedies that
|
||||||
|
// and can be viewed as an extension to ACTION() and ACTION_P*().
|
||||||
|
//
|
||||||
|
// The syntax:
|
||||||
|
//
|
||||||
|
// ACTION_TEMPLATE(ActionName,
|
||||||
|
// HAS_m_TEMPLATE_PARAMS(kind1, name1, ..., kind_m, name_m),
|
||||||
|
// AND_n_VALUE_PARAMS(p1, ..., p_n)) { statements; }
|
||||||
|
//
|
||||||
|
// defines an action template that takes m explicit template
|
||||||
|
// parameters and n value parameters. name_i is the name of the i-th
|
||||||
|
// template parameter, and kind_i specifies whether it's a typename,
|
||||||
|
// an integral constant, or a template. p_i is the name of the i-th
|
||||||
|
// value parameter.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// // DuplicateArg<k, T>(output) converts the k-th argument of the mock
|
||||||
|
// // function to type T and copies it to *output.
|
||||||
|
// ACTION_TEMPLATE(DuplicateArg,
|
||||||
|
// HAS_2_TEMPLATE_PARAMS(int, k, typename, T),
|
||||||
|
// AND_1_VALUE_PARAMS(output)) {
|
||||||
|
// *output = T(::std::get<k>(args));
|
||||||
|
// }
|
||||||
|
// ...
|
||||||
|
// int n;
|
||||||
|
// EXPECT_CALL(mock, Foo(_, _))
|
||||||
|
// .WillOnce(DuplicateArg<1, unsigned char>(&n));
|
||||||
|
//
|
||||||
|
// To create an instance of an action template, write:
|
||||||
|
//
|
||||||
|
// ActionName<t1, ..., t_m>(v1, ..., v_n)
|
||||||
|
//
|
||||||
|
// where the ts are the template arguments and the vs are the value
|
||||||
|
// arguments. The value argument types are inferred by the compiler.
|
||||||
|
// If you want to explicitly specify the value argument types, you can
|
||||||
|
// provide additional template arguments:
|
||||||
|
//
|
||||||
|
// ActionName<t1, ..., t_m, u1, ..., u_k>(v1, ..., v_n)
|
||||||
|
//
|
||||||
|
// where u_i is the desired type of v_i.
|
||||||
|
//
|
||||||
|
// ACTION_TEMPLATE and ACTION/ACTION_P* can be overloaded on the
|
||||||
|
// number of value parameters, but not on the number of template
|
||||||
|
// parameters. Without the restriction, the meaning of the following
|
||||||
|
// is unclear:
|
||||||
|
//
|
||||||
|
// OverloadedAction<int, bool>(x);
|
||||||
|
//
|
||||||
|
// Are we using a single-template-parameter action where 'bool' refers
|
||||||
|
// to the type of x, or are we using a two-template-parameter action
|
||||||
|
// where the compiler is asked to infer the type of x?
|
||||||
|
//
|
||||||
|
// Implementation notes:
|
||||||
|
//
|
||||||
|
// GMOCK_INTERNAL_*_HAS_m_TEMPLATE_PARAMS and
|
||||||
|
// GMOCK_INTERNAL_*_AND_n_VALUE_PARAMS are internal macros for
|
||||||
|
// implementing ACTION_TEMPLATE. The main trick we use is to create
|
||||||
|
// new macro invocations when expanding a macro. For example, we have
|
||||||
|
//
|
||||||
|
// #define ACTION_TEMPLATE(name, template_params, value_params)
|
||||||
|
// ... GMOCK_INTERNAL_DECL_##template_params ...
|
||||||
|
//
|
||||||
|
// which causes ACTION_TEMPLATE(..., HAS_1_TEMPLATE_PARAMS(typename, T), ...)
|
||||||
|
// to expand to
|
||||||
|
//
|
||||||
|
// ... GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS(typename, T) ...
|
||||||
|
//
|
||||||
|
// Since GMOCK_INTERNAL_DECL_HAS_1_TEMPLATE_PARAMS is a macro, the
|
||||||
|
// preprocessor will continue to expand it to
|
||||||
|
//
|
||||||
|
// ... typename T ...
|
||||||
|
//
|
||||||
|
// This technique conforms to the C++ standard and is portable. It
|
||||||
|
// allows us to implement action templates using O(N) code, where N is
|
||||||
|
// the maximum number of template/value parameters supported. Without
|
||||||
|
// using it, we'd have to devote O(N^2) amount of code to implement all
|
||||||
|
// combinations of m and n.
|
||||||
|
|
||||||
|
// Declares the template parameters.
|
||||||
|
|
||||||
|
$range j 1..n
|
||||||
|
$for j [[
|
||||||
|
$range m 0..j-1
|
||||||
|
#define GMOCK_INTERNAL_DECL_HAS_$j[[]]
|
||||||
|
_TEMPLATE_PARAMS($for m, [[kind$m, name$m]]) $for m, [[kind$m name$m]]
|
||||||
|
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
// Lists the template parameters.
|
||||||
|
|
||||||
|
$for j [[
|
||||||
|
$range m 0..j-1
|
||||||
|
#define GMOCK_INTERNAL_LIST_HAS_$j[[]]
|
||||||
|
_TEMPLATE_PARAMS($for m, [[kind$m, name$m]]) $for m, [[name$m]]
|
||||||
|
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
// Declares the types of value parameters.
|
||||||
|
|
||||||
|
$for i [[
|
||||||
|
$range j 0..i-1
|
||||||
|
#define GMOCK_INTERNAL_DECL_TYPE_AND_$i[[]]
|
||||||
|
_VALUE_PARAMS($for j, [[p$j]]) $for j [[, typename p$j##_type]]
|
||||||
|
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
// Initializes the value parameters.
|
||||||
|
|
||||||
|
$for i [[
|
||||||
|
$range j 0..i-1
|
||||||
|
#define GMOCK_INTERNAL_INIT_AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]])\
|
||||||
|
($for j, [[p$j##_type gmock_p$j]])$if i>0 [[ : ]]$for j, [[p$j(::std::move(gmock_p$j))]]
|
||||||
|
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
// Declares the fields for storing the value parameters.
|
||||||
|
|
||||||
|
$for i [[
|
||||||
|
$range j 0..i-1
|
||||||
|
#define GMOCK_INTERNAL_DEFN_AND_$i[[]]
|
||||||
|
_VALUE_PARAMS($for j, [[p$j]]) $for j [[p$j##_type p$j; ]]
|
||||||
|
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
// Lists the value parameters.
|
||||||
|
|
||||||
|
$for i [[
|
||||||
|
$range j 0..i-1
|
||||||
|
#define GMOCK_INTERNAL_LIST_AND_$i[[]]
|
||||||
|
_VALUE_PARAMS($for j, [[p$j]]) $for j, [[p$j]]
|
||||||
|
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
// Lists the value parameter types.
|
||||||
|
|
||||||
|
$for i [[
|
||||||
|
$range j 0..i-1
|
||||||
|
#define GMOCK_INTERNAL_LIST_TYPE_AND_$i[[]]
|
||||||
|
_VALUE_PARAMS($for j, [[p$j]]) $for j [[, p$j##_type]]
|
||||||
|
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
// Declares the value parameters.
|
||||||
|
|
||||||
|
$for i [[
|
||||||
|
$range j 0..i-1
|
||||||
|
#define GMOCK_INTERNAL_DECL_AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]]) [[]]
|
||||||
|
$for j, [[p$j##_type p$j]]
|
||||||
|
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
// The suffix of the class template implementing the action template.
|
||||||
|
$for i [[
|
||||||
|
|
||||||
|
|
||||||
|
$range j 0..i-1
|
||||||
|
#define GMOCK_INTERNAL_COUNT_AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]]) [[]]
|
||||||
|
$if i==1 [[P]] $elif i>=2 [[P$i]]
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
// The name of the class template implementing the action template.
|
||||||
|
#define GMOCK_ACTION_CLASS_(name, value_params)\
|
||||||
|
GTEST_CONCAT_TOKEN_(name##Action, GMOCK_INTERNAL_COUNT_##value_params)
|
||||||
|
|
||||||
|
$range k 0..n-1
|
||||||
|
|
||||||
|
#define ACTION_TEMPLATE(name, template_params, value_params)\
|
||||||
|
template <GMOCK_INTERNAL_DECL_##template_params\
|
||||||
|
GMOCK_INTERNAL_DECL_TYPE_##value_params>\
|
||||||
|
class GMOCK_ACTION_CLASS_(name, value_params) {\
|
||||||
|
public:\
|
||||||
|
explicit GMOCK_ACTION_CLASS_(name, value_params)\
|
||||||
|
GMOCK_INTERNAL_INIT_##value_params {}\
|
||||||
|
template <typename F>\
|
||||||
|
class gmock_Impl : public ::testing::ActionInterface<F> {\
|
||||||
|
public:\
|
||||||
|
typedef F function_type;\
|
||||||
|
typedef typename ::testing::internal::Function<F>::Result return_type;\
|
||||||
|
typedef typename ::testing::internal::Function<F>::ArgumentTuple\
|
||||||
|
args_type;\
|
||||||
|
explicit gmock_Impl GMOCK_INTERNAL_INIT_##value_params {}\
|
||||||
|
virtual return_type Perform(const args_type& args) {\
|
||||||
|
return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
|
||||||
|
Perform(this, args);\
|
||||||
|
}\
|
||||||
|
template <$for k, [[typename arg$k[[]]_type]]>\
|
||||||
|
return_type gmock_PerformImpl(const args_type& args[[]]
|
||||||
|
$for k [[, const arg$k[[]]_type& arg$k]]) const;\
|
||||||
|
GMOCK_INTERNAL_DEFN_##value_params\
|
||||||
|
private:\
|
||||||
|
GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
|
||||||
|
};\
|
||||||
|
template <typename F> operator ::testing::Action<F>() const {\
|
||||||
|
return ::testing::Action<F>(\
|
||||||
|
new gmock_Impl<F>(GMOCK_INTERNAL_LIST_##value_params));\
|
||||||
|
}\
|
||||||
|
GMOCK_INTERNAL_DEFN_##value_params\
|
||||||
|
private:\
|
||||||
|
GTEST_DISALLOW_ASSIGN_(GMOCK_ACTION_CLASS_(name, value_params));\
|
||||||
|
};\
|
||||||
|
template <GMOCK_INTERNAL_DECL_##template_params\
|
||||||
|
GMOCK_INTERNAL_DECL_TYPE_##value_params>\
|
||||||
|
inline GMOCK_ACTION_CLASS_(name, value_params)<\
|
||||||
|
GMOCK_INTERNAL_LIST_##template_params\
|
||||||
|
GMOCK_INTERNAL_LIST_TYPE_##value_params> name(\
|
||||||
|
GMOCK_INTERNAL_DECL_##value_params) {\
|
||||||
|
return GMOCK_ACTION_CLASS_(name, value_params)<\
|
||||||
|
GMOCK_INTERNAL_LIST_##template_params\
|
||||||
|
GMOCK_INTERNAL_LIST_TYPE_##value_params>(\
|
||||||
|
GMOCK_INTERNAL_LIST_##value_params);\
|
||||||
|
}\
|
||||||
|
template <GMOCK_INTERNAL_DECL_##template_params\
|
||||||
|
GMOCK_INTERNAL_DECL_TYPE_##value_params>\
|
||||||
|
template <typename F>\
|
||||||
|
template <typename arg0_type, typename arg1_type, typename arg2_type, \
|
||||||
|
typename arg3_type, typename arg4_type, typename arg5_type, \
|
||||||
|
typename arg6_type, typename arg7_type, typename arg8_type, \
|
||||||
|
typename arg9_type>\
|
||||||
|
typename ::testing::internal::Function<F>::Result\
|
||||||
|
GMOCK_ACTION_CLASS_(name, value_params)<\
|
||||||
|
GMOCK_INTERNAL_LIST_##template_params\
|
||||||
|
GMOCK_INTERNAL_LIST_TYPE_##value_params>::gmock_Impl<F>::\
|
||||||
|
gmock_PerformImpl(\
|
||||||
|
GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
|
||||||
|
|
||||||
|
$for i
|
||||||
|
|
||||||
|
[[
|
||||||
|
$var template = [[$if i==0 [[]] $else [[
|
||||||
|
$range j 0..i-1
|
||||||
|
|
||||||
|
template <$for j, [[typename p$j##_type]]>\
|
||||||
|
]]]]
|
||||||
|
$var class_name = [[name##Action[[$if i==0 [[]] $elif i==1 [[P]]
|
||||||
|
$else [[P$i]]]]]]
|
||||||
|
$range j 0..i-1
|
||||||
|
$var ctor_param_list = [[$for j, [[p$j##_type gmock_p$j]]]]
|
||||||
|
$var param_types_and_names = [[$for j, [[p$j##_type p$j]]]]
|
||||||
|
$var inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(::std::forward<p$j##_type>(gmock_p$j))]]]]]]
|
||||||
|
$var param_field_decls = [[$for j
|
||||||
|
[[
|
||||||
|
|
||||||
|
p$j##_type p$j;\
|
||||||
|
]]]]
|
||||||
|
$var param_field_decls2 = [[$for j
|
||||||
|
[[
|
||||||
|
|
||||||
|
p$j##_type p$j;\
|
||||||
|
]]]]
|
||||||
|
$var params = [[$for j, [[p$j]]]]
|
||||||
|
$var param_types = [[$if i==0 [[]] $else [[<$for j, [[p$j##_type]]>]]]]
|
||||||
|
$var typename_arg_types = [[$for k, [[typename arg$k[[]]_type]]]]
|
||||||
|
$var arg_types_and_names = [[$for k, [[const arg$k[[]]_type& arg$k]]]]
|
||||||
|
$var macro_name = [[$if i==0 [[ACTION]] $elif i==1 [[ACTION_P]]
|
||||||
|
$else [[ACTION_P$i]]]]
|
||||||
|
|
||||||
|
#define $macro_name(name$for j [[, p$j]])\$template
|
||||||
|
class $class_name {\
|
||||||
|
public:\
|
||||||
|
[[$if i==1 [[explicit ]]]]$class_name($ctor_param_list)$inits {}\
|
||||||
|
template <typename F>\
|
||||||
|
class gmock_Impl : public ::testing::ActionInterface<F> {\
|
||||||
|
public:\
|
||||||
|
typedef F function_type;\
|
||||||
|
typedef typename ::testing::internal::Function<F>::Result return_type;\
|
||||||
|
typedef typename ::testing::internal::Function<F>::ArgumentTuple\
|
||||||
|
args_type;\
|
||||||
|
[[$if i==1 [[explicit ]]]]gmock_Impl($ctor_param_list)$inits {}\
|
||||||
|
virtual return_type Perform(const args_type& args) {\
|
||||||
|
return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
|
||||||
|
Perform(this, args);\
|
||||||
|
}\
|
||||||
|
template <$typename_arg_types>\
|
||||||
|
return_type gmock_PerformImpl(const args_type& args, [[]]
|
||||||
|
$arg_types_and_names) const;\$param_field_decls
|
||||||
|
private:\
|
||||||
|
GTEST_DISALLOW_ASSIGN_(gmock_Impl);\
|
||||||
|
};\
|
||||||
|
template <typename F> operator ::testing::Action<F>() const {\
|
||||||
|
return ::testing::Action<F>(new gmock_Impl<F>($params));\
|
||||||
|
}\$param_field_decls2
|
||||||
|
private:\
|
||||||
|
GTEST_DISALLOW_ASSIGN_($class_name);\
|
||||||
|
};\$template
|
||||||
|
inline $class_name$param_types name($param_types_and_names) {\
|
||||||
|
return $class_name$param_types($params);\
|
||||||
|
}\$template
|
||||||
|
template <typename F>\
|
||||||
|
template <$typename_arg_types>\
|
||||||
|
typename ::testing::internal::Function<F>::Result\
|
||||||
|
$class_name$param_types::gmock_Impl<F>::gmock_PerformImpl(\
|
||||||
|
GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
|
||||||
|
]]
|
||||||
|
$$ } // This meta comment fixes auto-indentation in Emacs. It won't
|
||||||
|
$$ // show up in the generated code.
|
||||||
|
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
|
||||||
|
// The ACTION*() macros trigger warning C4100 (unreferenced formal
|
||||||
|
// parameter) in MSVC with -W4. Unfortunately they cannot be fixed in
|
||||||
|
// the macro definition, as the warnings are generated when the macro
|
||||||
|
// is expanded and macro expansion cannot contain #pragma. Therefore
|
||||||
|
// we suppress them here.
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning(disable:4100)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Various overloads for InvokeArgument<N>().
|
||||||
|
//
|
||||||
|
// The InvokeArgument<N>(a1, a2, ..., a_k) action invokes the N-th
|
||||||
|
// (0-based) argument, which must be a k-ary callable, of the mock
|
||||||
|
// function, with arguments a1, a2, ..., a_k.
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
//
|
||||||
|
// 1. The arguments are passed by value by default. If you need to
|
||||||
|
// pass an argument by reference, wrap it inside ByRef(). For
|
||||||
|
// example,
|
||||||
|
//
|
||||||
|
// InvokeArgument<1>(5, string("Hello"), ByRef(foo))
|
||||||
|
//
|
||||||
|
// passes 5 and string("Hello") by value, and passes foo by
|
||||||
|
// reference.
|
||||||
|
//
|
||||||
|
// 2. If the callable takes an argument by reference but ByRef() is
|
||||||
|
// not used, it will receive the reference to a copy of the value,
|
||||||
|
// instead of the original value. For example, when the 0-th
|
||||||
|
// argument of the mock function takes a const string&, the action
|
||||||
|
//
|
||||||
|
// InvokeArgument<0>(string("Hello"))
|
||||||
|
//
|
||||||
|
// makes a copy of the temporary string("Hello") object and passes a
|
||||||
|
// reference of the copy, instead of the original temporary object,
|
||||||
|
// to the callable. This makes it easy for a user to define an
|
||||||
|
// InvokeArgument action from temporary values and have it performed
|
||||||
|
// later.
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
namespace invoke_argument {
|
||||||
|
|
||||||
|
// Appears in InvokeArgumentAdl's argument list to help avoid
|
||||||
|
// accidental calls to user functions of the same name.
|
||||||
|
struct AdlTag {};
|
||||||
|
|
||||||
|
// InvokeArgumentAdl - a helper for InvokeArgument.
|
||||||
|
// The basic overloads are provided here for generic functors.
|
||||||
|
// Overloads for other custom-callables are provided in the
|
||||||
|
// internal/custom/callback-actions.h header.
|
||||||
|
|
||||||
|
$range i 0..n
|
||||||
|
$for i
|
||||||
|
[[
|
||||||
|
$range j 1..i
|
||||||
|
|
||||||
|
template <typename R, typename F[[$for j [[, typename A$j]]]]>
|
||||||
|
R InvokeArgumentAdl(AdlTag, F f[[$for j [[, A$j a$j]]]]) {
|
||||||
|
return f([[$for j, [[a$j]]]]);
|
||||||
|
}
|
||||||
|
]]
|
||||||
|
|
||||||
|
} // namespace invoke_argument
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
$range i 0..n
|
||||||
|
$for i [[
|
||||||
|
$range j 0..i-1
|
||||||
|
|
||||||
|
ACTION_TEMPLATE(InvokeArgument,
|
||||||
|
HAS_1_TEMPLATE_PARAMS(int, k),
|
||||||
|
AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]])) {
|
||||||
|
using internal::invoke_argument::InvokeArgumentAdl;
|
||||||
|
return InvokeArgumentAdl<return_type>(
|
||||||
|
internal::invoke_argument::AdlTag(),
|
||||||
|
::std::get<k>(args)$for j [[, p$j]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
// Various overloads for ReturnNew<T>().
|
||||||
|
//
|
||||||
|
// The ReturnNew<T>(a1, a2, ..., a_k) action returns a pointer to a new
|
||||||
|
// instance of type T, constructed on the heap with constructor arguments
|
||||||
|
// a1, a2, ..., and a_k. The caller assumes ownership of the returned value.
|
||||||
|
$range i 0..n
|
||||||
|
$for i [[
|
||||||
|
$range j 0..i-1
|
||||||
|
$var ps = [[$for j, [[p$j]]]]
|
||||||
|
|
||||||
|
ACTION_TEMPLATE(ReturnNew,
|
||||||
|
HAS_1_TEMPLATE_PARAMS(typename, T),
|
||||||
|
AND_$i[[]]_VALUE_PARAMS($ps)) {
|
||||||
|
return new T($ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
// Include any custom callback actions added by the local installation.
|
||||||
|
// We must include this header at the end to make sure it can use the
|
||||||
|
// declarations from this file.
|
||||||
|
#include "gmock/internal/custom/gmock-generated-actions.h"
|
||||||
|
|
||||||
|
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
|
@ -0,0 +1,752 @@
|
|||||||
|
// This file was GENERATED by command:
|
||||||
|
// pump.py gmock-generated-function-mockers.h.pump
|
||||||
|
// DO NOT EDIT BY HAND!!!
|
||||||
|
|
||||||
|
// Copyright 2007, 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.
|
||||||
|
|
||||||
|
|
||||||
|
// Google Mock - a framework for writing C++ mock classes.
|
||||||
|
//
|
||||||
|
// This file implements function mockers of various arities.
|
||||||
|
|
||||||
|
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||||
|
|
||||||
|
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_
|
||||||
|
#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "gmock/gmock-spec-builders.h"
|
||||||
|
#include "gmock/internal/gmock-internal-utils.h"
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
namespace internal {
|
||||||
|
// Removes the given pointer; this is a helper for the expectation setter method
|
||||||
|
// for parameterless matchers.
|
||||||
|
//
|
||||||
|
// We want to make sure that the user cannot set a parameterless expectation on
|
||||||
|
// overloaded methods, including methods which are overloaded on const. Example:
|
||||||
|
//
|
||||||
|
// class MockClass {
|
||||||
|
// MOCK_METHOD0(GetName, string&());
|
||||||
|
// MOCK_CONST_METHOD0(GetName, const string&());
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// TEST() {
|
||||||
|
// // This should be an error, as it's not clear which overload is expected.
|
||||||
|
// EXPECT_CALL(mock, GetName).WillOnce(ReturnRef(value));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Here are the generated expectation-setter methods:
|
||||||
|
//
|
||||||
|
// class MockClass {
|
||||||
|
// // Overload 1
|
||||||
|
// MockSpec<string&()> gmock_GetName() { ... }
|
||||||
|
// // Overload 2. Declared const so that the compiler will generate an
|
||||||
|
// // error when trying to resolve between this and overload 4 in
|
||||||
|
// // 'gmock_GetName(WithoutMatchers(), nullptr)'.
|
||||||
|
// MockSpec<string&()> gmock_GetName(
|
||||||
|
// const WithoutMatchers&, const Function<string&()>*) const {
|
||||||
|
// // Removes const from this, calls overload 1
|
||||||
|
// return AdjustConstness_(this)->gmock_GetName();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Overload 3
|
||||||
|
// const string& gmock_GetName() const { ... }
|
||||||
|
// // Overload 4
|
||||||
|
// MockSpec<const string&()> gmock_GetName(
|
||||||
|
// const WithoutMatchers&, const Function<const string&()>*) const {
|
||||||
|
// // Does not remove const, calls overload 3
|
||||||
|
// return AdjustConstness_const(this)->gmock_GetName();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
template <typename MockType>
|
||||||
|
const MockType* AdjustConstness_const(const MockType* mock) {
|
||||||
|
return mock;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes const from and returns the given pointer; this is a helper for the
|
||||||
|
// expectation setter method for parameterless matchers.
|
||||||
|
template <typename MockType>
|
||||||
|
MockType* AdjustConstness_(const MockType* mock) {
|
||||||
|
return const_cast<MockType*>(mock);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
// The style guide prohibits "using" statements in a namespace scope
|
||||||
|
// inside a header file. However, the FunctionMocker class template
|
||||||
|
// is meant to be defined in the ::testing namespace. The following
|
||||||
|
// line is just a trick for working around a bug in MSVC 8.0, which
|
||||||
|
// cannot handle it if we define FunctionMocker in ::testing.
|
||||||
|
using internal::FunctionMocker;
|
||||||
|
|
||||||
|
// GMOCK_RESULT_(tn, F) expands to the result type of function type F.
|
||||||
|
// We define this as a variadic macro in case F contains unprotected
|
||||||
|
// commas (the same reason that we use variadic macros in other places
|
||||||
|
// in this file).
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_RESULT_(tn, ...) \
|
||||||
|
tn ::testing::internal::Function<__VA_ARGS__>::Result
|
||||||
|
|
||||||
|
// The type of argument N of the given function type.
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_ARG_(tn, N, ...) \
|
||||||
|
tn ::testing::internal::Function<__VA_ARGS__>::template Arg<N-1>::type
|
||||||
|
|
||||||
|
// The matcher type for argument N of the given function type.
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_MATCHER_(tn, N, ...) \
|
||||||
|
const ::testing::Matcher<GMOCK_ARG_(tn, N, __VA_ARGS__)>&
|
||||||
|
|
||||||
|
// The variable for mocking the given method.
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_MOCKER_(arity, constness, Method) \
|
||||||
|
GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__)
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_METHOD0_(tn, constness, ct, Method, ...) \
|
||||||
|
static_assert(0 == \
|
||||||
|
::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
|
||||||
|
"MOCK_METHOD<N> must match argument count.");\
|
||||||
|
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
|
||||||
|
) constness { \
|
||||||
|
GMOCK_MOCKER_(0, constness, Method).SetOwnerAndName(this, #Method); \
|
||||||
|
return GMOCK_MOCKER_(0, constness, Method).Invoke(); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> \
|
||||||
|
gmock_##Method() constness { \
|
||||||
|
GMOCK_MOCKER_(0, constness, Method).RegisterOwner(this); \
|
||||||
|
return GMOCK_MOCKER_(0, constness, Method).With(); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
|
||||||
|
const ::testing::internal::WithoutMatchers&, \
|
||||||
|
constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
|
||||||
|
return ::testing::internal::AdjustConstness_##constness(this)-> \
|
||||||
|
gmock_##Method(); \
|
||||||
|
} \
|
||||||
|
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(0, constness, \
|
||||||
|
Method)
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_METHOD1_(tn, constness, ct, Method, ...) \
|
||||||
|
static_assert(1 == \
|
||||||
|
::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
|
||||||
|
"MOCK_METHOD<N> must match argument count.");\
|
||||||
|
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
|
||||||
|
GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1) constness { \
|
||||||
|
GMOCK_MOCKER_(1, constness, Method).SetOwnerAndName(this, #Method); \
|
||||||
|
return GMOCK_MOCKER_(1, constness, \
|
||||||
|
Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
|
||||||
|
__VA_ARGS__)>(gmock_a1)); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> \
|
||||||
|
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1) constness { \
|
||||||
|
GMOCK_MOCKER_(1, constness, Method).RegisterOwner(this); \
|
||||||
|
return GMOCK_MOCKER_(1, constness, Method).With(gmock_a1); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
|
||||||
|
const ::testing::internal::WithoutMatchers&, \
|
||||||
|
constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
|
||||||
|
return ::testing::internal::AdjustConstness_##constness(this)-> \
|
||||||
|
gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>()); \
|
||||||
|
} \
|
||||||
|
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(1, constness, \
|
||||||
|
Method)
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_METHOD2_(tn, constness, ct, Method, ...) \
|
||||||
|
static_assert(2 == \
|
||||||
|
::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
|
||||||
|
"MOCK_METHOD<N> must match argument count.");\
|
||||||
|
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
|
||||||
|
GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
|
||||||
|
__VA_ARGS__) gmock_a2) constness { \
|
||||||
|
GMOCK_MOCKER_(2, constness, Method).SetOwnerAndName(this, #Method); \
|
||||||
|
return GMOCK_MOCKER_(2, constness, \
|
||||||
|
Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
|
||||||
|
__VA_ARGS__)>(gmock_a1), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2)); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> \
|
||||||
|
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
|
||||||
|
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2) constness { \
|
||||||
|
GMOCK_MOCKER_(2, constness, Method).RegisterOwner(this); \
|
||||||
|
return GMOCK_MOCKER_(2, constness, Method).With(gmock_a1, gmock_a2); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
|
||||||
|
const ::testing::internal::WithoutMatchers&, \
|
||||||
|
constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
|
||||||
|
return ::testing::internal::AdjustConstness_##constness(this)-> \
|
||||||
|
gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>()); \
|
||||||
|
} \
|
||||||
|
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(2, constness, \
|
||||||
|
Method)
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_METHOD3_(tn, constness, ct, Method, ...) \
|
||||||
|
static_assert(3 == \
|
||||||
|
::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
|
||||||
|
"MOCK_METHOD<N> must match argument count.");\
|
||||||
|
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
|
||||||
|
GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
|
||||||
|
__VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, \
|
||||||
|
__VA_ARGS__) gmock_a3) constness { \
|
||||||
|
GMOCK_MOCKER_(3, constness, Method).SetOwnerAndName(this, #Method); \
|
||||||
|
return GMOCK_MOCKER_(3, constness, \
|
||||||
|
Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
|
||||||
|
__VA_ARGS__)>(gmock_a1), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3)); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> \
|
||||||
|
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
|
||||||
|
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
|
||||||
|
GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3) constness { \
|
||||||
|
GMOCK_MOCKER_(3, constness, Method).RegisterOwner(this); \
|
||||||
|
return GMOCK_MOCKER_(3, constness, Method).With(gmock_a1, gmock_a2, \
|
||||||
|
gmock_a3); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
|
||||||
|
const ::testing::internal::WithoutMatchers&, \
|
||||||
|
constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
|
||||||
|
return ::testing::internal::AdjustConstness_##constness(this)-> \
|
||||||
|
gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>()); \
|
||||||
|
} \
|
||||||
|
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(3, constness, \
|
||||||
|
Method)
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_METHOD4_(tn, constness, ct, Method, ...) \
|
||||||
|
static_assert(4 == \
|
||||||
|
::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
|
||||||
|
"MOCK_METHOD<N> must match argument count.");\
|
||||||
|
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
|
||||||
|
GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
|
||||||
|
__VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
|
||||||
|
GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4) constness { \
|
||||||
|
GMOCK_MOCKER_(4, constness, Method).SetOwnerAndName(this, #Method); \
|
||||||
|
return GMOCK_MOCKER_(4, constness, \
|
||||||
|
Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
|
||||||
|
__VA_ARGS__)>(gmock_a1), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4)); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> \
|
||||||
|
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
|
||||||
|
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
|
||||||
|
GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
|
||||||
|
GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4) constness { \
|
||||||
|
GMOCK_MOCKER_(4, constness, Method).RegisterOwner(this); \
|
||||||
|
return GMOCK_MOCKER_(4, constness, Method).With(gmock_a1, gmock_a2, \
|
||||||
|
gmock_a3, gmock_a4); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
|
||||||
|
const ::testing::internal::WithoutMatchers&, \
|
||||||
|
constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
|
||||||
|
return ::testing::internal::AdjustConstness_##constness(this)-> \
|
||||||
|
gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>()); \
|
||||||
|
} \
|
||||||
|
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(4, constness, \
|
||||||
|
Method)
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_METHOD5_(tn, constness, ct, Method, ...) \
|
||||||
|
static_assert(5 == \
|
||||||
|
::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
|
||||||
|
"MOCK_METHOD<N> must match argument count.");\
|
||||||
|
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
|
||||||
|
GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
|
||||||
|
__VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
|
||||||
|
GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
|
||||||
|
__VA_ARGS__) gmock_a5) constness { \
|
||||||
|
GMOCK_MOCKER_(5, constness, Method).SetOwnerAndName(this, #Method); \
|
||||||
|
return GMOCK_MOCKER_(5, constness, \
|
||||||
|
Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
|
||||||
|
__VA_ARGS__)>(gmock_a1), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5)); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> \
|
||||||
|
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
|
||||||
|
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
|
||||||
|
GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
|
||||||
|
GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
|
||||||
|
GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5) constness { \
|
||||||
|
GMOCK_MOCKER_(5, constness, Method).RegisterOwner(this); \
|
||||||
|
return GMOCK_MOCKER_(5, constness, Method).With(gmock_a1, gmock_a2, \
|
||||||
|
gmock_a3, gmock_a4, gmock_a5); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
|
||||||
|
const ::testing::internal::WithoutMatchers&, \
|
||||||
|
constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
|
||||||
|
return ::testing::internal::AdjustConstness_##constness(this)-> \
|
||||||
|
gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>()); \
|
||||||
|
} \
|
||||||
|
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(5, constness, \
|
||||||
|
Method)
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_METHOD6_(tn, constness, ct, Method, ...) \
|
||||||
|
static_assert(6 == \
|
||||||
|
::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
|
||||||
|
"MOCK_METHOD<N> must match argument count.");\
|
||||||
|
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
|
||||||
|
GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
|
||||||
|
__VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
|
||||||
|
GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
|
||||||
|
__VA_ARGS__) gmock_a5, GMOCK_ARG_(tn, 6, \
|
||||||
|
__VA_ARGS__) gmock_a6) constness { \
|
||||||
|
GMOCK_MOCKER_(6, constness, Method).SetOwnerAndName(this, #Method); \
|
||||||
|
return GMOCK_MOCKER_(6, constness, \
|
||||||
|
Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
|
||||||
|
__VA_ARGS__)>(gmock_a1), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(gmock_a6)); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> \
|
||||||
|
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
|
||||||
|
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
|
||||||
|
GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
|
||||||
|
GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
|
||||||
|
GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \
|
||||||
|
GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6) constness { \
|
||||||
|
GMOCK_MOCKER_(6, constness, Method).RegisterOwner(this); \
|
||||||
|
return GMOCK_MOCKER_(6, constness, Method).With(gmock_a1, gmock_a2, \
|
||||||
|
gmock_a3, gmock_a4, gmock_a5, gmock_a6); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
|
||||||
|
const ::testing::internal::WithoutMatchers&, \
|
||||||
|
constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
|
||||||
|
return ::testing::internal::AdjustConstness_##constness(this)-> \
|
||||||
|
gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 6, __VA_ARGS__)>()); \
|
||||||
|
} \
|
||||||
|
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(6, constness, \
|
||||||
|
Method)
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_METHOD7_(tn, constness, ct, Method, ...) \
|
||||||
|
static_assert(7 == \
|
||||||
|
::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
|
||||||
|
"MOCK_METHOD<N> must match argument count.");\
|
||||||
|
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
|
||||||
|
GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
|
||||||
|
__VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
|
||||||
|
GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
|
||||||
|
__VA_ARGS__) gmock_a5, GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
|
||||||
|
GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7) constness { \
|
||||||
|
GMOCK_MOCKER_(7, constness, Method).SetOwnerAndName(this, #Method); \
|
||||||
|
return GMOCK_MOCKER_(7, constness, \
|
||||||
|
Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
|
||||||
|
__VA_ARGS__)>(gmock_a1), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(gmock_a6), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(gmock_a7)); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> \
|
||||||
|
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
|
||||||
|
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
|
||||||
|
GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
|
||||||
|
GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
|
||||||
|
GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \
|
||||||
|
GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \
|
||||||
|
GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7) constness { \
|
||||||
|
GMOCK_MOCKER_(7, constness, Method).RegisterOwner(this); \
|
||||||
|
return GMOCK_MOCKER_(7, constness, Method).With(gmock_a1, gmock_a2, \
|
||||||
|
gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
|
||||||
|
const ::testing::internal::WithoutMatchers&, \
|
||||||
|
constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
|
||||||
|
return ::testing::internal::AdjustConstness_##constness(this)-> \
|
||||||
|
gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 7, __VA_ARGS__)>()); \
|
||||||
|
} \
|
||||||
|
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(7, constness, \
|
||||||
|
Method)
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_METHOD8_(tn, constness, ct, Method, ...) \
|
||||||
|
static_assert(8 == \
|
||||||
|
::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
|
||||||
|
"MOCK_METHOD<N> must match argument count.");\
|
||||||
|
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
|
||||||
|
GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
|
||||||
|
__VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
|
||||||
|
GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
|
||||||
|
__VA_ARGS__) gmock_a5, GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
|
||||||
|
GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, GMOCK_ARG_(tn, 8, \
|
||||||
|
__VA_ARGS__) gmock_a8) constness { \
|
||||||
|
GMOCK_MOCKER_(8, constness, Method).SetOwnerAndName(this, #Method); \
|
||||||
|
return GMOCK_MOCKER_(8, constness, \
|
||||||
|
Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
|
||||||
|
__VA_ARGS__)>(gmock_a1), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(gmock_a6), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(gmock_a7), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 8, __VA_ARGS__)>(gmock_a8)); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> \
|
||||||
|
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
|
||||||
|
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
|
||||||
|
GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
|
||||||
|
GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
|
||||||
|
GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \
|
||||||
|
GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \
|
||||||
|
GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \
|
||||||
|
GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8) constness { \
|
||||||
|
GMOCK_MOCKER_(8, constness, Method).RegisterOwner(this); \
|
||||||
|
return GMOCK_MOCKER_(8, constness, Method).With(gmock_a1, gmock_a2, \
|
||||||
|
gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
|
||||||
|
const ::testing::internal::WithoutMatchers&, \
|
||||||
|
constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
|
||||||
|
return ::testing::internal::AdjustConstness_##constness(this)-> \
|
||||||
|
gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 8, __VA_ARGS__)>()); \
|
||||||
|
} \
|
||||||
|
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(8, constness, \
|
||||||
|
Method)
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_METHOD9_(tn, constness, ct, Method, ...) \
|
||||||
|
static_assert(9 == \
|
||||||
|
::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
|
||||||
|
"MOCK_METHOD<N> must match argument count.");\
|
||||||
|
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
|
||||||
|
GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
|
||||||
|
__VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
|
||||||
|
GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
|
||||||
|
__VA_ARGS__) gmock_a5, GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
|
||||||
|
GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, GMOCK_ARG_(tn, 8, \
|
||||||
|
__VA_ARGS__) gmock_a8, GMOCK_ARG_(tn, 9, \
|
||||||
|
__VA_ARGS__) gmock_a9) constness { \
|
||||||
|
GMOCK_MOCKER_(9, constness, Method).SetOwnerAndName(this, #Method); \
|
||||||
|
return GMOCK_MOCKER_(9, constness, \
|
||||||
|
Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
|
||||||
|
__VA_ARGS__)>(gmock_a1), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(gmock_a6), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(gmock_a7), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 8, __VA_ARGS__)>(gmock_a8), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 9, __VA_ARGS__)>(gmock_a9)); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> \
|
||||||
|
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
|
||||||
|
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
|
||||||
|
GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
|
||||||
|
GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
|
||||||
|
GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \
|
||||||
|
GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \
|
||||||
|
GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \
|
||||||
|
GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8, \
|
||||||
|
GMOCK_MATCHER_(tn, 9, __VA_ARGS__) gmock_a9) constness { \
|
||||||
|
GMOCK_MOCKER_(9, constness, Method).RegisterOwner(this); \
|
||||||
|
return GMOCK_MOCKER_(9, constness, Method).With(gmock_a1, gmock_a2, \
|
||||||
|
gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \
|
||||||
|
gmock_a9); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
|
||||||
|
const ::testing::internal::WithoutMatchers&, \
|
||||||
|
constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
|
||||||
|
return ::testing::internal::AdjustConstness_##constness(this)-> \
|
||||||
|
gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 8, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 9, __VA_ARGS__)>()); \
|
||||||
|
} \
|
||||||
|
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(9, constness, \
|
||||||
|
Method)
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_METHOD10_(tn, constness, ct, Method, ...) \
|
||||||
|
static_assert(10 == \
|
||||||
|
::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
|
||||||
|
"MOCK_METHOD<N> must match argument count.");\
|
||||||
|
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
|
||||||
|
GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
|
||||||
|
__VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
|
||||||
|
GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
|
||||||
|
__VA_ARGS__) gmock_a5, GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
|
||||||
|
GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, GMOCK_ARG_(tn, 8, \
|
||||||
|
__VA_ARGS__) gmock_a8, GMOCK_ARG_(tn, 9, __VA_ARGS__) gmock_a9, \
|
||||||
|
GMOCK_ARG_(tn, 10, __VA_ARGS__) gmock_a10) constness { \
|
||||||
|
GMOCK_MOCKER_(10, constness, Method).SetOwnerAndName(this, #Method); \
|
||||||
|
return GMOCK_MOCKER_(10, constness, \
|
||||||
|
Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
|
||||||
|
__VA_ARGS__)>(gmock_a1), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(gmock_a6), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(gmock_a7), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 8, __VA_ARGS__)>(gmock_a8), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 9, __VA_ARGS__)>(gmock_a9), \
|
||||||
|
::std::forward<GMOCK_ARG_(tn, 10, __VA_ARGS__)>(gmock_a10)); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> \
|
||||||
|
gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
|
||||||
|
GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
|
||||||
|
GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
|
||||||
|
GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
|
||||||
|
GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \
|
||||||
|
GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \
|
||||||
|
GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \
|
||||||
|
GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8, \
|
||||||
|
GMOCK_MATCHER_(tn, 9, __VA_ARGS__) gmock_a9, \
|
||||||
|
GMOCK_MATCHER_(tn, 10, \
|
||||||
|
__VA_ARGS__) gmock_a10) constness { \
|
||||||
|
GMOCK_MOCKER_(10, constness, Method).RegisterOwner(this); \
|
||||||
|
return GMOCK_MOCKER_(10, constness, Method).With(gmock_a1, gmock_a2, \
|
||||||
|
gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \
|
||||||
|
gmock_a10); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
|
||||||
|
const ::testing::internal::WithoutMatchers&, \
|
||||||
|
constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
|
||||||
|
return ::testing::internal::AdjustConstness_##constness(this)-> \
|
||||||
|
gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 8, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 9, __VA_ARGS__)>(), \
|
||||||
|
::testing::A<GMOCK_ARG_(tn, 10, __VA_ARGS__)>()); \
|
||||||
|
} \
|
||||||
|
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(10, constness, \
|
||||||
|
Method)
|
||||||
|
|
||||||
|
#define MOCK_METHOD0(m, ...) GMOCK_METHOD0_(, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD1(m, ...) GMOCK_METHOD1_(, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD2(m, ...) GMOCK_METHOD2_(, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD3(m, ...) GMOCK_METHOD3_(, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD4(m, ...) GMOCK_METHOD4_(, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD5(m, ...) GMOCK_METHOD5_(, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD6(m, ...) GMOCK_METHOD6_(, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD7(m, ...) GMOCK_METHOD7_(, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD8(m, ...) GMOCK_METHOD8_(, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD9(m, ...) GMOCK_METHOD9_(, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD10(m, ...) GMOCK_METHOD10_(, , , m, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define MOCK_CONST_METHOD0(m, ...) GMOCK_METHOD0_(, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD1(m, ...) GMOCK_METHOD1_(, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD2(m, ...) GMOCK_METHOD2_(, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD3(m, ...) GMOCK_METHOD3_(, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD4(m, ...) GMOCK_METHOD4_(, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD5(m, ...) GMOCK_METHOD5_(, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD6(m, ...) GMOCK_METHOD6_(, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD7(m, ...) GMOCK_METHOD7_(, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD8(m, ...) GMOCK_METHOD8_(, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD9(m, ...) GMOCK_METHOD9_(, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD10(m, ...) GMOCK_METHOD10_(, const, , m, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define MOCK_METHOD0_T(m, ...) GMOCK_METHOD0_(typename, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD1_T(m, ...) GMOCK_METHOD1_(typename, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD2_T(m, ...) GMOCK_METHOD2_(typename, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD3_T(m, ...) GMOCK_METHOD3_(typename, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD4_T(m, ...) GMOCK_METHOD4_(typename, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD5_T(m, ...) GMOCK_METHOD5_(typename, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD6_T(m, ...) GMOCK_METHOD6_(typename, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD7_T(m, ...) GMOCK_METHOD7_(typename, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD8_T(m, ...) GMOCK_METHOD8_(typename, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD9_T(m, ...) GMOCK_METHOD9_(typename, , , m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD10_T(m, ...) GMOCK_METHOD10_(typename, , , m, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define MOCK_CONST_METHOD0_T(m, ...) \
|
||||||
|
GMOCK_METHOD0_(typename, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD1_T(m, ...) \
|
||||||
|
GMOCK_METHOD1_(typename, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD2_T(m, ...) \
|
||||||
|
GMOCK_METHOD2_(typename, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD3_T(m, ...) \
|
||||||
|
GMOCK_METHOD3_(typename, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD4_T(m, ...) \
|
||||||
|
GMOCK_METHOD4_(typename, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD5_T(m, ...) \
|
||||||
|
GMOCK_METHOD5_(typename, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD6_T(m, ...) \
|
||||||
|
GMOCK_METHOD6_(typename, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD7_T(m, ...) \
|
||||||
|
GMOCK_METHOD7_(typename, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD8_T(m, ...) \
|
||||||
|
GMOCK_METHOD8_(typename, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD9_T(m, ...) \
|
||||||
|
GMOCK_METHOD9_(typename, const, , m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD10_T(m, ...) \
|
||||||
|
GMOCK_METHOD10_(typename, const, , m, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define MOCK_METHOD0_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD0_(, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD1_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD1_(, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD2_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD2_(, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD3_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD3_(, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD4_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD4_(, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD5_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD5_(, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD6_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD6_(, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD7_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD7_(, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD8_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD8_(, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD9_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD9_(, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD10_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD10_(, , ct, m, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD0_(, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD1_(, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD2_(, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD3_(, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD4_(, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD5_(, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD6_(, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD7_(, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD8_(, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD9_(, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD10_(, const, ct, m, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define MOCK_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD0_(typename, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD1_(typename, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD2_(typename, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD3_(typename, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD4_(typename, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD5_(typename, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD6_(typename, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD7_(typename, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD8_(typename, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD9_(typename, , ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD10_(typename, , ct, m, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define MOCK_CONST_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD0_(typename, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD1_(typename, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD2_(typename, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD3_(typename, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD4_(typename, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD5_(typename, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD6_(typename, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD7_(typename, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD8_(typename, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD9_(typename, const, ct, m, __VA_ARGS__)
|
||||||
|
#define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD10_(typename, const, ct, m, __VA_ARGS__)
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_
|
@ -0,0 +1,227 @@
|
|||||||
|
$$ -*- mode: c++; -*-
|
||||||
|
$$ This is a Pump source file. Please use Pump to convert
|
||||||
|
$$ it to gmock-generated-function-mockers.h.
|
||||||
|
$$
|
||||||
|
$var n = 10 $$ The maximum arity we support.
|
||||||
|
// Copyright 2007, 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.
|
||||||
|
|
||||||
|
|
||||||
|
// Google Mock - a framework for writing C++ mock classes.
|
||||||
|
//
|
||||||
|
// This file implements function mockers of various arities.
|
||||||
|
|
||||||
|
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||||
|
|
||||||
|
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_
|
||||||
|
#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "gmock/gmock-spec-builders.h"
|
||||||
|
#include "gmock/internal/gmock-internal-utils.h"
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
$range i 0..n
|
||||||
|
// Removes the given pointer; this is a helper for the expectation setter method
|
||||||
|
// for parameterless matchers.
|
||||||
|
//
|
||||||
|
// We want to make sure that the user cannot set a parameterless expectation on
|
||||||
|
// overloaded methods, including methods which are overloaded on const. Example:
|
||||||
|
//
|
||||||
|
// class MockClass {
|
||||||
|
// MOCK_METHOD0(GetName, string&());
|
||||||
|
// MOCK_CONST_METHOD0(GetName, const string&());
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// TEST() {
|
||||||
|
// // This should be an error, as it's not clear which overload is expected.
|
||||||
|
// EXPECT_CALL(mock, GetName).WillOnce(ReturnRef(value));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Here are the generated expectation-setter methods:
|
||||||
|
//
|
||||||
|
// class MockClass {
|
||||||
|
// // Overload 1
|
||||||
|
// MockSpec<string&()> gmock_GetName() { ... }
|
||||||
|
// // Overload 2. Declared const so that the compiler will generate an
|
||||||
|
// // error when trying to resolve between this and overload 4 in
|
||||||
|
// // 'gmock_GetName(WithoutMatchers(), nullptr)'.
|
||||||
|
// MockSpec<string&()> gmock_GetName(
|
||||||
|
// const WithoutMatchers&, const Function<string&()>*) const {
|
||||||
|
// // Removes const from this, calls overload 1
|
||||||
|
// return AdjustConstness_(this)->gmock_GetName();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Overload 3
|
||||||
|
// const string& gmock_GetName() const { ... }
|
||||||
|
// // Overload 4
|
||||||
|
// MockSpec<const string&()> gmock_GetName(
|
||||||
|
// const WithoutMatchers&, const Function<const string&()>*) const {
|
||||||
|
// // Does not remove const, calls overload 3
|
||||||
|
// return AdjustConstness_const(this)->gmock_GetName();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
template <typename MockType>
|
||||||
|
const MockType* AdjustConstness_const(const MockType* mock) {
|
||||||
|
return mock;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes const from and returns the given pointer; this is a helper for the
|
||||||
|
// expectation setter method for parameterless matchers.
|
||||||
|
template <typename MockType>
|
||||||
|
MockType* AdjustConstness_(const MockType* mock) {
|
||||||
|
return const_cast<MockType*>(mock);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
// The style guide prohibits "using" statements in a namespace scope
|
||||||
|
// inside a header file. However, the FunctionMocker class template
|
||||||
|
// is meant to be defined in the ::testing namespace. The following
|
||||||
|
// line is just a trick for working around a bug in MSVC 8.0, which
|
||||||
|
// cannot handle it if we define FunctionMocker in ::testing.
|
||||||
|
using internal::FunctionMocker;
|
||||||
|
|
||||||
|
// GMOCK_RESULT_(tn, F) expands to the result type of function type F.
|
||||||
|
// We define this as a variadic macro in case F contains unprotected
|
||||||
|
// commas (the same reason that we use variadic macros in other places
|
||||||
|
// in this file).
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_RESULT_(tn, ...) \
|
||||||
|
tn ::testing::internal::Function<__VA_ARGS__>::Result
|
||||||
|
|
||||||
|
// The type of argument N of the given function type.
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_ARG_(tn, N, ...) \
|
||||||
|
tn ::testing::internal::Function<__VA_ARGS__>::template Arg<N-1>::type
|
||||||
|
|
||||||
|
// The matcher type for argument N of the given function type.
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_MATCHER_(tn, N, ...) \
|
||||||
|
const ::testing::Matcher<GMOCK_ARG_(tn, N, __VA_ARGS__)>&
|
||||||
|
|
||||||
|
// The variable for mocking the given method.
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_MOCKER_(arity, constness, Method) \
|
||||||
|
GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__)
|
||||||
|
|
||||||
|
|
||||||
|
$for i [[
|
||||||
|
$range j 1..i
|
||||||
|
$var arg_as = [[$for j, [[GMOCK_ARG_(tn, $j, __VA_ARGS__) gmock_a$j]]]]
|
||||||
|
$var as = [[$for j, \
|
||||||
|
[[::std::forward<GMOCK_ARG_(tn, $j, __VA_ARGS__)>(gmock_a$j)]]]]
|
||||||
|
$var matcher_arg_as = [[$for j, \
|
||||||
|
[[GMOCK_MATCHER_(tn, $j, __VA_ARGS__) gmock_a$j]]]]
|
||||||
|
$var matcher_as = [[$for j, [[gmock_a$j]]]]
|
||||||
|
$var anything_matchers = [[$for j, \
|
||||||
|
[[::testing::A<GMOCK_ARG_(tn, $j, __VA_ARGS__)>()]]]]
|
||||||
|
// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
|
||||||
|
#define GMOCK_METHOD$i[[]]_(tn, constness, ct, Method, ...) \
|
||||||
|
static_assert($i == ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, "MOCK_METHOD<N> must match argument count.");\
|
||||||
|
GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
|
||||||
|
$arg_as) constness { \
|
||||||
|
GMOCK_MOCKER_($i, constness, Method).SetOwnerAndName(this, #Method); \
|
||||||
|
return GMOCK_MOCKER_($i, constness, Method).Invoke($as); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> \
|
||||||
|
gmock_##Method($matcher_arg_as) constness { \
|
||||||
|
GMOCK_MOCKER_($i, constness, Method).RegisterOwner(this); \
|
||||||
|
return GMOCK_MOCKER_($i, constness, Method).With($matcher_as); \
|
||||||
|
} \
|
||||||
|
::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
|
||||||
|
const ::testing::internal::WithoutMatchers&, \
|
||||||
|
constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
|
||||||
|
return ::testing::internal::AdjustConstness_##constness(this)-> \
|
||||||
|
gmock_##Method($anything_matchers); \
|
||||||
|
} \
|
||||||
|
mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_($i, constness, Method)
|
||||||
|
|
||||||
|
|
||||||
|
]]
|
||||||
|
$for i [[
|
||||||
|
#define MOCK_METHOD$i(m, ...) GMOCK_METHOD$i[[]]_(, , , m, __VA_ARGS__)
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
$for i [[
|
||||||
|
#define MOCK_CONST_METHOD$i(m, ...) GMOCK_METHOD$i[[]]_(, const, , m, __VA_ARGS__)
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
$for i [[
|
||||||
|
#define MOCK_METHOD$i[[]]_T(m, ...) GMOCK_METHOD$i[[]]_(typename, , , m, __VA_ARGS__)
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
$for i [[
|
||||||
|
#define MOCK_CONST_METHOD$i[[]]_T(m, ...) \
|
||||||
|
GMOCK_METHOD$i[[]]_(typename, const, , m, __VA_ARGS__)
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
$for i [[
|
||||||
|
#define MOCK_METHOD$i[[]]_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD$i[[]]_(, , ct, m, __VA_ARGS__)
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
$for i [[
|
||||||
|
#define MOCK_CONST_METHOD$i[[]]_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD$i[[]]_(, const, ct, m, __VA_ARGS__)
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
$for i [[
|
||||||
|
#define MOCK_METHOD$i[[]]_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD$i[[]]_(typename, , ct, m, __VA_ARGS__)
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
$for i [[
|
||||||
|
#define MOCK_CONST_METHOD$i[[]]_T_WITH_CALLTYPE(ct, m, ...) \
|
||||||
|
GMOCK_METHOD$i[[]]_(typename, const, ct, m, __VA_ARGS__)
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,346 @@
|
|||||||
|
$$ -*- mode: c++; -*-
|
||||||
|
$$ This is a Pump source file. Please use Pump to convert
|
||||||
|
$$ it to gmock-generated-matchers.h.
|
||||||
|
$$
|
||||||
|
$var n = 10 $$ The maximum arity we support.
|
||||||
|
$$ }} This line fixes auto-indentation of the following code in Emacs.
|
||||||
|
// Copyright 2008, 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.
|
||||||
|
|
||||||
|
// Google Mock - a framework for writing C++ mock classes.
|
||||||
|
//
|
||||||
|
// This file implements some commonly used variadic matchers.
|
||||||
|
|
||||||
|
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||||
|
|
||||||
|
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_
|
||||||
|
#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
#include "gmock/gmock-matchers.h"
|
||||||
|
|
||||||
|
// The MATCHER* family of macros can be used in a namespace scope to
|
||||||
|
// define custom matchers easily.
|
||||||
|
//
|
||||||
|
// Basic Usage
|
||||||
|
// ===========
|
||||||
|
//
|
||||||
|
// The syntax
|
||||||
|
//
|
||||||
|
// MATCHER(name, description_string) { statements; }
|
||||||
|
//
|
||||||
|
// defines a matcher with the given name that executes the statements,
|
||||||
|
// which must return a bool to indicate if the match succeeds. Inside
|
||||||
|
// the statements, you can refer to the value being matched by 'arg',
|
||||||
|
// and refer to its type by 'arg_type'.
|
||||||
|
//
|
||||||
|
// The description string documents what the matcher does, and is used
|
||||||
|
// to generate the failure message when the match fails. Since a
|
||||||
|
// MATCHER() is usually defined in a header file shared by multiple
|
||||||
|
// C++ source files, we require the description to be a C-string
|
||||||
|
// literal to avoid possible side effects. It can be empty, in which
|
||||||
|
// case we'll use the sequence of words in the matcher name as the
|
||||||
|
// description.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
//
|
||||||
|
// MATCHER(IsEven, "") { return (arg % 2) == 0; }
|
||||||
|
//
|
||||||
|
// allows you to write
|
||||||
|
//
|
||||||
|
// // Expects mock_foo.Bar(n) to be called where n is even.
|
||||||
|
// EXPECT_CALL(mock_foo, Bar(IsEven()));
|
||||||
|
//
|
||||||
|
// or,
|
||||||
|
//
|
||||||
|
// // Verifies that the value of some_expression is even.
|
||||||
|
// EXPECT_THAT(some_expression, IsEven());
|
||||||
|
//
|
||||||
|
// If the above assertion fails, it will print something like:
|
||||||
|
//
|
||||||
|
// Value of: some_expression
|
||||||
|
// Expected: is even
|
||||||
|
// Actual: 7
|
||||||
|
//
|
||||||
|
// where the description "is even" is automatically calculated from the
|
||||||
|
// matcher name IsEven.
|
||||||
|
//
|
||||||
|
// Argument Type
|
||||||
|
// =============
|
||||||
|
//
|
||||||
|
// Note that the type of the value being matched (arg_type) is
|
||||||
|
// determined by the context in which you use the matcher and is
|
||||||
|
// supplied to you by the compiler, so you don't need to worry about
|
||||||
|
// declaring it (nor can you). This allows the matcher to be
|
||||||
|
// polymorphic. For example, IsEven() can be used to match any type
|
||||||
|
// where the value of "(arg % 2) == 0" can be implicitly converted to
|
||||||
|
// a bool. In the "Bar(IsEven())" example above, if method Bar()
|
||||||
|
// takes an int, 'arg_type' will be int; if it takes an unsigned long,
|
||||||
|
// 'arg_type' will be unsigned long; and so on.
|
||||||
|
//
|
||||||
|
// Parameterizing Matchers
|
||||||
|
// =======================
|
||||||
|
//
|
||||||
|
// Sometimes you'll want to parameterize the matcher. For that you
|
||||||
|
// can use another macro:
|
||||||
|
//
|
||||||
|
// MATCHER_P(name, param_name, description_string) { statements; }
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
//
|
||||||
|
// MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; }
|
||||||
|
//
|
||||||
|
// will allow you to write:
|
||||||
|
//
|
||||||
|
// EXPECT_THAT(Blah("a"), HasAbsoluteValue(n));
|
||||||
|
//
|
||||||
|
// which may lead to this message (assuming n is 10):
|
||||||
|
//
|
||||||
|
// Value of: Blah("a")
|
||||||
|
// Expected: has absolute value 10
|
||||||
|
// Actual: -9
|
||||||
|
//
|
||||||
|
// Note that both the matcher description and its parameter are
|
||||||
|
// printed, making the message human-friendly.
|
||||||
|
//
|
||||||
|
// In the matcher definition body, you can write 'foo_type' to
|
||||||
|
// reference the type of a parameter named 'foo'. For example, in the
|
||||||
|
// body of MATCHER_P(HasAbsoluteValue, value) above, you can write
|
||||||
|
// 'value_type' to refer to the type of 'value'.
|
||||||
|
//
|
||||||
|
// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P$n to
|
||||||
|
// support multi-parameter matchers.
|
||||||
|
//
|
||||||
|
// Describing Parameterized Matchers
|
||||||
|
// =================================
|
||||||
|
//
|
||||||
|
// The last argument to MATCHER*() is a string-typed expression. The
|
||||||
|
// expression can reference all of the matcher's parameters and a
|
||||||
|
// special bool-typed variable named 'negation'. When 'negation' is
|
||||||
|
// false, the expression should evaluate to the matcher's description;
|
||||||
|
// otherwise it should evaluate to the description of the negation of
|
||||||
|
// the matcher. For example,
|
||||||
|
//
|
||||||
|
// using testing::PrintToString;
|
||||||
|
//
|
||||||
|
// MATCHER_P2(InClosedRange, low, hi,
|
||||||
|
// std::string(negation ? "is not" : "is") + " in range [" +
|
||||||
|
// PrintToString(low) + ", " + PrintToString(hi) + "]") {
|
||||||
|
// return low <= arg && arg <= hi;
|
||||||
|
// }
|
||||||
|
// ...
|
||||||
|
// EXPECT_THAT(3, InClosedRange(4, 6));
|
||||||
|
// EXPECT_THAT(3, Not(InClosedRange(2, 4)));
|
||||||
|
//
|
||||||
|
// would generate two failures that contain the text:
|
||||||
|
//
|
||||||
|
// Expected: is in range [4, 6]
|
||||||
|
// ...
|
||||||
|
// Expected: is not in range [2, 4]
|
||||||
|
//
|
||||||
|
// If you specify "" as the description, the failure message will
|
||||||
|
// contain the sequence of words in the matcher name followed by the
|
||||||
|
// parameter values printed as a tuple. For example,
|
||||||
|
//
|
||||||
|
// MATCHER_P2(InClosedRange, low, hi, "") { ... }
|
||||||
|
// ...
|
||||||
|
// EXPECT_THAT(3, InClosedRange(4, 6));
|
||||||
|
// EXPECT_THAT(3, Not(InClosedRange(2, 4)));
|
||||||
|
//
|
||||||
|
// would generate two failures that contain the text:
|
||||||
|
//
|
||||||
|
// Expected: in closed range (4, 6)
|
||||||
|
// ...
|
||||||
|
// Expected: not (in closed range (2, 4))
|
||||||
|
//
|
||||||
|
// Types of Matcher Parameters
|
||||||
|
// ===========================
|
||||||
|
//
|
||||||
|
// For the purpose of typing, you can view
|
||||||
|
//
|
||||||
|
// MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... }
|
||||||
|
//
|
||||||
|
// as shorthand for
|
||||||
|
//
|
||||||
|
// template <typename p1_type, ..., typename pk_type>
|
||||||
|
// FooMatcherPk<p1_type, ..., pk_type>
|
||||||
|
// Foo(p1_type p1, ..., pk_type pk) { ... }
|
||||||
|
//
|
||||||
|
// When you write Foo(v1, ..., vk), the compiler infers the types of
|
||||||
|
// the parameters v1, ..., and vk for you. If you are not happy with
|
||||||
|
// the result of the type inference, you can specify the types by
|
||||||
|
// explicitly instantiating the template, as in Foo<long, bool>(5,
|
||||||
|
// false). As said earlier, you don't get to (or need to) specify
|
||||||
|
// 'arg_type' as that's determined by the context in which the matcher
|
||||||
|
// is used. You can assign the result of expression Foo(p1, ..., pk)
|
||||||
|
// to a variable of type FooMatcherPk<p1_type, ..., pk_type>. This
|
||||||
|
// can be useful when composing matchers.
|
||||||
|
//
|
||||||
|
// While you can instantiate a matcher template with reference types,
|
||||||
|
// passing the parameters by pointer usually makes your code more
|
||||||
|
// readable. If, however, you still want to pass a parameter by
|
||||||
|
// reference, be aware that in the failure message generated by the
|
||||||
|
// matcher you will see the value of the referenced object but not its
|
||||||
|
// address.
|
||||||
|
//
|
||||||
|
// Explaining Match Results
|
||||||
|
// ========================
|
||||||
|
//
|
||||||
|
// Sometimes the matcher description alone isn't enough to explain why
|
||||||
|
// the match has failed or succeeded. For example, when expecting a
|
||||||
|
// long string, it can be very helpful to also print the diff between
|
||||||
|
// the expected string and the actual one. To achieve that, you can
|
||||||
|
// optionally stream additional information to a special variable
|
||||||
|
// named result_listener, whose type is a pointer to class
|
||||||
|
// MatchResultListener:
|
||||||
|
//
|
||||||
|
// MATCHER_P(EqualsLongString, str, "") {
|
||||||
|
// if (arg == str) return true;
|
||||||
|
//
|
||||||
|
// *result_listener << "the difference: "
|
||||||
|
/// << DiffStrings(str, arg);
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Overloading Matchers
|
||||||
|
// ====================
|
||||||
|
//
|
||||||
|
// You can overload matchers with different numbers of parameters:
|
||||||
|
//
|
||||||
|
// MATCHER_P(Blah, a, description_string1) { ... }
|
||||||
|
// MATCHER_P2(Blah, a, b, description_string2) { ... }
|
||||||
|
//
|
||||||
|
// Caveats
|
||||||
|
// =======
|
||||||
|
//
|
||||||
|
// When defining a new matcher, you should also consider implementing
|
||||||
|
// MatcherInterface or using MakePolymorphicMatcher(). These
|
||||||
|
// approaches require more work than the MATCHER* macros, but also
|
||||||
|
// give you more control on the types of the value being matched and
|
||||||
|
// the matcher parameters, which may leads to better compiler error
|
||||||
|
// messages when the matcher is used wrong. They also allow
|
||||||
|
// overloading matchers based on parameter types (as opposed to just
|
||||||
|
// based on the number of parameters).
|
||||||
|
//
|
||||||
|
// MATCHER*() can only be used in a namespace scope as templates cannot be
|
||||||
|
// declared inside of a local class.
|
||||||
|
//
|
||||||
|
// More Information
|
||||||
|
// ================
|
||||||
|
//
|
||||||
|
// To learn more about using these macros, please search for 'MATCHER'
|
||||||
|
// on
|
||||||
|
// https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md
|
||||||
|
|
||||||
|
$range i 0..n
|
||||||
|
$for i
|
||||||
|
|
||||||
|
[[
|
||||||
|
$var macro_name = [[$if i==0 [[MATCHER]] $elif i==1 [[MATCHER_P]]
|
||||||
|
$else [[MATCHER_P$i]]]]
|
||||||
|
$var class_name = [[name##Matcher[[$if i==0 [[]] $elif i==1 [[P]]
|
||||||
|
$else [[P$i]]]]]]
|
||||||
|
$range j 0..i-1
|
||||||
|
$var template = [[$if i==0 [[]] $else [[
|
||||||
|
|
||||||
|
template <$for j, [[typename p$j##_type]]>\
|
||||||
|
]]]]
|
||||||
|
$var ctor_param_list = [[$for j, [[p$j##_type gmock_p$j]]]]
|
||||||
|
$var impl_ctor_param_list = [[$for j, [[p$j##_type gmock_p$j]]]]
|
||||||
|
$var impl_inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(::std::move(gmock_p$j))]]]]]]
|
||||||
|
$var inits = [[$if i==0 [[]] $else [[ : $for j, [[p$j(::std::move(gmock_p$j))]]]]]]
|
||||||
|
$var params = [[$for j, [[p$j]]]]
|
||||||
|
$var param_types = [[$if i==0 [[]] $else [[<$for j, [[p$j##_type]]>]]]]
|
||||||
|
$var param_types_and_names = [[$for j, [[p$j##_type p$j]]]]
|
||||||
|
$var param_field_decls = [[$for j
|
||||||
|
[[
|
||||||
|
|
||||||
|
p$j##_type const p$j;\
|
||||||
|
]]]]
|
||||||
|
$var param_field_decls2 = [[$for j
|
||||||
|
[[
|
||||||
|
|
||||||
|
p$j##_type const p$j;\
|
||||||
|
]]]]
|
||||||
|
|
||||||
|
#define $macro_name(name$for j [[, p$j]], description)\$template
|
||||||
|
class $class_name {\
|
||||||
|
public:\
|
||||||
|
template <typename arg_type>\
|
||||||
|
class gmock_Impl : public ::testing::MatcherInterface<\
|
||||||
|
GTEST_REFERENCE_TO_CONST_(arg_type)> {\
|
||||||
|
public:\
|
||||||
|
[[$if i==1 [[explicit ]]]]gmock_Impl($impl_ctor_param_list)\
|
||||||
|
$impl_inits {}\
|
||||||
|
virtual bool MatchAndExplain(\
|
||||||
|
GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
|
||||||
|
::testing::MatchResultListener* result_listener) const;\
|
||||||
|
virtual void DescribeTo(::std::ostream* gmock_os) const {\
|
||||||
|
*gmock_os << FormatDescription(false);\
|
||||||
|
}\
|
||||||
|
virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
|
||||||
|
*gmock_os << FormatDescription(true);\
|
||||||
|
}\$param_field_decls
|
||||||
|
private:\
|
||||||
|
::std::string FormatDescription(bool negation) const {\
|
||||||
|
::std::string gmock_description = (description);\
|
||||||
|
if (!gmock_description.empty()) {\
|
||||||
|
return gmock_description;\
|
||||||
|
}\
|
||||||
|
return ::testing::internal::FormatMatcherDescription(\
|
||||||
|
negation, #name, \
|
||||||
|
::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
|
||||||
|
::std::tuple<$for j, [[p$j##_type]]>($for j, [[p$j]])));\
|
||||||
|
}\
|
||||||
|
};\
|
||||||
|
template <typename arg_type>\
|
||||||
|
operator ::testing::Matcher<arg_type>() const {\
|
||||||
|
return ::testing::Matcher<arg_type>(\
|
||||||
|
new gmock_Impl<arg_type>($params));\
|
||||||
|
}\
|
||||||
|
[[$if i==1 [[explicit ]]]]$class_name($ctor_param_list)$inits {\
|
||||||
|
}\$param_field_decls2
|
||||||
|
private:\
|
||||||
|
};\$template
|
||||||
|
inline $class_name$param_types name($param_types_and_names) {\
|
||||||
|
return $class_name$param_types($params);\
|
||||||
|
}\$template
|
||||||
|
template <typename arg_type>\
|
||||||
|
bool $class_name$param_types::gmock_Impl<arg_type>::MatchAndExplain(\
|
||||||
|
GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
|
||||||
|
::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
|
||||||
|
const
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,162 @@
|
|||||||
|
// Copyright 2007, 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.
|
||||||
|
|
||||||
|
|
||||||
|
// Google Mock - a framework for writing C++ mock classes.
|
||||||
|
//
|
||||||
|
// This file implements some actions that depend on gmock-generated-actions.h.
|
||||||
|
|
||||||
|
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||||
|
|
||||||
|
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
|
||||||
|
#define GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "gmock/gmock-generated-actions.h"
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// An internal replacement for std::copy which mimics its behavior. This is
|
||||||
|
// necessary because Visual Studio deprecates ::std::copy, issuing warning 4996.
|
||||||
|
// However Visual Studio 2010 and later do not honor #pragmas which disable that
|
||||||
|
// warning.
|
||||||
|
template<typename InputIterator, typename OutputIterator>
|
||||||
|
inline OutputIterator CopyElements(InputIterator first,
|
||||||
|
InputIterator last,
|
||||||
|
OutputIterator output) {
|
||||||
|
for (; first != last; ++first, ++output) {
|
||||||
|
*output = *first;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
// Various overloads for Invoke().
|
||||||
|
|
||||||
|
// The ACTION*() macros trigger warning C4100 (unreferenced formal
|
||||||
|
// parameter) in MSVC with -W4. Unfortunately they cannot be fixed in
|
||||||
|
// the macro definition, as the warnings are generated when the macro
|
||||||
|
// is expanded and macro expansion cannot contain #pragma. Therefore
|
||||||
|
// we suppress them here.
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning(disable:4100)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Action ReturnArg<k>() returns the k-th argument of the mock function.
|
||||||
|
ACTION_TEMPLATE(ReturnArg,
|
||||||
|
HAS_1_TEMPLATE_PARAMS(int, k),
|
||||||
|
AND_0_VALUE_PARAMS()) {
|
||||||
|
return ::std::get<k>(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action SaveArg<k>(pointer) saves the k-th (0-based) argument of the
|
||||||
|
// mock function to *pointer.
|
||||||
|
ACTION_TEMPLATE(SaveArg,
|
||||||
|
HAS_1_TEMPLATE_PARAMS(int, k),
|
||||||
|
AND_1_VALUE_PARAMS(pointer)) {
|
||||||
|
*pointer = ::std::get<k>(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action SaveArgPointee<k>(pointer) saves the value pointed to
|
||||||
|
// by the k-th (0-based) argument of the mock function to *pointer.
|
||||||
|
ACTION_TEMPLATE(SaveArgPointee,
|
||||||
|
HAS_1_TEMPLATE_PARAMS(int, k),
|
||||||
|
AND_1_VALUE_PARAMS(pointer)) {
|
||||||
|
*pointer = *::std::get<k>(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action SetArgReferee<k>(value) assigns 'value' to the variable
|
||||||
|
// referenced by the k-th (0-based) argument of the mock function.
|
||||||
|
ACTION_TEMPLATE(SetArgReferee,
|
||||||
|
HAS_1_TEMPLATE_PARAMS(int, k),
|
||||||
|
AND_1_VALUE_PARAMS(value)) {
|
||||||
|
typedef typename ::std::tuple_element<k, args_type>::type argk_type;
|
||||||
|
// Ensures that argument #k is a reference. If you get a compiler
|
||||||
|
// error on the next line, you are using SetArgReferee<k>(value) in
|
||||||
|
// a mock function whose k-th (0-based) argument is not a reference.
|
||||||
|
GTEST_COMPILE_ASSERT_(std::is_reference<argk_type>::value,
|
||||||
|
SetArgReferee_must_be_used_with_a_reference_argument);
|
||||||
|
::std::get<k>(args) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action SetArrayArgument<k>(first, last) copies the elements in
|
||||||
|
// source range [first, last) to the array pointed to by the k-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.
|
||||||
|
ACTION_TEMPLATE(SetArrayArgument,
|
||||||
|
HAS_1_TEMPLATE_PARAMS(int, k),
|
||||||
|
AND_2_VALUE_PARAMS(first, last)) {
|
||||||
|
// Visual Studio deprecates ::std::copy, so we use our own copy in that case.
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
internal::CopyElements(first, last, ::std::get<k>(args));
|
||||||
|
#else
|
||||||
|
::std::copy(first, last, ::std::get<k>(args));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action DeleteArg<k>() deletes the k-th (0-based) argument of the mock
|
||||||
|
// function.
|
||||||
|
ACTION_TEMPLATE(DeleteArg,
|
||||||
|
HAS_1_TEMPLATE_PARAMS(int, k),
|
||||||
|
AND_0_VALUE_PARAMS()) {
|
||||||
|
delete ::std::get<k>(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This action returns the value pointed to by 'pointer'.
|
||||||
|
ACTION_P(ReturnPointee, pointer) { return *pointer; }
|
||||||
|
|
||||||
|
// Action Throw(exception) can be used in a mock function of any type
|
||||||
|
// to throw the given exception. Any copyable value can be thrown.
|
||||||
|
#if GTEST_HAS_EXCEPTIONS
|
||||||
|
|
||||||
|
// Suppresses the 'unreachable code' warning that VC generates in opt modes.
|
||||||
|
# ifdef _MSC_VER
|
||||||
|
# pragma warning(push) // Saves the current warning state.
|
||||||
|
# pragma warning(disable:4702) // Temporarily disables warning 4702.
|
||||||
|
# endif
|
||||||
|
ACTION_P(Throw, exception) { throw exception; }
|
||||||
|
# ifdef _MSC_VER
|
||||||
|
# pragma warning(pop) // Restores the warning state.
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif // GTEST_HAS_EXCEPTIONS
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
|
@ -0,0 +1,92 @@
|
|||||||
|
// Copyright 2013, 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.
|
||||||
|
|
||||||
|
|
||||||
|
// Google Mock - a framework for writing C++ mock classes.
|
||||||
|
//
|
||||||
|
// This file implements some matchers that depend on gmock-generated-matchers.h.
|
||||||
|
//
|
||||||
|
// Note that tests are implemented in gmock-matchers_test.cc rather than
|
||||||
|
// gmock-more-matchers-test.cc.
|
||||||
|
|
||||||
|
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||||
|
|
||||||
|
#ifndef GMOCK_INCLUDE_GMOCK_MORE_MATCHERS_H_
|
||||||
|
#define GMOCK_INCLUDE_GMOCK_MORE_MATCHERS_H_
|
||||||
|
|
||||||
|
#include "gmock/gmock-generated-matchers.h"
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
// Silence C4100 (unreferenced formal
|
||||||
|
// parameter) for MSVC
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning(disable:4100)
|
||||||
|
#if (_MSC_VER == 1900)
|
||||||
|
// and silence C4800 (C4800: 'int *const ': forcing value
|
||||||
|
// to bool 'true' or 'false') for MSVC 14
|
||||||
|
# pragma warning(disable:4800)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Defines a matcher that matches an empty container. The container must
|
||||||
|
// support both size() and empty(), which all STL-like containers provide.
|
||||||
|
MATCHER(IsEmpty, negation ? "isn't empty" : "is empty") {
|
||||||
|
if (arg.empty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*result_listener << "whose size is " << arg.size();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define a matcher that matches a value that evaluates in boolean
|
||||||
|
// context to true. Useful for types that define "explicit operator
|
||||||
|
// bool" operators and so can't be compared for equality with true
|
||||||
|
// and false.
|
||||||
|
MATCHER(IsTrue, negation ? "is false" : "is true") {
|
||||||
|
return static_cast<bool>(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define a matcher that matches a value that evaluates in boolean
|
||||||
|
// context to false. Useful for types that define "explicit operator
|
||||||
|
// bool" operators and so can't be compared for equality with true
|
||||||
|
// and false.
|
||||||
|
MATCHER(IsFalse, negation ? "is true" : "is false") {
|
||||||
|
return !static_cast<bool>(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
#endif // GMOCK_INCLUDE_GMOCK_MORE_MATCHERS_H_
|
@ -0,0 +1,215 @@
|
|||||||
|
// Copyright 2008, 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.
|
||||||
|
|
||||||
|
|
||||||
|
// Implements class templates NiceMock, NaggyMock, and StrictMock.
|
||||||
|
//
|
||||||
|
// Given a mock class MockFoo that is created using Google Mock,
|
||||||
|
// NiceMock<MockFoo> is a subclass of MockFoo that allows
|
||||||
|
// uninteresting calls (i.e. calls to mock methods that have no
|
||||||
|
// EXPECT_CALL specs), NaggyMock<MockFoo> is a subclass of MockFoo
|
||||||
|
// that prints a warning when an uninteresting call occurs, and
|
||||||
|
// StrictMock<MockFoo> is a subclass of MockFoo that treats all
|
||||||
|
// uninteresting calls as errors.
|
||||||
|
//
|
||||||
|
// Currently a mock is naggy by default, so MockFoo and
|
||||||
|
// NaggyMock<MockFoo> behave like the same. However, we will soon
|
||||||
|
// switch the default behavior of mocks to be nice, as that in general
|
||||||
|
// leads to more maintainable tests. When that happens, MockFoo will
|
||||||
|
// stop behaving like NaggyMock<MockFoo> and start behaving like
|
||||||
|
// NiceMock<MockFoo>.
|
||||||
|
//
|
||||||
|
// NiceMock, NaggyMock, and StrictMock "inherit" the constructors of
|
||||||
|
// their respective base class. Therefore you can write
|
||||||
|
// NiceMock<MockFoo>(5, "a") to construct a nice mock where MockFoo
|
||||||
|
// has a constructor that accepts (int, const char*), for example.
|
||||||
|
//
|
||||||
|
// A known limitation is that NiceMock<MockFoo>, NaggyMock<MockFoo>,
|
||||||
|
// and StrictMock<MockFoo> only works for mock methods defined using
|
||||||
|
// the MOCK_METHOD* family of macros DIRECTLY in the MockFoo class.
|
||||||
|
// If a mock method is defined in a base class of MockFoo, the "nice"
|
||||||
|
// or "strict" modifier may not affect it, depending on the compiler.
|
||||||
|
// In particular, nesting NiceMock, NaggyMock, and StrictMock is NOT
|
||||||
|
// supported.
|
||||||
|
|
||||||
|
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||||
|
|
||||||
|
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_NICE_STRICT_H_
|
||||||
|
#define GMOCK_INCLUDE_GMOCK_GMOCK_NICE_STRICT_H_
|
||||||
|
|
||||||
|
#include "gmock/gmock-spec-builders.h"
|
||||||
|
#include "gmock/internal/gmock-port.h"
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
template <class MockClass>
|
||||||
|
class NiceMock : public MockClass {
|
||||||
|
public:
|
||||||
|
NiceMock() : MockClass() {
|
||||||
|
::testing::Mock::AllowUninterestingCalls(
|
||||||
|
internal::ImplicitCast_<MockClass*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ideally, we would inherit base class's constructors through a using
|
||||||
|
// declaration, which would preserve their visibility. However, many existing
|
||||||
|
// tests rely on the fact that current implementation reexports protected
|
||||||
|
// constructors as public. These tests would need to be cleaned up first.
|
||||||
|
|
||||||
|
// Single argument constructor is special-cased so that it can be
|
||||||
|
// made explicit.
|
||||||
|
template <typename A>
|
||||||
|
explicit NiceMock(A&& arg) : MockClass(std::forward<A>(arg)) {
|
||||||
|
::testing::Mock::AllowUninterestingCalls(
|
||||||
|
internal::ImplicitCast_<MockClass*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A1, typename A2, typename... An>
|
||||||
|
NiceMock(A1&& arg1, A2&& arg2, An&&... args)
|
||||||
|
: MockClass(std::forward<A1>(arg1), std::forward<A2>(arg2),
|
||||||
|
std::forward<An>(args)...) {
|
||||||
|
::testing::Mock::AllowUninterestingCalls(
|
||||||
|
internal::ImplicitCast_<MockClass*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
~NiceMock() { // NOLINT
|
||||||
|
::testing::Mock::UnregisterCallReaction(
|
||||||
|
internal::ImplicitCast_<MockClass*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(NiceMock);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class MockClass>
|
||||||
|
class NaggyMock : public MockClass {
|
||||||
|
public:
|
||||||
|
NaggyMock() : MockClass() {
|
||||||
|
::testing::Mock::WarnUninterestingCalls(
|
||||||
|
internal::ImplicitCast_<MockClass*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ideally, we would inherit base class's constructors through a using
|
||||||
|
// declaration, which would preserve their visibility. However, many existing
|
||||||
|
// tests rely on the fact that current implementation reexports protected
|
||||||
|
// constructors as public. These tests would need to be cleaned up first.
|
||||||
|
|
||||||
|
// Single argument constructor is special-cased so that it can be
|
||||||
|
// made explicit.
|
||||||
|
template <typename A>
|
||||||
|
explicit NaggyMock(A&& arg) : MockClass(std::forward<A>(arg)) {
|
||||||
|
::testing::Mock::WarnUninterestingCalls(
|
||||||
|
internal::ImplicitCast_<MockClass*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A1, typename A2, typename... An>
|
||||||
|
NaggyMock(A1&& arg1, A2&& arg2, An&&... args)
|
||||||
|
: MockClass(std::forward<A1>(arg1), std::forward<A2>(arg2),
|
||||||
|
std::forward<An>(args)...) {
|
||||||
|
::testing::Mock::WarnUninterestingCalls(
|
||||||
|
internal::ImplicitCast_<MockClass*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
~NaggyMock() { // NOLINT
|
||||||
|
::testing::Mock::UnregisterCallReaction(
|
||||||
|
internal::ImplicitCast_<MockClass*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(NaggyMock);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class MockClass>
|
||||||
|
class StrictMock : public MockClass {
|
||||||
|
public:
|
||||||
|
StrictMock() : MockClass() {
|
||||||
|
::testing::Mock::FailUninterestingCalls(
|
||||||
|
internal::ImplicitCast_<MockClass*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ideally, we would inherit base class's constructors through a using
|
||||||
|
// declaration, which would preserve their visibility. However, many existing
|
||||||
|
// tests rely on the fact that current implementation reexports protected
|
||||||
|
// constructors as public. These tests would need to be cleaned up first.
|
||||||
|
|
||||||
|
// Single argument constructor is special-cased so that it can be
|
||||||
|
// made explicit.
|
||||||
|
template <typename A>
|
||||||
|
explicit StrictMock(A&& arg) : MockClass(std::forward<A>(arg)) {
|
||||||
|
::testing::Mock::FailUninterestingCalls(
|
||||||
|
internal::ImplicitCast_<MockClass*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A1, typename A2, typename... An>
|
||||||
|
StrictMock(A1&& arg1, A2&& arg2, An&&... args)
|
||||||
|
: MockClass(std::forward<A1>(arg1), std::forward<A2>(arg2),
|
||||||
|
std::forward<An>(args)...) {
|
||||||
|
::testing::Mock::FailUninterestingCalls(
|
||||||
|
internal::ImplicitCast_<MockClass*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
~StrictMock() { // NOLINT
|
||||||
|
::testing::Mock::UnregisterCallReaction(
|
||||||
|
internal::ImplicitCast_<MockClass*>(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(StrictMock);
|
||||||
|
};
|
||||||
|
|
||||||
|
// The following specializations catch some (relatively more common)
|
||||||
|
// user errors of nesting nice and strict mocks. They do NOT catch
|
||||||
|
// all possible errors.
|
||||||
|
|
||||||
|
// These specializations are declared but not defined, as NiceMock,
|
||||||
|
// NaggyMock, and StrictMock cannot be nested.
|
||||||
|
|
||||||
|
template <typename MockClass>
|
||||||
|
class NiceMock<NiceMock<MockClass> >;
|
||||||
|
template <typename MockClass>
|
||||||
|
class NiceMock<NaggyMock<MockClass> >;
|
||||||
|
template <typename MockClass>
|
||||||
|
class NiceMock<StrictMock<MockClass> >;
|
||||||
|
|
||||||
|
template <typename MockClass>
|
||||||
|
class NaggyMock<NiceMock<MockClass> >;
|
||||||
|
template <typename MockClass>
|
||||||
|
class NaggyMock<NaggyMock<MockClass> >;
|
||||||
|
template <typename MockClass>
|
||||||
|
class NaggyMock<StrictMock<MockClass> >;
|
||||||
|
|
||||||
|
template <typename MockClass>
|
||||||
|
class StrictMock<NiceMock<MockClass> >;
|
||||||
|
template <typename MockClass>
|
||||||
|
class StrictMock<NaggyMock<MockClass> >;
|
||||||
|
template <typename MockClass>
|
||||||
|
class StrictMock<StrictMock<MockClass> >;
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_NICE_STRICT_H_
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,101 @@
|
|||||||
|
// Copyright 2007, 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.
|
||||||
|
|
||||||
|
|
||||||
|
// Google Mock - a framework for writing C++ mock classes.
|
||||||
|
//
|
||||||
|
// This is the main header file a user should include.
|
||||||
|
|
||||||
|
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||||
|
|
||||||
|
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_H_
|
||||||
|
#define GMOCK_INCLUDE_GMOCK_GMOCK_H_
|
||||||
|
|
||||||
|
// This file implements the following syntax:
|
||||||
|
//
|
||||||
|
// ON_CALL(mock_object, Method(...))
|
||||||
|
// .With(...) ?
|
||||||
|
// .WillByDefault(...);
|
||||||
|
//
|
||||||
|
// where With() is optional and WillByDefault() must appear exactly
|
||||||
|
// once.
|
||||||
|
//
|
||||||
|
// EXPECT_CALL(mock_object, Method(...))
|
||||||
|
// .With(...) ?
|
||||||
|
// .Times(...) ?
|
||||||
|
// .InSequence(...) *
|
||||||
|
// .WillOnce(...) *
|
||||||
|
// .WillRepeatedly(...) ?
|
||||||
|
// .RetiresOnSaturation() ? ;
|
||||||
|
//
|
||||||
|
// where all clauses are optional and WillOnce() can be repeated.
|
||||||
|
|
||||||
|
#include "gmock/gmock-actions.h"
|
||||||
|
#include "gmock/gmock-cardinalities.h"
|
||||||
|
#include "gmock/gmock-function-mocker.h"
|
||||||
|
#include "gmock/gmock-generated-actions.h"
|
||||||
|
#include "gmock/gmock-generated-function-mockers.h"
|
||||||
|
#include "gmock/gmock-generated-matchers.h"
|
||||||
|
#include "gmock/gmock-matchers.h"
|
||||||
|
#include "gmock/gmock-more-actions.h"
|
||||||
|
#include "gmock/gmock-more-matchers.h"
|
||||||
|
#include "gmock/gmock-nice-strict.h"
|
||||||
|
#include "gmock/internal/gmock-internal-utils.h"
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
// Declares Google Mock flags that we want a user to use programmatically.
|
||||||
|
GMOCK_DECLARE_bool_(catch_leaked_mocks);
|
||||||
|
GMOCK_DECLARE_string_(verbose);
|
||||||
|
GMOCK_DECLARE_int32_(default_mock_behavior);
|
||||||
|
|
||||||
|
// Initializes Google Mock. This must be called before running the
|
||||||
|
// tests. In particular, it parses the command line for the flags
|
||||||
|
// that Google Mock recognizes. Whenever a Google Mock flag is seen,
|
||||||
|
// it is removed from argv, and *argc is decremented.
|
||||||
|
//
|
||||||
|
// No value is returned. Instead, the Google Mock flag variables are
|
||||||
|
// updated.
|
||||||
|
//
|
||||||
|
// Since Google Test is needed for Google Mock to work, this function
|
||||||
|
// also initializes Google Test and parses its flags, if that hasn't
|
||||||
|
// been done.
|
||||||
|
GTEST_API_ void InitGoogleMock(int* argc, char** argv);
|
||||||
|
|
||||||
|
// This overloaded version can be used in Windows programs compiled in
|
||||||
|
// UNICODE mode.
|
||||||
|
GTEST_API_ void InitGoogleMock(int* argc, wchar_t** argv);
|
||||||
|
|
||||||
|
// This overloaded version can be used on Arduino/embedded platforms where
|
||||||
|
// there is no argc/argv.
|
||||||
|
GTEST_API_ void InitGoogleMock();
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
#endif // GMOCK_INCLUDE_GMOCK_GMOCK_H_
|
@ -0,0 +1,16 @@
|
|||||||
|
# Customization Points
|
||||||
|
|
||||||
|
The custom directory is an injection point for custom user configurations.
|
||||||
|
|
||||||
|
## Header `gmock-port.h`
|
||||||
|
|
||||||
|
The following macros can be defined:
|
||||||
|
|
||||||
|
### Flag related macros:
|
||||||
|
|
||||||
|
* `GMOCK_DECLARE_bool_(name)`
|
||||||
|
* `GMOCK_DECLARE_int32_(name)`
|
||||||
|
* `GMOCK_DECLARE_string_(name)`
|
||||||
|
* `GMOCK_DEFINE_bool_(name, default_val, doc)`
|
||||||
|
* `GMOCK_DEFINE_int32_(name, default_val, doc)`
|
||||||
|
* `GMOCK_DEFINE_string_(name, default_val, doc)`
|
@ -0,0 +1,10 @@
|
|||||||
|
// This file was GENERATED by command:
|
||||||
|
// pump.py gmock-generated-actions.h.pump
|
||||||
|
// DO NOT EDIT BY HAND!!!
|
||||||
|
|
||||||
|
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||||
|
|
||||||
|
#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
|
||||||
|
#define GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
|
||||||
|
|
||||||
|
#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
|
@ -0,0 +1,12 @@
|
|||||||
|
$$ -*- mode: c++; -*-
|
||||||
|
$$ This is a Pump source file. Please use Pump to convert
|
||||||
|
$$ it to callback-actions.h.
|
||||||
|
$$
|
||||||
|
$var max_callback_arity = 5
|
||||||
|
$$}} This meta comment fixes auto-indentation in editors.
|
||||||
|
|
||||||
|
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||||
|
#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
|
||||||
|
#define GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
|
||||||
|
|
||||||
|
#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
|
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2015, 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.
|
||||||
|
//
|
||||||
|
// Injection point for custom user configurations. See README for details
|
||||||
|
//
|
||||||
|
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||||
|
|
||||||
|
#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_MATCHERS_H_
|
||||||
|
#define GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_MATCHERS_H_
|
||||||
|
#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_MATCHERS_H_
|
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2015, 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.
|
||||||
|
//
|
||||||
|
// Injection point for custom user configurations. See README for details
|
||||||
|
//
|
||||||
|
// ** Custom implementation starts here **
|
||||||
|
|
||||||
|
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||||
|
|
||||||
|
#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_PORT_H_
|
||||||
|
#define GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_PORT_H_
|
||||||
|
|
||||||
|
#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_PORT_H_
|
@ -0,0 +1,513 @@
|
|||||||
|
// Copyright 2007, 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.
|
||||||
|
|
||||||
|
|
||||||
|
// Google Mock - a framework for writing C++ mock classes.
|
||||||
|
//
|
||||||
|
// This file defines some utilities useful for implementing Google
|
||||||
|
// Mock. They are subject to change without notice, so please DO NOT
|
||||||
|
// USE THEM IN USER CODE.
|
||||||
|
|
||||||
|
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||||
|
|
||||||
|
#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_
|
||||||
|
#define GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ostream> // NOLINT
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include "gmock/internal/gmock-port.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
template <typename>
|
||||||
|
class Matcher;
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// Silence MSVC C4100 (unreferenced formal parameter) and
|
||||||
|
// C4805('==': unsafe mix of type 'const int' and type 'const bool')
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning(disable:4100)
|
||||||
|
# pragma warning(disable:4805)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Joins a vector of strings as if they are fields of a tuple; returns
|
||||||
|
// the joined string.
|
||||||
|
GTEST_API_ std::string JoinAsTuple(const Strings& fields);
|
||||||
|
|
||||||
|
// Converts an identifier name to a space-separated list of lower-case
|
||||||
|
// words. Each maximum substring of the form [A-Za-z][a-z]*|\d+ is
|
||||||
|
// treated as one word. For example, both "FooBar123" and
|
||||||
|
// "foo_bar_123" are converted to "foo bar 123".
|
||||||
|
GTEST_API_ std::string ConvertIdentifierNameToWords(const char* id_name);
|
||||||
|
|
||||||
|
// PointeeOf<Pointer>::type is the type of a value pointed to by a
|
||||||
|
// Pointer, which can be either a smart pointer or a raw pointer. The
|
||||||
|
// following default implementation is for the case where Pointer is a
|
||||||
|
// smart pointer.
|
||||||
|
template <typename Pointer>
|
||||||
|
struct PointeeOf {
|
||||||
|
// Smart pointer classes define type element_type as the type of
|
||||||
|
// their pointees.
|
||||||
|
typedef typename Pointer::element_type type;
|
||||||
|
};
|
||||||
|
// This specialization is for the raw pointer case.
|
||||||
|
template <typename T>
|
||||||
|
struct PointeeOf<T*> { typedef T type; }; // NOLINT
|
||||||
|
|
||||||
|
// GetRawPointer(p) returns the raw pointer underlying p when p is a
|
||||||
|
// smart pointer, or returns p itself when p is already a raw pointer.
|
||||||
|
// The following default implementation is for the smart pointer case.
|
||||||
|
template <typename Pointer>
|
||||||
|
inline const typename Pointer::element_type* GetRawPointer(const Pointer& p) {
|
||||||
|
return p.get();
|
||||||
|
}
|
||||||
|
// This overloaded version is for the raw pointer case.
|
||||||
|
template <typename Element>
|
||||||
|
inline Element* GetRawPointer(Element* p) { return p; }
|
||||||
|
|
||||||
|
// MSVC treats wchar_t as a native type usually, but treats it as the
|
||||||
|
// same as unsigned short when the compiler option /Zc:wchar_t- is
|
||||||
|
// specified. It defines _NATIVE_WCHAR_T_DEFINED symbol when wchar_t
|
||||||
|
// is a native type.
|
||||||
|
#if defined(_MSC_VER) && !defined(_NATIVE_WCHAR_T_DEFINED)
|
||||||
|
// wchar_t is a typedef.
|
||||||
|
#else
|
||||||
|
# define GMOCK_WCHAR_T_IS_NATIVE_ 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// In what follows, we use the term "kind" to indicate whether a type
|
||||||
|
// is bool, an integer type (excluding bool), a floating-point type,
|
||||||
|
// or none of them. This categorization is useful for determining
|
||||||
|
// when a matcher argument type can be safely converted to another
|
||||||
|
// type in the implementation of SafeMatcherCast.
|
||||||
|
enum TypeKind {
|
||||||
|
kBool, kInteger, kFloatingPoint, kOther
|
||||||
|
};
|
||||||
|
|
||||||
|
// KindOf<T>::value is the kind of type T.
|
||||||
|
template <typename T> struct KindOf {
|
||||||
|
enum { value = kOther }; // The default kind.
|
||||||
|
};
|
||||||
|
|
||||||
|
// This macro declares that the kind of 'type' is 'kind'.
|
||||||
|
#define GMOCK_DECLARE_KIND_(type, kind) \
|
||||||
|
template <> struct KindOf<type> { enum { value = kind }; }
|
||||||
|
|
||||||
|
GMOCK_DECLARE_KIND_(bool, kBool);
|
||||||
|
|
||||||
|
// All standard integer types.
|
||||||
|
GMOCK_DECLARE_KIND_(char, kInteger);
|
||||||
|
GMOCK_DECLARE_KIND_(signed char, kInteger);
|
||||||
|
GMOCK_DECLARE_KIND_(unsigned char, kInteger);
|
||||||
|
GMOCK_DECLARE_KIND_(short, kInteger); // NOLINT
|
||||||
|
GMOCK_DECLARE_KIND_(unsigned short, kInteger); // NOLINT
|
||||||
|
GMOCK_DECLARE_KIND_(int, kInteger);
|
||||||
|
GMOCK_DECLARE_KIND_(unsigned int, kInteger);
|
||||||
|
GMOCK_DECLARE_KIND_(long, kInteger); // NOLINT
|
||||||
|
GMOCK_DECLARE_KIND_(unsigned long, kInteger); // NOLINT
|
||||||
|
|
||||||
|
#if GMOCK_WCHAR_T_IS_NATIVE_
|
||||||
|
GMOCK_DECLARE_KIND_(wchar_t, kInteger);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Non-standard integer types.
|
||||||
|
GMOCK_DECLARE_KIND_(Int64, kInteger);
|
||||||
|
GMOCK_DECLARE_KIND_(UInt64, kInteger);
|
||||||
|
|
||||||
|
// All standard floating-point types.
|
||||||
|
GMOCK_DECLARE_KIND_(float, kFloatingPoint);
|
||||||
|
GMOCK_DECLARE_KIND_(double, kFloatingPoint);
|
||||||
|
GMOCK_DECLARE_KIND_(long double, kFloatingPoint);
|
||||||
|
|
||||||
|
#undef GMOCK_DECLARE_KIND_
|
||||||
|
|
||||||
|
// Evaluates to the kind of 'type'.
|
||||||
|
#define GMOCK_KIND_OF_(type) \
|
||||||
|
static_cast< ::testing::internal::TypeKind>( \
|
||||||
|
::testing::internal::KindOf<type>::value)
|
||||||
|
|
||||||
|
// Evaluates to true if and only if integer type T is signed.
|
||||||
|
#define GMOCK_IS_SIGNED_(T) (static_cast<T>(-1) < 0)
|
||||||
|
|
||||||
|
// LosslessArithmeticConvertibleImpl<kFromKind, From, kToKind, To>::value
|
||||||
|
// is true if and only if arithmetic type From can be losslessly converted to
|
||||||
|
// arithmetic type To.
|
||||||
|
//
|
||||||
|
// It's the user's responsibility to ensure that both From and To are
|
||||||
|
// raw (i.e. has no CV modifier, is not a pointer, and is not a
|
||||||
|
// reference) built-in arithmetic types, kFromKind is the kind of
|
||||||
|
// From, and kToKind is the kind of To; the value is
|
||||||
|
// implementation-defined when the above pre-condition is violated.
|
||||||
|
template <TypeKind kFromKind, typename From, TypeKind kToKind, typename To>
|
||||||
|
struct LosslessArithmeticConvertibleImpl : public std::false_type {};
|
||||||
|
|
||||||
|
// Converting bool to bool is lossless.
|
||||||
|
template <>
|
||||||
|
struct LosslessArithmeticConvertibleImpl<kBool, bool, kBool, bool>
|
||||||
|
: public std::true_type {};
|
||||||
|
|
||||||
|
// Converting bool to any integer type is lossless.
|
||||||
|
template <typename To>
|
||||||
|
struct LosslessArithmeticConvertibleImpl<kBool, bool, kInteger, To>
|
||||||
|
: public std::true_type {};
|
||||||
|
|
||||||
|
// Converting bool to any floating-point type is lossless.
|
||||||
|
template <typename To>
|
||||||
|
struct LosslessArithmeticConvertibleImpl<kBool, bool, kFloatingPoint, To>
|
||||||
|
: public std::true_type {};
|
||||||
|
|
||||||
|
// Converting an integer to bool is lossy.
|
||||||
|
template <typename From>
|
||||||
|
struct LosslessArithmeticConvertibleImpl<kInteger, From, kBool, bool>
|
||||||
|
: public std::false_type {};
|
||||||
|
|
||||||
|
// Converting an integer to another non-bool integer is lossless
|
||||||
|
// if and only if the target type's range encloses the source type's range.
|
||||||
|
template <typename From, typename To>
|
||||||
|
struct LosslessArithmeticConvertibleImpl<kInteger, From, kInteger, To>
|
||||||
|
: public bool_constant<
|
||||||
|
// When converting from a smaller size to a larger size, we are
|
||||||
|
// fine as long as we are not converting from signed to unsigned.
|
||||||
|
((sizeof(From) < sizeof(To)) &&
|
||||||
|
(!GMOCK_IS_SIGNED_(From) || GMOCK_IS_SIGNED_(To))) ||
|
||||||
|
// When converting between the same size, the signedness must match.
|
||||||
|
((sizeof(From) == sizeof(To)) &&
|
||||||
|
(GMOCK_IS_SIGNED_(From) == GMOCK_IS_SIGNED_(To)))> {}; // NOLINT
|
||||||
|
|
||||||
|
#undef GMOCK_IS_SIGNED_
|
||||||
|
|
||||||
|
// Converting an integer to a floating-point type may be lossy, since
|
||||||
|
// the format of a floating-point number is implementation-defined.
|
||||||
|
template <typename From, typename To>
|
||||||
|
struct LosslessArithmeticConvertibleImpl<kInteger, From, kFloatingPoint, To>
|
||||||
|
: public std::false_type {};
|
||||||
|
|
||||||
|
// Converting a floating-point to bool is lossy.
|
||||||
|
template <typename From>
|
||||||
|
struct LosslessArithmeticConvertibleImpl<kFloatingPoint, From, kBool, bool>
|
||||||
|
: public std::false_type {};
|
||||||
|
|
||||||
|
// Converting a floating-point to an integer is lossy.
|
||||||
|
template <typename From, typename To>
|
||||||
|
struct LosslessArithmeticConvertibleImpl<kFloatingPoint, From, kInteger, To>
|
||||||
|
: public std::false_type {};
|
||||||
|
|
||||||
|
// Converting a floating-point to another floating-point is lossless
|
||||||
|
// if and only if the target type is at least as big as the source type.
|
||||||
|
template <typename From, typename To>
|
||||||
|
struct LosslessArithmeticConvertibleImpl<
|
||||||
|
kFloatingPoint, From, kFloatingPoint, To>
|
||||||
|
: public bool_constant<sizeof(From) <= sizeof(To)> {}; // NOLINT
|
||||||
|
|
||||||
|
// LosslessArithmeticConvertible<From, To>::value is true if and only if
|
||||||
|
// arithmetic type From can be losslessly converted to arithmetic type To.
|
||||||
|
//
|
||||||
|
// It's the user's responsibility to ensure that both From and To are
|
||||||
|
// raw (i.e. has no CV modifier, is not a pointer, and is not a
|
||||||
|
// reference) built-in arithmetic types; the value is
|
||||||
|
// implementation-defined when the above pre-condition is violated.
|
||||||
|
template <typename From, typename To>
|
||||||
|
struct LosslessArithmeticConvertible
|
||||||
|
: public LosslessArithmeticConvertibleImpl<
|
||||||
|
GMOCK_KIND_OF_(From), From, GMOCK_KIND_OF_(To), To> {}; // NOLINT
|
||||||
|
|
||||||
|
// This interface knows how to report a Google Mock failure (either
|
||||||
|
// non-fatal or fatal).
|
||||||
|
class FailureReporterInterface {
|
||||||
|
public:
|
||||||
|
// The type of a failure (either non-fatal or fatal).
|
||||||
|
enum FailureType {
|
||||||
|
kNonfatal, kFatal
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~FailureReporterInterface() {}
|
||||||
|
|
||||||
|
// Reports a failure that occurred at the given source file location.
|
||||||
|
virtual void ReportFailure(FailureType type, const char* file, int line,
|
||||||
|
const std::string& message) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns the failure reporter used by Google Mock.
|
||||||
|
GTEST_API_ FailureReporterInterface* GetFailureReporter();
|
||||||
|
|
||||||
|
// Asserts that condition is true; aborts the process with the given
|
||||||
|
// message if condition is false. We cannot use LOG(FATAL) or CHECK()
|
||||||
|
// as Google Mock might be used to mock the log sink itself. We
|
||||||
|
// inline this function to prevent it from showing up in the stack
|
||||||
|
// trace.
|
||||||
|
inline void Assert(bool condition, const char* file, int line,
|
||||||
|
const std::string& msg) {
|
||||||
|
if (!condition) {
|
||||||
|
GetFailureReporter()->ReportFailure(FailureReporterInterface::kFatal,
|
||||||
|
file, line, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline void Assert(bool condition, const char* file, int line) {
|
||||||
|
Assert(condition, file, line, "Assertion failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifies that condition is true; generates a non-fatal failure if
|
||||||
|
// condition is false.
|
||||||
|
inline void Expect(bool condition, const char* file, int line,
|
||||||
|
const std::string& msg) {
|
||||||
|
if (!condition) {
|
||||||
|
GetFailureReporter()->ReportFailure(FailureReporterInterface::kNonfatal,
|
||||||
|
file, line, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline void Expect(bool condition, const char* file, int line) {
|
||||||
|
Expect(condition, file, line, "Expectation failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Severity level of a log.
|
||||||
|
enum LogSeverity {
|
||||||
|
kInfo = 0,
|
||||||
|
kWarning = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
// Valid values for the --gmock_verbose flag.
|
||||||
|
|
||||||
|
// All logs (informational and warnings) are printed.
|
||||||
|
const char kInfoVerbosity[] = "info";
|
||||||
|
// Only warnings are printed.
|
||||||
|
const char kWarningVerbosity[] = "warning";
|
||||||
|
// No logs are printed.
|
||||||
|
const char kErrorVerbosity[] = "error";
|
||||||
|
|
||||||
|
// Returns true if and only if a log with the given severity is visible
|
||||||
|
// according to the --gmock_verbose flag.
|
||||||
|
GTEST_API_ bool LogIsVisible(LogSeverity severity);
|
||||||
|
|
||||||
|
// Prints the given message to stdout if and only if 'severity' >= the level
|
||||||
|
// specified by the --gmock_verbose flag. If stack_frames_to_skip >=
|
||||||
|
// 0, also prints the stack trace excluding the top
|
||||||
|
// stack_frames_to_skip frames. In opt mode, any positive
|
||||||
|
// stack_frames_to_skip is treated as 0, since we don't know which
|
||||||
|
// function calls will be inlined by the compiler and need to be
|
||||||
|
// conservative.
|
||||||
|
GTEST_API_ void Log(LogSeverity severity, const std::string& message,
|
||||||
|
int stack_frames_to_skip);
|
||||||
|
|
||||||
|
// A marker class that is used to resolve parameterless expectations to the
|
||||||
|
// correct overload. This must not be instantiable, to prevent client code from
|
||||||
|
// accidentally resolving to the overload; for example:
|
||||||
|
//
|
||||||
|
// ON_CALL(mock, Method({}, nullptr))...
|
||||||
|
//
|
||||||
|
class WithoutMatchers {
|
||||||
|
private:
|
||||||
|
WithoutMatchers() {}
|
||||||
|
friend GTEST_API_ WithoutMatchers GetWithoutMatchers();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal use only: access the singleton instance of WithoutMatchers.
|
||||||
|
GTEST_API_ WithoutMatchers GetWithoutMatchers();
|
||||||
|
|
||||||
|
// Type traits.
|
||||||
|
|
||||||
|
// Disable MSVC warnings for infinite recursion, since in this case the
|
||||||
|
// the recursion is unreachable.
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning(disable:4717)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Invalid<T>() is usable as an expression of type T, but will terminate
|
||||||
|
// the program with an assertion failure if actually run. This is useful
|
||||||
|
// when a value of type T is needed for compilation, but the statement
|
||||||
|
// will not really be executed (or we don't care if the statement
|
||||||
|
// crashes).
|
||||||
|
template <typename T>
|
||||||
|
inline T Invalid() {
|
||||||
|
Assert(false, "", -1, "Internal error: attempt to return invalid value");
|
||||||
|
// This statement is unreachable, and would never terminate even if it
|
||||||
|
// could be reached. It is provided only to placate compiler warnings
|
||||||
|
// about missing return statements.
|
||||||
|
return Invalid<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Given a raw type (i.e. having no top-level reference or const
|
||||||
|
// modifier) RawContainer that's either an STL-style container or a
|
||||||
|
// native array, class StlContainerView<RawContainer> has the
|
||||||
|
// following members:
|
||||||
|
//
|
||||||
|
// - type is a type that provides an STL-style container view to
|
||||||
|
// (i.e. implements the STL container concept for) RawContainer;
|
||||||
|
// - const_reference is a type that provides a reference to a const
|
||||||
|
// RawContainer;
|
||||||
|
// - ConstReference(raw_container) returns a const reference to an STL-style
|
||||||
|
// container view to raw_container, which is a RawContainer.
|
||||||
|
// - Copy(raw_container) returns an STL-style container view of a
|
||||||
|
// copy of raw_container, which is a RawContainer.
|
||||||
|
//
|
||||||
|
// This generic version is used when RawContainer itself is already an
|
||||||
|
// STL-style container.
|
||||||
|
template <class RawContainer>
|
||||||
|
class StlContainerView {
|
||||||
|
public:
|
||||||
|
typedef RawContainer type;
|
||||||
|
typedef const type& const_reference;
|
||||||
|
|
||||||
|
static const_reference ConstReference(const RawContainer& container) {
|
||||||
|
static_assert(!std::is_const<RawContainer>::value,
|
||||||
|
"RawContainer type must not be const");
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
static type Copy(const RawContainer& container) { return container; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// This specialization is used when RawContainer is a native array type.
|
||||||
|
template <typename Element, size_t N>
|
||||||
|
class StlContainerView<Element[N]> {
|
||||||
|
public:
|
||||||
|
typedef typename std::remove_const<Element>::type RawElement;
|
||||||
|
typedef internal::NativeArray<RawElement> type;
|
||||||
|
// NativeArray<T> can represent a native array either by value or by
|
||||||
|
// reference (selected by a constructor argument), so 'const type'
|
||||||
|
// can be used to reference a const native array. We cannot
|
||||||
|
// 'typedef const type& const_reference' here, as that would mean
|
||||||
|
// ConstReference() has to return a reference to a local variable.
|
||||||
|
typedef const type const_reference;
|
||||||
|
|
||||||
|
static const_reference ConstReference(const Element (&array)[N]) {
|
||||||
|
static_assert(std::is_same<Element, RawElement>::value,
|
||||||
|
"Element type must not be const");
|
||||||
|
return type(array, N, RelationToSourceReference());
|
||||||
|
}
|
||||||
|
static type Copy(const Element (&array)[N]) {
|
||||||
|
return type(array, N, RelationToSourceCopy());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This specialization is used when RawContainer is a native array
|
||||||
|
// represented as a (pointer, size) tuple.
|
||||||
|
template <typename ElementPointer, typename Size>
|
||||||
|
class StlContainerView< ::std::tuple<ElementPointer, Size> > {
|
||||||
|
public:
|
||||||
|
typedef typename std::remove_const<
|
||||||
|
typename internal::PointeeOf<ElementPointer>::type>::type RawElement;
|
||||||
|
typedef internal::NativeArray<RawElement> type;
|
||||||
|
typedef const type const_reference;
|
||||||
|
|
||||||
|
static const_reference ConstReference(
|
||||||
|
const ::std::tuple<ElementPointer, Size>& array) {
|
||||||
|
return type(std::get<0>(array), std::get<1>(array),
|
||||||
|
RelationToSourceReference());
|
||||||
|
}
|
||||||
|
static type Copy(const ::std::tuple<ElementPointer, Size>& array) {
|
||||||
|
return type(std::get<0>(array), std::get<1>(array), RelationToSourceCopy());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// The following specialization prevents the user from instantiating
|
||||||
|
// StlContainer with a reference type.
|
||||||
|
template <typename T> class StlContainerView<T&>;
|
||||||
|
|
||||||
|
// A type transform to remove constness from the first part of a pair.
|
||||||
|
// Pairs like that are used as the value_type of associative containers,
|
||||||
|
// and this transform produces a similar but assignable pair.
|
||||||
|
template <typename T>
|
||||||
|
struct RemoveConstFromKey {
|
||||||
|
typedef T type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Partially specialized to remove constness from std::pair<const K, V>.
|
||||||
|
template <typename K, typename V>
|
||||||
|
struct RemoveConstFromKey<std::pair<const K, V> > {
|
||||||
|
typedef std::pair<K, V> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Emit an assertion failure due to incorrect DoDefault() usage. Out-of-lined to
|
||||||
|
// reduce code size.
|
||||||
|
GTEST_API_ void IllegalDoDefault(const char* file, int line);
|
||||||
|
|
||||||
|
template <typename F, typename Tuple, size_t... Idx>
|
||||||
|
auto ApplyImpl(F&& f, Tuple&& args, IndexSequence<Idx...>) -> decltype(
|
||||||
|
std::forward<F>(f)(std::get<Idx>(std::forward<Tuple>(args))...)) {
|
||||||
|
return std::forward<F>(f)(std::get<Idx>(std::forward<Tuple>(args))...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the function to a tuple of arguments.
|
||||||
|
template <typename F, typename Tuple>
|
||||||
|
auto Apply(F&& f, Tuple&& args)
|
||||||
|
-> decltype(ApplyImpl(std::forward<F>(f), std::forward<Tuple>(args),
|
||||||
|
MakeIndexSequence<std::tuple_size<Tuple>::value>())) {
|
||||||
|
return ApplyImpl(std::forward<F>(f), std::forward<Tuple>(args),
|
||||||
|
MakeIndexSequence<std::tuple_size<Tuple>::value>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Template struct Function<F>, where F must be a function type, contains
|
||||||
|
// the following typedefs:
|
||||||
|
//
|
||||||
|
// Result: the function's return type.
|
||||||
|
// Arg<N>: the type of the N-th argument, where N starts with 0.
|
||||||
|
// ArgumentTuple: the tuple type consisting of all parameters of F.
|
||||||
|
// ArgumentMatcherTuple: the tuple type consisting of Matchers for all
|
||||||
|
// parameters of F.
|
||||||
|
// MakeResultVoid: the function type obtained by substituting void
|
||||||
|
// for the return type of F.
|
||||||
|
// MakeResultIgnoredValue:
|
||||||
|
// the function type obtained by substituting Something
|
||||||
|
// for the return type of F.
|
||||||
|
template <typename T>
|
||||||
|
struct Function;
|
||||||
|
|
||||||
|
template <typename R, typename... Args>
|
||||||
|
struct Function<R(Args...)> {
|
||||||
|
using Result = R;
|
||||||
|
static constexpr size_t ArgumentCount = sizeof...(Args);
|
||||||
|
template <size_t I>
|
||||||
|
using Arg = ElemFromList<I, typename MakeIndexSequence<sizeof...(Args)>::type,
|
||||||
|
Args...>;
|
||||||
|
using ArgumentTuple = std::tuple<Args...>;
|
||||||
|
using ArgumentMatcherTuple = std::tuple<Matcher<Args>...>;
|
||||||
|
using MakeResultVoid = void(Args...);
|
||||||
|
using MakeResultIgnoredValue = IgnoredValue(Args...);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename R, typename... Args>
|
||||||
|
constexpr size_t Function<R(Args...)>::ArgumentCount;
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_
|
@ -0,0 +1,87 @@
|
|||||||
|
// Copyright 2008, 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.
|
||||||
|
|
||||||
|
//
|
||||||
|
// Low-level types and utilities for porting Google Mock to various
|
||||||
|
// platforms. All macros ending with _ and symbols defined in an
|
||||||
|
// internal namespace are subject to change without notice. Code
|
||||||
|
// outside Google Mock MUST NOT USE THEM DIRECTLY. Macros that don't
|
||||||
|
// end with _ are part of Google Mock's public API and can be used by
|
||||||
|
// code outside Google Mock.
|
||||||
|
|
||||||
|
// GOOGLETEST_CM0002 DO NOT DELETE
|
||||||
|
|
||||||
|
#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_
|
||||||
|
#define GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// Most of the utilities needed for porting Google Mock are also
|
||||||
|
// required for Google Test and are defined in gtest-port.h.
|
||||||
|
//
|
||||||
|
// Note to maintainers: to reduce code duplication, prefer adding
|
||||||
|
// portability utilities to Google Test's gtest-port.h instead of
|
||||||
|
// here, as Google Mock depends on Google Test. Only add a utility
|
||||||
|
// here if it's truly specific to Google Mock.
|
||||||
|
|
||||||
|
#include "gtest/internal/gtest-port.h"
|
||||||
|
#include "gmock/internal/custom/gmock-port.h"
|
||||||
|
|
||||||
|
// For MS Visual C++, check the compiler version. At least VS 2015 is
|
||||||
|
// required to compile Google Mock.
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||||
|
# error "At least Visual C++ 2015 (14.0) is required to compile Google Mock."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Macro for referencing flags. This is public as we want the user to
|
||||||
|
// use this syntax to reference Google Mock flags.
|
||||||
|
#define GMOCK_FLAG(name) FLAGS_gmock_##name
|
||||||
|
|
||||||
|
#if !defined(GMOCK_DECLARE_bool_)
|
||||||
|
|
||||||
|
// Macros for declaring flags.
|
||||||
|
# define GMOCK_DECLARE_bool_(name) extern GTEST_API_ bool GMOCK_FLAG(name)
|
||||||
|
# define GMOCK_DECLARE_int32_(name) \
|
||||||
|
extern GTEST_API_ ::testing::internal::Int32 GMOCK_FLAG(name)
|
||||||
|
# define GMOCK_DECLARE_string_(name) \
|
||||||
|
extern GTEST_API_ ::std::string GMOCK_FLAG(name)
|
||||||
|
|
||||||
|
// Macros for defining flags.
|
||||||
|
# define GMOCK_DEFINE_bool_(name, default_val, doc) \
|
||||||
|
GTEST_API_ bool GMOCK_FLAG(name) = (default_val)
|
||||||
|
# define GMOCK_DEFINE_int32_(name, default_val, doc) \
|
||||||
|
GTEST_API_ ::testing::internal::Int32 GMOCK_FLAG(name) = (default_val)
|
||||||
|
# define GMOCK_DEFINE_string_(name, default_val, doc) \
|
||||||
|
GTEST_API_ ::std::string GMOCK_FLAG(name) = (default_val)
|
||||||
|
|
||||||
|
#endif // !defined(GMOCK_DECLARE_bool_)
|
||||||
|
|
||||||
|
#endif // GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_
|
@ -0,0 +1,317 @@
|
|||||||
|
#ifndef THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_PP_H_
|
||||||
|
#define THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_PP_H_
|
||||||
|
|
||||||
|
#undef GMOCK_PP_INTERNAL_USE_MSVC
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define GMOCK_PP_INTERNAL_USE_MSVC 0
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
// TODO(iserna): Also verify tradional versus comformant preprocessor.
|
||||||
|
static_assert(
|
||||||
|
_MSC_VER >= 1900,
|
||||||
|
"MSVC version not supported. There is support for MSVC 14.0 and above.");
|
||||||
|
#define GMOCK_PP_INTERNAL_USE_MSVC 1
|
||||||
|
#else
|
||||||
|
#define GMOCK_PP_INTERNAL_USE_MSVC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Expands and concatenates the arguments. Constructed macros reevaluate.
|
||||||
|
#define GMOCK_PP_CAT(_1, _2) GMOCK_PP_INTERNAL_CAT(_1, _2)
|
||||||
|
|
||||||
|
// Expands and stringifies the only argument.
|
||||||
|
#define GMOCK_PP_STRINGIZE(...) GMOCK_PP_INTERNAL_STRINGIZE(__VA_ARGS__)
|
||||||
|
|
||||||
|
// Returns empty. Given a variadic number of arguments.
|
||||||
|
#define GMOCK_PP_EMPTY(...)
|
||||||
|
|
||||||
|
// Returns a comma. Given a variadic number of arguments.
|
||||||
|
#define GMOCK_PP_COMMA(...) ,
|
||||||
|
|
||||||
|
// Returns the only argument.
|
||||||
|
#define GMOCK_PP_IDENTITY(_1) _1
|
||||||
|
|
||||||
|
// MSVC preprocessor collapses __VA_ARGS__ in a single argument, we use a
|
||||||
|
// CAT-like directive to force correct evaluation. Each macro has its own.
|
||||||
|
#if GMOCK_PP_INTERNAL_USE_MSVC
|
||||||
|
|
||||||
|
// Evaluates to the number of arguments after expansion.
|
||||||
|
//
|
||||||
|
// #define PAIR x, y
|
||||||
|
//
|
||||||
|
// GMOCK_PP_NARG() => 1
|
||||||
|
// GMOCK_PP_NARG(x) => 1
|
||||||
|
// GMOCK_PP_NARG(x, y) => 2
|
||||||
|
// GMOCK_PP_NARG(PAIR) => 2
|
||||||
|
//
|
||||||
|
// Requires: the number of arguments after expansion is at most 15.
|
||||||
|
#define GMOCK_PP_NARG(...) \
|
||||||
|
GMOCK_PP_INTERNAL_NARG_CAT( \
|
||||||
|
GMOCK_PP_INTERNAL_INTERNAL_16TH(__VA_ARGS__, 15, 14, 13, 12, 11, 10, 9, \
|
||||||
|
8, 7, 6, 5, 4, 3, 2, 1), )
|
||||||
|
|
||||||
|
// Returns 1 if the expansion of arguments has an unprotected comma. Otherwise
|
||||||
|
// returns 0. Requires no more than 15 unprotected commas.
|
||||||
|
#define GMOCK_PP_HAS_COMMA(...) \
|
||||||
|
GMOCK_PP_INTERNAL_HAS_COMMA_CAT( \
|
||||||
|
GMOCK_PP_INTERNAL_INTERNAL_16TH(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
|
||||||
|
1, 1, 1, 1, 1, 0), )
|
||||||
|
// Returns the first argument.
|
||||||
|
#define GMOCK_PP_HEAD(...) \
|
||||||
|
GMOCK_PP_INTERNAL_HEAD_CAT(GMOCK_PP_INTERNAL_HEAD(__VA_ARGS__), )
|
||||||
|
|
||||||
|
// Returns the tail. A variadic list of all arguments minus the first. Requires
|
||||||
|
// at least one argument.
|
||||||
|
#define GMOCK_PP_TAIL(...) \
|
||||||
|
GMOCK_PP_INTERNAL_TAIL_CAT(GMOCK_PP_INTERNAL_TAIL(__VA_ARGS__), )
|
||||||
|
|
||||||
|
// Calls CAT(_Macro, NARG(__VA_ARGS__))(__VA_ARGS__)
|
||||||
|
#define GMOCK_PP_VARIADIC_CALL(_Macro, ...) \
|
||||||
|
GMOCK_PP_INTERNAL_VARIADIC_CALL_CAT( \
|
||||||
|
GMOCK_PP_CAT(_Macro, GMOCK_PP_NARG(__VA_ARGS__))(__VA_ARGS__), )
|
||||||
|
|
||||||
|
#else // GMOCK_PP_INTERNAL_USE_MSVC
|
||||||
|
|
||||||
|
#define GMOCK_PP_NARG(...) \
|
||||||
|
GMOCK_PP_INTERNAL_INTERNAL_16TH(__VA_ARGS__, 15, 14, 13, 12, 11, 10, 9, 8, \
|
||||||
|
7, 6, 5, 4, 3, 2, 1)
|
||||||
|
#define GMOCK_PP_HAS_COMMA(...) \
|
||||||
|
GMOCK_PP_INTERNAL_INTERNAL_16TH(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
|
||||||
|
1, 1, 1, 1, 0)
|
||||||
|
#define GMOCK_PP_HEAD(...) GMOCK_PP_INTERNAL_HEAD(__VA_ARGS__)
|
||||||
|
#define GMOCK_PP_TAIL(...) GMOCK_PP_INTERNAL_TAIL(__VA_ARGS__)
|
||||||
|
#define GMOCK_PP_VARIADIC_CALL(_Macro, ...) \
|
||||||
|
GMOCK_PP_CAT(_Macro, GMOCK_PP_NARG(__VA_ARGS__))(__VA_ARGS__)
|
||||||
|
|
||||||
|
#endif // GMOCK_PP_INTERNAL_USE_MSVC
|
||||||
|
|
||||||
|
// If the arguments after expansion have no tokens, evaluates to `1`. Otherwise
|
||||||
|
// evaluates to `0`.
|
||||||
|
//
|
||||||
|
// Requires: * the number of arguments after expansion is at most 15.
|
||||||
|
// * If the argument is a macro, it must be able to be called with one
|
||||||
|
// argument.
|
||||||
|
//
|
||||||
|
// Implementation details:
|
||||||
|
//
|
||||||
|
// There is one case when it generates a compile error: if the argument is macro
|
||||||
|
// that cannot be called with one argument.
|
||||||
|
//
|
||||||
|
// #define M(a, b) // it doesn't matter what it expands to
|
||||||
|
//
|
||||||
|
// // Expected: expands to `0`.
|
||||||
|
// // Actual: compile error.
|
||||||
|
// GMOCK_PP_IS_EMPTY(M)
|
||||||
|
//
|
||||||
|
// There are 4 cases tested:
|
||||||
|
//
|
||||||
|
// * __VA_ARGS__ possible expansion has no unparen'd commas. Expected 0.
|
||||||
|
// * __VA_ARGS__ possible expansion is not enclosed in parenthesis. Expected 0.
|
||||||
|
// * __VA_ARGS__ possible expansion is not a macro that ()-evaluates to a comma.
|
||||||
|
// Expected 0
|
||||||
|
// * __VA_ARGS__ is empty, or has unparen'd commas, or is enclosed in
|
||||||
|
// parenthesis, or is a macro that ()-evaluates to comma. Expected 1.
|
||||||
|
//
|
||||||
|
// We trigger detection on '0001', i.e. on empty.
|
||||||
|
#define GMOCK_PP_IS_EMPTY(...) \
|
||||||
|
GMOCK_PP_INTERNAL_IS_EMPTY(GMOCK_PP_HAS_COMMA(__VA_ARGS__), \
|
||||||
|
GMOCK_PP_HAS_COMMA(GMOCK_PP_COMMA __VA_ARGS__), \
|
||||||
|
GMOCK_PP_HAS_COMMA(__VA_ARGS__()), \
|
||||||
|
GMOCK_PP_HAS_COMMA(GMOCK_PP_COMMA __VA_ARGS__()))
|
||||||
|
|
||||||
|
// Evaluates to _Then if _Cond is 1 and _Else if _Cond is 0.
|
||||||
|
#define GMOCK_PP_IF(_Cond, _Then, _Else) \
|
||||||
|
GMOCK_PP_CAT(GMOCK_PP_INTERNAL_IF_, _Cond)(_Then, _Else)
|
||||||
|
|
||||||
|
// Evaluates to the number of arguments after expansion. Identifies 'empty' as
|
||||||
|
// 0.
|
||||||
|
//
|
||||||
|
// #define PAIR x, y
|
||||||
|
//
|
||||||
|
// GMOCK_PP_NARG0() => 0
|
||||||
|
// GMOCK_PP_NARG0(x) => 1
|
||||||
|
// GMOCK_PP_NARG0(x, y) => 2
|
||||||
|
// GMOCK_PP_NARG0(PAIR) => 2
|
||||||
|
//
|
||||||
|
// Requires: * the number of arguments after expansion is at most 15.
|
||||||
|
// * If the argument is a macro, it must be able to be called with one
|
||||||
|
// argument.
|
||||||
|
#define GMOCK_PP_NARG0(...) \
|
||||||
|
GMOCK_PP_IF(GMOCK_PP_IS_EMPTY(__VA_ARGS__), 0, GMOCK_PP_NARG(__VA_ARGS__))
|
||||||
|
|
||||||
|
// Expands to 1 if the first argument starts with something in parentheses,
|
||||||
|
// otherwise to 0.
|
||||||
|
#define GMOCK_PP_IS_BEGIN_PARENS(...) \
|
||||||
|
GMOCK_PP_INTERNAL_ALTERNATE_HEAD( \
|
||||||
|
GMOCK_PP_CAT(GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_R_, \
|
||||||
|
GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_C __VA_ARGS__))
|
||||||
|
|
||||||
|
// Expands to 1 is there is only one argument and it is enclosed in parentheses.
|
||||||
|
#define GMOCK_PP_IS_ENCLOSED_PARENS(...) \
|
||||||
|
GMOCK_PP_IF(GMOCK_PP_IS_BEGIN_PARENS(__VA_ARGS__), \
|
||||||
|
GMOCK_PP_IS_EMPTY(GMOCK_PP_EMPTY __VA_ARGS__), 0)
|
||||||
|
|
||||||
|
// Remove the parens, requires GMOCK_PP_IS_ENCLOSED_PARENS(args) => 1.
|
||||||
|
#define GMOCK_PP_REMOVE_PARENS(...) GMOCK_PP_INTERNAL_REMOVE_PARENS __VA_ARGS__
|
||||||
|
|
||||||
|
// Expands to _Macro(0, _Data, e1) _Macro(1, _Data, e2) ... _Macro(K -1, _Data,
|
||||||
|
// eK) as many of GMOCK_INTERNAL_NARG0 _Tuple.
|
||||||
|
// Requires: * |_Macro| can be called with 3 arguments.
|
||||||
|
// * |_Tuple| expansion has no more than 15 elements.
|
||||||
|
#define GMOCK_PP_FOR_EACH(_Macro, _Data, _Tuple) \
|
||||||
|
GMOCK_PP_CAT(GMOCK_PP_INTERNAL_FOR_EACH_IMPL_, GMOCK_PP_NARG0 _Tuple) \
|
||||||
|
(0, _Macro, _Data, _Tuple)
|
||||||
|
|
||||||
|
// Expands to _Macro(0, _Data, ) _Macro(1, _Data, ) ... _Macro(K - 1, _Data, )
|
||||||
|
// Empty if _K = 0.
|
||||||
|
// Requires: * |_Macro| can be called with 3 arguments.
|
||||||
|
// * |_K| literal between 0 and 15
|
||||||
|
#define GMOCK_PP_REPEAT(_Macro, _Data, _N) \
|
||||||
|
GMOCK_PP_CAT(GMOCK_PP_INTERNAL_FOR_EACH_IMPL_, _N) \
|
||||||
|
(0, _Macro, _Data, GMOCK_PP_INTENRAL_EMPTY_TUPLE)
|
||||||
|
|
||||||
|
// Increments the argument, requires the argument to be between 0 and 15.
|
||||||
|
#define GMOCK_PP_INC(_i) GMOCK_PP_CAT(GMOCK_PP_INTERNAL_INC_, _i)
|
||||||
|
|
||||||
|
// Returns comma if _i != 0. Requires _i to be between 0 and 15.
|
||||||
|
#define GMOCK_PP_COMMA_IF(_i) GMOCK_PP_CAT(GMOCK_PP_INTERNAL_COMMA_IF_, _i)
|
||||||
|
|
||||||
|
// Internal details follow. Do not use any of these symbols outside of this
|
||||||
|
// file or we will break your code.
|
||||||
|
#define GMOCK_PP_INTENRAL_EMPTY_TUPLE (, , , , , , , , , , , , , , , )
|
||||||
|
#define GMOCK_PP_INTERNAL_CAT(_1, _2) _1##_2
|
||||||
|
#define GMOCK_PP_INTERNAL_STRINGIZE(...) #__VA_ARGS__
|
||||||
|
#define GMOCK_PP_INTERNAL_INTERNAL_16TH(_1, _2, _3, _4, _5, _6, _7, _8, _9, \
|
||||||
|
_10, _11, _12, _13, _14, _15, _16, \
|
||||||
|
...) \
|
||||||
|
_16
|
||||||
|
#define GMOCK_PP_INTERNAL_CAT_5(_1, _2, _3, _4, _5) _1##_2##_3##_4##_5
|
||||||
|
#define GMOCK_PP_INTERNAL_IS_EMPTY(_1, _2, _3, _4) \
|
||||||
|
GMOCK_PP_HAS_COMMA(GMOCK_PP_INTERNAL_CAT_5(GMOCK_PP_INTERNAL_IS_EMPTY_CASE_, \
|
||||||
|
_1, _2, _3, _4))
|
||||||
|
#define GMOCK_PP_INTERNAL_IS_EMPTY_CASE_0001 ,
|
||||||
|
#define GMOCK_PP_INTERNAL_IF_1(_Then, _Else) _Then
|
||||||
|
#define GMOCK_PP_INTERNAL_IF_0(_Then, _Else) _Else
|
||||||
|
#define GMOCK_PP_INTERNAL_HEAD(_1, ...) _1
|
||||||
|
#define GMOCK_PP_INTERNAL_TAIL(_1, ...) __VA_ARGS__
|
||||||
|
|
||||||
|
#if GMOCK_PP_INTERNAL_USE_MSVC
|
||||||
|
#define GMOCK_PP_INTERNAL_NARG_CAT(_1, _2) GMOCK_PP_INTERNAL_NARG_CAT_I(_1, _2)
|
||||||
|
#define GMOCK_PP_INTERNAL_HEAD_CAT(_1, _2) GMOCK_PP_INTERNAL_HEAD_CAT_I(_1, _2)
|
||||||
|
#define GMOCK_PP_INTERNAL_HAS_COMMA_CAT(_1, _2) \
|
||||||
|
GMOCK_PP_INTERNAL_HAS_COMMA_CAT_I(_1, _2)
|
||||||
|
#define GMOCK_PP_INTERNAL_TAIL_CAT(_1, _2) GMOCK_PP_INTERNAL_TAIL_CAT_I(_1, _2)
|
||||||
|
#define GMOCK_PP_INTERNAL_VARIADIC_CALL_CAT(_1, _2) \
|
||||||
|
GMOCK_PP_INTERNAL_VARIADIC_CALL_CAT_I(_1, _2)
|
||||||
|
#define GMOCK_PP_INTERNAL_NARG_CAT_I(_1, _2) _1##_2
|
||||||
|
#define GMOCK_PP_INTERNAL_HEAD_CAT_I(_1, _2) _1##_2
|
||||||
|
#define GMOCK_PP_INTERNAL_HAS_COMMA_CAT_I(_1, _2) _1##_2
|
||||||
|
#define GMOCK_PP_INTERNAL_TAIL_CAT_I(_1, _2) _1##_2
|
||||||
|
#define GMOCK_PP_INTERNAL_VARIADIC_CALL_CAT_I(_1, _2) _1##_2
|
||||||
|
#define GMOCK_PP_INTERNAL_ALTERNATE_HEAD(...) \
|
||||||
|
GMOCK_PP_INTERNAL_ALTERNATE_HEAD_CAT(GMOCK_PP_HEAD(__VA_ARGS__), )
|
||||||
|
#define GMOCK_PP_INTERNAL_ALTERNATE_HEAD_CAT(_1, _2) \
|
||||||
|
GMOCK_PP_INTERNAL_ALTERNATE_HEAD_CAT_I(_1, _2)
|
||||||
|
#define GMOCK_PP_INTERNAL_ALTERNATE_HEAD_CAT_I(_1, _2) _1##_2
|
||||||
|
#else // GMOCK_PP_INTERNAL_USE_MSVC
|
||||||
|
#define GMOCK_PP_INTERNAL_ALTERNATE_HEAD(...) GMOCK_PP_HEAD(__VA_ARGS__)
|
||||||
|
#endif // GMOCK_PP_INTERNAL_USE_MSVC
|
||||||
|
|
||||||
|
#define GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_C(...) 1 _
|
||||||
|
#define GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_R_1 1,
|
||||||
|
#define GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_R_GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_C \
|
||||||
|
0,
|
||||||
|
#define GMOCK_PP_INTERNAL_REMOVE_PARENS(...) __VA_ARGS__
|
||||||
|
#define GMOCK_PP_INTERNAL_INC_0 1
|
||||||
|
#define GMOCK_PP_INTERNAL_INC_1 2
|
||||||
|
#define GMOCK_PP_INTERNAL_INC_2 3
|
||||||
|
#define GMOCK_PP_INTERNAL_INC_3 4
|
||||||
|
#define GMOCK_PP_INTERNAL_INC_4 5
|
||||||
|
#define GMOCK_PP_INTERNAL_INC_5 6
|
||||||
|
#define GMOCK_PP_INTERNAL_INC_6 7
|
||||||
|
#define GMOCK_PP_INTERNAL_INC_7 8
|
||||||
|
#define GMOCK_PP_INTERNAL_INC_8 9
|
||||||
|
#define GMOCK_PP_INTERNAL_INC_9 10
|
||||||
|
#define GMOCK_PP_INTERNAL_INC_10 11
|
||||||
|
#define GMOCK_PP_INTERNAL_INC_11 12
|
||||||
|
#define GMOCK_PP_INTERNAL_INC_12 13
|
||||||
|
#define GMOCK_PP_INTERNAL_INC_13 14
|
||||||
|
#define GMOCK_PP_INTERNAL_INC_14 15
|
||||||
|
#define GMOCK_PP_INTERNAL_INC_15 16
|
||||||
|
#define GMOCK_PP_INTERNAL_COMMA_IF_0
|
||||||
|
#define GMOCK_PP_INTERNAL_COMMA_IF_1 ,
|
||||||
|
#define GMOCK_PP_INTERNAL_COMMA_IF_2 ,
|
||||||
|
#define GMOCK_PP_INTERNAL_COMMA_IF_3 ,
|
||||||
|
#define GMOCK_PP_INTERNAL_COMMA_IF_4 ,
|
||||||
|
#define GMOCK_PP_INTERNAL_COMMA_IF_5 ,
|
||||||
|
#define GMOCK_PP_INTERNAL_COMMA_IF_6 ,
|
||||||
|
#define GMOCK_PP_INTERNAL_COMMA_IF_7 ,
|
||||||
|
#define GMOCK_PP_INTERNAL_COMMA_IF_8 ,
|
||||||
|
#define GMOCK_PP_INTERNAL_COMMA_IF_9 ,
|
||||||
|
#define GMOCK_PP_INTERNAL_COMMA_IF_10 ,
|
||||||
|
#define GMOCK_PP_INTERNAL_COMMA_IF_11 ,
|
||||||
|
#define GMOCK_PP_INTERNAL_COMMA_IF_12 ,
|
||||||
|
#define GMOCK_PP_INTERNAL_COMMA_IF_13 ,
|
||||||
|
#define GMOCK_PP_INTERNAL_COMMA_IF_14 ,
|
||||||
|
#define GMOCK_PP_INTERNAL_COMMA_IF_15 ,
|
||||||
|
#define GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, _element) \
|
||||||
|
_Macro(_i, _Data, _element)
|
||||||
|
#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_0(_i, _Macro, _Data, _Tuple)
|
||||||
|
#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_1(_i, _Macro, _Data, _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple)
|
||||||
|
#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_2(_i, _Macro, _Data, _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_FOR_EACH_IMPL_1(GMOCK_PP_INC(_i), _Macro, _Data, \
|
||||||
|
(GMOCK_PP_TAIL _Tuple))
|
||||||
|
#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_3(_i, _Macro, _Data, _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_FOR_EACH_IMPL_2(GMOCK_PP_INC(_i), _Macro, _Data, \
|
||||||
|
(GMOCK_PP_TAIL _Tuple))
|
||||||
|
#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_4(_i, _Macro, _Data, _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_FOR_EACH_IMPL_3(GMOCK_PP_INC(_i), _Macro, _Data, \
|
||||||
|
(GMOCK_PP_TAIL _Tuple))
|
||||||
|
#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_5(_i, _Macro, _Data, _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_FOR_EACH_IMPL_4(GMOCK_PP_INC(_i), _Macro, _Data, \
|
||||||
|
(GMOCK_PP_TAIL _Tuple))
|
||||||
|
#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_6(_i, _Macro, _Data, _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_FOR_EACH_IMPL_5(GMOCK_PP_INC(_i), _Macro, _Data, \
|
||||||
|
(GMOCK_PP_TAIL _Tuple))
|
||||||
|
#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_7(_i, _Macro, _Data, _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_FOR_EACH_IMPL_6(GMOCK_PP_INC(_i), _Macro, _Data, \
|
||||||
|
(GMOCK_PP_TAIL _Tuple))
|
||||||
|
#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_8(_i, _Macro, _Data, _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_FOR_EACH_IMPL_7(GMOCK_PP_INC(_i), _Macro, _Data, \
|
||||||
|
(GMOCK_PP_TAIL _Tuple))
|
||||||
|
#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_9(_i, _Macro, _Data, _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_FOR_EACH_IMPL_8(GMOCK_PP_INC(_i), _Macro, _Data, \
|
||||||
|
(GMOCK_PP_TAIL _Tuple))
|
||||||
|
#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_10(_i, _Macro, _Data, _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_FOR_EACH_IMPL_9(GMOCK_PP_INC(_i), _Macro, _Data, \
|
||||||
|
(GMOCK_PP_TAIL _Tuple))
|
||||||
|
#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_11(_i, _Macro, _Data, _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_FOR_EACH_IMPL_10(GMOCK_PP_INC(_i), _Macro, _Data, \
|
||||||
|
(GMOCK_PP_TAIL _Tuple))
|
||||||
|
#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_12(_i, _Macro, _Data, _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_FOR_EACH_IMPL_11(GMOCK_PP_INC(_i), _Macro, _Data, \
|
||||||
|
(GMOCK_PP_TAIL _Tuple))
|
||||||
|
#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_13(_i, _Macro, _Data, _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_FOR_EACH_IMPL_12(GMOCK_PP_INC(_i), _Macro, _Data, \
|
||||||
|
(GMOCK_PP_TAIL _Tuple))
|
||||||
|
#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_14(_i, _Macro, _Data, _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_FOR_EACH_IMPL_13(GMOCK_PP_INC(_i), _Macro, _Data, \
|
||||||
|
(GMOCK_PP_TAIL _Tuple))
|
||||||
|
#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_15(_i, _Macro, _Data, _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
|
||||||
|
GMOCK_PP_INTERNAL_FOR_EACH_IMPL_14(GMOCK_PP_INC(_i), _Macro, _Data, \
|
||||||
|
(GMOCK_PP_TAIL _Tuple))
|
||||||
|
|
||||||
|
#endif // THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PP_H_
|
@ -0,0 +1,240 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2009, 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.
|
||||||
|
|
||||||
|
"""fuse_gmock_files.py v0.1.0
|
||||||
|
Fuses Google Mock and Google Test source code into two .h files and a .cc file.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
fuse_gmock_files.py [GMOCK_ROOT_DIR] OUTPUT_DIR
|
||||||
|
|
||||||
|
Scans GMOCK_ROOT_DIR for Google Mock and Google Test source
|
||||||
|
code, assuming Google Test is in the GMOCK_ROOT_DIR/../googletest
|
||||||
|
directory, and generates three files:
|
||||||
|
OUTPUT_DIR/gtest/gtest.h, OUTPUT_DIR/gmock/gmock.h, and
|
||||||
|
OUTPUT_DIR/gmock-gtest-all.cc. Then you can build your tests
|
||||||
|
by adding OUTPUT_DIR to the include search path and linking
|
||||||
|
with OUTPUT_DIR/gmock-gtest-all.cc. These three files contain
|
||||||
|
everything you need to use Google Mock. Hence you can
|
||||||
|
"install" Google Mock by copying them to wherever you want.
|
||||||
|
|
||||||
|
GMOCK_ROOT_DIR can be omitted and defaults to the parent
|
||||||
|
directory of the directory holding this script.
|
||||||
|
|
||||||
|
EXAMPLES
|
||||||
|
./fuse_gmock_files.py fused_gmock
|
||||||
|
./fuse_gmock_files.py path/to/unpacked/gmock fused_gmock
|
||||||
|
|
||||||
|
This tool is experimental. In particular, it assumes that there is no
|
||||||
|
conditional inclusion of Google Mock or Google Test headers. Please
|
||||||
|
report any problems to googlemock@googlegroups.com. You can read
|
||||||
|
https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md for more
|
||||||
|
information.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = 'wan@google.com (Zhanyong Wan)'
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sets
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# We assume that this file is in the scripts/ directory in the Google
|
||||||
|
# Mock root directory.
|
||||||
|
DEFAULT_GMOCK_ROOT_DIR = os.path.join(os.path.dirname(__file__), '..')
|
||||||
|
|
||||||
|
# We need to call into googletest/scripts/fuse_gtest_files.py.
|
||||||
|
sys.path.append(os.path.join(DEFAULT_GMOCK_ROOT_DIR, '../googletest/scripts'))
|
||||||
|
import fuse_gtest_files
|
||||||
|
gtest = fuse_gtest_files
|
||||||
|
|
||||||
|
# Regex for matching '#include "gmock/..."'.
|
||||||
|
INCLUDE_GMOCK_FILE_REGEX = re.compile(r'^\s*#\s*include\s*"(gmock/.+)"')
|
||||||
|
|
||||||
|
# Where to find the source seed files.
|
||||||
|
GMOCK_H_SEED = 'include/gmock/gmock.h'
|
||||||
|
GMOCK_ALL_CC_SEED = 'src/gmock-all.cc'
|
||||||
|
|
||||||
|
# Where to put the generated files.
|
||||||
|
GTEST_H_OUTPUT = 'gtest/gtest.h'
|
||||||
|
GMOCK_H_OUTPUT = 'gmock/gmock.h'
|
||||||
|
GMOCK_GTEST_ALL_CC_OUTPUT = 'gmock-gtest-all.cc'
|
||||||
|
|
||||||
|
|
||||||
|
def GetGTestRootDir(gmock_root):
|
||||||
|
"""Returns the root directory of Google Test."""
|
||||||
|
|
||||||
|
return os.path.join(gmock_root, '../googletest')
|
||||||
|
|
||||||
|
|
||||||
|
def ValidateGMockRootDir(gmock_root):
|
||||||
|
"""Makes sure gmock_root points to a valid gmock root directory.
|
||||||
|
|
||||||
|
The function aborts the program on failure.
|
||||||
|
"""
|
||||||
|
|
||||||
|
gtest.ValidateGTestRootDir(GetGTestRootDir(gmock_root))
|
||||||
|
gtest.VerifyFileExists(gmock_root, GMOCK_H_SEED)
|
||||||
|
gtest.VerifyFileExists(gmock_root, GMOCK_ALL_CC_SEED)
|
||||||
|
|
||||||
|
|
||||||
|
def ValidateOutputDir(output_dir):
|
||||||
|
"""Makes sure output_dir points to a valid output directory.
|
||||||
|
|
||||||
|
The function aborts the program on failure.
|
||||||
|
"""
|
||||||
|
|
||||||
|
gtest.VerifyOutputFile(output_dir, gtest.GTEST_H_OUTPUT)
|
||||||
|
gtest.VerifyOutputFile(output_dir, GMOCK_H_OUTPUT)
|
||||||
|
gtest.VerifyOutputFile(output_dir, GMOCK_GTEST_ALL_CC_OUTPUT)
|
||||||
|
|
||||||
|
|
||||||
|
def FuseGMockH(gmock_root, output_dir):
|
||||||
|
"""Scans folder gmock_root to generate gmock/gmock.h in output_dir."""
|
||||||
|
|
||||||
|
output_file = file(os.path.join(output_dir, GMOCK_H_OUTPUT), 'w')
|
||||||
|
processed_files = sets.Set() # Holds all gmock headers we've processed.
|
||||||
|
|
||||||
|
def ProcessFile(gmock_header_path):
|
||||||
|
"""Processes the given gmock header file."""
|
||||||
|
|
||||||
|
# We don't process the same header twice.
|
||||||
|
if gmock_header_path in processed_files:
|
||||||
|
return
|
||||||
|
|
||||||
|
processed_files.add(gmock_header_path)
|
||||||
|
|
||||||
|
# Reads each line in the given gmock header.
|
||||||
|
for line in file(os.path.join(gmock_root, gmock_header_path), 'r'):
|
||||||
|
m = INCLUDE_GMOCK_FILE_REGEX.match(line)
|
||||||
|
if m:
|
||||||
|
# It's '#include "gmock/..."' - let's process it recursively.
|
||||||
|
ProcessFile('include/' + m.group(1))
|
||||||
|
else:
|
||||||
|
m = gtest.INCLUDE_GTEST_FILE_REGEX.match(line)
|
||||||
|
if m:
|
||||||
|
# It's '#include "gtest/foo.h"'. We translate it to
|
||||||
|
# "gtest/gtest.h", regardless of what foo is, since all
|
||||||
|
# gtest headers are fused into gtest/gtest.h.
|
||||||
|
|
||||||
|
# There is no need to #include gtest.h twice.
|
||||||
|
if not gtest.GTEST_H_SEED in processed_files:
|
||||||
|
processed_files.add(gtest.GTEST_H_SEED)
|
||||||
|
output_file.write('#include "%s"\n' % (gtest.GTEST_H_OUTPUT,))
|
||||||
|
else:
|
||||||
|
# Otherwise we copy the line unchanged to the output file.
|
||||||
|
output_file.write(line)
|
||||||
|
|
||||||
|
ProcessFile(GMOCK_H_SEED)
|
||||||
|
output_file.close()
|
||||||
|
|
||||||
|
|
||||||
|
def FuseGMockAllCcToFile(gmock_root, output_file):
|
||||||
|
"""Scans folder gmock_root to fuse gmock-all.cc into output_file."""
|
||||||
|
|
||||||
|
processed_files = sets.Set()
|
||||||
|
|
||||||
|
def ProcessFile(gmock_source_file):
|
||||||
|
"""Processes the given gmock source file."""
|
||||||
|
|
||||||
|
# We don't process the same #included file twice.
|
||||||
|
if gmock_source_file in processed_files:
|
||||||
|
return
|
||||||
|
|
||||||
|
processed_files.add(gmock_source_file)
|
||||||
|
|
||||||
|
# Reads each line in the given gmock source file.
|
||||||
|
for line in file(os.path.join(gmock_root, gmock_source_file), 'r'):
|
||||||
|
m = INCLUDE_GMOCK_FILE_REGEX.match(line)
|
||||||
|
if m:
|
||||||
|
# It's '#include "gmock/foo.h"'. We treat it as '#include
|
||||||
|
# "gmock/gmock.h"', as all other gmock headers are being fused
|
||||||
|
# into gmock.h and cannot be #included directly.
|
||||||
|
|
||||||
|
# There is no need to #include "gmock/gmock.h" more than once.
|
||||||
|
if not GMOCK_H_SEED in processed_files:
|
||||||
|
processed_files.add(GMOCK_H_SEED)
|
||||||
|
output_file.write('#include "%s"\n' % (GMOCK_H_OUTPUT,))
|
||||||
|
else:
|
||||||
|
m = gtest.INCLUDE_GTEST_FILE_REGEX.match(line)
|
||||||
|
if m:
|
||||||
|
# It's '#include "gtest/..."'.
|
||||||
|
# There is no need to #include gtest.h as it has been
|
||||||
|
# #included by gtest-all.cc.
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
m = gtest.INCLUDE_SRC_FILE_REGEX.match(line)
|
||||||
|
if m:
|
||||||
|
# It's '#include "src/foo"' - let's process it recursively.
|
||||||
|
ProcessFile(m.group(1))
|
||||||
|
else:
|
||||||
|
# Otherwise we copy the line unchanged to the output file.
|
||||||
|
output_file.write(line)
|
||||||
|
|
||||||
|
ProcessFile(GMOCK_ALL_CC_SEED)
|
||||||
|
|
||||||
|
|
||||||
|
def FuseGMockGTestAllCc(gmock_root, output_dir):
|
||||||
|
"""Scans folder gmock_root to generate gmock-gtest-all.cc in output_dir."""
|
||||||
|
|
||||||
|
output_file = file(os.path.join(output_dir, GMOCK_GTEST_ALL_CC_OUTPUT), 'w')
|
||||||
|
# First, fuse gtest-all.cc into gmock-gtest-all.cc.
|
||||||
|
gtest.FuseGTestAllCcToFile(GetGTestRootDir(gmock_root), output_file)
|
||||||
|
# Next, append fused gmock-all.cc to gmock-gtest-all.cc.
|
||||||
|
FuseGMockAllCcToFile(gmock_root, output_file)
|
||||||
|
output_file.close()
|
||||||
|
|
||||||
|
|
||||||
|
def FuseGMock(gmock_root, output_dir):
|
||||||
|
"""Fuses gtest.h, gmock.h, and gmock-gtest-all.h."""
|
||||||
|
|
||||||
|
ValidateGMockRootDir(gmock_root)
|
||||||
|
ValidateOutputDir(output_dir)
|
||||||
|
|
||||||
|
gtest.FuseGTestH(GetGTestRootDir(gmock_root), output_dir)
|
||||||
|
FuseGMockH(gmock_root, output_dir)
|
||||||
|
FuseGMockGTestAllCc(gmock_root, output_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argc = len(sys.argv)
|
||||||
|
if argc == 2:
|
||||||
|
# fuse_gmock_files.py OUTPUT_DIR
|
||||||
|
FuseGMock(DEFAULT_GMOCK_ROOT_DIR, sys.argv[1])
|
||||||
|
elif argc == 3:
|
||||||
|
# fuse_gmock_files.py GMOCK_ROOT_DIR OUTPUT_DIR
|
||||||
|
FuseGMock(sys.argv[1], sys.argv[2])
|
||||||
|
else:
|
||||||
|
print __doc__
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -0,0 +1,203 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [2007] Neal Norwitz
|
||||||
|
Portions Copyright [2007] Google Inc.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
The Google Mock class generator is an application that is part of cppclean.
|
||||||
|
For more information about cppclean, visit http://code.google.com/p/cppclean/
|
||||||
|
|
||||||
|
The mock generator requires Python 2.3.5 or later. If you don't have Python
|
||||||
|
installed on your system, you will also need to install it. You can download
|
||||||
|
Python from: http://www.python.org/download/releases/
|
||||||
|
|
||||||
|
To use the Google Mock class generator, you need to call it
|
||||||
|
on the command line passing the header file and class for which you want
|
||||||
|
to generate a Google Mock class.
|
||||||
|
|
||||||
|
Make sure to install the scripts somewhere in your path. Then you can
|
||||||
|
run the program.
|
||||||
|
|
||||||
|
gmock_gen.py header-file.h [ClassName]...
|
||||||
|
|
||||||
|
If no ClassNames are specified, all classes in the file are emitted.
|
||||||
|
|
||||||
|
To change the indentation from the default of 2, set INDENT in
|
||||||
|
the environment. For example to use an indent of 4 spaces:
|
||||||
|
|
||||||
|
INDENT=4 gmock_gen.py header-file.h ClassName
|
||||||
|
|
||||||
|
This version was made from SVN revision 281 in the cppclean repository.
|
||||||
|
|
||||||
|
Known Limitations
|
||||||
|
-----------------
|
||||||
|
Not all code will be generated properly. For example, when mocking templated
|
||||||
|
classes, the template information is lost. You will need to add the template
|
||||||
|
information manually.
|
||||||
|
|
||||||
|
Not all permutations of using multiple pointers/references will be rendered
|
||||||
|
properly. These will also have to be fixed manually.
|
@ -0,0 +1,115 @@
|
|||||||
|
Goal:
|
||||||
|
-----
|
||||||
|
CppClean attempts to find problems in C++ source that slow development
|
||||||
|
in large code bases, for example various forms of unused code.
|
||||||
|
Unused code can be unused functions, methods, data members, types, etc
|
||||||
|
to unnecessary #include directives. Unnecessary #includes can cause
|
||||||
|
considerable extra compiles increasing the edit-compile-run cycle.
|
||||||
|
|
||||||
|
The project home page is: http://code.google.com/p/cppclean/
|
||||||
|
|
||||||
|
|
||||||
|
Features:
|
||||||
|
---------
|
||||||
|
* Find and print C++ language constructs: classes, methods, functions, etc.
|
||||||
|
* Find classes with virtual methods, no virtual destructor, and no bases
|
||||||
|
* Find global/static data that are potential problems when using threads
|
||||||
|
* Unnecessary forward class declarations
|
||||||
|
* Unnecessary function declarations
|
||||||
|
* Undeclared function definitions
|
||||||
|
* (planned) Find unnecessary header files #included
|
||||||
|
- No direct reference to anything in the header
|
||||||
|
- Header is unnecessary if classes were forward declared instead
|
||||||
|
* (planned) Source files that reference headers not directly #included,
|
||||||
|
ie, files that rely on a transitive #include from another header
|
||||||
|
* (planned) Unused members (private, protected, & public) methods and data
|
||||||
|
* (planned) Store AST in a SQL database so relationships can be queried
|
||||||
|
|
||||||
|
AST is Abstract Syntax Tree, a representation of parsed source code.
|
||||||
|
http://en.wikipedia.org/wiki/Abstract_syntax_tree
|
||||||
|
|
||||||
|
|
||||||
|
System Requirements:
|
||||||
|
--------------------
|
||||||
|
* Python 2.4 or later (2.3 probably works too)
|
||||||
|
* Works on Windows (untested), Mac OS X, and Unix
|
||||||
|
|
||||||
|
|
||||||
|
How to Run:
|
||||||
|
-----------
|
||||||
|
For all examples, it is assumed that cppclean resides in a directory called
|
||||||
|
/cppclean.
|
||||||
|
|
||||||
|
To print warnings for classes with virtual methods, no virtual destructor and
|
||||||
|
no base classes:
|
||||||
|
|
||||||
|
/cppclean/run.sh nonvirtual_dtors.py file1.h file2.h file3.cc ...
|
||||||
|
|
||||||
|
To print all the functions defined in header file(s):
|
||||||
|
|
||||||
|
/cppclean/run.sh functions.py file1.h file2.h ...
|
||||||
|
|
||||||
|
All the commands take multiple files on the command line. Other programs
|
||||||
|
include: find_warnings, headers, methods, and types. Some other programs
|
||||||
|
are available, but used primarily for debugging.
|
||||||
|
|
||||||
|
run.sh is a simple wrapper that sets PYTHONPATH to /cppclean and then
|
||||||
|
runs the program in /cppclean/cpp/PROGRAM.py. There is currently
|
||||||
|
no equivalent for Windows. Contributions for a run.bat file
|
||||||
|
would be greatly appreciated.
|
||||||
|
|
||||||
|
|
||||||
|
How to Configure:
|
||||||
|
-----------------
|
||||||
|
You can add a siteheaders.py file in /cppclean/cpp to configure where
|
||||||
|
to look for other headers (typically -I options passed to a compiler).
|
||||||
|
Currently two values are supported: _TRANSITIVE and GetIncludeDirs.
|
||||||
|
_TRANSITIVE should be set to a boolean value (True or False) indicating
|
||||||
|
whether to transitively process all header files. The default is False.
|
||||||
|
|
||||||
|
GetIncludeDirs is a function that takes a single argument and returns
|
||||||
|
a sequence of directories to include. This can be a generator or
|
||||||
|
return a static list.
|
||||||
|
|
||||||
|
def GetIncludeDirs(filename):
|
||||||
|
return ['/some/path/with/other/headers']
|
||||||
|
|
||||||
|
# Here is a more complicated example.
|
||||||
|
def GetIncludeDirs(filename):
|
||||||
|
yield '/path1'
|
||||||
|
yield os.path.join('/path2', os.path.dirname(filename))
|
||||||
|
yield '/path3'
|
||||||
|
|
||||||
|
|
||||||
|
How to Test:
|
||||||
|
------------
|
||||||
|
For all examples, it is assumed that cppclean resides in a directory called
|
||||||
|
/cppclean. The tests require
|
||||||
|
|
||||||
|
cd /cppclean
|
||||||
|
make test
|
||||||
|
# To generate expected results after a change:
|
||||||
|
make expected
|
||||||
|
|
||||||
|
|
||||||
|
Current Status:
|
||||||
|
---------------
|
||||||
|
The parser works pretty well for header files, parsing about 99% of Google's
|
||||||
|
header files. Anything which inspects structure of C++ source files should
|
||||||
|
work reasonably well. Function bodies are not transformed to an AST,
|
||||||
|
but left as tokens. Much work is still needed on finding unused header files
|
||||||
|
and storing an AST in a database.
|
||||||
|
|
||||||
|
|
||||||
|
Non-goals:
|
||||||
|
----------
|
||||||
|
* Parsing all valid C++ source
|
||||||
|
* Handling invalid C++ source gracefully
|
||||||
|
* Compiling to machine code (or anything beyond an AST)
|
||||||
|
|
||||||
|
|
||||||
|
Contact:
|
||||||
|
--------
|
||||||
|
If you used cppclean, I would love to hear about your experiences
|
||||||
|
cppclean@googlegroups.com. Even if you don't use cppclean, I'd like to
|
||||||
|
hear from you. :-) (You can contact me directly at: nnorwitz@gmail.com)
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,227 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2008 Google Inc. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
"""Generate Google Mock classes from base classes.
|
||||||
|
|
||||||
|
This program will read in a C++ source file and output the Google Mock
|
||||||
|
classes for the specified classes. If no class is specified, all
|
||||||
|
classes in the source file are emitted.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
gmock_class.py header-file.h [ClassName]...
|
||||||
|
|
||||||
|
Output is sent to stdout.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = 'nnorwitz@google.com (Neal Norwitz)'
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from cpp import ast
|
||||||
|
from cpp import utils
|
||||||
|
|
||||||
|
# Preserve compatibility with Python 2.3.
|
||||||
|
try:
|
||||||
|
_dummy = set
|
||||||
|
except NameError:
|
||||||
|
import sets
|
||||||
|
set = sets.Set
|
||||||
|
|
||||||
|
_VERSION = (1, 0, 1) # The version of this script.
|
||||||
|
# How many spaces to indent. Can set me with the INDENT environment variable.
|
||||||
|
_INDENT = 2
|
||||||
|
|
||||||
|
|
||||||
|
def _GenerateMethods(output_lines, source, class_node):
|
||||||
|
function_type = (ast.FUNCTION_VIRTUAL | ast.FUNCTION_PURE_VIRTUAL |
|
||||||
|
ast.FUNCTION_OVERRIDE)
|
||||||
|
ctor_or_dtor = ast.FUNCTION_CTOR | ast.FUNCTION_DTOR
|
||||||
|
indent = ' ' * _INDENT
|
||||||
|
|
||||||
|
for node in class_node.body:
|
||||||
|
# We only care about virtual functions.
|
||||||
|
if (isinstance(node, ast.Function) and
|
||||||
|
node.modifiers & function_type and
|
||||||
|
not node.modifiers & ctor_or_dtor):
|
||||||
|
# Pick out all the elements we need from the original function.
|
||||||
|
const = ''
|
||||||
|
if node.modifiers & ast.FUNCTION_CONST:
|
||||||
|
const = 'CONST_'
|
||||||
|
return_type = 'void'
|
||||||
|
if node.return_type:
|
||||||
|
# Add modifiers like 'const'.
|
||||||
|
modifiers = ''
|
||||||
|
if node.return_type.modifiers:
|
||||||
|
modifiers = ' '.join(node.return_type.modifiers) + ' '
|
||||||
|
return_type = modifiers + node.return_type.name
|
||||||
|
template_args = [arg.name for arg in node.return_type.templated_types]
|
||||||
|
if template_args:
|
||||||
|
return_type += '<' + ', '.join(template_args) + '>'
|
||||||
|
if len(template_args) > 1:
|
||||||
|
for line in [
|
||||||
|
'// The following line won\'t really compile, as the return',
|
||||||
|
'// type has multiple template arguments. To fix it, use a',
|
||||||
|
'// typedef for the return type.']:
|
||||||
|
output_lines.append(indent + line)
|
||||||
|
if node.return_type.pointer:
|
||||||
|
return_type += '*'
|
||||||
|
if node.return_type.reference:
|
||||||
|
return_type += '&'
|
||||||
|
num_parameters = len(node.parameters)
|
||||||
|
if len(node.parameters) == 1:
|
||||||
|
first_param = node.parameters[0]
|
||||||
|
if source[first_param.start:first_param.end].strip() == 'void':
|
||||||
|
# We must treat T(void) as a function with no parameters.
|
||||||
|
num_parameters = 0
|
||||||
|
tmpl = ''
|
||||||
|
if class_node.templated_types:
|
||||||
|
tmpl = '_T'
|
||||||
|
mock_method_macro = 'MOCK_%sMETHOD%d%s' % (const, num_parameters, tmpl)
|
||||||
|
|
||||||
|
args = ''
|
||||||
|
if node.parameters:
|
||||||
|
# Due to the parser limitations, it is impossible to keep comments
|
||||||
|
# while stripping the default parameters. When defaults are
|
||||||
|
# present, we choose to strip them and comments (and produce
|
||||||
|
# compilable code).
|
||||||
|
# TODO(nnorwitz@google.com): Investigate whether it is possible to
|
||||||
|
# preserve parameter name when reconstructing parameter text from
|
||||||
|
# the AST.
|
||||||
|
if len([param for param in node.parameters if param.default]) > 0:
|
||||||
|
args = ', '.join(param.type.name for param in node.parameters)
|
||||||
|
else:
|
||||||
|
# Get the full text of the parameters from the start
|
||||||
|
# of the first parameter to the end of the last parameter.
|
||||||
|
start = node.parameters[0].start
|
||||||
|
end = node.parameters[-1].end
|
||||||
|
# Remove // comments.
|
||||||
|
args_strings = re.sub(r'//.*', '', source[start:end])
|
||||||
|
# Condense multiple spaces and eliminate newlines putting the
|
||||||
|
# parameters together on a single line. Ensure there is a
|
||||||
|
# space in an argument which is split by a newline without
|
||||||
|
# intervening whitespace, e.g.: int\nBar
|
||||||
|
args = re.sub(' +', ' ', args_strings.replace('\n', ' '))
|
||||||
|
|
||||||
|
# Create the mock method definition.
|
||||||
|
output_lines.extend(['%s%s(%s,' % (indent, mock_method_macro, node.name),
|
||||||
|
'%s%s(%s));' % (indent*3, return_type, args)])
|
||||||
|
|
||||||
|
|
||||||
|
def _GenerateMocks(filename, source, ast_list, desired_class_names):
|
||||||
|
processed_class_names = set()
|
||||||
|
lines = []
|
||||||
|
for node in ast_list:
|
||||||
|
if (isinstance(node, ast.Class) and node.body and
|
||||||
|
# desired_class_names being None means that all classes are selected.
|
||||||
|
(not desired_class_names or node.name in desired_class_names)):
|
||||||
|
class_name = node.name
|
||||||
|
parent_name = class_name
|
||||||
|
processed_class_names.add(class_name)
|
||||||
|
class_node = node
|
||||||
|
# Add namespace before the class.
|
||||||
|
if class_node.namespace:
|
||||||
|
lines.extend(['namespace %s {' % n for n in class_node.namespace]) # }
|
||||||
|
lines.append('')
|
||||||
|
|
||||||
|
# Add template args for templated classes.
|
||||||
|
if class_node.templated_types:
|
||||||
|
# TODO(paulchang): The AST doesn't preserve template argument order,
|
||||||
|
# so we have to make up names here.
|
||||||
|
# TODO(paulchang): Handle non-type template arguments (e.g.
|
||||||
|
# template<typename T, int N>).
|
||||||
|
template_arg_count = len(class_node.templated_types.keys())
|
||||||
|
template_args = ['T%d' % n for n in range(template_arg_count)]
|
||||||
|
template_decls = ['typename ' + arg for arg in template_args]
|
||||||
|
lines.append('template <' + ', '.join(template_decls) + '>')
|
||||||
|
parent_name += '<' + ', '.join(template_args) + '>'
|
||||||
|
|
||||||
|
# Add the class prolog.
|
||||||
|
lines.append('class Mock%s : public %s {' # }
|
||||||
|
% (class_name, parent_name))
|
||||||
|
lines.append('%spublic:' % (' ' * (_INDENT // 2)))
|
||||||
|
|
||||||
|
# Add all the methods.
|
||||||
|
_GenerateMethods(lines, source, class_node)
|
||||||
|
|
||||||
|
# Close the class.
|
||||||
|
if lines:
|
||||||
|
# If there are no virtual methods, no need for a public label.
|
||||||
|
if len(lines) == 2:
|
||||||
|
del lines[-1]
|
||||||
|
|
||||||
|
# Only close the class if there really is a class.
|
||||||
|
lines.append('};')
|
||||||
|
lines.append('') # Add an extra newline.
|
||||||
|
|
||||||
|
# Close the namespace.
|
||||||
|
if class_node.namespace:
|
||||||
|
for i in range(len(class_node.namespace)-1, -1, -1):
|
||||||
|
lines.append('} // namespace %s' % class_node.namespace[i])
|
||||||
|
lines.append('') # Add an extra newline.
|
||||||
|
|
||||||
|
if desired_class_names:
|
||||||
|
missing_class_name_list = list(desired_class_names - processed_class_names)
|
||||||
|
if missing_class_name_list:
|
||||||
|
missing_class_name_list.sort()
|
||||||
|
sys.stderr.write('Class(es) not found in %s: %s\n' %
|
||||||
|
(filename, ', '.join(missing_class_name_list)))
|
||||||
|
elif not processed_class_names:
|
||||||
|
sys.stderr.write('No class found in %s\n' % filename)
|
||||||
|
|
||||||
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv=sys.argv):
|
||||||
|
if len(argv) < 2:
|
||||||
|
sys.stderr.write('Google Mock Class Generator v%s\n\n' %
|
||||||
|
'.'.join(map(str, _VERSION)))
|
||||||
|
sys.stderr.write(__doc__)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
global _INDENT
|
||||||
|
try:
|
||||||
|
_INDENT = int(os.environ['INDENT'])
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
except:
|
||||||
|
sys.stderr.write('Unable to use indent of %s\n' % os.environ.get('INDENT'))
|
||||||
|
|
||||||
|
filename = argv[1]
|
||||||
|
desired_class_names = None # None means all classes in the source file.
|
||||||
|
if len(argv) >= 3:
|
||||||
|
desired_class_names = set(argv[2:])
|
||||||
|
source = utils.ReadFile(filename)
|
||||||
|
if source is None:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
builder = ast.BuilderFromSource(source, filename)
|
||||||
|
try:
|
||||||
|
entire_ast = filter(None, builder.Generate())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
return
|
||||||
|
except:
|
||||||
|
# An error message was already printed since we couldn't parse.
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
lines = _GenerateMocks(filename, source, entire_ast, desired_class_names)
|
||||||
|
sys.stdout.write('\n'.join(lines))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main(sys.argv)
|
@ -0,0 +1,466 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2009 Neal Norwitz All Rights Reserved.
|
||||||
|
# Portions Copyright 2009 Google Inc. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
"""Tests for gmock.scripts.generator.cpp.gmock_class."""
|
||||||
|
|
||||||
|
__author__ = 'nnorwitz@google.com (Neal Norwitz)'
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
# Allow the cpp imports below to work when run as a standalone script.
|
||||||
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
|
||||||
|
|
||||||
|
from cpp import ast
|
||||||
|
from cpp import gmock_class
|
||||||
|
|
||||||
|
|
||||||
|
class TestCase(unittest.TestCase):
|
||||||
|
"""Helper class that adds assert methods."""
|
||||||
|
|
||||||
|
def StripLeadingWhitespace(self, lines):
|
||||||
|
"""Strip leading whitespace in each line in 'lines'."""
|
||||||
|
return '\n'.join([s.lstrip() for s in lines.split('\n')])
|
||||||
|
|
||||||
|
def assertEqualIgnoreLeadingWhitespace(self, expected_lines, lines):
|
||||||
|
"""Specialized assert that ignores the indent level."""
|
||||||
|
self.assertEqual(expected_lines, self.StripLeadingWhitespace(lines))
|
||||||
|
|
||||||
|
|
||||||
|
class GenerateMethodsTest(TestCase):
|
||||||
|
|
||||||
|
def GenerateMethodSource(self, cpp_source):
|
||||||
|
"""Convert C++ source to Google Mock output source lines."""
|
||||||
|
method_source_lines = []
|
||||||
|
# <test> is a pseudo-filename, it is not read or written.
|
||||||
|
builder = ast.BuilderFromSource(cpp_source, '<test>')
|
||||||
|
ast_list = list(builder.Generate())
|
||||||
|
gmock_class._GenerateMethods(method_source_lines, cpp_source, ast_list[0])
|
||||||
|
return '\n'.join(method_source_lines)
|
||||||
|
|
||||||
|
def testSimpleMethod(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
virtual int Bar();
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD0(Bar,\nint());',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testSimpleConstructorsAndDestructor(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
Foo();
|
||||||
|
Foo(int x);
|
||||||
|
Foo(const Foo& f);
|
||||||
|
Foo(Foo&& f);
|
||||||
|
~Foo();
|
||||||
|
virtual int Bar() = 0;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
# The constructors and destructor should be ignored.
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD0(Bar,\nint());',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testVirtualDestructor(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
virtual ~Foo();
|
||||||
|
virtual int Bar() = 0;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
# The destructor should be ignored.
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD0(Bar,\nint());',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testExplicitlyDefaultedConstructorsAndDestructor(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
Foo() = default;
|
||||||
|
Foo(const Foo& f) = default;
|
||||||
|
Foo(Foo&& f) = default;
|
||||||
|
~Foo() = default;
|
||||||
|
virtual int Bar() = 0;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
# The constructors and destructor should be ignored.
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD0(Bar,\nint());',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testExplicitlyDeletedConstructorsAndDestructor(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
Foo() = delete;
|
||||||
|
Foo(const Foo& f) = delete;
|
||||||
|
Foo(Foo&& f) = delete;
|
||||||
|
~Foo() = delete;
|
||||||
|
virtual int Bar() = 0;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
# The constructors and destructor should be ignored.
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD0(Bar,\nint());',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testSimpleOverrideMethod(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
int Bar() override;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD0(Bar,\nint());',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testSimpleConstMethod(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
virtual void Bar(bool flag) const;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_CONST_METHOD1(Bar,\nvoid(bool flag));',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testExplicitVoid(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
virtual int Bar(void);
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD0(Bar,\nint(void));',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testStrangeNewlineInParameter(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
virtual void Bar(int
|
||||||
|
a) = 0;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD1(Bar,\nvoid(int a));',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testDefaultParameters(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
virtual void Bar(int a, char c = 'x') = 0;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD2(Bar,\nvoid(int, char));',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testMultipleDefaultParameters(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
virtual void Bar(int a = 42, char c = 'x') = 0;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD2(Bar,\nvoid(int, char));',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testRemovesCommentsWhenDefaultsArePresent(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
virtual void Bar(int a = 42 /* a comment */,
|
||||||
|
char /* other comment */ c= 'x') = 0;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD2(Bar,\nvoid(int, char));',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testDoubleSlashCommentsInParameterListAreRemoved(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
virtual void Bar(int a, // inline comments should be elided.
|
||||||
|
int b // inline comments should be elided.
|
||||||
|
) const = 0;
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_CONST_METHOD2(Bar,\nvoid(int a, int b));',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testCStyleCommentsInParameterListAreNotRemoved(self):
|
||||||
|
# NOTE(nnorwitz): I'm not sure if it's the best behavior to keep these
|
||||||
|
# comments. Also note that C style comments after the last parameter
|
||||||
|
# are still elided.
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
virtual const string& Bar(int /* keeper */, int b);
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD2(Bar,\nconst string&(int /* keeper */, int b));',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testArgsOfTemplateTypes(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
virtual int Bar(const vector<int>& v, map<int, string>* output);
|
||||||
|
};"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD2(Bar,\n'
|
||||||
|
'int(const vector<int>& v, map<int, string>* output));',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testReturnTypeWithOneTemplateArg(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
virtual vector<int>* Bar(int n);
|
||||||
|
};"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD1(Bar,\nvector<int>*(int n));',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testReturnTypeWithManyTemplateArgs(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
virtual map<int, string> Bar();
|
||||||
|
};"""
|
||||||
|
# Comparing the comment text is brittle - we'll think of something
|
||||||
|
# better in case this gets annoying, but for now let's keep it simple.
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'// The following line won\'t really compile, as the return\n'
|
||||||
|
'// type has multiple template arguments. To fix it, use a\n'
|
||||||
|
'// typedef for the return type.\n'
|
||||||
|
'MOCK_METHOD0(Bar,\nmap<int, string>());',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testSimpleMethodInTemplatedClass(self):
|
||||||
|
source = """
|
||||||
|
template<class T>
|
||||||
|
class Foo {
|
||||||
|
public:
|
||||||
|
virtual int Bar();
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD0_T(Bar,\nint());',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testPointerArgWithoutNames(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
virtual int Bar(C*);
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD1(Bar,\nint(C*));',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testReferenceArgWithoutNames(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
virtual int Bar(C&);
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD1(Bar,\nint(C&));',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
def testArrayArgWithoutNames(self):
|
||||||
|
source = """
|
||||||
|
class Foo {
|
||||||
|
virtual int Bar(C[]);
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
'MOCK_METHOD1(Bar,\nint(C[]));',
|
||||||
|
self.GenerateMethodSource(source))
|
||||||
|
|
||||||
|
|
||||||
|
class GenerateMocksTest(TestCase):
|
||||||
|
|
||||||
|
def GenerateMocks(self, cpp_source):
|
||||||
|
"""Convert C++ source to complete Google Mock output source."""
|
||||||
|
# <test> is a pseudo-filename, it is not read or written.
|
||||||
|
filename = '<test>'
|
||||||
|
builder = ast.BuilderFromSource(cpp_source, filename)
|
||||||
|
ast_list = list(builder.Generate())
|
||||||
|
lines = gmock_class._GenerateMocks(filename, cpp_source, ast_list, None)
|
||||||
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
def testNamespaces(self):
|
||||||
|
source = """
|
||||||
|
namespace Foo {
|
||||||
|
namespace Bar { class Forward; }
|
||||||
|
namespace Baz {
|
||||||
|
|
||||||
|
class Test {
|
||||||
|
public:
|
||||||
|
virtual void Foo();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Baz
|
||||||
|
} // namespace Foo
|
||||||
|
"""
|
||||||
|
expected = """\
|
||||||
|
namespace Foo {
|
||||||
|
namespace Baz {
|
||||||
|
|
||||||
|
class MockTest : public Test {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD0(Foo,
|
||||||
|
void());
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Baz
|
||||||
|
} // namespace Foo
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
expected, self.GenerateMocks(source))
|
||||||
|
|
||||||
|
def testClassWithStorageSpecifierMacro(self):
|
||||||
|
source = """
|
||||||
|
class STORAGE_SPECIFIER Test {
|
||||||
|
public:
|
||||||
|
virtual void Foo();
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
expected = """\
|
||||||
|
class MockTest : public Test {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD0(Foo,
|
||||||
|
void());
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
expected, self.GenerateMocks(source))
|
||||||
|
|
||||||
|
def testTemplatedForwardDeclaration(self):
|
||||||
|
source = """
|
||||||
|
template <class T> class Forward; // Forward declaration should be ignored.
|
||||||
|
class Test {
|
||||||
|
public:
|
||||||
|
virtual void Foo();
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
expected = """\
|
||||||
|
class MockTest : public Test {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD0(Foo,
|
||||||
|
void());
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
expected, self.GenerateMocks(source))
|
||||||
|
|
||||||
|
def testTemplatedClass(self):
|
||||||
|
source = """
|
||||||
|
template <typename S, typename T>
|
||||||
|
class Test {
|
||||||
|
public:
|
||||||
|
virtual void Foo();
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
expected = """\
|
||||||
|
template <typename T0, typename T1>
|
||||||
|
class MockTest : public Test<T0, T1> {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD0_T(Foo,
|
||||||
|
void());
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
expected, self.GenerateMocks(source))
|
||||||
|
|
||||||
|
def testTemplateInATemplateTypedef(self):
|
||||||
|
source = """
|
||||||
|
class Test {
|
||||||
|
public:
|
||||||
|
typedef std::vector<std::list<int>> FooType;
|
||||||
|
virtual void Bar(const FooType& test_arg);
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
expected = """\
|
||||||
|
class MockTest : public Test {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD1(Bar,
|
||||||
|
void(const FooType& test_arg));
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
expected, self.GenerateMocks(source))
|
||||||
|
|
||||||
|
def testTemplateInATemplateTypedefWithComma(self):
|
||||||
|
source = """
|
||||||
|
class Test {
|
||||||
|
public:
|
||||||
|
typedef std::function<void(
|
||||||
|
const vector<std::list<int>>&, int> FooType;
|
||||||
|
virtual void Bar(const FooType& test_arg);
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
expected = """\
|
||||||
|
class MockTest : public Test {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD1(Bar,
|
||||||
|
void(const FooType& test_arg));
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
expected, self.GenerateMocks(source))
|
||||||
|
|
||||||
|
def testEnumClass(self):
|
||||||
|
source = """
|
||||||
|
class Test {
|
||||||
|
public:
|
||||||
|
enum class Baz { BAZINGA };
|
||||||
|
virtual void Bar(const FooType& test_arg);
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
expected = """\
|
||||||
|
class MockTest : public Test {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD1(Bar,
|
||||||
|
void(const FooType& test_arg));
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
self.assertEqualIgnoreLeadingWhitespace(
|
||||||
|
expected, self.GenerateMocks(source))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2007 Neal Norwitz
|
||||||
|
# Portions Copyright 2007 Google Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
"""C++ keywords and helper utilities for determining keywords."""
|
||||||
|
|
||||||
|
__author__ = 'nnorwitz@google.com (Neal Norwitz)'
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Python 3.x
|
||||||
|
import builtins
|
||||||
|
except ImportError:
|
||||||
|
# Python 2.x
|
||||||
|
import __builtin__ as builtins
|
||||||
|
|
||||||
|
|
||||||
|
if not hasattr(builtins, 'set'):
|
||||||
|
# Nominal support for Python 2.3.
|
||||||
|
from sets import Set as set
|
||||||
|
|
||||||
|
|
||||||
|
TYPES = set('bool char int long short double float void wchar_t unsigned signed'.split())
|
||||||
|
TYPE_MODIFIERS = set('auto register const inline extern static virtual volatile mutable'.split())
|
||||||
|
ACCESS = set('public protected private friend'.split())
|
||||||
|
|
||||||
|
CASTS = set('static_cast const_cast dynamic_cast reinterpret_cast'.split())
|
||||||
|
|
||||||
|
OTHERS = set('true false asm class namespace using explicit this operator sizeof'.split())
|
||||||
|
OTHER_TYPES = set('new delete typedef struct union enum typeid typename template'.split())
|
||||||
|
|
||||||
|
CONTROL = set('case switch default if else return goto'.split())
|
||||||
|
EXCEPTION = set('try catch throw'.split())
|
||||||
|
LOOP = set('while do for break continue'.split())
|
||||||
|
|
||||||
|
ALL = TYPES | TYPE_MODIFIERS | ACCESS | CASTS | OTHERS | OTHER_TYPES | CONTROL | EXCEPTION | LOOP
|
||||||
|
|
||||||
|
|
||||||
|
def IsKeyword(token):
|
||||||
|
return token in ALL
|
||||||
|
|
||||||
|
def IsBuiltinType(token):
|
||||||
|
if token in ('virtual', 'inline'):
|
||||||
|
# These only apply to methods, they can't be types by themselves.
|
||||||
|
return False
|
||||||
|
return token in TYPES or token in TYPE_MODIFIERS
|
@ -0,0 +1,287 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2007 Neal Norwitz
|
||||||
|
# Portions Copyright 2007 Google Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
"""Tokenize C++ source code."""
|
||||||
|
|
||||||
|
__author__ = 'nnorwitz@google.com (Neal Norwitz)'
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Python 3.x
|
||||||
|
import builtins
|
||||||
|
except ImportError:
|
||||||
|
# Python 2.x
|
||||||
|
import __builtin__ as builtins
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from cpp import utils
|
||||||
|
|
||||||
|
|
||||||
|
if not hasattr(builtins, 'set'):
|
||||||
|
# Nominal support for Python 2.3.
|
||||||
|
from sets import Set as set
|
||||||
|
|
||||||
|
|
||||||
|
# Add $ as a valid identifier char since so much code uses it.
|
||||||
|
_letters = 'abcdefghijklmnopqrstuvwxyz'
|
||||||
|
VALID_IDENTIFIER_CHARS = set(_letters + _letters.upper() + '_0123456789$')
|
||||||
|
HEX_DIGITS = set('0123456789abcdefABCDEF')
|
||||||
|
INT_OR_FLOAT_DIGITS = set('01234567890eE-+')
|
||||||
|
|
||||||
|
|
||||||
|
# C++0x string preffixes.
|
||||||
|
_STR_PREFIXES = set(('R', 'u8', 'u8R', 'u', 'uR', 'U', 'UR', 'L', 'LR'))
|
||||||
|
|
||||||
|
|
||||||
|
# Token types.
|
||||||
|
UNKNOWN = 'UNKNOWN'
|
||||||
|
SYNTAX = 'SYNTAX'
|
||||||
|
CONSTANT = 'CONSTANT'
|
||||||
|
NAME = 'NAME'
|
||||||
|
PREPROCESSOR = 'PREPROCESSOR'
|
||||||
|
|
||||||
|
# Where the token originated from. This can be used for backtracking.
|
||||||
|
# It is always set to WHENCE_STREAM in this code.
|
||||||
|
WHENCE_STREAM, WHENCE_QUEUE = range(2)
|
||||||
|
|
||||||
|
|
||||||
|
class Token(object):
|
||||||
|
"""Data container to represent a C++ token.
|
||||||
|
|
||||||
|
Tokens can be identifiers, syntax char(s), constants, or
|
||||||
|
pre-processor directives.
|
||||||
|
|
||||||
|
start contains the index of the first char of the token in the source
|
||||||
|
end contains the index of the last char of the token in the source
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, token_type, name, start, end):
|
||||||
|
self.token_type = token_type
|
||||||
|
self.name = name
|
||||||
|
self.start = start
|
||||||
|
self.end = end
|
||||||
|
self.whence = WHENCE_STREAM
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if not utils.DEBUG:
|
||||||
|
return 'Token(%r)' % self.name
|
||||||
|
return 'Token(%r, %s, %s)' % (self.name, self.start, self.end)
|
||||||
|
|
||||||
|
__repr__ = __str__
|
||||||
|
|
||||||
|
|
||||||
|
def _GetString(source, start, i):
|
||||||
|
i = source.find('"', i+1)
|
||||||
|
while source[i-1] == '\\':
|
||||||
|
# Count the trailing backslashes.
|
||||||
|
backslash_count = 1
|
||||||
|
j = i - 2
|
||||||
|
while source[j] == '\\':
|
||||||
|
backslash_count += 1
|
||||||
|
j -= 1
|
||||||
|
# When trailing backslashes are even, they escape each other.
|
||||||
|
if (backslash_count % 2) == 0:
|
||||||
|
break
|
||||||
|
i = source.find('"', i+1)
|
||||||
|
return i + 1
|
||||||
|
|
||||||
|
|
||||||
|
def _GetChar(source, start, i):
|
||||||
|
# NOTE(nnorwitz): may not be quite correct, should be good enough.
|
||||||
|
i = source.find("'", i+1)
|
||||||
|
while source[i-1] == '\\':
|
||||||
|
# Need to special case '\\'.
|
||||||
|
if (i - 2) > start and source[i-2] == '\\':
|
||||||
|
break
|
||||||
|
i = source.find("'", i+1)
|
||||||
|
# Try to handle unterminated single quotes (in a #if 0 block).
|
||||||
|
if i < 0:
|
||||||
|
i = start
|
||||||
|
return i + 1
|
||||||
|
|
||||||
|
|
||||||
|
def GetTokens(source):
|
||||||
|
"""Returns a sequence of Tokens.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
source: string of C++ source code.
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
Token that represents the next token in the source.
|
||||||
|
"""
|
||||||
|
# Cache various valid character sets for speed.
|
||||||
|
valid_identifier_chars = VALID_IDENTIFIER_CHARS
|
||||||
|
hex_digits = HEX_DIGITS
|
||||||
|
int_or_float_digits = INT_OR_FLOAT_DIGITS
|
||||||
|
int_or_float_digits2 = int_or_float_digits | set('.')
|
||||||
|
|
||||||
|
# Only ignore errors while in a #if 0 block.
|
||||||
|
ignore_errors = False
|
||||||
|
count_ifs = 0
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
end = len(source)
|
||||||
|
while i < end:
|
||||||
|
# Skip whitespace.
|
||||||
|
while i < end and source[i].isspace():
|
||||||
|
i += 1
|
||||||
|
if i >= end:
|
||||||
|
return
|
||||||
|
|
||||||
|
token_type = UNKNOWN
|
||||||
|
start = i
|
||||||
|
c = source[i]
|
||||||
|
if c.isalpha() or c == '_': # Find a string token.
|
||||||
|
token_type = NAME
|
||||||
|
while source[i] in valid_identifier_chars:
|
||||||
|
i += 1
|
||||||
|
# String and character constants can look like a name if
|
||||||
|
# they are something like L"".
|
||||||
|
if (source[i] == "'" and (i - start) == 1 and
|
||||||
|
source[start:i] in 'uUL'):
|
||||||
|
# u, U, and L are valid C++0x character preffixes.
|
||||||
|
token_type = CONSTANT
|
||||||
|
i = _GetChar(source, start, i)
|
||||||
|
elif source[i] == "'" and source[start:i] in _STR_PREFIXES:
|
||||||
|
token_type = CONSTANT
|
||||||
|
i = _GetString(source, start, i)
|
||||||
|
elif c == '/' and source[i+1] == '/': # Find // comments.
|
||||||
|
i = source.find('\n', i)
|
||||||
|
if i == -1: # Handle EOF.
|
||||||
|
i = end
|
||||||
|
continue
|
||||||
|
elif c == '/' and source[i+1] == '*': # Find /* comments. */
|
||||||
|
i = source.find('*/', i) + 2
|
||||||
|
continue
|
||||||
|
elif c in ':+-<>&|*=': # : or :: (plus other chars).
|
||||||
|
token_type = SYNTAX
|
||||||
|
i += 1
|
||||||
|
new_ch = source[i]
|
||||||
|
if new_ch == c and c != '>': # Treat ">>" as two tokens.
|
||||||
|
i += 1
|
||||||
|
elif c == '-' and new_ch == '>':
|
||||||
|
i += 1
|
||||||
|
elif new_ch == '=':
|
||||||
|
i += 1
|
||||||
|
elif c in '()[]{}~!?^%;/.,': # Handle single char tokens.
|
||||||
|
token_type = SYNTAX
|
||||||
|
i += 1
|
||||||
|
if c == '.' and source[i].isdigit():
|
||||||
|
token_type = CONSTANT
|
||||||
|
i += 1
|
||||||
|
while source[i] in int_or_float_digits:
|
||||||
|
i += 1
|
||||||
|
# Handle float suffixes.
|
||||||
|
for suffix in ('l', 'f'):
|
||||||
|
if suffix == source[i:i+1].lower():
|
||||||
|
i += 1
|
||||||
|
break
|
||||||
|
elif c.isdigit(): # Find integer.
|
||||||
|
token_type = CONSTANT
|
||||||
|
if c == '0' and source[i+1] in 'xX':
|
||||||
|
# Handle hex digits.
|
||||||
|
i += 2
|
||||||
|
while source[i] in hex_digits:
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
while source[i] in int_or_float_digits2:
|
||||||
|
i += 1
|
||||||
|
# Handle integer (and float) suffixes.
|
||||||
|
for suffix in ('ull', 'll', 'ul', 'l', 'f', 'u'):
|
||||||
|
size = len(suffix)
|
||||||
|
if suffix == source[i:i+size].lower():
|
||||||
|
i += size
|
||||||
|
break
|
||||||
|
elif c == '"': # Find string.
|
||||||
|
token_type = CONSTANT
|
||||||
|
i = _GetString(source, start, i)
|
||||||
|
elif c == "'": # Find char.
|
||||||
|
token_type = CONSTANT
|
||||||
|
i = _GetChar(source, start, i)
|
||||||
|
elif c == '#': # Find pre-processor command.
|
||||||
|
token_type = PREPROCESSOR
|
||||||
|
got_if = source[i:i+3] == '#if' and source[i+3:i+4].isspace()
|
||||||
|
if got_if:
|
||||||
|
count_ifs += 1
|
||||||
|
elif source[i:i+6] == '#endif':
|
||||||
|
count_ifs -= 1
|
||||||
|
if count_ifs == 0:
|
||||||
|
ignore_errors = False
|
||||||
|
|
||||||
|
# TODO(nnorwitz): handle preprocessor statements (\ continuations).
|
||||||
|
while 1:
|
||||||
|
i1 = source.find('\n', i)
|
||||||
|
i2 = source.find('//', i)
|
||||||
|
i3 = source.find('/*', i)
|
||||||
|
i4 = source.find('"', i)
|
||||||
|
# NOTE(nnorwitz): doesn't handle comments in #define macros.
|
||||||
|
# Get the first important symbol (newline, comment, EOF/end).
|
||||||
|
i = min([x for x in (i1, i2, i3, i4, end) if x != -1])
|
||||||
|
|
||||||
|
# Handle #include "dir//foo.h" properly.
|
||||||
|
if source[i] == '"':
|
||||||
|
i = source.find('"', i+1) + 1
|
||||||
|
assert i > 0
|
||||||
|
continue
|
||||||
|
# Keep going if end of the line and the line ends with \.
|
||||||
|
if not (i == i1 and source[i-1] == '\\'):
|
||||||
|
if got_if:
|
||||||
|
condition = source[start+4:i].lstrip()
|
||||||
|
if (condition.startswith('0') or
|
||||||
|
condition.startswith('(0)')):
|
||||||
|
ignore_errors = True
|
||||||
|
break
|
||||||
|
i += 1
|
||||||
|
elif c == '\\': # Handle \ in code.
|
||||||
|
# This is different from the pre-processor \ handling.
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
elif ignore_errors:
|
||||||
|
# The tokenizer seems to be in pretty good shape. This
|
||||||
|
# raise is conditionally disabled so that bogus code
|
||||||
|
# in an #if 0 block can be handled. Since we will ignore
|
||||||
|
# it anyways, this is probably fine. So disable the
|
||||||
|
# exception and return the bogus char.
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
sys.stderr.write('Got invalid token in %s @ %d token:%s: %r\n' %
|
||||||
|
('?', i, c, source[i-10:i+10]))
|
||||||
|
raise RuntimeError('unexpected token')
|
||||||
|
|
||||||
|
if i <= 0:
|
||||||
|
print('Invalid index, exiting now.')
|
||||||
|
return
|
||||||
|
yield Token(token_type, source[start:i], start, i)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
def main(argv):
|
||||||
|
"""Driver mostly for testing purposes."""
|
||||||
|
for filename in argv[1:]:
|
||||||
|
source = utils.ReadFile(filename)
|
||||||
|
if source is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for token in GetTokens(source):
|
||||||
|
print('%-12s: %s' % (token.token_type, token.name))
|
||||||
|
# print('\r%6.2f%%' % (100.0 * index / token.end),)
|
||||||
|
sys.stdout.write('\n')
|
||||||
|
|
||||||
|
|
||||||
|
main(sys.argv)
|
@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2007 Neal Norwitz
|
||||||
|
# Portions Copyright 2007 Google Inc.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
"""Generic utilities for C++ parsing."""
|
||||||
|
|
||||||
|
__author__ = 'nnorwitz@google.com (Neal Norwitz)'
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
# Set to True to see the start/end token indices.
|
||||||
|
DEBUG = True
|
||||||
|
|
||||||
|
|
||||||
|
def ReadFile(filename, print_error=True):
|
||||||
|
"""Returns the contents of a file."""
|
||||||
|
try:
|
||||||
|
fp = open(filename)
|
||||||
|
try:
|
||||||
|
return fp.read()
|
||||||
|
finally:
|
||||||
|
fp.close()
|
||||||
|
except IOError:
|
||||||
|
if print_error:
|
||||||
|
print('Error reading %s: %s' % (filename, sys.exc_info()[1]))
|
||||||
|
return None
|
@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2008 Google Inc. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
"""Driver for starting up Google Mock class generator."""
|
||||||
|
|
||||||
|
__author__ = 'nnorwitz@google.com (Neal Norwitz)'
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Add the directory of this script to the path so we can import gmock_class.
|
||||||
|
sys.path.append(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
from cpp import gmock_class
|
||||||
|
# Fix the docstring in case they require the usage.
|
||||||
|
gmock_class.__doc__ = gmock_class.__doc__.replace('gmock_class.py', __file__)
|
||||||
|
gmock_class.main()
|
@ -0,0 +1,303 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# These variables are automatically filled in by the configure script.
|
||||||
|
name="@PACKAGE_TARNAME@"
|
||||||
|
version="@PACKAGE_VERSION@"
|
||||||
|
|
||||||
|
show_usage()
|
||||||
|
{
|
||||||
|
echo "Usage: gmock-config [OPTIONS...]"
|
||||||
|
}
|
||||||
|
|
||||||
|
show_help()
|
||||||
|
{
|
||||||
|
show_usage
|
||||||
|
cat <<\EOF
|
||||||
|
|
||||||
|
The `gmock-config' script provides access to the necessary compile and linking
|
||||||
|
flags to connect with Google C++ Mocking Framework, both in a build prior to
|
||||||
|
installation, and on the system proper after installation. The installation
|
||||||
|
overrides may be issued in combination with any other queries, but will only
|
||||||
|
affect installation queries if called on a built but not installed gmock. The
|
||||||
|
installation queries may not be issued with any other types of queries, and
|
||||||
|
only one installation query may be made at a time. The version queries and
|
||||||
|
compiler flag queries may be combined as desired but not mixed. Different
|
||||||
|
version queries are always combined with logical "and" semantics, and only the
|
||||||
|
last of any particular query is used while all previous ones ignored. All
|
||||||
|
versions must be specified as a sequence of numbers separated by periods.
|
||||||
|
Compiler flag queries output the union of the sets of flags when combined.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
gmock-config --min-version=1.0 || echo "Insufficient Google Mock version."
|
||||||
|
|
||||||
|
g++ $(gmock-config --cppflags --cxxflags) -o foo.o -c foo.cpp
|
||||||
|
g++ $(gmock-config --ldflags --libs) -o foo foo.o
|
||||||
|
|
||||||
|
# When using a built but not installed Google Mock:
|
||||||
|
g++ $(../../my_gmock_build/scripts/gmock-config ...) ...
|
||||||
|
|
||||||
|
# When using an installed Google Mock, but with installation overrides:
|
||||||
|
export GMOCK_PREFIX="/opt"
|
||||||
|
g++ $(gmock-config --libdir="/opt/lib64" ...) ...
|
||||||
|
|
||||||
|
Help:
|
||||||
|
--usage brief usage information
|
||||||
|
--help display this help message
|
||||||
|
|
||||||
|
Installation Overrides:
|
||||||
|
--prefix=<dir> overrides the installation prefix
|
||||||
|
--exec-prefix=<dir> overrides the executable installation prefix
|
||||||
|
--libdir=<dir> overrides the library installation prefix
|
||||||
|
--includedir=<dir> overrides the header file installation prefix
|
||||||
|
|
||||||
|
Installation Queries:
|
||||||
|
--prefix installation prefix
|
||||||
|
--exec-prefix executable installation prefix
|
||||||
|
--libdir library installation directory
|
||||||
|
--includedir header file installation directory
|
||||||
|
--version the version of the Google Mock installation
|
||||||
|
|
||||||
|
Version Queries:
|
||||||
|
--min-version=VERSION return 0 if the version is at least VERSION
|
||||||
|
--exact-version=VERSION return 0 if the version is exactly VERSION
|
||||||
|
--max-version=VERSION return 0 if the version is at most VERSION
|
||||||
|
|
||||||
|
Compilation Flag Queries:
|
||||||
|
--cppflags compile flags specific to the C-like preprocessors
|
||||||
|
--cxxflags compile flags appropriate for C++ programs
|
||||||
|
--ldflags linker flags
|
||||||
|
--libs libraries for linking
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# This function bounds our version with a min and a max. It uses some clever
|
||||||
|
# POSIX-compliant variable expansion to portably do all the work in the shell
|
||||||
|
# and avoid any dependency on a particular "sed" or "awk" implementation.
|
||||||
|
# Notable is that it will only ever compare the first 3 components of versions.
|
||||||
|
# Further components will be cleanly stripped off. All versions must be
|
||||||
|
# unadorned, so "v1.0" will *not* work. The minimum version must be in $1, and
|
||||||
|
# the max in $2. TODO(chandlerc@google.com): If this ever breaks, we should
|
||||||
|
# investigate expanding this via autom4te from AS_VERSION_COMPARE rather than
|
||||||
|
# continuing to maintain our own shell version.
|
||||||
|
check_versions()
|
||||||
|
{
|
||||||
|
major_version=${version%%.*}
|
||||||
|
minor_version="0"
|
||||||
|
point_version="0"
|
||||||
|
if test "${version#*.}" != "${version}"; then
|
||||||
|
minor_version=${version#*.}
|
||||||
|
minor_version=${minor_version%%.*}
|
||||||
|
fi
|
||||||
|
if test "${version#*.*.}" != "${version}"; then
|
||||||
|
point_version=${version#*.*.}
|
||||||
|
point_version=${point_version%%.*}
|
||||||
|
fi
|
||||||
|
|
||||||
|
min_version="$1"
|
||||||
|
min_major_version=${min_version%%.*}
|
||||||
|
min_minor_version="0"
|
||||||
|
min_point_version="0"
|
||||||
|
if test "${min_version#*.}" != "${min_version}"; then
|
||||||
|
min_minor_version=${min_version#*.}
|
||||||
|
min_minor_version=${min_minor_version%%.*}
|
||||||
|
fi
|
||||||
|
if test "${min_version#*.*.}" != "${min_version}"; then
|
||||||
|
min_point_version=${min_version#*.*.}
|
||||||
|
min_point_version=${min_point_version%%.*}
|
||||||
|
fi
|
||||||
|
|
||||||
|
max_version="$2"
|
||||||
|
max_major_version=${max_version%%.*}
|
||||||
|
max_minor_version="0"
|
||||||
|
max_point_version="0"
|
||||||
|
if test "${max_version#*.}" != "${max_version}"; then
|
||||||
|
max_minor_version=${max_version#*.}
|
||||||
|
max_minor_version=${max_minor_version%%.*}
|
||||||
|
fi
|
||||||
|
if test "${max_version#*.*.}" != "${max_version}"; then
|
||||||
|
max_point_version=${max_version#*.*.}
|
||||||
|
max_point_version=${max_point_version%%.*}
|
||||||
|
fi
|
||||||
|
|
||||||
|
test $(($major_version)) -lt $(($min_major_version)) && exit 1
|
||||||
|
if test $(($major_version)) -eq $(($min_major_version)); then
|
||||||
|
test $(($minor_version)) -lt $(($min_minor_version)) && exit 1
|
||||||
|
if test $(($minor_version)) -eq $(($min_minor_version)); then
|
||||||
|
test $(($point_version)) -lt $(($min_point_version)) && exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
test $(($major_version)) -gt $(($max_major_version)) && exit 1
|
||||||
|
if test $(($major_version)) -eq $(($max_major_version)); then
|
||||||
|
test $(($minor_version)) -gt $(($max_minor_version)) && exit 1
|
||||||
|
if test $(($minor_version)) -eq $(($max_minor_version)); then
|
||||||
|
test $(($point_version)) -gt $(($max_point_version)) && exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Show the usage line when no arguments are specified.
|
||||||
|
if test $# -eq 0; then
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
while test $# -gt 0; do
|
||||||
|
case $1 in
|
||||||
|
--usage) show_usage; exit 0;;
|
||||||
|
--help) show_help; exit 0;;
|
||||||
|
|
||||||
|
# Installation overrides
|
||||||
|
--prefix=*) GMOCK_PREFIX=${1#--prefix=};;
|
||||||
|
--exec-prefix=*) GMOCK_EXEC_PREFIX=${1#--exec-prefix=};;
|
||||||
|
--libdir=*) GMOCK_LIBDIR=${1#--libdir=};;
|
||||||
|
--includedir=*) GMOCK_INCLUDEDIR=${1#--includedir=};;
|
||||||
|
|
||||||
|
# Installation queries
|
||||||
|
--prefix|--exec-prefix|--libdir|--includedir|--version)
|
||||||
|
if test -n "${do_query}"; then
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
do_query=${1#--}
|
||||||
|
;;
|
||||||
|
|
||||||
|
# Version checking
|
||||||
|
--min-version=*)
|
||||||
|
do_check_versions=yes
|
||||||
|
min_version=${1#--min-version=}
|
||||||
|
;;
|
||||||
|
--max-version=*)
|
||||||
|
do_check_versions=yes
|
||||||
|
max_version=${1#--max-version=}
|
||||||
|
;;
|
||||||
|
--exact-version=*)
|
||||||
|
do_check_versions=yes
|
||||||
|
exact_version=${1#--exact-version=}
|
||||||
|
;;
|
||||||
|
|
||||||
|
# Compiler flag output
|
||||||
|
--cppflags) echo_cppflags=yes;;
|
||||||
|
--cxxflags) echo_cxxflags=yes;;
|
||||||
|
--ldflags) echo_ldflags=yes;;
|
||||||
|
--libs) echo_libs=yes;;
|
||||||
|
|
||||||
|
# Everything else is an error
|
||||||
|
*) show_usage; exit 1;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# These have defaults filled in by the configure script but can also be
|
||||||
|
# overridden by environment variables or command line parameters.
|
||||||
|
prefix="${GMOCK_PREFIX:-@prefix@}"
|
||||||
|
exec_prefix="${GMOCK_EXEC_PREFIX:-@exec_prefix@}"
|
||||||
|
libdir="${GMOCK_LIBDIR:-@libdir@}"
|
||||||
|
includedir="${GMOCK_INCLUDEDIR:-@includedir@}"
|
||||||
|
|
||||||
|
# We try and detect if our binary is not located at its installed location. If
|
||||||
|
# it's not, we provide variables pointing to the source and build tree rather
|
||||||
|
# than to the install tree. We also locate Google Test using the configured
|
||||||
|
# gtest-config script rather than searching the PATH and our bindir for one.
|
||||||
|
# This allows building against a just-built gmock rather than an installed
|
||||||
|
# gmock.
|
||||||
|
bindir="@bindir@"
|
||||||
|
this_relative_bindir=`dirname $0`
|
||||||
|
this_bindir=`cd ${this_relative_bindir}; pwd -P`
|
||||||
|
if test "${this_bindir}" = "${this_bindir%${bindir}}"; then
|
||||||
|
# The path to the script doesn't end in the bindir sequence from Autoconf,
|
||||||
|
# assume that we are in a build tree.
|
||||||
|
build_dir=`dirname ${this_bindir}`
|
||||||
|
src_dir=`cd ${this_bindir}/@top_srcdir@; pwd -P`
|
||||||
|
|
||||||
|
# TODO(chandlerc@google.com): This is a dangerous dependency on libtool, we
|
||||||
|
# should work to remove it, and/or remove libtool altogether, replacing it
|
||||||
|
# with direct references to the library and a link path.
|
||||||
|
gmock_libs="${build_dir}/lib/libgmock.la"
|
||||||
|
gmock_ldflags=""
|
||||||
|
|
||||||
|
# We provide hooks to include from either the source or build dir, where the
|
||||||
|
# build dir is always preferred. This will potentially allow us to write
|
||||||
|
# build rules for generated headers and have them automatically be preferred
|
||||||
|
# over provided versions.
|
||||||
|
gmock_cppflags="-I${build_dir}/include -I${src_dir}/include"
|
||||||
|
gmock_cxxflags=""
|
||||||
|
|
||||||
|
# Directly invoke the gtest-config script used during the build process.
|
||||||
|
gtest_config="@GTEST_CONFIG@"
|
||||||
|
else
|
||||||
|
# We're using an installed gmock, although it may be staged under some
|
||||||
|
# prefix. Assume (as our own libraries do) that we can resolve the prefix,
|
||||||
|
# and are present in the dynamic link paths.
|
||||||
|
gmock_ldflags="-L${libdir}"
|
||||||
|
gmock_libs="-l${name}"
|
||||||
|
gmock_cppflags="-I${includedir}"
|
||||||
|
gmock_cxxflags=""
|
||||||
|
|
||||||
|
# We also prefer any gtest-config script installed in our prefix. Lacking
|
||||||
|
# one, we look in the PATH for one.
|
||||||
|
gtest_config="${bindir}/gtest-config"
|
||||||
|
if test ! -x "${gtest_config}"; then
|
||||||
|
gtest_config=`which gtest-config`
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure that we have located a Google Test to link against.
|
||||||
|
if ! test -x "${gtest_config}"; then
|
||||||
|
echo "Unable to locate Google Test, check your Google Mock configuration" \
|
||||||
|
"and installation" >&2
|
||||||
|
exit 1
|
||||||
|
elif ! "${gtest_config}" "--exact-version=@GTEST_VERSION@"; then
|
||||||
|
echo "The Google Test found is not the same version as Google Mock was " \
|
||||||
|
"built against" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add the necessary Google Test bits into the various flag variables
|
||||||
|
gmock_cppflags="${gmock_cppflags} `${gtest_config} --cppflags`"
|
||||||
|
gmock_cxxflags="${gmock_cxxflags} `${gtest_config} --cxxflags`"
|
||||||
|
gmock_ldflags="${gmock_ldflags} `${gtest_config} --ldflags`"
|
||||||
|
gmock_libs="${gmock_libs} `${gtest_config} --libs`"
|
||||||
|
|
||||||
|
# Do an installation query if requested.
|
||||||
|
if test -n "$do_query"; then
|
||||||
|
case $do_query in
|
||||||
|
prefix) echo $prefix; exit 0;;
|
||||||
|
exec-prefix) echo $exec_prefix; exit 0;;
|
||||||
|
libdir) echo $libdir; exit 0;;
|
||||||
|
includedir) echo $includedir; exit 0;;
|
||||||
|
version) echo $version; exit 0;;
|
||||||
|
*) show_usage; exit 1;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Do a version check if requested.
|
||||||
|
if test "$do_check_versions" = "yes"; then
|
||||||
|
# Make sure we didn't receive a bad combination of parameters.
|
||||||
|
test "$echo_cppflags" = "yes" && show_usage && exit 1
|
||||||
|
test "$echo_cxxflags" = "yes" && show_usage && exit 1
|
||||||
|
test "$echo_ldflags" = "yes" && show_usage && exit 1
|
||||||
|
test "$echo_libs" = "yes" && show_usage && exit 1
|
||||||
|
|
||||||
|
if test "$exact_version" != ""; then
|
||||||
|
check_versions $exact_version $exact_version
|
||||||
|
# unreachable
|
||||||
|
else
|
||||||
|
check_versions ${min_version:-0.0.0} ${max_version:-9999.9999.9999}
|
||||||
|
# unreachable
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Do the output in the correct order so that these can be used in-line of
|
||||||
|
# a compiler invocation.
|
||||||
|
output=""
|
||||||
|
test "$echo_cppflags" = "yes" && output="$output $gmock_cppflags"
|
||||||
|
test "$echo_cxxflags" = "yes" && output="$output $gmock_cxxflags"
|
||||||
|
test "$echo_ldflags" = "yes" && output="$output $gmock_ldflags"
|
||||||
|
test "$echo_libs" = "yes" && output="$output $gmock_libs"
|
||||||
|
echo $output
|
||||||
|
|
||||||
|
exit 0
|
@ -0,0 +1,640 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2008, 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.
|
||||||
|
|
||||||
|
"""Converts compiler's errors in code using Google Mock to plain English."""
|
||||||
|
|
||||||
|
__author__ = 'wan@google.com (Zhanyong Wan)'
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
_VERSION = '1.0.3'
|
||||||
|
|
||||||
|
_EMAIL = 'googlemock@googlegroups.com'
|
||||||
|
|
||||||
|
_COMMON_GMOCK_SYMBOLS = [
|
||||||
|
# Matchers
|
||||||
|
'_',
|
||||||
|
'A',
|
||||||
|
'AddressSatisfies',
|
||||||
|
'AllOf',
|
||||||
|
'An',
|
||||||
|
'AnyOf',
|
||||||
|
'ContainerEq',
|
||||||
|
'Contains',
|
||||||
|
'ContainsRegex',
|
||||||
|
'DoubleEq',
|
||||||
|
'ElementsAre',
|
||||||
|
'ElementsAreArray',
|
||||||
|
'EndsWith',
|
||||||
|
'Eq',
|
||||||
|
'Field',
|
||||||
|
'FloatEq',
|
||||||
|
'Ge',
|
||||||
|
'Gt',
|
||||||
|
'HasSubstr',
|
||||||
|
'IsInitializedProto',
|
||||||
|
'Le',
|
||||||
|
'Lt',
|
||||||
|
'MatcherCast',
|
||||||
|
'Matches',
|
||||||
|
'MatchesRegex',
|
||||||
|
'NanSensitiveDoubleEq',
|
||||||
|
'NanSensitiveFloatEq',
|
||||||
|
'Ne',
|
||||||
|
'Not',
|
||||||
|
'NotNull',
|
||||||
|
'Pointee',
|
||||||
|
'Property',
|
||||||
|
'Ref',
|
||||||
|
'ResultOf',
|
||||||
|
'SafeMatcherCast',
|
||||||
|
'StartsWith',
|
||||||
|
'StrCaseEq',
|
||||||
|
'StrCaseNe',
|
||||||
|
'StrEq',
|
||||||
|
'StrNe',
|
||||||
|
'Truly',
|
||||||
|
'TypedEq',
|
||||||
|
'Value',
|
||||||
|
|
||||||
|
# Actions
|
||||||
|
'Assign',
|
||||||
|
'ByRef',
|
||||||
|
'DeleteArg',
|
||||||
|
'DoAll',
|
||||||
|
'DoDefault',
|
||||||
|
'IgnoreResult',
|
||||||
|
'Invoke',
|
||||||
|
'InvokeArgument',
|
||||||
|
'InvokeWithoutArgs',
|
||||||
|
'Return',
|
||||||
|
'ReturnNew',
|
||||||
|
'ReturnNull',
|
||||||
|
'ReturnRef',
|
||||||
|
'SaveArg',
|
||||||
|
'SetArgReferee',
|
||||||
|
'SetArgPointee',
|
||||||
|
'SetArgumentPointee',
|
||||||
|
'SetArrayArgument',
|
||||||
|
'SetErrnoAndReturn',
|
||||||
|
'Throw',
|
||||||
|
'WithArg',
|
||||||
|
'WithArgs',
|
||||||
|
'WithoutArgs',
|
||||||
|
|
||||||
|
# Cardinalities
|
||||||
|
'AnyNumber',
|
||||||
|
'AtLeast',
|
||||||
|
'AtMost',
|
||||||
|
'Between',
|
||||||
|
'Exactly',
|
||||||
|
|
||||||
|
# Sequences
|
||||||
|
'InSequence',
|
||||||
|
'Sequence',
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
'DefaultValue',
|
||||||
|
'Mock',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Regex for matching source file path and line number in the compiler's errors.
|
||||||
|
_GCC_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):(\d+:)?\s+'
|
||||||
|
_CLANG_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):(?P<column>\d+):\s+'
|
||||||
|
_CLANG_NON_GMOCK_FILE_LINE_RE = (
|
||||||
|
r'(?P<file>.*[/\\^](?!gmock-)[^/\\]+):(?P<line>\d+):(?P<column>\d+):\s+')
|
||||||
|
|
||||||
|
|
||||||
|
def _FindAllMatches(regex, s):
|
||||||
|
"""Generates all matches of regex in string s."""
|
||||||
|
|
||||||
|
r = re.compile(regex)
|
||||||
|
return r.finditer(s)
|
||||||
|
|
||||||
|
|
||||||
|
def _GenericDiagnoser(short_name, long_name, diagnoses, msg):
|
||||||
|
"""Diagnoses the given disease by pattern matching.
|
||||||
|
|
||||||
|
Can provide different diagnoses for different patterns.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
short_name: Short name of the disease.
|
||||||
|
long_name: Long name of the disease.
|
||||||
|
diagnoses: A list of pairs (regex, pattern for formatting the diagnosis
|
||||||
|
for matching regex).
|
||||||
|
msg: Compiler's error messages.
|
||||||
|
Yields:
|
||||||
|
Tuples of the form
|
||||||
|
(short name of disease, long name of disease, diagnosis).
|
||||||
|
"""
|
||||||
|
for regex, diagnosis in diagnoses:
|
||||||
|
if re.search(regex, msg):
|
||||||
|
diagnosis = '%(file)s:%(line)s:' + diagnosis
|
||||||
|
for m in _FindAllMatches(regex, msg):
|
||||||
|
yield (short_name, long_name, diagnosis % m.groupdict())
|
||||||
|
|
||||||
|
|
||||||
|
def _NeedToReturnReferenceDiagnoser(msg):
|
||||||
|
"""Diagnoses the NRR disease, given the error messages by the compiler."""
|
||||||
|
|
||||||
|
gcc_regex = (r'In member function \'testing::internal::ReturnAction<R>.*\n'
|
||||||
|
+ _GCC_FILE_LINE_RE + r'instantiated from here\n'
|
||||||
|
r'.*gmock-actions\.h.*error: creating array with negative size')
|
||||||
|
clang_regex = (r'error:.*array.*negative.*\r?\n'
|
||||||
|
r'(.*\n)*?' +
|
||||||
|
_CLANG_NON_GMOCK_FILE_LINE_RE +
|
||||||
|
r'note: in instantiation of function template specialization '
|
||||||
|
r'\'testing::internal::ReturnAction<(?P<type>.*)>'
|
||||||
|
r'::operator Action<.*>\' requested here')
|
||||||
|
clang11_re = (r'use_ReturnRef_instead_of_Return_to_return_a_reference.*'
|
||||||
|
r'(.*\n)*?' + _CLANG_NON_GMOCK_FILE_LINE_RE)
|
||||||
|
|
||||||
|
diagnosis = """
|
||||||
|
You are using a Return() action in a function that returns a reference to
|
||||||
|
%(type)s. Please use ReturnRef() instead."""
|
||||||
|
return _GenericDiagnoser('NRR', 'Need to Return Reference',
|
||||||
|
[(clang_regex, diagnosis),
|
||||||
|
(clang11_re, diagnosis % {'type': 'a type'}),
|
||||||
|
(gcc_regex, diagnosis % {'type': 'a type'})],
|
||||||
|
msg)
|
||||||
|
|
||||||
|
|
||||||
|
def _NeedToReturnSomethingDiagnoser(msg):
|
||||||
|
"""Diagnoses the NRS disease, given the error messages by the compiler."""
|
||||||
|
|
||||||
|
gcc_regex = (_GCC_FILE_LINE_RE + r'(instantiated from here\n.'
|
||||||
|
r'*gmock.*actions\.h.*error: void value not ignored)'
|
||||||
|
r'|(error: control reaches end of non-void function)')
|
||||||
|
clang_regex1 = (_CLANG_FILE_LINE_RE +
|
||||||
|
r'error: cannot initialize return object '
|
||||||
|
r'of type \'Result\' \(aka \'(?P<return_type>.*)\'\) '
|
||||||
|
r'with an rvalue of type \'void\'')
|
||||||
|
clang_regex2 = (_CLANG_FILE_LINE_RE +
|
||||||
|
r'error: cannot initialize return object '
|
||||||
|
r'of type \'(?P<return_type>.*)\' '
|
||||||
|
r'with an rvalue of type \'void\'')
|
||||||
|
diagnosis = """
|
||||||
|
You are using an action that returns void, but it needs to return
|
||||||
|
%(return_type)s. Please tell it *what* to return. Perhaps you can use
|
||||||
|
the pattern DoAll(some_action, Return(some_value))?"""
|
||||||
|
return _GenericDiagnoser(
|
||||||
|
'NRS',
|
||||||
|
'Need to Return Something',
|
||||||
|
[(gcc_regex, diagnosis % {'return_type': '*something*'}),
|
||||||
|
(clang_regex1, diagnosis),
|
||||||
|
(clang_regex2, diagnosis)],
|
||||||
|
msg)
|
||||||
|
|
||||||
|
|
||||||
|
def _NeedToReturnNothingDiagnoser(msg):
|
||||||
|
"""Diagnoses the NRN disease, given the error messages by the compiler."""
|
||||||
|
|
||||||
|
gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n'
|
||||||
|
r'.*gmock-actions\.h.*error: instantiation of '
|
||||||
|
r'\'testing::internal::ReturnAction<R>::Impl<F>::value_\' '
|
||||||
|
r'as type \'void\'')
|
||||||
|
clang_regex1 = (r'error: field has incomplete type '
|
||||||
|
r'\'Result\' \(aka \'void\'\)(\r)?\n'
|
||||||
|
r'(.*\n)*?' +
|
||||||
|
_CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
|
||||||
|
r'of function template specialization '
|
||||||
|
r'\'testing::internal::ReturnAction<(?P<return_type>.*)>'
|
||||||
|
r'::operator Action<void \(.*\)>\' requested here')
|
||||||
|
clang_regex2 = (r'error: field has incomplete type '
|
||||||
|
r'\'Result\' \(aka \'void\'\)(\r)?\n'
|
||||||
|
r'(.*\n)*?' +
|
||||||
|
_CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
|
||||||
|
r'of function template specialization '
|
||||||
|
r'\'testing::internal::DoBothAction<.*>'
|
||||||
|
r'::operator Action<(?P<return_type>.*) \(.*\)>\' '
|
||||||
|
r'requested here')
|
||||||
|
diagnosis = """
|
||||||
|
You are using an action that returns %(return_type)s, but it needs to return
|
||||||
|
void. Please use a void-returning action instead.
|
||||||
|
|
||||||
|
All actions but the last in DoAll(...) must return void. Perhaps you need
|
||||||
|
to re-arrange the order of actions in a DoAll(), if you are using one?"""
|
||||||
|
return _GenericDiagnoser(
|
||||||
|
'NRN',
|
||||||
|
'Need to Return Nothing',
|
||||||
|
[(gcc_regex, diagnosis % {'return_type': '*something*'}),
|
||||||
|
(clang_regex1, diagnosis),
|
||||||
|
(clang_regex2, diagnosis)],
|
||||||
|
msg)
|
||||||
|
|
||||||
|
|
||||||
|
def _IncompleteByReferenceArgumentDiagnoser(msg):
|
||||||
|
"""Diagnoses the IBRA disease, given the error messages by the compiler."""
|
||||||
|
|
||||||
|
gcc_regex = (_GCC_FILE_LINE_RE + r'instantiated from here\n'
|
||||||
|
r'.*gtest-printers\.h.*error: invalid application of '
|
||||||
|
r'\'sizeof\' to incomplete type \'(?P<type>.*)\'')
|
||||||
|
|
||||||
|
clang_regex = (r'.*gtest-printers\.h.*error: invalid application of '
|
||||||
|
r'\'sizeof\' to an incomplete type '
|
||||||
|
r'\'(?P<type>.*)( const)?\'\r?\n'
|
||||||
|
r'(.*\n)*?' +
|
||||||
|
_CLANG_NON_GMOCK_FILE_LINE_RE +
|
||||||
|
r'note: in instantiation of member function '
|
||||||
|
r'\'testing::internal2::TypeWithoutFormatter<.*>::'
|
||||||
|
r'PrintValue\' requested here')
|
||||||
|
diagnosis = """
|
||||||
|
In order to mock this function, Google Mock needs to see the definition
|
||||||
|
of type "%(type)s" - declaration alone is not enough. Either #include
|
||||||
|
the header that defines it, or change the argument to be passed
|
||||||
|
by pointer."""
|
||||||
|
|
||||||
|
return _GenericDiagnoser('IBRA', 'Incomplete By-Reference Argument Type',
|
||||||
|
[(gcc_regex, diagnosis),
|
||||||
|
(clang_regex, diagnosis)],
|
||||||
|
msg)
|
||||||
|
|
||||||
|
|
||||||
|
def _OverloadedFunctionMatcherDiagnoser(msg):
|
||||||
|
"""Diagnoses the OFM disease, given the error messages by the compiler."""
|
||||||
|
|
||||||
|
gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for '
|
||||||
|
r'call to \'Truly\(<unresolved overloaded function type>\)')
|
||||||
|
clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function for '
|
||||||
|
r'call to \'Truly')
|
||||||
|
diagnosis = """
|
||||||
|
The argument you gave to Truly() is an overloaded function. Please tell
|
||||||
|
your compiler which overloaded version you want to use.
|
||||||
|
|
||||||
|
For example, if you want to use the version whose signature is
|
||||||
|
bool Foo(int n);
|
||||||
|
you should write
|
||||||
|
Truly(static_cast<bool (*)(int n)>(Foo))"""
|
||||||
|
return _GenericDiagnoser('OFM', 'Overloaded Function Matcher',
|
||||||
|
[(gcc_regex, diagnosis),
|
||||||
|
(clang_regex, diagnosis)],
|
||||||
|
msg)
|
||||||
|
|
||||||
|
|
||||||
|
def _OverloadedFunctionActionDiagnoser(msg):
|
||||||
|
"""Diagnoses the OFA disease, given the error messages by the compiler."""
|
||||||
|
|
||||||
|
gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for call to '
|
||||||
|
r'\'Invoke\(<unresolved overloaded function type>')
|
||||||
|
clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching '
|
||||||
|
r'function for call to \'Invoke\'\r?\n'
|
||||||
|
r'(.*\n)*?'
|
||||||
|
r'.*\bgmock-generated-actions\.h:\d+:\d+:\s+'
|
||||||
|
r'note: candidate template ignored:\s+'
|
||||||
|
r'couldn\'t infer template argument \'FunctionImpl\'')
|
||||||
|
diagnosis = """
|
||||||
|
Function you are passing to Invoke is overloaded. Please tell your compiler
|
||||||
|
which overloaded version you want to use.
|
||||||
|
|
||||||
|
For example, if you want to use the version whose signature is
|
||||||
|
bool MyFunction(int n, double x);
|
||||||
|
you should write something like
|
||||||
|
Invoke(static_cast<bool (*)(int n, double x)>(MyFunction))"""
|
||||||
|
return _GenericDiagnoser('OFA', 'Overloaded Function Action',
|
||||||
|
[(gcc_regex, diagnosis),
|
||||||
|
(clang_regex, diagnosis)],
|
||||||
|
msg)
|
||||||
|
|
||||||
|
|
||||||
|
def _OverloadedMethodActionDiagnoser(msg):
|
||||||
|
"""Diagnoses the OMA disease, given the error messages by the compiler."""
|
||||||
|
|
||||||
|
gcc_regex = (_GCC_FILE_LINE_RE + r'error: no matching function for '
|
||||||
|
r'call to \'Invoke\(.+, <unresolved overloaded function '
|
||||||
|
r'type>\)')
|
||||||
|
clang_regex = (_CLANG_FILE_LINE_RE + r'error: no matching function '
|
||||||
|
r'for call to \'Invoke\'\r?\n'
|
||||||
|
r'(.*\n)*?'
|
||||||
|
r'.*\bgmock-generated-actions\.h:\d+:\d+: '
|
||||||
|
r'note: candidate function template not viable: '
|
||||||
|
r'requires .*, but 2 (arguments )?were provided')
|
||||||
|
diagnosis = """
|
||||||
|
The second argument you gave to Invoke() is an overloaded method. Please
|
||||||
|
tell your compiler which overloaded version you want to use.
|
||||||
|
|
||||||
|
For example, if you want to use the version whose signature is
|
||||||
|
class Foo {
|
||||||
|
...
|
||||||
|
bool Bar(int n, double x);
|
||||||
|
};
|
||||||
|
you should write something like
|
||||||
|
Invoke(foo, static_cast<bool (Foo::*)(int n, double x)>(&Foo::Bar))"""
|
||||||
|
return _GenericDiagnoser('OMA', 'Overloaded Method Action',
|
||||||
|
[(gcc_regex, diagnosis),
|
||||||
|
(clang_regex, diagnosis)],
|
||||||
|
msg)
|
||||||
|
|
||||||
|
|
||||||
|
def _MockObjectPointerDiagnoser(msg):
|
||||||
|
"""Diagnoses the MOP disease, given the error messages by the compiler."""
|
||||||
|
|
||||||
|
gcc_regex = (_GCC_FILE_LINE_RE + r'error: request for member '
|
||||||
|
r'\'gmock_(?P<method>.+)\' in \'(?P<mock_object>.+)\', '
|
||||||
|
r'which is of non-class type \'(.*::)*(?P<class_name>.+)\*\'')
|
||||||
|
clang_regex = (_CLANG_FILE_LINE_RE + r'error: member reference type '
|
||||||
|
r'\'(?P<class_name>.*?) *\' is a pointer; '
|
||||||
|
r'(did you mean|maybe you meant) to use \'->\'\?')
|
||||||
|
diagnosis = """
|
||||||
|
The first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*,
|
||||||
|
not a *pointer* to it. Please write '*(%(mock_object)s)' instead of
|
||||||
|
'%(mock_object)s' as your first argument.
|
||||||
|
|
||||||
|
For example, given the mock class:
|
||||||
|
|
||||||
|
class %(class_name)s : public ... {
|
||||||
|
...
|
||||||
|
MOCK_METHOD0(%(method)s, ...);
|
||||||
|
};
|
||||||
|
|
||||||
|
and the following mock instance:
|
||||||
|
|
||||||
|
%(class_name)s* mock_ptr = ...
|
||||||
|
|
||||||
|
you should use the EXPECT_CALL like this:
|
||||||
|
|
||||||
|
EXPECT_CALL(*mock_ptr, %(method)s(...));"""
|
||||||
|
|
||||||
|
return _GenericDiagnoser(
|
||||||
|
'MOP',
|
||||||
|
'Mock Object Pointer',
|
||||||
|
[(gcc_regex, diagnosis),
|
||||||
|
(clang_regex, diagnosis % {'mock_object': 'mock_object',
|
||||||
|
'method': 'method',
|
||||||
|
'class_name': '%(class_name)s'})],
|
||||||
|
msg)
|
||||||
|
|
||||||
|
|
||||||
|
def _NeedToUseSymbolDiagnoser(msg):
|
||||||
|
"""Diagnoses the NUS disease, given the error messages by the compiler."""
|
||||||
|
|
||||||
|
gcc_regex = (_GCC_FILE_LINE_RE + r'error: \'(?P<symbol>.+)\' '
|
||||||
|
r'(was not declared in this scope|has not been declared)')
|
||||||
|
clang_regex = (_CLANG_FILE_LINE_RE +
|
||||||
|
r'error: (use of undeclared identifier|unknown type name|'
|
||||||
|
r'no template named) \'(?P<symbol>[^\']+)\'')
|
||||||
|
diagnosis = """
|
||||||
|
'%(symbol)s' is defined by Google Mock in the testing namespace.
|
||||||
|
Did you forget to write
|
||||||
|
using testing::%(symbol)s;
|
||||||
|
?"""
|
||||||
|
for m in (list(_FindAllMatches(gcc_regex, msg)) +
|
||||||
|
list(_FindAllMatches(clang_regex, msg))):
|
||||||
|
symbol = m.groupdict()['symbol']
|
||||||
|
if symbol in _COMMON_GMOCK_SYMBOLS:
|
||||||
|
yield ('NUS', 'Need to Use Symbol', diagnosis % m.groupdict())
|
||||||
|
|
||||||
|
|
||||||
|
def _NeedToUseReturnNullDiagnoser(msg):
|
||||||
|
"""Diagnoses the NRNULL disease, given the error messages by the compiler."""
|
||||||
|
|
||||||
|
gcc_regex = ('instantiated from \'testing::internal::ReturnAction<R>'
|
||||||
|
'::operator testing::Action<Func>\(\) const.*\n' +
|
||||||
|
_GCC_FILE_LINE_RE + r'instantiated from here\n'
|
||||||
|
r'.*error: no matching function for call to \'ImplicitCast_\('
|
||||||
|
r'(:?long )?int&\)')
|
||||||
|
clang_regex = (r'\bgmock-actions.h:.* error: no matching function for '
|
||||||
|
r'call to \'ImplicitCast_\'\r?\n'
|
||||||
|
r'(.*\n)*?' +
|
||||||
|
_CLANG_NON_GMOCK_FILE_LINE_RE + r'note: in instantiation '
|
||||||
|
r'of function template specialization '
|
||||||
|
r'\'testing::internal::ReturnAction<(int|long)>::operator '
|
||||||
|
r'Action<(?P<type>.*)\(\)>\' requested here')
|
||||||
|
diagnosis = """
|
||||||
|
You are probably calling Return(NULL) and the compiler isn't sure how to turn
|
||||||
|
NULL into %(type)s. Use ReturnNull() instead.
|
||||||
|
Note: the line number may be off; please fix all instances of Return(NULL)."""
|
||||||
|
return _GenericDiagnoser(
|
||||||
|
'NRNULL', 'Need to use ReturnNull',
|
||||||
|
[(clang_regex, diagnosis),
|
||||||
|
(gcc_regex, diagnosis % {'type': 'the right type'})],
|
||||||
|
msg)
|
||||||
|
|
||||||
|
|
||||||
|
def _TypeInTemplatedBaseDiagnoser(msg):
|
||||||
|
"""Diagnoses the TTB disease, given the error messages by the compiler."""
|
||||||
|
|
||||||
|
# This version works when the type is used as the mock function's return
|
||||||
|
# type.
|
||||||
|
gcc_4_3_1_regex_type_in_retval = (
|
||||||
|
r'In member function \'int .*\n' + _GCC_FILE_LINE_RE +
|
||||||
|
r'error: a function call cannot appear in a constant-expression')
|
||||||
|
gcc_4_4_0_regex_type_in_retval = (
|
||||||
|
r'error: a function call cannot appear in a constant-expression'
|
||||||
|
+ _GCC_FILE_LINE_RE + r'error: template argument 1 is invalid\n')
|
||||||
|
# This version works when the type is used as the mock function's sole
|
||||||
|
# parameter type.
|
||||||
|
gcc_regex_type_of_sole_param = (
|
||||||
|
_GCC_FILE_LINE_RE +
|
||||||
|
r'error: \'(?P<type>.+)\' was not declared in this scope\n'
|
||||||
|
r'.*error: template argument 1 is invalid\n')
|
||||||
|
# This version works when the type is used as a parameter of a mock
|
||||||
|
# function that has multiple parameters.
|
||||||
|
gcc_regex_type_of_a_param = (
|
||||||
|
r'error: expected `;\' before \'::\' token\n'
|
||||||
|
+ _GCC_FILE_LINE_RE +
|
||||||
|
r'error: \'(?P<type>.+)\' was not declared in this scope\n'
|
||||||
|
r'.*error: template argument 1 is invalid\n'
|
||||||
|
r'.*error: \'.+\' was not declared in this scope')
|
||||||
|
clang_regex_type_of_retval_or_sole_param = (
|
||||||
|
_CLANG_FILE_LINE_RE +
|
||||||
|
r'error: use of undeclared identifier \'(?P<type>.*)\'\n'
|
||||||
|
r'(.*\n)*?'
|
||||||
|
r'(?P=file):(?P=line):\d+: error: '
|
||||||
|
r'non-friend class member \'Result\' cannot have a qualified name'
|
||||||
|
)
|
||||||
|
clang_regex_type_of_a_param = (
|
||||||
|
_CLANG_FILE_LINE_RE +
|
||||||
|
r'error: C\+\+ requires a type specifier for all declarations\n'
|
||||||
|
r'(.*\n)*?'
|
||||||
|
r'(?P=file):(?P=line):(?P=column): error: '
|
||||||
|
r'C\+\+ requires a type specifier for all declarations'
|
||||||
|
)
|
||||||
|
clang_regex_unknown_type = (
|
||||||
|
_CLANG_FILE_LINE_RE +
|
||||||
|
r'error: unknown type name \'(?P<type>[^\']+)\''
|
||||||
|
)
|
||||||
|
|
||||||
|
diagnosis = """
|
||||||
|
In a mock class template, types or typedefs defined in the base class
|
||||||
|
template are *not* automatically visible. This is how C++ works. Before
|
||||||
|
you can use a type or typedef named %(type)s defined in base class Base<T>, you
|
||||||
|
need to make it visible. One way to do it is:
|
||||||
|
|
||||||
|
typedef typename Base<T>::%(type)s %(type)s;"""
|
||||||
|
|
||||||
|
for diag in _GenericDiagnoser(
|
||||||
|
'TTB', 'Type in Template Base',
|
||||||
|
[(gcc_4_3_1_regex_type_in_retval, diagnosis % {'type': 'Foo'}),
|
||||||
|
(gcc_4_4_0_regex_type_in_retval, diagnosis % {'type': 'Foo'}),
|
||||||
|
(gcc_regex_type_of_sole_param, diagnosis),
|
||||||
|
(gcc_regex_type_of_a_param, diagnosis),
|
||||||
|
(clang_regex_type_of_retval_or_sole_param, diagnosis),
|
||||||
|
(clang_regex_type_of_a_param, diagnosis % {'type': 'Foo'})],
|
||||||
|
msg):
|
||||||
|
yield diag
|
||||||
|
# Avoid overlap with the NUS pattern.
|
||||||
|
for m in _FindAllMatches(clang_regex_unknown_type, msg):
|
||||||
|
type_ = m.groupdict()['type']
|
||||||
|
if type_ not in _COMMON_GMOCK_SYMBOLS:
|
||||||
|
yield ('TTB', 'Type in Template Base', diagnosis % m.groupdict())
|
||||||
|
|
||||||
|
|
||||||
|
def _WrongMockMethodMacroDiagnoser(msg):
|
||||||
|
"""Diagnoses the WMM disease, given the error messages by the compiler."""
|
||||||
|
|
||||||
|
gcc_regex = (_GCC_FILE_LINE_RE +
|
||||||
|
r'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n'
|
||||||
|
r'.*\n'
|
||||||
|
r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>')
|
||||||
|
clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
|
||||||
|
r'error:.*array.*negative.*r?\n'
|
||||||
|
r'(.*\n)*?'
|
||||||
|
r'(?P=file):(?P=line):(?P=column): error: too few arguments '
|
||||||
|
r'to function call, expected (?P<args>\d+), '
|
||||||
|
r'have (?P<wrong_args>\d+)')
|
||||||
|
clang11_re = (_CLANG_NON_GMOCK_FILE_LINE_RE +
|
||||||
|
r'.*this_method_does_not_take_'
|
||||||
|
r'(?P<wrong_args>\d+)_argument.*')
|
||||||
|
diagnosis = """
|
||||||
|
You are using MOCK_METHOD%(wrong_args)s to define a mock method that has
|
||||||
|
%(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s,
|
||||||
|
MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead."""
|
||||||
|
return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn Macro',
|
||||||
|
[(gcc_regex, diagnosis),
|
||||||
|
(clang11_re, diagnosis % {'wrong_args': 'm',
|
||||||
|
'args': 'n'}),
|
||||||
|
(clang_regex, diagnosis)],
|
||||||
|
msg)
|
||||||
|
|
||||||
|
|
||||||
|
def _WrongParenPositionDiagnoser(msg):
|
||||||
|
"""Diagnoses the WPP disease, given the error messages by the compiler."""
|
||||||
|
|
||||||
|
gcc_regex = (_GCC_FILE_LINE_RE +
|
||||||
|
r'error:.*testing::internal::MockSpec<.* has no member named \''
|
||||||
|
r'(?P<method>\w+)\'')
|
||||||
|
clang_regex = (_CLANG_NON_GMOCK_FILE_LINE_RE +
|
||||||
|
r'error: no member named \'(?P<method>\w+)\' in '
|
||||||
|
r'\'testing::internal::MockSpec<.*>\'')
|
||||||
|
diagnosis = """
|
||||||
|
The closing parenthesis of ON_CALL or EXPECT_CALL should be *before*
|
||||||
|
".%(method)s". For example, you should write:
|
||||||
|
EXPECT_CALL(my_mock, Foo(_)).%(method)s(...);
|
||||||
|
instead of:
|
||||||
|
EXPECT_CALL(my_mock, Foo(_).%(method)s(...));"""
|
||||||
|
return _GenericDiagnoser('WPP', 'Wrong Parenthesis Position',
|
||||||
|
[(gcc_regex, diagnosis),
|
||||||
|
(clang_regex, diagnosis)],
|
||||||
|
msg)
|
||||||
|
|
||||||
|
|
||||||
|
_DIAGNOSERS = [
|
||||||
|
_IncompleteByReferenceArgumentDiagnoser,
|
||||||
|
_MockObjectPointerDiagnoser,
|
||||||
|
_NeedToReturnNothingDiagnoser,
|
||||||
|
_NeedToReturnReferenceDiagnoser,
|
||||||
|
_NeedToReturnSomethingDiagnoser,
|
||||||
|
_NeedToUseReturnNullDiagnoser,
|
||||||
|
_NeedToUseSymbolDiagnoser,
|
||||||
|
_OverloadedFunctionActionDiagnoser,
|
||||||
|
_OverloadedFunctionMatcherDiagnoser,
|
||||||
|
_OverloadedMethodActionDiagnoser,
|
||||||
|
_TypeInTemplatedBaseDiagnoser,
|
||||||
|
_WrongMockMethodMacroDiagnoser,
|
||||||
|
_WrongParenPositionDiagnoser,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def Diagnose(msg):
|
||||||
|
"""Generates all possible diagnoses given the compiler error message."""
|
||||||
|
|
||||||
|
msg = re.sub(r'\x1b\[[^m]*m', '', msg) # Strips all color formatting.
|
||||||
|
# Assuming the string is using the UTF-8 encoding, replaces the left and
|
||||||
|
# the right single quote characters with apostrophes.
|
||||||
|
msg = re.sub(r'(\xe2\x80\x98|\xe2\x80\x99)', "'", msg)
|
||||||
|
|
||||||
|
diagnoses = []
|
||||||
|
for diagnoser in _DIAGNOSERS:
|
||||||
|
for diag in diagnoser(msg):
|
||||||
|
diagnosis = '[%s - %s]\n%s' % diag
|
||||||
|
if not diagnosis in diagnoses:
|
||||||
|
diagnoses.append(diagnosis)
|
||||||
|
return diagnoses
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print ('Google Mock Doctor v%s - '
|
||||||
|
'diagnoses problems in code using Google Mock.' % _VERSION)
|
||||||
|
|
||||||
|
if sys.stdin.isatty():
|
||||||
|
print ('Please copy and paste the compiler errors here. Press c-D when '
|
||||||
|
'you are done:')
|
||||||
|
else:
|
||||||
|
print ('Waiting for compiler errors on stdin . . .')
|
||||||
|
|
||||||
|
msg = sys.stdin.read().strip()
|
||||||
|
diagnoses = Diagnose(msg)
|
||||||
|
count = len(diagnoses)
|
||||||
|
if not count:
|
||||||
|
print ("""
|
||||||
|
Your compiler complained:
|
||||||
|
8<------------------------------------------------------------
|
||||||
|
%s
|
||||||
|
------------------------------------------------------------>8
|
||||||
|
|
||||||
|
Uh-oh, I'm not smart enough to figure out what the problem is. :-(
|
||||||
|
However...
|
||||||
|
If you send your source code and the compiler's error messages to
|
||||||
|
%s, you can be helped and I can get smarter --
|
||||||
|
win-win for us!""" % (msg, _EMAIL))
|
||||||
|
else:
|
||||||
|
print ('------------------------------------------------------------')
|
||||||
|
print ('Your code appears to have the following',)
|
||||||
|
if count > 1:
|
||||||
|
print ('%s diseases:' % (count,))
|
||||||
|
else:
|
||||||
|
print ('disease:')
|
||||||
|
i = 0
|
||||||
|
for d in diagnoses:
|
||||||
|
i += 1
|
||||||
|
if count > 1:
|
||||||
|
print ('\n#%s:' % (i,))
|
||||||
|
print (d)
|
||||||
|
print ("""
|
||||||
|
How did I do? If you think I'm wrong or unhelpful, please send your
|
||||||
|
source code and the compiler's error messages to %s.
|
||||||
|
Then you can be helped and I can get smarter -- I promise I won't be upset!""" %
|
||||||
|
_EMAIL)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,78 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright 2009, 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.
|
||||||
|
|
||||||
|
"""upload_gmock.py v0.1.0 -- uploads a Google Mock patch for review.
|
||||||
|
|
||||||
|
This simple wrapper passes all command line flags and
|
||||||
|
--cc=googlemock@googlegroups.com to upload.py.
|
||||||
|
|
||||||
|
USAGE: upload_gmock.py [options for upload.py]
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = 'wan@google.com (Zhanyong Wan)'
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
CC_FLAG = '--cc='
|
||||||
|
GMOCK_GROUP = 'googlemock@googlegroups.com'
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Finds the path to upload.py, assuming it is in the same directory
|
||||||
|
# as this file.
|
||||||
|
my_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
upload_py_path = os.path.join(my_dir, 'upload.py')
|
||||||
|
|
||||||
|
# Adds Google Mock discussion group to the cc line if it's not there
|
||||||
|
# already.
|
||||||
|
upload_py_argv = [upload_py_path]
|
||||||
|
found_cc_flag = False
|
||||||
|
for arg in sys.argv[1:]:
|
||||||
|
if arg.startswith(CC_FLAG):
|
||||||
|
found_cc_flag = True
|
||||||
|
cc_line = arg[len(CC_FLAG):]
|
||||||
|
cc_list = [addr for addr in cc_line.split(',') if addr]
|
||||||
|
if GMOCK_GROUP not in cc_list:
|
||||||
|
cc_list.append(GMOCK_GROUP)
|
||||||
|
upload_py_argv.append(CC_FLAG + ','.join(cc_list))
|
||||||
|
else:
|
||||||
|
upload_py_argv.append(arg)
|
||||||
|
|
||||||
|
if not found_cc_flag:
|
||||||
|
upload_py_argv.append(CC_FLAG + GMOCK_GROUP)
|
||||||
|
|
||||||
|
# Invokes upload.py with the modified command line flags.
|
||||||
|
os.execv(upload_py_path, upload_py_argv)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2008, 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.
|
||||||
|
|
||||||
|
//
|
||||||
|
// Google C++ Mocking Framework (Google Mock)
|
||||||
|
//
|
||||||
|
// This file #includes all Google Mock implementation .cc files. The
|
||||||
|
// purpose is to allow a user to build Google Mock by compiling this
|
||||||
|
// file alone.
|
||||||
|
|
||||||
|
// This line ensures that gmock.h can be compiled on its own, even
|
||||||
|
// when it's fused.
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
|
||||||
|
// The following lines pull in the real gmock *.cc files.
|
||||||
|
#include "src/gmock-cardinalities.cc"
|
||||||
|
#include "src/gmock-internal-utils.cc"
|
||||||
|
#include "src/gmock-matchers.cc"
|
||||||
|
#include "src/gmock-spec-builders.cc"
|
||||||
|
#include "src/gmock.cc"
|
@ -0,0 +1,155 @@
|
|||||||
|
// Copyright 2007, 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.
|
||||||
|
|
||||||
|
|
||||||
|
// Google Mock - a framework for writing C++ mock classes.
|
||||||
|
//
|
||||||
|
// This file implements cardinalities.
|
||||||
|
|
||||||
|
#include "gmock/gmock-cardinalities.h"
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <ostream> // NOLINT
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include "gmock/internal/gmock-internal-utils.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Implements the Between(m, n) cardinality.
|
||||||
|
class BetweenCardinalityImpl : public CardinalityInterface {
|
||||||
|
public:
|
||||||
|
BetweenCardinalityImpl(int min, int max)
|
||||||
|
: min_(min >= 0 ? min : 0),
|
||||||
|
max_(max >= min_ ? max : min_) {
|
||||||
|
std::stringstream ss;
|
||||||
|
if (min < 0) {
|
||||||
|
ss << "The invocation lower bound must be >= 0, "
|
||||||
|
<< "but is actually " << min << ".";
|
||||||
|
internal::Expect(false, __FILE__, __LINE__, ss.str());
|
||||||
|
} else if (max < 0) {
|
||||||
|
ss << "The invocation upper bound must be >= 0, "
|
||||||
|
<< "but is actually " << max << ".";
|
||||||
|
internal::Expect(false, __FILE__, __LINE__, ss.str());
|
||||||
|
} else if (min > max) {
|
||||||
|
ss << "The invocation upper bound (" << max
|
||||||
|
<< ") must be >= the invocation lower bound (" << min
|
||||||
|
<< ").";
|
||||||
|
internal::Expect(false, __FILE__, __LINE__, ss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conservative estimate on the lower/upper bound of the number of
|
||||||
|
// calls allowed.
|
||||||
|
int ConservativeLowerBound() const override { return min_; }
|
||||||
|
int ConservativeUpperBound() const override { return max_; }
|
||||||
|
|
||||||
|
bool IsSatisfiedByCallCount(int call_count) const override {
|
||||||
|
return min_ <= call_count && call_count <= max_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSaturatedByCallCount(int call_count) const override {
|
||||||
|
return call_count >= max_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DescribeTo(::std::ostream* os) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const int min_;
|
||||||
|
const int max_;
|
||||||
|
|
||||||
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(BetweenCardinalityImpl);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Formats "n times" in a human-friendly way.
|
||||||
|
inline std::string FormatTimes(int n) {
|
||||||
|
if (n == 1) {
|
||||||
|
return "once";
|
||||||
|
} else if (n == 2) {
|
||||||
|
return "twice";
|
||||||
|
} else {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << n << " times";
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describes the Between(m, n) cardinality in human-friendly text.
|
||||||
|
void BetweenCardinalityImpl::DescribeTo(::std::ostream* os) const {
|
||||||
|
if (min_ == 0) {
|
||||||
|
if (max_ == 0) {
|
||||||
|
*os << "never called";
|
||||||
|
} else if (max_ == INT_MAX) {
|
||||||
|
*os << "called any number of times";
|
||||||
|
} else {
|
||||||
|
*os << "called at most " << FormatTimes(max_);
|
||||||
|
}
|
||||||
|
} else if (min_ == max_) {
|
||||||
|
*os << "called " << FormatTimes(min_);
|
||||||
|
} else if (max_ == INT_MAX) {
|
||||||
|
*os << "called at least " << FormatTimes(min_);
|
||||||
|
} else {
|
||||||
|
// 0 < min_ < max_ < INT_MAX
|
||||||
|
*os << "called between " << min_ << " and " << max_ << " times";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Unnamed namespace
|
||||||
|
|
||||||
|
// Describes the given call count to an ostream.
|
||||||
|
void Cardinality::DescribeActualCallCountTo(int actual_call_count,
|
||||||
|
::std::ostream* os) {
|
||||||
|
if (actual_call_count > 0) {
|
||||||
|
*os << "called " << FormatTimes(actual_call_count);
|
||||||
|
} else {
|
||||||
|
*os << "never called";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a cardinality that allows at least n calls.
|
||||||
|
GTEST_API_ Cardinality AtLeast(int n) { return Between(n, INT_MAX); }
|
||||||
|
|
||||||
|
// Creates a cardinality that allows at most n calls.
|
||||||
|
GTEST_API_ Cardinality AtMost(int n) { return Between(0, n); }
|
||||||
|
|
||||||
|
// Creates a cardinality that allows any number of calls.
|
||||||
|
GTEST_API_ Cardinality AnyNumber() { return AtLeast(0); }
|
||||||
|
|
||||||
|
// Creates a cardinality that allows between min and max calls.
|
||||||
|
GTEST_API_ Cardinality Between(int min, int max) {
|
||||||
|
return Cardinality(new BetweenCardinalityImpl(min, max));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a cardinality that allows exactly n calls.
|
||||||
|
GTEST_API_ Cardinality Exactly(int n) { return Between(n, n); }
|
||||||
|
|
||||||
|
} // namespace testing
|
@ -0,0 +1,200 @@
|
|||||||
|
// Copyright 2007, 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.
|
||||||
|
|
||||||
|
|
||||||
|
// Google Mock - a framework for writing C++ mock classes.
|
||||||
|
//
|
||||||
|
// This file defines some utilities useful for implementing Google
|
||||||
|
// Mock. They are subject to change without notice, so please DO NOT
|
||||||
|
// USE THEM IN USER CODE.
|
||||||
|
|
||||||
|
#include "gmock/internal/gmock-internal-utils.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <ostream> // NOLINT
|
||||||
|
#include <string>
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
#include "gmock/internal/gmock-port.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// Joins a vector of strings as if they are fields of a tuple; returns
|
||||||
|
// the joined string.
|
||||||
|
GTEST_API_ std::string JoinAsTuple(const Strings& fields) {
|
||||||
|
switch (fields.size()) {
|
||||||
|
case 0:
|
||||||
|
return "";
|
||||||
|
case 1:
|
||||||
|
return fields[0];
|
||||||
|
default:
|
||||||
|
std::string result = "(" + fields[0];
|
||||||
|
for (size_t i = 1; i < fields.size(); i++) {
|
||||||
|
result += ", ";
|
||||||
|
result += fields[i];
|
||||||
|
}
|
||||||
|
result += ")";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts an identifier name to a space-separated list of lower-case
|
||||||
|
// words. Each maximum substring of the form [A-Za-z][a-z]*|\d+ is
|
||||||
|
// treated as one word. For example, both "FooBar123" and
|
||||||
|
// "foo_bar_123" are converted to "foo bar 123".
|
||||||
|
GTEST_API_ std::string ConvertIdentifierNameToWords(const char* id_name) {
|
||||||
|
std::string result;
|
||||||
|
char prev_char = '\0';
|
||||||
|
for (const char* p = id_name; *p != '\0'; prev_char = *(p++)) {
|
||||||
|
// We don't care about the current locale as the input is
|
||||||
|
// guaranteed to be a valid C++ identifier name.
|
||||||
|
const bool starts_new_word = IsUpper(*p) ||
|
||||||
|
(!IsAlpha(prev_char) && IsLower(*p)) ||
|
||||||
|
(!IsDigit(prev_char) && IsDigit(*p));
|
||||||
|
|
||||||
|
if (IsAlNum(*p)) {
|
||||||
|
if (starts_new_word && result != "")
|
||||||
|
result += ' ';
|
||||||
|
result += ToLower(*p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This class reports Google Mock failures as Google Test failures. A
|
||||||
|
// user can define another class in a similar fashion if they intend to
|
||||||
|
// use Google Mock with a testing framework other than Google Test.
|
||||||
|
class GoogleTestFailureReporter : public FailureReporterInterface {
|
||||||
|
public:
|
||||||
|
void ReportFailure(FailureType type, const char* file, int line,
|
||||||
|
const std::string& message) override {
|
||||||
|
AssertHelper(type == kFatal ?
|
||||||
|
TestPartResult::kFatalFailure :
|
||||||
|
TestPartResult::kNonFatalFailure,
|
||||||
|
file,
|
||||||
|
line,
|
||||||
|
message.c_str()) = Message();
|
||||||
|
if (type == kFatal) {
|
||||||
|
posix::Abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns the global failure reporter. Will create a
|
||||||
|
// GoogleTestFailureReporter and return it the first time called.
|
||||||
|
GTEST_API_ FailureReporterInterface* GetFailureReporter() {
|
||||||
|
// Points to the global failure reporter used by Google Mock. gcc
|
||||||
|
// guarantees that the following use of failure_reporter is
|
||||||
|
// thread-safe. We may need to add additional synchronization to
|
||||||
|
// protect failure_reporter if we port Google Mock to other
|
||||||
|
// compilers.
|
||||||
|
static FailureReporterInterface* const failure_reporter =
|
||||||
|
new GoogleTestFailureReporter();
|
||||||
|
return failure_reporter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protects global resources (stdout in particular) used by Log().
|
||||||
|
static GTEST_DEFINE_STATIC_MUTEX_(g_log_mutex);
|
||||||
|
|
||||||
|
// Returns true if and only if a log with the given severity is visible
|
||||||
|
// according to the --gmock_verbose flag.
|
||||||
|
GTEST_API_ bool LogIsVisible(LogSeverity severity) {
|
||||||
|
if (GMOCK_FLAG(verbose) == kInfoVerbosity) {
|
||||||
|
// Always show the log if --gmock_verbose=info.
|
||||||
|
return true;
|
||||||
|
} else if (GMOCK_FLAG(verbose) == kErrorVerbosity) {
|
||||||
|
// Always hide it if --gmock_verbose=error.
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// If --gmock_verbose is neither "info" nor "error", we treat it
|
||||||
|
// as "warning" (its default value).
|
||||||
|
return severity == kWarning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the given message to stdout if and only if 'severity' >= the level
|
||||||
|
// specified by the --gmock_verbose flag. If stack_frames_to_skip >=
|
||||||
|
// 0, also prints the stack trace excluding the top
|
||||||
|
// stack_frames_to_skip frames. In opt mode, any positive
|
||||||
|
// stack_frames_to_skip is treated as 0, since we don't know which
|
||||||
|
// function calls will be inlined by the compiler and need to be
|
||||||
|
// conservative.
|
||||||
|
GTEST_API_ void Log(LogSeverity severity, const std::string& message,
|
||||||
|
int stack_frames_to_skip) {
|
||||||
|
if (!LogIsVisible(severity))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Ensures that logs from different threads don't interleave.
|
||||||
|
MutexLock l(&g_log_mutex);
|
||||||
|
|
||||||
|
if (severity == kWarning) {
|
||||||
|
// Prints a GMOCK WARNING marker to make the warnings easily searchable.
|
||||||
|
std::cout << "\nGMOCK WARNING:";
|
||||||
|
}
|
||||||
|
// Pre-pends a new-line to message if it doesn't start with one.
|
||||||
|
if (message.empty() || message[0] != '\n') {
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
std::cout << message;
|
||||||
|
if (stack_frames_to_skip >= 0) {
|
||||||
|
#ifdef NDEBUG
|
||||||
|
// In opt mode, we have to be conservative and skip no stack frame.
|
||||||
|
const int actual_to_skip = 0;
|
||||||
|
#else
|
||||||
|
// In dbg mode, we can do what the caller tell us to do (plus one
|
||||||
|
// for skipping this function's stack frame).
|
||||||
|
const int actual_to_skip = stack_frames_to_skip + 1;
|
||||||
|
#endif // NDEBUG
|
||||||
|
|
||||||
|
// Appends a new-line to message if it doesn't end with one.
|
||||||
|
if (!message.empty() && *message.rbegin() != '\n') {
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
std::cout << "Stack trace:\n"
|
||||||
|
<< ::testing::internal::GetCurrentOsStackTraceExceptTop(
|
||||||
|
::testing::UnitTest::GetInstance(), actual_to_skip);
|
||||||
|
}
|
||||||
|
std::cout << ::std::flush;
|
||||||
|
}
|
||||||
|
|
||||||
|
GTEST_API_ WithoutMatchers GetWithoutMatchers() { return WithoutMatchers(); }
|
||||||
|
|
||||||
|
GTEST_API_ void IllegalDoDefault(const char* file, int line) {
|
||||||
|
internal::Assert(
|
||||||
|
false, file, line,
|
||||||
|
"You are using DoDefault() inside a composite action like "
|
||||||
|
"DoAll() or WithArgs(). This is not supported for technical "
|
||||||
|
"reasons. Please instead spell out the default action, or "
|
||||||
|
"assign the default action to an Action variable and use "
|
||||||
|
"the variable in various places.");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace testing
|
@ -0,0 +1,462 @@
|
|||||||
|
// Copyright 2007, 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.
|
||||||
|
|
||||||
|
|
||||||
|
// Google Mock - a framework for writing C++ mock classes.
|
||||||
|
//
|
||||||
|
// This file implements Matcher<const string&>, Matcher<string>, and
|
||||||
|
// utilities for defining matchers.
|
||||||
|
|
||||||
|
#include "gmock/gmock-matchers.h"
|
||||||
|
#include "gmock/gmock-generated-matchers.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// Returns the description for a matcher defined using the MATCHER*()
|
||||||
|
// macro where the user-supplied description string is "", if
|
||||||
|
// 'negation' is false; otherwise returns the description of the
|
||||||
|
// negation of the matcher. 'param_values' contains a list of strings
|
||||||
|
// that are the print-out of the matcher's parameters.
|
||||||
|
GTEST_API_ std::string FormatMatcherDescription(bool negation,
|
||||||
|
const char* matcher_name,
|
||||||
|
const Strings& param_values) {
|
||||||
|
std::string result = ConvertIdentifierNameToWords(matcher_name);
|
||||||
|
if (param_values.size() >= 1) result += " " + JoinAsTuple(param_values);
|
||||||
|
return negation ? "not (" + result + ")" : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindMaxBipartiteMatching and its helper class.
|
||||||
|
//
|
||||||
|
// Uses the well-known Ford-Fulkerson max flow method to find a maximum
|
||||||
|
// bipartite matching. Flow is considered to be from left to right.
|
||||||
|
// There is an implicit source node that is connected to all of the left
|
||||||
|
// nodes, and an implicit sink node that is connected to all of the
|
||||||
|
// right nodes. All edges have unit capacity.
|
||||||
|
//
|
||||||
|
// Neither the flow graph nor the residual flow graph are represented
|
||||||
|
// explicitly. Instead, they are implied by the information in 'graph' and
|
||||||
|
// a vector<int> called 'left_' whose elements are initialized to the
|
||||||
|
// value kUnused. This represents the initial state of the algorithm,
|
||||||
|
// where the flow graph is empty, and the residual flow graph has the
|
||||||
|
// following edges:
|
||||||
|
// - An edge from source to each left_ node
|
||||||
|
// - An edge from each right_ node to sink
|
||||||
|
// - An edge from each left_ node to each right_ node, if the
|
||||||
|
// corresponding edge exists in 'graph'.
|
||||||
|
//
|
||||||
|
// When the TryAugment() method adds a flow, it sets left_[l] = r for some
|
||||||
|
// nodes l and r. This induces the following changes:
|
||||||
|
// - The edges (source, l), (l, r), and (r, sink) are added to the
|
||||||
|
// flow graph.
|
||||||
|
// - The same three edges are removed from the residual flow graph.
|
||||||
|
// - The reverse edges (l, source), (r, l), and (sink, r) are added
|
||||||
|
// to the residual flow graph, which is a directional graph
|
||||||
|
// representing unused flow capacity.
|
||||||
|
//
|
||||||
|
// When the method augments a flow (moving left_[l] from some r1 to some
|
||||||
|
// other r2), this can be thought of as "undoing" the above steps with
|
||||||
|
// respect to r1 and "redoing" them with respect to r2.
|
||||||
|
//
|
||||||
|
// It bears repeating that the flow graph and residual flow graph are
|
||||||
|
// never represented explicitly, but can be derived by looking at the
|
||||||
|
// information in 'graph' and in left_.
|
||||||
|
//
|
||||||
|
// As an optimization, there is a second vector<int> called right_ which
|
||||||
|
// does not provide any new information. Instead, it enables more
|
||||||
|
// efficient queries about edges entering or leaving the right-side nodes
|
||||||
|
// of the flow or residual flow graphs. The following invariants are
|
||||||
|
// maintained:
|
||||||
|
//
|
||||||
|
// left[l] == kUnused or right[left[l]] == l
|
||||||
|
// right[r] == kUnused or left[right[r]] == r
|
||||||
|
//
|
||||||
|
// . [ source ] .
|
||||||
|
// . ||| .
|
||||||
|
// . ||| .
|
||||||
|
// . ||\--> left[0]=1 ---\ right[0]=-1 ----\ .
|
||||||
|
// . || | | .
|
||||||
|
// . |\---> left[1]=-1 \--> right[1]=0 ---\| .
|
||||||
|
// . | || .
|
||||||
|
// . \----> left[2]=2 ------> right[2]=2 --\|| .
|
||||||
|
// . ||| .
|
||||||
|
// . elements matchers vvv .
|
||||||
|
// . [ sink ] .
|
||||||
|
//
|
||||||
|
// See Also:
|
||||||
|
// [1] Cormen, et al (2001). "Section 26.2: The Ford-Fulkerson method".
|
||||||
|
// "Introduction to Algorithms (Second ed.)", pp. 651-664.
|
||||||
|
// [2] "Ford-Fulkerson algorithm", Wikipedia,
|
||||||
|
// 'http://en.wikipedia.org/wiki/Ford%E2%80%93Fulkerson_algorithm'
|
||||||
|
class MaxBipartiteMatchState {
|
||||||
|
public:
|
||||||
|
explicit MaxBipartiteMatchState(const MatchMatrix& graph)
|
||||||
|
: graph_(&graph),
|
||||||
|
left_(graph_->LhsSize(), kUnused),
|
||||||
|
right_(graph_->RhsSize(), kUnused) {}
|
||||||
|
|
||||||
|
// Returns the edges of a maximal match, each in the form {left, right}.
|
||||||
|
ElementMatcherPairs Compute() {
|
||||||
|
// 'seen' is used for path finding { 0: unseen, 1: seen }.
|
||||||
|
::std::vector<char> seen;
|
||||||
|
// Searches the residual flow graph for a path from each left node to
|
||||||
|
// the sink in the residual flow graph, and if one is found, add flow
|
||||||
|
// to the graph. It's okay to search through the left nodes once. The
|
||||||
|
// edge from the implicit source node to each previously-visited left
|
||||||
|
// node will have flow if that left node has any path to the sink
|
||||||
|
// whatsoever. Subsequent augmentations can only add flow to the
|
||||||
|
// network, and cannot take away that previous flow unit from the source.
|
||||||
|
// Since the source-to-left edge can only carry one flow unit (or,
|
||||||
|
// each element can be matched to only one matcher), there is no need
|
||||||
|
// to visit the left nodes more than once looking for augmented paths.
|
||||||
|
// The flow is known to be possible or impossible by looking at the
|
||||||
|
// node once.
|
||||||
|
for (size_t ilhs = 0; ilhs < graph_->LhsSize(); ++ilhs) {
|
||||||
|
// Reset the path-marking vector and try to find a path from
|
||||||
|
// source to sink starting at the left_[ilhs] node.
|
||||||
|
GTEST_CHECK_(left_[ilhs] == kUnused)
|
||||||
|
<< "ilhs: " << ilhs << ", left_[ilhs]: " << left_[ilhs];
|
||||||
|
// 'seen' initialized to 'graph_->RhsSize()' copies of 0.
|
||||||
|
seen.assign(graph_->RhsSize(), 0);
|
||||||
|
TryAugment(ilhs, &seen);
|
||||||
|
}
|
||||||
|
ElementMatcherPairs result;
|
||||||
|
for (size_t ilhs = 0; ilhs < left_.size(); ++ilhs) {
|
||||||
|
size_t irhs = left_[ilhs];
|
||||||
|
if (irhs == kUnused) continue;
|
||||||
|
result.push_back(ElementMatcherPair(ilhs, irhs));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const size_t kUnused = static_cast<size_t>(-1);
|
||||||
|
|
||||||
|
// Perform a depth-first search from left node ilhs to the sink. If a
|
||||||
|
// path is found, flow is added to the network by linking the left and
|
||||||
|
// right vector elements corresponding each segment of the path.
|
||||||
|
// Returns true if a path to sink was found, which means that a unit of
|
||||||
|
// flow was added to the network. The 'seen' vector elements correspond
|
||||||
|
// to right nodes and are marked to eliminate cycles from the search.
|
||||||
|
//
|
||||||
|
// Left nodes will only be explored at most once because they
|
||||||
|
// are accessible from at most one right node in the residual flow
|
||||||
|
// graph.
|
||||||
|
//
|
||||||
|
// Note that left_[ilhs] is the only element of left_ that TryAugment will
|
||||||
|
// potentially transition from kUnused to another value. Any other
|
||||||
|
// left_ element holding kUnused before TryAugment will be holding it
|
||||||
|
// when TryAugment returns.
|
||||||
|
//
|
||||||
|
bool TryAugment(size_t ilhs, ::std::vector<char>* seen) {
|
||||||
|
for (size_t irhs = 0; irhs < graph_->RhsSize(); ++irhs) {
|
||||||
|
if ((*seen)[irhs]) continue;
|
||||||
|
if (!graph_->HasEdge(ilhs, irhs)) continue;
|
||||||
|
// There's an available edge from ilhs to irhs.
|
||||||
|
(*seen)[irhs] = 1;
|
||||||
|
// Next a search is performed to determine whether
|
||||||
|
// this edge is a dead end or leads to the sink.
|
||||||
|
//
|
||||||
|
// right_[irhs] == kUnused means that there is residual flow from
|
||||||
|
// right node irhs to the sink, so we can use that to finish this
|
||||||
|
// flow path and return success.
|
||||||
|
//
|
||||||
|
// Otherwise there is residual flow to some ilhs. We push flow
|
||||||
|
// along that path and call ourselves recursively to see if this
|
||||||
|
// ultimately leads to sink.
|
||||||
|
if (right_[irhs] == kUnused || TryAugment(right_[irhs], seen)) {
|
||||||
|
// Add flow from left_[ilhs] to right_[irhs].
|
||||||
|
left_[ilhs] = irhs;
|
||||||
|
right_[irhs] = ilhs;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MatchMatrix* graph_; // not owned
|
||||||
|
// Each element of the left_ vector represents a left hand side node
|
||||||
|
// (i.e. an element) and each element of right_ is a right hand side
|
||||||
|
// node (i.e. a matcher). The values in the left_ vector indicate
|
||||||
|
// outflow from that node to a node on the right_ side. The values
|
||||||
|
// in the right_ indicate inflow, and specify which left_ node is
|
||||||
|
// feeding that right_ node, if any. For example, left_[3] == 1 means
|
||||||
|
// there's a flow from element #3 to matcher #1. Such a flow would also
|
||||||
|
// be redundantly represented in the right_ vector as right_[1] == 3.
|
||||||
|
// Elements of left_ and right_ are either kUnused or mutually
|
||||||
|
// referent. Mutually referent means that left_[right_[i]] = i and
|
||||||
|
// right_[left_[i]] = i.
|
||||||
|
::std::vector<size_t> left_;
|
||||||
|
::std::vector<size_t> right_;
|
||||||
|
|
||||||
|
GTEST_DISALLOW_ASSIGN_(MaxBipartiteMatchState);
|
||||||
|
};
|
||||||
|
|
||||||
|
const size_t MaxBipartiteMatchState::kUnused;
|
||||||
|
|
||||||
|
GTEST_API_ ElementMatcherPairs FindMaxBipartiteMatching(const MatchMatrix& g) {
|
||||||
|
return MaxBipartiteMatchState(g).Compute();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LogElementMatcherPairVec(const ElementMatcherPairs& pairs,
|
||||||
|
::std::ostream* stream) {
|
||||||
|
typedef ElementMatcherPairs::const_iterator Iter;
|
||||||
|
::std::ostream& os = *stream;
|
||||||
|
os << "{";
|
||||||
|
const char* sep = "";
|
||||||
|
for (Iter it = pairs.begin(); it != pairs.end(); ++it) {
|
||||||
|
os << sep << "\n ("
|
||||||
|
<< "element #" << it->first << ", "
|
||||||
|
<< "matcher #" << it->second << ")";
|
||||||
|
sep = ",";
|
||||||
|
}
|
||||||
|
os << "\n}";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatchMatrix::NextGraph() {
|
||||||
|
for (size_t ilhs = 0; ilhs < LhsSize(); ++ilhs) {
|
||||||
|
for (size_t irhs = 0; irhs < RhsSize(); ++irhs) {
|
||||||
|
char& b = matched_[SpaceIndex(ilhs, irhs)];
|
||||||
|
if (!b) {
|
||||||
|
b = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
b = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MatchMatrix::Randomize() {
|
||||||
|
for (size_t ilhs = 0; ilhs < LhsSize(); ++ilhs) {
|
||||||
|
for (size_t irhs = 0; irhs < RhsSize(); ++irhs) {
|
||||||
|
char& b = matched_[SpaceIndex(ilhs, irhs)];
|
||||||
|
b = static_cast<char>(rand() & 1); // NOLINT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MatchMatrix::DebugString() const {
|
||||||
|
::std::stringstream ss;
|
||||||
|
const char* sep = "";
|
||||||
|
for (size_t i = 0; i < LhsSize(); ++i) {
|
||||||
|
ss << sep;
|
||||||
|
for (size_t j = 0; j < RhsSize(); ++j) {
|
||||||
|
ss << HasEdge(i, j);
|
||||||
|
}
|
||||||
|
sep = ";";
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnorderedElementsAreMatcherImplBase::DescribeToImpl(
|
||||||
|
::std::ostream* os) const {
|
||||||
|
switch (match_flags()) {
|
||||||
|
case UnorderedMatcherRequire::ExactMatch:
|
||||||
|
if (matcher_describers_.empty()) {
|
||||||
|
*os << "is empty";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (matcher_describers_.size() == 1) {
|
||||||
|
*os << "has " << Elements(1) << " and that element ";
|
||||||
|
matcher_describers_[0]->DescribeTo(os);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*os << "has " << Elements(matcher_describers_.size())
|
||||||
|
<< " and there exists some permutation of elements such that:\n";
|
||||||
|
break;
|
||||||
|
case UnorderedMatcherRequire::Superset:
|
||||||
|
*os << "a surjection from elements to requirements exists such that:\n";
|
||||||
|
break;
|
||||||
|
case UnorderedMatcherRequire::Subset:
|
||||||
|
*os << "an injection from elements to requirements exists such that:\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* sep = "";
|
||||||
|
for (size_t i = 0; i != matcher_describers_.size(); ++i) {
|
||||||
|
*os << sep;
|
||||||
|
if (match_flags() == UnorderedMatcherRequire::ExactMatch) {
|
||||||
|
*os << " - element #" << i << " ";
|
||||||
|
} else {
|
||||||
|
*os << " - an element ";
|
||||||
|
}
|
||||||
|
matcher_describers_[i]->DescribeTo(os);
|
||||||
|
if (match_flags() == UnorderedMatcherRequire::ExactMatch) {
|
||||||
|
sep = ", and\n";
|
||||||
|
} else {
|
||||||
|
sep = "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnorderedElementsAreMatcherImplBase::DescribeNegationToImpl(
|
||||||
|
::std::ostream* os) const {
|
||||||
|
switch (match_flags()) {
|
||||||
|
case UnorderedMatcherRequire::ExactMatch:
|
||||||
|
if (matcher_describers_.empty()) {
|
||||||
|
*os << "isn't empty";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (matcher_describers_.size() == 1) {
|
||||||
|
*os << "doesn't have " << Elements(1) << ", or has " << Elements(1)
|
||||||
|
<< " that ";
|
||||||
|
matcher_describers_[0]->DescribeNegationTo(os);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*os << "doesn't have " << Elements(matcher_describers_.size())
|
||||||
|
<< ", or there exists no permutation of elements such that:\n";
|
||||||
|
break;
|
||||||
|
case UnorderedMatcherRequire::Superset:
|
||||||
|
*os << "no surjection from elements to requirements exists such that:\n";
|
||||||
|
break;
|
||||||
|
case UnorderedMatcherRequire::Subset:
|
||||||
|
*os << "no injection from elements to requirements exists such that:\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const char* sep = "";
|
||||||
|
for (size_t i = 0; i != matcher_describers_.size(); ++i) {
|
||||||
|
*os << sep;
|
||||||
|
if (match_flags() == UnorderedMatcherRequire::ExactMatch) {
|
||||||
|
*os << " - element #" << i << " ";
|
||||||
|
} else {
|
||||||
|
*os << " - an element ";
|
||||||
|
}
|
||||||
|
matcher_describers_[i]->DescribeTo(os);
|
||||||
|
if (match_flags() == UnorderedMatcherRequire::ExactMatch) {
|
||||||
|
sep = ", and\n";
|
||||||
|
} else {
|
||||||
|
sep = "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks that all matchers match at least one element, and that all
|
||||||
|
// elements match at least one matcher. This enables faster matching
|
||||||
|
// and better error reporting.
|
||||||
|
// Returns false, writing an explanation to 'listener', if and only
|
||||||
|
// if the success criteria are not met.
|
||||||
|
bool UnorderedElementsAreMatcherImplBase::VerifyMatchMatrix(
|
||||||
|
const ::std::vector<std::string>& element_printouts,
|
||||||
|
const MatchMatrix& matrix, MatchResultListener* listener) const {
|
||||||
|
bool result = true;
|
||||||
|
::std::vector<char> element_matched(matrix.LhsSize(), 0);
|
||||||
|
::std::vector<char> matcher_matched(matrix.RhsSize(), 0);
|
||||||
|
|
||||||
|
for (size_t ilhs = 0; ilhs < matrix.LhsSize(); ilhs++) {
|
||||||
|
for (size_t irhs = 0; irhs < matrix.RhsSize(); irhs++) {
|
||||||
|
char matched = matrix.HasEdge(ilhs, irhs);
|
||||||
|
element_matched[ilhs] |= matched;
|
||||||
|
matcher_matched[irhs] |= matched;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match_flags() & UnorderedMatcherRequire::Superset) {
|
||||||
|
const char* sep =
|
||||||
|
"where the following matchers don't match any elements:\n";
|
||||||
|
for (size_t mi = 0; mi < matcher_matched.size(); ++mi) {
|
||||||
|
if (matcher_matched[mi]) continue;
|
||||||
|
result = false;
|
||||||
|
if (listener->IsInterested()) {
|
||||||
|
*listener << sep << "matcher #" << mi << ": ";
|
||||||
|
matcher_describers_[mi]->DescribeTo(listener->stream());
|
||||||
|
sep = ",\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match_flags() & UnorderedMatcherRequire::Subset) {
|
||||||
|
const char* sep =
|
||||||
|
"where the following elements don't match any matchers:\n";
|
||||||
|
const char* outer_sep = "";
|
||||||
|
if (!result) {
|
||||||
|
outer_sep = "\nand ";
|
||||||
|
}
|
||||||
|
for (size_t ei = 0; ei < element_matched.size(); ++ei) {
|
||||||
|
if (element_matched[ei]) continue;
|
||||||
|
result = false;
|
||||||
|
if (listener->IsInterested()) {
|
||||||
|
*listener << outer_sep << sep << "element #" << ei << ": "
|
||||||
|
<< element_printouts[ei];
|
||||||
|
sep = ",\n";
|
||||||
|
outer_sep = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnorderedElementsAreMatcherImplBase::FindPairing(
|
||||||
|
const MatchMatrix& matrix, MatchResultListener* listener) const {
|
||||||
|
ElementMatcherPairs matches = FindMaxBipartiteMatching(matrix);
|
||||||
|
|
||||||
|
size_t max_flow = matches.size();
|
||||||
|
if ((match_flags() & UnorderedMatcherRequire::Superset) &&
|
||||||
|
max_flow < matrix.RhsSize()) {
|
||||||
|
if (listener->IsInterested()) {
|
||||||
|
*listener << "where no permutation of the elements can satisfy all "
|
||||||
|
"matchers, and the closest match is "
|
||||||
|
<< max_flow << " of " << matrix.RhsSize()
|
||||||
|
<< " matchers with the pairings:\n";
|
||||||
|
LogElementMatcherPairVec(matches, listener->stream());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((match_flags() & UnorderedMatcherRequire::Subset) &&
|
||||||
|
max_flow < matrix.LhsSize()) {
|
||||||
|
if (listener->IsInterested()) {
|
||||||
|
*listener
|
||||||
|
<< "where not all elements can be matched, and the closest match is "
|
||||||
|
<< max_flow << " of " << matrix.RhsSize()
|
||||||
|
<< " matchers with the pairings:\n";
|
||||||
|
LogElementMatcherPairVec(matches, listener->stream());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches.size() > 1) {
|
||||||
|
if (listener->IsInterested()) {
|
||||||
|
const char* sep = "where:\n";
|
||||||
|
for (size_t mi = 0; mi < matches.size(); ++mi) {
|
||||||
|
*listener << sep << " - element #" << matches[mi].first
|
||||||
|
<< " is matched by matcher #" << matches[mi].second;
|
||||||
|
sep = ",\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace testing
|
@ -0,0 +1,888 @@
|
|||||||
|
// Copyright 2007, 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.
|
||||||
|
|
||||||
|
|
||||||
|
// Google Mock - a framework for writing C++ mock classes.
|
||||||
|
//
|
||||||
|
// This file implements the spec builder syntax (ON_CALL and
|
||||||
|
// EXPECT_CALL).
|
||||||
|
|
||||||
|
#include "gmock/gmock-spec-builders.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <iostream> // NOLINT
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC
|
||||||
|
# include <unistd.h> // NOLINT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Silence C4800 (C4800: 'int *const ': forcing value
|
||||||
|
// to bool 'true' or 'false') for MSVC 15
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#if _MSC_VER == 1900
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning(disable:4800)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// Protects the mock object registry (in class Mock), all function
|
||||||
|
// mockers, and all expectations.
|
||||||
|
GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_gmock_mutex);
|
||||||
|
|
||||||
|
// Logs a message including file and line number information.
|
||||||
|
GTEST_API_ void LogWithLocation(testing::internal::LogSeverity severity,
|
||||||
|
const char* file, int line,
|
||||||
|
const std::string& message) {
|
||||||
|
::std::ostringstream s;
|
||||||
|
s << file << ":" << line << ": " << message << ::std::endl;
|
||||||
|
Log(severity, s.str(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs an ExpectationBase object.
|
||||||
|
ExpectationBase::ExpectationBase(const char* a_file, int a_line,
|
||||||
|
const std::string& a_source_text)
|
||||||
|
: file_(a_file),
|
||||||
|
line_(a_line),
|
||||||
|
source_text_(a_source_text),
|
||||||
|
cardinality_specified_(false),
|
||||||
|
cardinality_(Exactly(1)),
|
||||||
|
call_count_(0),
|
||||||
|
retired_(false),
|
||||||
|
extra_matcher_specified_(false),
|
||||||
|
repeated_action_specified_(false),
|
||||||
|
retires_on_saturation_(false),
|
||||||
|
last_clause_(kNone),
|
||||||
|
action_count_checked_(false) {}
|
||||||
|
|
||||||
|
// Destructs an ExpectationBase object.
|
||||||
|
ExpectationBase::~ExpectationBase() {}
|
||||||
|
|
||||||
|
// Explicitly specifies the cardinality of this expectation. Used by
|
||||||
|
// the subclasses to implement the .Times() clause.
|
||||||
|
void ExpectationBase::SpecifyCardinality(const Cardinality& a_cardinality) {
|
||||||
|
cardinality_specified_ = true;
|
||||||
|
cardinality_ = a_cardinality;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retires all pre-requisites of this expectation.
|
||||||
|
void ExpectationBase::RetireAllPreRequisites()
|
||||||
|
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
|
||||||
|
if (is_retired()) {
|
||||||
|
// We can take this short-cut as we never retire an expectation
|
||||||
|
// until we have retired all its pre-requisites.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
::std::vector<ExpectationBase*> expectations(1, this);
|
||||||
|
while (!expectations.empty()) {
|
||||||
|
ExpectationBase* exp = expectations.back();
|
||||||
|
expectations.pop_back();
|
||||||
|
|
||||||
|
for (ExpectationSet::const_iterator it =
|
||||||
|
exp->immediate_prerequisites_.begin();
|
||||||
|
it != exp->immediate_prerequisites_.end(); ++it) {
|
||||||
|
ExpectationBase* next = it->expectation_base().get();
|
||||||
|
if (!next->is_retired()) {
|
||||||
|
next->Retire();
|
||||||
|
expectations.push_back(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if and only if all pre-requisites of this expectation
|
||||||
|
// have been satisfied.
|
||||||
|
bool ExpectationBase::AllPrerequisitesAreSatisfied() const
|
||||||
|
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
|
||||||
|
g_gmock_mutex.AssertHeld();
|
||||||
|
::std::vector<const ExpectationBase*> expectations(1, this);
|
||||||
|
while (!expectations.empty()) {
|
||||||
|
const ExpectationBase* exp = expectations.back();
|
||||||
|
expectations.pop_back();
|
||||||
|
|
||||||
|
for (ExpectationSet::const_iterator it =
|
||||||
|
exp->immediate_prerequisites_.begin();
|
||||||
|
it != exp->immediate_prerequisites_.end(); ++it) {
|
||||||
|
const ExpectationBase* next = it->expectation_base().get();
|
||||||
|
if (!next->IsSatisfied()) return false;
|
||||||
|
expectations.push_back(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds unsatisfied pre-requisites of this expectation to 'result'.
|
||||||
|
void ExpectationBase::FindUnsatisfiedPrerequisites(ExpectationSet* result) const
|
||||||
|
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
|
||||||
|
g_gmock_mutex.AssertHeld();
|
||||||
|
::std::vector<const ExpectationBase*> expectations(1, this);
|
||||||
|
while (!expectations.empty()) {
|
||||||
|
const ExpectationBase* exp = expectations.back();
|
||||||
|
expectations.pop_back();
|
||||||
|
|
||||||
|
for (ExpectationSet::const_iterator it =
|
||||||
|
exp->immediate_prerequisites_.begin();
|
||||||
|
it != exp->immediate_prerequisites_.end(); ++it) {
|
||||||
|
const ExpectationBase* next = it->expectation_base().get();
|
||||||
|
|
||||||
|
if (next->IsSatisfied()) {
|
||||||
|
// If *it is satisfied and has a call count of 0, some of its
|
||||||
|
// pre-requisites may not be satisfied yet.
|
||||||
|
if (next->call_count_ == 0) {
|
||||||
|
expectations.push_back(next);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Now that we know next is unsatisfied, we are not so interested
|
||||||
|
// in whether its pre-requisites are satisfied. Therefore we
|
||||||
|
// don't iterate into it here.
|
||||||
|
*result += *it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describes how many times a function call matching this
|
||||||
|
// expectation has occurred.
|
||||||
|
void ExpectationBase::DescribeCallCountTo(::std::ostream* os) const
|
||||||
|
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
|
||||||
|
g_gmock_mutex.AssertHeld();
|
||||||
|
|
||||||
|
// Describes how many times the function is expected to be called.
|
||||||
|
*os << " Expected: to be ";
|
||||||
|
cardinality().DescribeTo(os);
|
||||||
|
*os << "\n Actual: ";
|
||||||
|
Cardinality::DescribeActualCallCountTo(call_count(), os);
|
||||||
|
|
||||||
|
// Describes the state of the expectation (e.g. is it satisfied?
|
||||||
|
// is it active?).
|
||||||
|
*os << " - " << (IsOverSaturated() ? "over-saturated" :
|
||||||
|
IsSaturated() ? "saturated" :
|
||||||
|
IsSatisfied() ? "satisfied" : "unsatisfied")
|
||||||
|
<< " and "
|
||||||
|
<< (is_retired() ? "retired" : "active");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks the action count (i.e. the number of WillOnce() and
|
||||||
|
// WillRepeatedly() clauses) against the cardinality if this hasn't
|
||||||
|
// been done before. Prints a warning if there are too many or too
|
||||||
|
// few actions.
|
||||||
|
void ExpectationBase::CheckActionCountIfNotDone() const
|
||||||
|
GTEST_LOCK_EXCLUDED_(mutex_) {
|
||||||
|
bool should_check = false;
|
||||||
|
{
|
||||||
|
MutexLock l(&mutex_);
|
||||||
|
if (!action_count_checked_) {
|
||||||
|
action_count_checked_ = true;
|
||||||
|
should_check = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_check) {
|
||||||
|
if (!cardinality_specified_) {
|
||||||
|
// The cardinality was inferred - no need to check the action
|
||||||
|
// count against it.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The cardinality was explicitly specified.
|
||||||
|
const int action_count = static_cast<int>(untyped_actions_.size());
|
||||||
|
const int upper_bound = cardinality().ConservativeUpperBound();
|
||||||
|
const int lower_bound = cardinality().ConservativeLowerBound();
|
||||||
|
bool too_many; // True if there are too many actions, or false
|
||||||
|
// if there are too few.
|
||||||
|
if (action_count > upper_bound ||
|
||||||
|
(action_count == upper_bound && repeated_action_specified_)) {
|
||||||
|
too_many = true;
|
||||||
|
} else if (0 < action_count && action_count < lower_bound &&
|
||||||
|
!repeated_action_specified_) {
|
||||||
|
too_many = false;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
::std::stringstream ss;
|
||||||
|
DescribeLocationTo(&ss);
|
||||||
|
ss << "Too " << (too_many ? "many" : "few")
|
||||||
|
<< " actions specified in " << source_text() << "...\n"
|
||||||
|
<< "Expected to be ";
|
||||||
|
cardinality().DescribeTo(&ss);
|
||||||
|
ss << ", but has " << (too_many ? "" : "only ")
|
||||||
|
<< action_count << " WillOnce()"
|
||||||
|
<< (action_count == 1 ? "" : "s");
|
||||||
|
if (repeated_action_specified_) {
|
||||||
|
ss << " and a WillRepeatedly()";
|
||||||
|
}
|
||||||
|
ss << ".";
|
||||||
|
Log(kWarning, ss.str(), -1); // -1 means "don't print stack trace".
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements the .Times() clause.
|
||||||
|
void ExpectationBase::UntypedTimes(const Cardinality& a_cardinality) {
|
||||||
|
if (last_clause_ == kTimes) {
|
||||||
|
ExpectSpecProperty(false,
|
||||||
|
".Times() cannot appear "
|
||||||
|
"more than once in an EXPECT_CALL().");
|
||||||
|
} else {
|
||||||
|
ExpectSpecProperty(last_clause_ < kTimes,
|
||||||
|
".Times() cannot appear after "
|
||||||
|
".InSequence(), .WillOnce(), .WillRepeatedly(), "
|
||||||
|
"or .RetiresOnSaturation().");
|
||||||
|
}
|
||||||
|
last_clause_ = kTimes;
|
||||||
|
|
||||||
|
SpecifyCardinality(a_cardinality);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Points to the implicit sequence introduced by a living InSequence
|
||||||
|
// object (if any) in the current thread or NULL.
|
||||||
|
GTEST_API_ ThreadLocal<Sequence*> g_gmock_implicit_sequence;
|
||||||
|
|
||||||
|
// Reports an uninteresting call (whose description is in msg) in the
|
||||||
|
// manner specified by 'reaction'.
|
||||||
|
void ReportUninterestingCall(CallReaction reaction, const std::string& msg) {
|
||||||
|
// Include a stack trace only if --gmock_verbose=info is specified.
|
||||||
|
const int stack_frames_to_skip =
|
||||||
|
GMOCK_FLAG(verbose) == kInfoVerbosity ? 3 : -1;
|
||||||
|
switch (reaction) {
|
||||||
|
case kAllow:
|
||||||
|
Log(kInfo, msg, stack_frames_to_skip);
|
||||||
|
break;
|
||||||
|
case kWarn:
|
||||||
|
Log(kWarning,
|
||||||
|
msg +
|
||||||
|
"\nNOTE: You can safely ignore the above warning unless this "
|
||||||
|
"call should not happen. Do not suppress it by blindly adding "
|
||||||
|
"an EXPECT_CALL() if you don't mean to enforce the call. "
|
||||||
|
"See "
|
||||||
|
"https://github.com/google/googletest/blob/master/googlemock/"
|
||||||
|
"docs/cook_book.md#"
|
||||||
|
"knowing-when-to-expect for details.\n",
|
||||||
|
stack_frames_to_skip);
|
||||||
|
break;
|
||||||
|
default: // FAIL
|
||||||
|
Expect(false, nullptr, -1, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UntypedFunctionMockerBase::UntypedFunctionMockerBase()
|
||||||
|
: mock_obj_(nullptr), name_("") {}
|
||||||
|
|
||||||
|
UntypedFunctionMockerBase::~UntypedFunctionMockerBase() {}
|
||||||
|
|
||||||
|
// Sets the mock object this mock method belongs to, and registers
|
||||||
|
// this information in the global mock registry. Will be called
|
||||||
|
// whenever an EXPECT_CALL() or ON_CALL() is executed on this mock
|
||||||
|
// method.
|
||||||
|
void UntypedFunctionMockerBase::RegisterOwner(const void* mock_obj)
|
||||||
|
GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
|
||||||
|
{
|
||||||
|
MutexLock l(&g_gmock_mutex);
|
||||||
|
mock_obj_ = mock_obj;
|
||||||
|
}
|
||||||
|
Mock::Register(mock_obj, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the mock object this mock method belongs to, and sets the name
|
||||||
|
// of the mock function. Will be called upon each invocation of this
|
||||||
|
// mock function.
|
||||||
|
void UntypedFunctionMockerBase::SetOwnerAndName(const void* mock_obj,
|
||||||
|
const char* name)
|
||||||
|
GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
|
||||||
|
// We protect name_ under g_gmock_mutex in case this mock function
|
||||||
|
// is called from two threads concurrently.
|
||||||
|
MutexLock l(&g_gmock_mutex);
|
||||||
|
mock_obj_ = mock_obj;
|
||||||
|
name_ = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the name of the function being mocked. Must be called
|
||||||
|
// after RegisterOwner() or SetOwnerAndName() has been called.
|
||||||
|
const void* UntypedFunctionMockerBase::MockObject() const
|
||||||
|
GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
|
||||||
|
const void* mock_obj;
|
||||||
|
{
|
||||||
|
// We protect mock_obj_ under g_gmock_mutex in case this mock
|
||||||
|
// function is called from two threads concurrently.
|
||||||
|
MutexLock l(&g_gmock_mutex);
|
||||||
|
Assert(mock_obj_ != nullptr, __FILE__, __LINE__,
|
||||||
|
"MockObject() must not be called before RegisterOwner() or "
|
||||||
|
"SetOwnerAndName() has been called.");
|
||||||
|
mock_obj = mock_obj_;
|
||||||
|
}
|
||||||
|
return mock_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the name of this mock method. Must be called after
|
||||||
|
// SetOwnerAndName() has been called.
|
||||||
|
const char* UntypedFunctionMockerBase::Name() const
|
||||||
|
GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
|
||||||
|
const char* name;
|
||||||
|
{
|
||||||
|
// We protect name_ under g_gmock_mutex in case this mock
|
||||||
|
// function is called from two threads concurrently.
|
||||||
|
MutexLock l(&g_gmock_mutex);
|
||||||
|
Assert(name_ != nullptr, __FILE__, __LINE__,
|
||||||
|
"Name() must not be called before SetOwnerAndName() has "
|
||||||
|
"been called.");
|
||||||
|
name = name_;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates the result of invoking this mock function with the given
|
||||||
|
// arguments, prints it, and returns it. The caller is responsible
|
||||||
|
// for deleting the result.
|
||||||
|
UntypedActionResultHolderBase* UntypedFunctionMockerBase::UntypedInvokeWith(
|
||||||
|
void* const untyped_args) GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
|
||||||
|
// See the definition of untyped_expectations_ for why access to it
|
||||||
|
// is unprotected here.
|
||||||
|
if (untyped_expectations_.size() == 0) {
|
||||||
|
// No expectation is set on this mock method - we have an
|
||||||
|
// uninteresting call.
|
||||||
|
|
||||||
|
// We must get Google Mock's reaction on uninteresting calls
|
||||||
|
// made on this mock object BEFORE performing the action,
|
||||||
|
// because the action may DELETE the mock object and make the
|
||||||
|
// following expression meaningless.
|
||||||
|
const CallReaction reaction =
|
||||||
|
Mock::GetReactionOnUninterestingCalls(MockObject());
|
||||||
|
|
||||||
|
// True if and only if we need to print this call's arguments and return
|
||||||
|
// value. This definition must be kept in sync with
|
||||||
|
// the behavior of ReportUninterestingCall().
|
||||||
|
const bool need_to_report_uninteresting_call =
|
||||||
|
// If the user allows this uninteresting call, we print it
|
||||||
|
// only when they want informational messages.
|
||||||
|
reaction == kAllow ? LogIsVisible(kInfo) :
|
||||||
|
// If the user wants this to be a warning, we print
|
||||||
|
// it only when they want to see warnings.
|
||||||
|
reaction == kWarn
|
||||||
|
? LogIsVisible(kWarning)
|
||||||
|
:
|
||||||
|
// Otherwise, the user wants this to be an error, and we
|
||||||
|
// should always print detailed information in the error.
|
||||||
|
true;
|
||||||
|
|
||||||
|
if (!need_to_report_uninteresting_call) {
|
||||||
|
// Perform the action without printing the call information.
|
||||||
|
return this->UntypedPerformDefaultAction(
|
||||||
|
untyped_args, "Function call: " + std::string(Name()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warns about the uninteresting call.
|
||||||
|
::std::stringstream ss;
|
||||||
|
this->UntypedDescribeUninterestingCall(untyped_args, &ss);
|
||||||
|
|
||||||
|
// Calculates the function result.
|
||||||
|
UntypedActionResultHolderBase* const result =
|
||||||
|
this->UntypedPerformDefaultAction(untyped_args, ss.str());
|
||||||
|
|
||||||
|
// Prints the function result.
|
||||||
|
if (result != nullptr) result->PrintAsActionResult(&ss);
|
||||||
|
|
||||||
|
ReportUninterestingCall(reaction, ss.str());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_excessive = false;
|
||||||
|
::std::stringstream ss;
|
||||||
|
::std::stringstream why;
|
||||||
|
::std::stringstream loc;
|
||||||
|
const void* untyped_action = nullptr;
|
||||||
|
|
||||||
|
// The UntypedFindMatchingExpectation() function acquires and
|
||||||
|
// releases g_gmock_mutex.
|
||||||
|
const ExpectationBase* const untyped_expectation =
|
||||||
|
this->UntypedFindMatchingExpectation(
|
||||||
|
untyped_args, &untyped_action, &is_excessive,
|
||||||
|
&ss, &why);
|
||||||
|
const bool found = untyped_expectation != nullptr;
|
||||||
|
|
||||||
|
// True if and only if we need to print the call's arguments
|
||||||
|
// and return value.
|
||||||
|
// This definition must be kept in sync with the uses of Expect()
|
||||||
|
// and Log() in this function.
|
||||||
|
const bool need_to_report_call =
|
||||||
|
!found || is_excessive || LogIsVisible(kInfo);
|
||||||
|
if (!need_to_report_call) {
|
||||||
|
// Perform the action without printing the call information.
|
||||||
|
return untyped_action == nullptr
|
||||||
|
? this->UntypedPerformDefaultAction(untyped_args, "")
|
||||||
|
: this->UntypedPerformAction(untyped_action, untyped_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
ss << " Function call: " << Name();
|
||||||
|
this->UntypedPrintArgs(untyped_args, &ss);
|
||||||
|
|
||||||
|
// In case the action deletes a piece of the expectation, we
|
||||||
|
// generate the message beforehand.
|
||||||
|
if (found && !is_excessive) {
|
||||||
|
untyped_expectation->DescribeLocationTo(&loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
UntypedActionResultHolderBase* const result =
|
||||||
|
untyped_action == nullptr
|
||||||
|
? this->UntypedPerformDefaultAction(untyped_args, ss.str())
|
||||||
|
: this->UntypedPerformAction(untyped_action, untyped_args);
|
||||||
|
if (result != nullptr) result->PrintAsActionResult(&ss);
|
||||||
|
ss << "\n" << why.str();
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
// No expectation matches this call - reports a failure.
|
||||||
|
Expect(false, nullptr, -1, ss.str());
|
||||||
|
} else if (is_excessive) {
|
||||||
|
// We had an upper-bound violation and the failure message is in ss.
|
||||||
|
Expect(false, untyped_expectation->file(),
|
||||||
|
untyped_expectation->line(), ss.str());
|
||||||
|
} else {
|
||||||
|
// We had an expected call and the matching expectation is
|
||||||
|
// described in ss.
|
||||||
|
Log(kInfo, loc.str() + ss.str(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an Expectation object that references and co-owns exp,
|
||||||
|
// which must be an expectation on this mock function.
|
||||||
|
Expectation UntypedFunctionMockerBase::GetHandleOf(ExpectationBase* exp) {
|
||||||
|
// See the definition of untyped_expectations_ for why access to it
|
||||||
|
// is unprotected here.
|
||||||
|
for (UntypedExpectations::const_iterator it =
|
||||||
|
untyped_expectations_.begin();
|
||||||
|
it != untyped_expectations_.end(); ++it) {
|
||||||
|
if (it->get() == exp) {
|
||||||
|
return Expectation(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert(false, __FILE__, __LINE__, "Cannot find expectation.");
|
||||||
|
return Expectation();
|
||||||
|
// The above statement is just to make the code compile, and will
|
||||||
|
// never be executed.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifies that all expectations on this mock function have been
|
||||||
|
// satisfied. Reports one or more Google Test non-fatal failures
|
||||||
|
// and returns false if not.
|
||||||
|
bool UntypedFunctionMockerBase::VerifyAndClearExpectationsLocked()
|
||||||
|
GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
|
||||||
|
g_gmock_mutex.AssertHeld();
|
||||||
|
bool expectations_met = true;
|
||||||
|
for (UntypedExpectations::const_iterator it =
|
||||||
|
untyped_expectations_.begin();
|
||||||
|
it != untyped_expectations_.end(); ++it) {
|
||||||
|
ExpectationBase* const untyped_expectation = it->get();
|
||||||
|
if (untyped_expectation->IsOverSaturated()) {
|
||||||
|
// There was an upper-bound violation. Since the error was
|
||||||
|
// already reported when it occurred, there is no need to do
|
||||||
|
// anything here.
|
||||||
|
expectations_met = false;
|
||||||
|
} else if (!untyped_expectation->IsSatisfied()) {
|
||||||
|
expectations_met = false;
|
||||||
|
::std::stringstream ss;
|
||||||
|
ss << "Actual function call count doesn't match "
|
||||||
|
<< untyped_expectation->source_text() << "...\n";
|
||||||
|
// No need to show the source file location of the expectation
|
||||||
|
// in the description, as the Expect() call that follows already
|
||||||
|
// takes care of it.
|
||||||
|
untyped_expectation->MaybeDescribeExtraMatcherTo(&ss);
|
||||||
|
untyped_expectation->DescribeCallCountTo(&ss);
|
||||||
|
Expect(false, untyped_expectation->file(),
|
||||||
|
untyped_expectation->line(), ss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deleting our expectations may trigger other mock objects to be deleted, for
|
||||||
|
// example if an action contains a reference counted smart pointer to that
|
||||||
|
// mock object, and that is the last reference. So if we delete our
|
||||||
|
// expectations within the context of the global mutex we may deadlock when
|
||||||
|
// this method is called again. Instead, make a copy of the set of
|
||||||
|
// expectations to delete, clear our set within the mutex, and then clear the
|
||||||
|
// copied set outside of it.
|
||||||
|
UntypedExpectations expectations_to_delete;
|
||||||
|
untyped_expectations_.swap(expectations_to_delete);
|
||||||
|
|
||||||
|
g_gmock_mutex.Unlock();
|
||||||
|
expectations_to_delete.clear();
|
||||||
|
g_gmock_mutex.Lock();
|
||||||
|
|
||||||
|
return expectations_met;
|
||||||
|
}
|
||||||
|
|
||||||
|
CallReaction intToCallReaction(int mock_behavior) {
|
||||||
|
if (mock_behavior >= kAllow && mock_behavior <= kFail) {
|
||||||
|
return static_cast<internal::CallReaction>(mock_behavior);
|
||||||
|
}
|
||||||
|
return kWarn;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
// Class Mock.
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
typedef std::set<internal::UntypedFunctionMockerBase*> FunctionMockers;
|
||||||
|
|
||||||
|
// The current state of a mock object. Such information is needed for
|
||||||
|
// detecting leaked mock objects and explicitly verifying a mock's
|
||||||
|
// expectations.
|
||||||
|
struct MockObjectState {
|
||||||
|
MockObjectState()
|
||||||
|
: first_used_file(nullptr), first_used_line(-1), leakable(false) {}
|
||||||
|
|
||||||
|
// Where in the source file an ON_CALL or EXPECT_CALL is first
|
||||||
|
// invoked on this mock object.
|
||||||
|
const char* first_used_file;
|
||||||
|
int first_used_line;
|
||||||
|
::std::string first_used_test_suite;
|
||||||
|
::std::string first_used_test;
|
||||||
|
bool leakable; // true if and only if it's OK to leak the object.
|
||||||
|
FunctionMockers function_mockers; // All registered methods of the object.
|
||||||
|
};
|
||||||
|
|
||||||
|
// A global registry holding the state of all mock objects that are
|
||||||
|
// alive. A mock object is added to this registry the first time
|
||||||
|
// Mock::AllowLeak(), ON_CALL(), or EXPECT_CALL() is called on it. It
|
||||||
|
// is removed from the registry in the mock object's destructor.
|
||||||
|
class MockObjectRegistry {
|
||||||
|
public:
|
||||||
|
// Maps a mock object (identified by its address) to its state.
|
||||||
|
typedef std::map<const void*, MockObjectState> StateMap;
|
||||||
|
|
||||||
|
// This destructor will be called when a program exits, after all
|
||||||
|
// tests in it have been run. By then, there should be no mock
|
||||||
|
// object alive. Therefore we report any living object as test
|
||||||
|
// failure, unless the user explicitly asked us to ignore it.
|
||||||
|
~MockObjectRegistry() {
|
||||||
|
if (!GMOCK_FLAG(catch_leaked_mocks))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int leaked_count = 0;
|
||||||
|
for (StateMap::const_iterator it = states_.begin(); it != states_.end();
|
||||||
|
++it) {
|
||||||
|
if (it->second.leakable) // The user said it's fine to leak this object.
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// FIXME: Print the type of the leaked object.
|
||||||
|
// This can help the user identify the leaked object.
|
||||||
|
std::cout << "\n";
|
||||||
|
const MockObjectState& state = it->second;
|
||||||
|
std::cout << internal::FormatFileLocation(state.first_used_file,
|
||||||
|
state.first_used_line);
|
||||||
|
std::cout << " ERROR: this mock object";
|
||||||
|
if (state.first_used_test != "") {
|
||||||
|
std::cout << " (used in test " << state.first_used_test_suite << "."
|
||||||
|
<< state.first_used_test << ")";
|
||||||
|
}
|
||||||
|
std::cout << " should be deleted but never is. Its address is @"
|
||||||
|
<< it->first << ".";
|
||||||
|
leaked_count++;
|
||||||
|
}
|
||||||
|
if (leaked_count > 0) {
|
||||||
|
std::cout << "\nERROR: " << leaked_count << " leaked mock "
|
||||||
|
<< (leaked_count == 1 ? "object" : "objects")
|
||||||
|
<< " found at program exit. Expectations on a mock object is "
|
||||||
|
"verified when the object is destructed. Leaking a mock "
|
||||||
|
"means that its expectations aren't verified, which is "
|
||||||
|
"usually a test bug. If you really intend to leak a mock, "
|
||||||
|
"you can suppress this error using "
|
||||||
|
"testing::Mock::AllowLeak(mock_object), or you may use a "
|
||||||
|
"fake or stub instead of a mock.\n";
|
||||||
|
std::cout.flush();
|
||||||
|
::std::cerr.flush();
|
||||||
|
// RUN_ALL_TESTS() has already returned when this destructor is
|
||||||
|
// called. Therefore we cannot use the normal Google Test
|
||||||
|
// failure reporting mechanism.
|
||||||
|
_exit(1); // We cannot call exit() as it is not reentrant and
|
||||||
|
// may already have been called.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StateMap& states() { return states_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
StateMap states_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Protected by g_gmock_mutex.
|
||||||
|
MockObjectRegistry g_mock_object_registry;
|
||||||
|
|
||||||
|
// Maps a mock object to the reaction Google Mock should have when an
|
||||||
|
// uninteresting method is called. Protected by g_gmock_mutex.
|
||||||
|
std::map<const void*, internal::CallReaction> g_uninteresting_call_reaction;
|
||||||
|
|
||||||
|
// Sets the reaction Google Mock should have when an uninteresting
|
||||||
|
// method of the given mock object is called.
|
||||||
|
void SetReactionOnUninterestingCalls(const void* mock_obj,
|
||||||
|
internal::CallReaction reaction)
|
||||||
|
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||||
|
internal::MutexLock l(&internal::g_gmock_mutex);
|
||||||
|
g_uninteresting_call_reaction[mock_obj] = reaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// Tells Google Mock to allow uninteresting calls on the given mock
|
||||||
|
// object.
|
||||||
|
void Mock::AllowUninterestingCalls(const void* mock_obj)
|
||||||
|
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||||
|
SetReactionOnUninterestingCalls(mock_obj, internal::kAllow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tells Google Mock to warn the user about uninteresting calls on the
|
||||||
|
// given mock object.
|
||||||
|
void Mock::WarnUninterestingCalls(const void* mock_obj)
|
||||||
|
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||||
|
SetReactionOnUninterestingCalls(mock_obj, internal::kWarn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tells Google Mock to fail uninteresting calls on the given mock
|
||||||
|
// object.
|
||||||
|
void Mock::FailUninterestingCalls(const void* mock_obj)
|
||||||
|
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||||
|
SetReactionOnUninterestingCalls(mock_obj, internal::kFail);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tells Google Mock the given mock object is being destroyed and its
|
||||||
|
// entry in the call-reaction table should be removed.
|
||||||
|
void Mock::UnregisterCallReaction(const void* mock_obj)
|
||||||
|
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||||
|
internal::MutexLock l(&internal::g_gmock_mutex);
|
||||||
|
g_uninteresting_call_reaction.erase(mock_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the reaction Google Mock will have on uninteresting calls
|
||||||
|
// made on the given mock object.
|
||||||
|
internal::CallReaction Mock::GetReactionOnUninterestingCalls(
|
||||||
|
const void* mock_obj)
|
||||||
|
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||||
|
internal::MutexLock l(&internal::g_gmock_mutex);
|
||||||
|
return (g_uninteresting_call_reaction.count(mock_obj) == 0) ?
|
||||||
|
internal::intToCallReaction(GMOCK_FLAG(default_mock_behavior)) :
|
||||||
|
g_uninteresting_call_reaction[mock_obj];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tells Google Mock to ignore mock_obj when checking for leaked mock
|
||||||
|
// objects.
|
||||||
|
void Mock::AllowLeak(const void* mock_obj)
|
||||||
|
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||||
|
internal::MutexLock l(&internal::g_gmock_mutex);
|
||||||
|
g_mock_object_registry.states()[mock_obj].leakable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifies and clears all expectations on the given mock object. If
|
||||||
|
// the expectations aren't satisfied, generates one or more Google
|
||||||
|
// Test non-fatal failures and returns false.
|
||||||
|
bool Mock::VerifyAndClearExpectations(void* mock_obj)
|
||||||
|
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||||
|
internal::MutexLock l(&internal::g_gmock_mutex);
|
||||||
|
return VerifyAndClearExpectationsLocked(mock_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifies all expectations on the given mock object and clears its
|
||||||
|
// default actions and expectations. Returns true if and only if the
|
||||||
|
// verification was successful.
|
||||||
|
bool Mock::VerifyAndClear(void* mock_obj)
|
||||||
|
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||||
|
internal::MutexLock l(&internal::g_gmock_mutex);
|
||||||
|
ClearDefaultActionsLocked(mock_obj);
|
||||||
|
return VerifyAndClearExpectationsLocked(mock_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifies and clears all expectations on the given mock object. If
|
||||||
|
// the expectations aren't satisfied, generates one or more Google
|
||||||
|
// Test non-fatal failures and returns false.
|
||||||
|
bool Mock::VerifyAndClearExpectationsLocked(void* mock_obj)
|
||||||
|
GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex) {
|
||||||
|
internal::g_gmock_mutex.AssertHeld();
|
||||||
|
if (g_mock_object_registry.states().count(mock_obj) == 0) {
|
||||||
|
// No EXPECT_CALL() was set on the given mock object.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifies and clears the expectations on each mock method in the
|
||||||
|
// given mock object.
|
||||||
|
bool expectations_met = true;
|
||||||
|
FunctionMockers& mockers =
|
||||||
|
g_mock_object_registry.states()[mock_obj].function_mockers;
|
||||||
|
for (FunctionMockers::const_iterator it = mockers.begin();
|
||||||
|
it != mockers.end(); ++it) {
|
||||||
|
if (!(*it)->VerifyAndClearExpectationsLocked()) {
|
||||||
|
expectations_met = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't clear the content of mockers, as they may still be
|
||||||
|
// needed by ClearDefaultActionsLocked().
|
||||||
|
return expectations_met;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mock::IsNaggy(void* mock_obj)
|
||||||
|
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||||
|
return Mock::GetReactionOnUninterestingCalls(mock_obj) == internal::kWarn;
|
||||||
|
}
|
||||||
|
bool Mock::IsNice(void* mock_obj)
|
||||||
|
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||||
|
return Mock::GetReactionOnUninterestingCalls(mock_obj) == internal::kAllow;
|
||||||
|
}
|
||||||
|
bool Mock::IsStrict(void* mock_obj)
|
||||||
|
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||||
|
return Mock::GetReactionOnUninterestingCalls(mock_obj) == internal::kFail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registers a mock object and a mock method it owns.
|
||||||
|
void Mock::Register(const void* mock_obj,
|
||||||
|
internal::UntypedFunctionMockerBase* mocker)
|
||||||
|
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||||
|
internal::MutexLock l(&internal::g_gmock_mutex);
|
||||||
|
g_mock_object_registry.states()[mock_obj].function_mockers.insert(mocker);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tells Google Mock where in the source code mock_obj is used in an
|
||||||
|
// ON_CALL or EXPECT_CALL. In case mock_obj is leaked, this
|
||||||
|
// information helps the user identify which object it is.
|
||||||
|
void Mock::RegisterUseByOnCallOrExpectCall(const void* mock_obj,
|
||||||
|
const char* file, int line)
|
||||||
|
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
|
||||||
|
internal::MutexLock l(&internal::g_gmock_mutex);
|
||||||
|
MockObjectState& state = g_mock_object_registry.states()[mock_obj];
|
||||||
|
if (state.first_used_file == nullptr) {
|
||||||
|
state.first_used_file = file;
|
||||||
|
state.first_used_line = line;
|
||||||
|
const TestInfo* const test_info =
|
||||||
|
UnitTest::GetInstance()->current_test_info();
|
||||||
|
if (test_info != nullptr) {
|
||||||
|
state.first_used_test_suite = test_info->test_suite_name();
|
||||||
|
state.first_used_test = test_info->name();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unregisters a mock method; removes the owning mock object from the
|
||||||
|
// registry when the last mock method associated with it has been
|
||||||
|
// unregistered. This is called only in the destructor of
|
||||||
|
// FunctionMockerBase.
|
||||||
|
void Mock::UnregisterLocked(internal::UntypedFunctionMockerBase* mocker)
|
||||||
|
GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex) {
|
||||||
|
internal::g_gmock_mutex.AssertHeld();
|
||||||
|
for (MockObjectRegistry::StateMap::iterator it =
|
||||||
|
g_mock_object_registry.states().begin();
|
||||||
|
it != g_mock_object_registry.states().end(); ++it) {
|
||||||
|
FunctionMockers& mockers = it->second.function_mockers;
|
||||||
|
if (mockers.erase(mocker) > 0) {
|
||||||
|
// mocker was in mockers and has been just removed.
|
||||||
|
if (mockers.empty()) {
|
||||||
|
g_mock_object_registry.states().erase(it);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clears all ON_CALL()s set on the given mock object.
|
||||||
|
void Mock::ClearDefaultActionsLocked(void* mock_obj)
|
||||||
|
GTEST_EXCLUSIVE_LOCK_REQUIRED_(internal::g_gmock_mutex) {
|
||||||
|
internal::g_gmock_mutex.AssertHeld();
|
||||||
|
|
||||||
|
if (g_mock_object_registry.states().count(mock_obj) == 0) {
|
||||||
|
// No ON_CALL() was set on the given mock object.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clears the default actions for each mock method in the given mock
|
||||||
|
// object.
|
||||||
|
FunctionMockers& mockers =
|
||||||
|
g_mock_object_registry.states()[mock_obj].function_mockers;
|
||||||
|
for (FunctionMockers::const_iterator it = mockers.begin();
|
||||||
|
it != mockers.end(); ++it) {
|
||||||
|
(*it)->ClearDefaultActionsLocked();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't clear the content of mockers, as they may still be
|
||||||
|
// needed by VerifyAndClearExpectationsLocked().
|
||||||
|
}
|
||||||
|
|
||||||
|
Expectation::Expectation() {}
|
||||||
|
|
||||||
|
Expectation::Expectation(
|
||||||
|
const std::shared_ptr<internal::ExpectationBase>& an_expectation_base)
|
||||||
|
: expectation_base_(an_expectation_base) {}
|
||||||
|
|
||||||
|
Expectation::~Expectation() {}
|
||||||
|
|
||||||
|
// Adds an expectation to a sequence.
|
||||||
|
void Sequence::AddExpectation(const Expectation& expectation) const {
|
||||||
|
if (*last_expectation_ != expectation) {
|
||||||
|
if (last_expectation_->expectation_base() != nullptr) {
|
||||||
|
expectation.expectation_base()->immediate_prerequisites_
|
||||||
|
+= *last_expectation_;
|
||||||
|
}
|
||||||
|
*last_expectation_ = expectation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates the implicit sequence if there isn't one.
|
||||||
|
InSequence::InSequence() {
|
||||||
|
if (internal::g_gmock_implicit_sequence.get() == nullptr) {
|
||||||
|
internal::g_gmock_implicit_sequence.set(new Sequence);
|
||||||
|
sequence_created_ = true;
|
||||||
|
} else {
|
||||||
|
sequence_created_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletes the implicit sequence if it was created by the constructor
|
||||||
|
// of this object.
|
||||||
|
InSequence::~InSequence() {
|
||||||
|
if (sequence_created_) {
|
||||||
|
delete internal::g_gmock_implicit_sequence.get();
|
||||||
|
internal::g_gmock_implicit_sequence.set(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#if _MSC_VER == 1900
|
||||||
|
# pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
#endif
|
@ -0,0 +1,213 @@
|
|||||||
|
// Copyright 2008, 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.
|
||||||
|
|
||||||
|
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
#include "gmock/internal/gmock-port.h"
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
GMOCK_DEFINE_bool_(catch_leaked_mocks, true,
|
||||||
|
"true if and only if Google Mock should report leaked "
|
||||||
|
"mock objects as failures.");
|
||||||
|
|
||||||
|
GMOCK_DEFINE_string_(verbose, internal::kWarningVerbosity,
|
||||||
|
"Controls how verbose Google Mock's output is."
|
||||||
|
" Valid values:\n"
|
||||||
|
" info - prints all messages.\n"
|
||||||
|
" warning - prints warnings and errors.\n"
|
||||||
|
" error - prints errors only.");
|
||||||
|
|
||||||
|
GMOCK_DEFINE_int32_(default_mock_behavior, 1,
|
||||||
|
"Controls the default behavior of mocks."
|
||||||
|
" Valid values:\n"
|
||||||
|
" 0 - by default, mocks act as NiceMocks.\n"
|
||||||
|
" 1 - by default, mocks act as NaggyMocks.\n"
|
||||||
|
" 2 - by default, mocks act as StrictMocks.");
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// Parses a string as a command line flag. The string should have the
|
||||||
|
// format "--gmock_flag=value". When def_optional is true, the
|
||||||
|
// "=value" part can be omitted.
|
||||||
|
//
|
||||||
|
// Returns the value of the flag, or NULL if the parsing failed.
|
||||||
|
static const char* ParseGoogleMockFlagValue(const char* str,
|
||||||
|
const char* flag,
|
||||||
|
bool def_optional) {
|
||||||
|
// str and flag must not be NULL.
|
||||||
|
if (str == nullptr || flag == nullptr) return nullptr;
|
||||||
|
|
||||||
|
// The flag must start with "--gmock_".
|
||||||
|
const std::string flag_str = std::string("--gmock_") + flag;
|
||||||
|
const size_t flag_len = flag_str.length();
|
||||||
|
if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr;
|
||||||
|
|
||||||
|
// Skips the flag name.
|
||||||
|
const char* flag_end = str + flag_len;
|
||||||
|
|
||||||
|
// When def_optional is true, it's OK to not have a "=value" part.
|
||||||
|
if (def_optional && (flag_end[0] == '\0')) {
|
||||||
|
return flag_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If def_optional is true and there are more characters after the
|
||||||
|
// flag name, or if def_optional is false, there must be a '=' after
|
||||||
|
// the flag name.
|
||||||
|
if (flag_end[0] != '=') return nullptr;
|
||||||
|
|
||||||
|
// Returns the string after "=".
|
||||||
|
return flag_end + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parses a string for a Google Mock bool flag, in the form of
|
||||||
|
// "--gmock_flag=value".
|
||||||
|
//
|
||||||
|
// On success, stores the value of the flag in *value, and returns
|
||||||
|
// true. On failure, returns false without changing *value.
|
||||||
|
static bool ParseGoogleMockBoolFlag(const char* str, const char* flag,
|
||||||
|
bool* value) {
|
||||||
|
// Gets the value of the flag as a string.
|
||||||
|
const char* const value_str = ParseGoogleMockFlagValue(str, flag, true);
|
||||||
|
|
||||||
|
// Aborts if the parsing failed.
|
||||||
|
if (value_str == nullptr) return false;
|
||||||
|
|
||||||
|
// Converts the string value to a bool.
|
||||||
|
*value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parses a string for a Google Mock string flag, in the form of
|
||||||
|
// "--gmock_flag=value".
|
||||||
|
//
|
||||||
|
// On success, stores the value of the flag in *value, and returns
|
||||||
|
// true. On failure, returns false without changing *value.
|
||||||
|
template <typename String>
|
||||||
|
static bool ParseGoogleMockStringFlag(const char* str, const char* flag,
|
||||||
|
String* value) {
|
||||||
|
// Gets the value of the flag as a string.
|
||||||
|
const char* const value_str = ParseGoogleMockFlagValue(str, flag, false);
|
||||||
|
|
||||||
|
// Aborts if the parsing failed.
|
||||||
|
if (value_str == nullptr) return false;
|
||||||
|
|
||||||
|
// Sets *value to the value of the flag.
|
||||||
|
*value = value_str;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ParseGoogleMockIntFlag(const char* str, const char* flag,
|
||||||
|
int* value) {
|
||||||
|
// Gets the value of the flag as a string.
|
||||||
|
const char* const value_str = ParseGoogleMockFlagValue(str, flag, true);
|
||||||
|
|
||||||
|
// Aborts if the parsing failed.
|
||||||
|
if (value_str == nullptr) return false;
|
||||||
|
|
||||||
|
// Sets *value to the value of the flag.
|
||||||
|
return ParseInt32(Message() << "The value of flag --" << flag,
|
||||||
|
value_str, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The internal implementation of InitGoogleMock().
|
||||||
|
//
|
||||||
|
// The type parameter CharType can be instantiated to either char or
|
||||||
|
// wchar_t.
|
||||||
|
template <typename CharType>
|
||||||
|
void InitGoogleMockImpl(int* argc, CharType** argv) {
|
||||||
|
// Makes sure Google Test is initialized. InitGoogleTest() is
|
||||||
|
// idempotent, so it's fine if the user has already called it.
|
||||||
|
InitGoogleTest(argc, argv);
|
||||||
|
if (*argc <= 0) return;
|
||||||
|
|
||||||
|
for (int i = 1; i != *argc; i++) {
|
||||||
|
const std::string arg_string = StreamableToString(argv[i]);
|
||||||
|
const char* const arg = arg_string.c_str();
|
||||||
|
|
||||||
|
// Do we see a Google Mock flag?
|
||||||
|
if (ParseGoogleMockBoolFlag(arg, "catch_leaked_mocks",
|
||||||
|
&GMOCK_FLAG(catch_leaked_mocks)) ||
|
||||||
|
ParseGoogleMockStringFlag(arg, "verbose", &GMOCK_FLAG(verbose)) ||
|
||||||
|
ParseGoogleMockIntFlag(arg, "default_mock_behavior",
|
||||||
|
&GMOCK_FLAG(default_mock_behavior))) {
|
||||||
|
// Yes. Shift the remainder of the argv list left by one. Note
|
||||||
|
// that argv has (*argc + 1) elements, the last one always being
|
||||||
|
// NULL. The following loop moves the trailing NULL element as
|
||||||
|
// well.
|
||||||
|
for (int j = i; j != *argc; j++) {
|
||||||
|
argv[j] = argv[j + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrements the argument count.
|
||||||
|
(*argc)--;
|
||||||
|
|
||||||
|
// We also need to decrement the iterator as we just removed
|
||||||
|
// an element.
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
// Initializes Google Mock. This must be called before running the
|
||||||
|
// tests. In particular, it parses a command line for the flags that
|
||||||
|
// Google Mock recognizes. Whenever a Google Mock flag is seen, it is
|
||||||
|
// removed from argv, and *argc is decremented.
|
||||||
|
//
|
||||||
|
// No value is returned. Instead, the Google Mock flag variables are
|
||||||
|
// updated.
|
||||||
|
//
|
||||||
|
// Since Google Test is needed for Google Mock to work, this function
|
||||||
|
// also initializes Google Test and parses its flags, if that hasn't
|
||||||
|
// been done.
|
||||||
|
GTEST_API_ void InitGoogleMock(int* argc, char** argv) {
|
||||||
|
internal::InitGoogleMockImpl(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This overloaded version can be used in Windows programs compiled in
|
||||||
|
// UNICODE mode.
|
||||||
|
GTEST_API_ void InitGoogleMock(int* argc, wchar_t** argv) {
|
||||||
|
internal::InitGoogleMockImpl(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This overloaded version can be used on Arduino/embedded platforms where
|
||||||
|
// there is no argc/argv.
|
||||||
|
GTEST_API_ void InitGoogleMock() {
|
||||||
|
// Since Arduino doesn't have a command line, fake out the argc/argv arguments
|
||||||
|
int argc = 1;
|
||||||
|
const auto arg0 = "dummy";
|
||||||
|
char* argv0 = const_cast<char*>(arg0);
|
||||||
|
char** argv = &argv0;
|
||||||
|
|
||||||
|
internal::InitGoogleMockImpl(&argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace testing
|
@ -0,0 +1,65 @@
|
|||||||
|
// Copyright 2008, 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.
|
||||||
|
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#ifdef ARDUINO
|
||||||
|
void setup() {
|
||||||
|
// Since Google Mock depends on Google Test, InitGoogleMock() is
|
||||||
|
// also responsible for initializing Google Test. Therefore there's
|
||||||
|
// no need for calling testing::InitGoogleTest() separately.
|
||||||
|
testing::InitGoogleMock();
|
||||||
|
}
|
||||||
|
void loop() { RUN_ALL_TESTS(); }
|
||||||
|
#else
|
||||||
|
|
||||||
|
// MS C++ compiler/linker has a bug on Windows (not on Windows CE), which
|
||||||
|
// causes a link error when _tmain is defined in a static library and UNICODE
|
||||||
|
// is enabled. For this reason instead of _tmain, main function is used on
|
||||||
|
// Windows. See the following link to track the current status of this bug:
|
||||||
|
// https://web.archive.org/web/20170912203238/connect.microsoft.com/VisualStudio/feedback/details/394464/wmain-link-error-in-the-static-library
|
||||||
|
// // NOLINT
|
||||||
|
#if GTEST_OS_WINDOWS_MOBILE
|
||||||
|
# include <tchar.h> // NOLINT
|
||||||
|
|
||||||
|
GTEST_API_ int _tmain(int argc, TCHAR** argv) {
|
||||||
|
#else
|
||||||
|
GTEST_API_ int main(int argc, char** argv) {
|
||||||
|
#endif // GTEST_OS_WINDOWS_MOBILE
|
||||||
|
std::cout << "Running main() from gmock_main.cc\n";
|
||||||
|
// Since Google Mock depends on Google Test, InitGoogleMock() is
|
||||||
|
// also responsible for initializing Google Test. Therefore there's
|
||||||
|
// no need for calling testing::InitGoogleTest() separately.
|
||||||
|
testing::InitGoogleMock(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,110 @@
|
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Author: misterg@google.com (Gennadiy Civil)
|
||||||
|
#
|
||||||
|
# Bazel Build for Google C++ Testing Framework(Google Test)-googlemock
|
||||||
|
|
||||||
|
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_test")
|
||||||
|
load("@rules_python//python:defs.bzl", "py_library", "py_test")
|
||||||
|
|
||||||
|
licenses(["notice"])
|
||||||
|
|
||||||
|
# Tests for GMock itself
|
||||||
|
cc_test(
|
||||||
|
name = "gmock_all_test",
|
||||||
|
size = "small",
|
||||||
|
srcs = glob(include = ["gmock-*.cc"]),
|
||||||
|
linkopts = select({
|
||||||
|
"//:windows": [],
|
||||||
|
"//conditions:default": ["-pthread"],
|
||||||
|
}),
|
||||||
|
deps = ["//:gtest"],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Python tests
|
||||||
|
py_library(
|
||||||
|
name = "gmock_test_utils",
|
||||||
|
testonly = 1,
|
||||||
|
srcs = ["gmock_test_utils.py"],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_binary(
|
||||||
|
name = "gmock_leak_test_",
|
||||||
|
testonly = 1,
|
||||||
|
srcs = ["gmock_leak_test_.cc"],
|
||||||
|
deps = ["//:gtest_main"],
|
||||||
|
)
|
||||||
|
|
||||||
|
py_test(
|
||||||
|
name = "gmock_leak_test",
|
||||||
|
size = "medium",
|
||||||
|
srcs = ["gmock_leak_test.py"],
|
||||||
|
data = [
|
||||||
|
":gmock_leak_test_",
|
||||||
|
":gmock_test_utils",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "gmock_link_test",
|
||||||
|
size = "small",
|
||||||
|
srcs = [
|
||||||
|
"gmock_link2_test.cc",
|
||||||
|
"gmock_link_test.cc",
|
||||||
|
"gmock_link_test.h",
|
||||||
|
],
|
||||||
|
deps = ["//:gtest_main"],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_binary(
|
||||||
|
name = "gmock_output_test_",
|
||||||
|
srcs = ["gmock_output_test_.cc"],
|
||||||
|
deps = ["//:gtest"],
|
||||||
|
)
|
||||||
|
|
||||||
|
py_test(
|
||||||
|
name = "gmock_output_test",
|
||||||
|
size = "medium",
|
||||||
|
srcs = ["gmock_output_test.py"],
|
||||||
|
data = [
|
||||||
|
":gmock_output_test_",
|
||||||
|
":gmock_output_test_golden.txt",
|
||||||
|
],
|
||||||
|
python_version = "PY2",
|
||||||
|
deps = [":gmock_test_utils"],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "gmock_test",
|
||||||
|
size = "small",
|
||||||
|
srcs = ["gmock_test.cc"],
|
||||||
|
deps = ["//:gtest_main"],
|
||||||
|
)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue