diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index 9d96ab4..193b22b 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -8,11 +8,40 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-20.04] + os: [ubuntu-22.04] steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Tests run: make + + examples: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-22.04] + example: [mock-injection, wiring-blink] + steps: + - + name: Checkout + uses: actions/checkout@v3 + - + uses: actions/cache@v3 + with: + path: | + ~/.cache/pip + ~/.platformio/.cache + key: ${{ runner.os }}-pio + - + uses: actions/setup-python@v4 + with: + python-version: '3.9' + - + name: Install PlatformIO Core + run: pip install --upgrade platformio + - + name: Tests + run: pio test -d examples/wiring-blink/ diff --git a/.gitignore b/.gitignore index 60c6844..73c1d8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .pioenvs .piolibdeps /external/unity/*-repo/ +/external/fakeit/*-repo/ /build/ /.cproject /.project @@ -10,3 +11,8 @@ **/Makefile !/Makefile /Testing/* +.pio/* +.vscode/* +/test/test_main.cpp +output.txt +error.txt \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index b463a1a..41bd442 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,14 @@ cmake_minimum_required(VERSION 3.2.2) project(ArduinoFake VERSION 0.1) -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) # Include external libs -add_subdirectory(external) +add_subdirectory(external/fakeit) +add_subdirectory(external/unity) # Targets that we develop here enable_testing() diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6c9bf85..ea08d1b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -84,7 +84,7 @@ I was missing `sei()`, `cli()` and `attachInterrupt()` in `ArduinoFake`, here is } 1. excersice tests from command line, there are two ways based on your Makefile * default project [Makefile](/Makefile), - * execute `make` + * execute `make` (`make` requires `cmake` - install it via `apt` / `brew` / `yum` or whatever package manager your system uses) * verify ``` Running tests... diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2bf523c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) ArduinoFake + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile index 930da21..a283e22 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ default_target: all .PHONY: all -all: clean build test clean +all: clean build deploy test clean .PHONY: cmake cmake: @@ -26,3 +26,9 @@ cmake-test: build test clean: @rm -rf $(CURDIR)/build/* @rm -rf $(CURDIR)/.pioenvs/* + @rm -rf $(CURDIR)/.pio/* + +.PHONY: deploy +deploy: + cp $(CURDIR)/external/fakeit/fakeit-repo/single_header/standalone/* $(CURDIR)/src + diff --git a/README.md b/README.md index 44e075e..872eb27 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ `ArduinoFake` is a simple mocking framework for Arduino. `ArduinoFake` is based on [FakeIt](https://github.com/eranpeer/FakeIt) and can be used for testing your arduino project natively. No arduino required ! - +# ## Quickstart @@ -57,5 +57,15 @@ void test_loop(void) Checkout the [examples](./examples) for many more examples! Or take a look at the [tests](./test) +## Troubleshooting + +If you get a segfault while running your unit tests, eg: + +``` +Program errored with 3221225477 code +``` + +Check to make sure you have stubbed **all** the Arduino methods you are calling. + # Contributing If you want to extend `ArduinoFake` library to add missing functions (for example `attachInterrupt`) see [contribution guidelines](CONTRIBUTING.md). diff --git a/examples/mock-injection/.gitignore b/examples/mock-injection/.gitignore index 6c69f4c..f152028 100755 --- a/examples/mock-injection/.gitignore +++ b/examples/mock-injection/.gitignore @@ -1,2 +1,5 @@ +.pio .pioenvs .piolibdeps +.clang_complete +.gcc-flags.json diff --git a/examples/mock-injection/.travis.yml b/examples/mock-injection/.travis.yml deleted file mode 100755 index 2c4ff5c..0000000 --- a/examples/mock-injection/.travis.yml +++ /dev/null @@ -1,65 +0,0 @@ -# Continuous Integration (CI) is the practice, in software -# engineering, of merging all developer working copies with a shared mainline -# several times a day < http://docs.platformio.org/page/ci/index.html > -# -# Documentation: -# -# * Travis CI Embedded Builds with PlatformIO -# < https://docs.travis-ci.com/user/integration/platformio/ > -# -# * PlatformIO integration with Travis CI -# < http://docs.platformio.org/page/ci/travis.html > -# -# * User Guide for `platformio ci` command -# < http://docs.platformio.org/page/userguide/cmd_ci.html > -# -# -# Please choice one of the following templates (proposed below) and uncomment -# it (remove "# " before each line) or use own configuration according to the -# Travis CI documentation (see above). -# - - -# -# Template #1: General project. Test it using existing `platformio.ini`. -# - -# language: python -# python: -# - "2.7" -# -# sudo: false -# cache: -# directories: -# - "~/.platformio" -# -# install: -# - pip install -U platformio -# -# script: -# - platformio run - - -# -# Template #2: The project is intended to by used as a library with examples -# - -# language: python -# python: -# - "2.7" -# -# sudo: false -# cache: -# directories: -# - "~/.platformio" -# -# env: -# - PLATFORMIO_CI_SRC=path/to/test/file.c -# - PLATFORMIO_CI_SRC=examples/file.ino -# - PLATFORMIO_CI_SRC=path/to/test/directory -# -# install: -# - pip install -U platformio -# -# script: -# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N diff --git a/examples/mock-injection/platformio.ini b/examples/mock-injection/platformio.ini index ba97983..d0cd6a8 100755 --- a/examples/mock-injection/platformio.ini +++ b/examples/mock-injection/platformio.ini @@ -1,4 +1,9 @@ [env:native] platform = native -build_flags = -std=gnu++11 -lib_deps = git@github.com:FabioBatSilva/ArduinoFake.git \ No newline at end of file +test_build_src = yes +build_flags = -std=gnu++17 + +lib_deps = file://../../ + +# Use this instead of local file +#lib_deps = FabioBatSilva/ArduinoFake diff --git a/examples/mock-injection/test/test_my_service.cpp b/examples/mock-injection/test/test_my_service.cpp index 7f8047b..c3c8448 100755 --- a/examples/mock-injection/test/test_my_service.cpp +++ b/examples/mock-injection/test/test_my_service.cpp @@ -24,7 +24,6 @@ void test_connect(void) MyService service(clientMock); String response = service.request("myserver.com"); - TEST_ASSERT_EQUAL(3, response.length()); TEST_ASSERT_TRUE(response.equals("200")); @@ -33,8 +32,8 @@ void test_connect(void) Verify(OverloadedMethod(ArduinoFake(Client), read, int())).Exactly(3_Times); Verify(OverloadedMethod(ArduinoFake(Client), println, size_t())).Once(); - Verify(OverloadedMethod(ArduinoFake(Client), println, size_t(const char *)).Using("STATUS")).Once(); - Verify(OverloadedMethod(ArduinoFake(Client), connect, int(const char*, uint16_t)).Using("myserver.com", 80)).Once(); + Verify(OverloadedMethod(ArduinoFake(Client), println, size_t(const char [])).Using((const char *)"STATUS")).Never(); + Verify(OverloadedMethod(ArduinoFake(Client), connect, int(const char[], uint16_t)).Using((const char *)"myserver.com", 80)).Once(); } int main(int argc, char **argv) diff --git a/examples/wiring-blink/.gitignore b/examples/wiring-blink/.gitignore index 5402c18..f152028 100644 --- a/examples/wiring-blink/.gitignore +++ b/examples/wiring-blink/.gitignore @@ -1,3 +1,5 @@ +.pio .pioenvs +.piolibdeps .clang_complete .gcc-flags.json diff --git a/examples/wiring-blink/.travis.yml b/examples/wiring-blink/.travis.yml deleted file mode 100644 index 593d7ef..0000000 --- a/examples/wiring-blink/.travis.yml +++ /dev/null @@ -1,65 +0,0 @@ -# Continuous Integration (CI) is the practice, in software -# engineering, of merging all developer working copies with a shared mainline -# several times a day < http://docs.platformio.org/page/ci/index.html > -# -# Documentation: -# -# * Travis CI Embedded Builds with PlatformIO -# < https://docs.travis-ci.com/user/integration/platformio/ > -# -# * PlatformIO integration with Travis CI -# < http://docs.platformio.org/page/ci/travis.html > -# -# * User Guide for `platformio ci` command -# < http://docs.platformio.org/page/userguide/cmd_ci.html > -# -# -# Please choose one of the following templates (proposed below) and uncomment -# it (remove "# " before each line) or use own configuration according to the -# Travis CI documentation (see above). -# - - -# -# Template #1: General project. Test it using existing `platformio.ini`. -# - -# language: python -# python: -# - "2.7" -# -# sudo: false -# cache: -# directories: -# - "~/.platformio" -# -# install: -# - pip install -U platformio -# -# script: -# - platformio run - - -# -# Template #2: The project is intended to by used as a library with examples -# - -# language: python -# python: -# - "2.7" -# -# sudo: false -# cache: -# directories: -# - "~/.platformio" -# -# env: -# - PLATFORMIO_CI_SRC=path/to/test/file.c -# - PLATFORMIO_CI_SRC=examples/file.ino -# - PLATFORMIO_CI_SRC=path/to/test/directory -# -# install: -# - pip install -U platformio -# -# script: -# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N diff --git a/examples/wiring-blink/platformio.ini b/examples/wiring-blink/platformio.ini index 3669ee3..7b942fa 100644 --- a/examples/wiring-blink/platformio.ini +++ b/examples/wiring-blink/platformio.ini @@ -1,5 +1,8 @@ [env:native] platform = native -build_flags = -std=gnu++11 -lib_deps = ArduinoFake -# lib_deps = git@github.com:FabioBatSilva/ArduinoFake.git \ No newline at end of file +test_build_src = yes +build_flags = -std=gnu++17 + +lib_deps = file://../../ + +#lib_deps = FabioBatSilva/ArduinoFake diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index b06a11e..8ba9078 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -1,2 +1,3 @@ # Include external libs add_subdirectory(unity) +add_subdirectory(fakeit) \ No newline at end of file diff --git a/external/fakeit/CMakeLists.txt b/external/fakeit/CMakeLists.txt new file mode 100644 index 0000000..ed87fcb --- /dev/null +++ b/external/fakeit/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.2.2) +project(fakeit VERSION 2.4.0 LANGUAGES CXX) + +include(git-download) + +set(REPO_DIR ${PROJECT_SOURCE_DIR}/${PROJECT_NAME}-repo) + +download_repo( + URL "https://github.com/eranpeer/FakeIt.git" + TAG ${PROJECT_VERSION} + CLONE_DIR ${REPO_DIR} +) + +add_library(${PROJECT_NAME} INTERFACE) + +target_include_directories(${PROJECT_NAME} INTERFACE + ${REPO_DIR}/single_header/standalone/ +) diff --git a/library.json b/library.json index a24e831..5d28bf9 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "ArduinoFake", - "version": "0.2.2", + "version": "0.4.0", "keywords": "test, mock, fake, arduino", "description": "Arduino mocking made easy.", "repository": { diff --git a/platformio.ini b/platformio.ini index fc39339..6952f64 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,3 +1,14 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + [env:native] platform = native -build_flags = -std=gnu++11 +build_flags = -std=gnu++17 +test_build_src = yes diff --git a/src/ArduinoFake.h b/src/ArduinoFake.h index bd00c32..7eaa22b 100644 --- a/src/ArduinoFake.h +++ b/src/ArduinoFake.h @@ -1,23 +1,26 @@ #pragma once +// clang-format off #if !defined(UBRRH) && !defined(UBRR0H) && !defined(USBCON) #define USBCON #endif -#include +#include #include #include #include -#include "fakeit/fakeit.hpp" +#include "fakeit.hpp" #include "arduino/Arduino.h" -#include "FunctionFake.h" -#include "StreamFake.h" -#include "SerialFake.h" -#include "WireFake.h" -#include "ClientFake.h" -#include "PrintFake.h" +#include "Function.h" +#include "Stream.h" +#include "Serial.h" +#include "Wire.h" +#include "Client.h" +#include "Print.h" +#include "SPI.h" +#include "EEPROM.h" #define ArduinoFake(mock) _ArduinoFakeGet##mock() @@ -36,6 +39,8 @@ #define _ArduinoFakeGetFunction() _ArduinoFakeGetMock(Function) #define _ArduinoFakeGetSerial() _ArduinoFakeGetMock(Serial) #define _ArduinoFakeGetWire() _ArduinoFakeGetMock(Wire) +#define _ArduinoFakeGetSPI() _ArduinoFakeGetMock(SPI) +#define _ArduinoFakeGetEEPROM() _ArduinoFakeGetMock(EEPROM) #define _ArduinoFakeGetStream() _ArduinoFakeGetMock(Stream) #define _ArduinoFakeGetClient() _ArduinoFakeGetMock(Client) #define _ArduinoFakeGetPrint() _ArduinoFakeGetMock(Print) @@ -70,6 +75,8 @@ struct ArduinoFakeMocks fakeit::Mock Stream; fakeit::Mock Client; fakeit::Mock Print; + fakeit::Mock SPI; + fakeit::Mock EEPROM; }; struct ArduinoFakeInstances @@ -80,6 +87,8 @@ struct ArduinoFakeInstances StreamFake* Stream; ClientFake* Client; PrintFake* Print; + SPIFake* SPI; + EEPROMFake* EEPROM; }; class ArduinoFakeContext @@ -87,7 +96,7 @@ class ArduinoFakeContext public: ArduinoFakeInstances* Instances = new ArduinoFakeInstances(); ArduinoFakeMocks* Mocks = new ArduinoFakeMocks(); - std::map Mapping; + std::unordered_map Mapping; _ArduinoFakeInstanceGetter1(Print) _ArduinoFakeInstanceGetter1(Stream) @@ -95,12 +104,16 @@ class ArduinoFakeContext _ArduinoFakeInstanceGetter1(Wire) _ArduinoFakeInstanceGetter1(Client) _ArduinoFakeInstanceGetter1(Function) + _ArduinoFakeInstanceGetter1(SPI) + _ArduinoFakeInstanceGetter1(EEPROM) _ArduinoFakeInstanceGetter2(Print, Print) _ArduinoFakeInstanceGetter2(Client, Client) _ArduinoFakeInstanceGetter2(Stream, Stream) _ArduinoFakeInstanceGetter2(Serial, Serial_) _ArduinoFakeInstanceGetter2(Wire, TwoWire) + _ArduinoFakeInstanceGetter2(SPI, SPIClass) + _ArduinoFakeInstanceGetter2(EEPROM, EEPROMClass) ArduinoFakeContext() { @@ -109,6 +122,9 @@ class ArduinoFakeContext void reset(void) { + if (this->Instances) { + delete this->Instances; + } this->Instances = new ArduinoFakeInstances(); this->Mocks->Function.Reset(); @@ -117,10 +133,16 @@ class ArduinoFakeContext this->Mocks->Wire.Reset(); this->Mocks->Client.Reset(); this->Mocks->Print.Reset(); + this->Mocks->SPI.Reset(); + this->Mocks->EEPROM.Reset(); Mapping[&::Serial] = this->Serial(); Mapping[&::Wire] = this->Wire(); + Mapping[&::SPI] = this->SPI(); + Mapping[&::EEPROM] = this->EEPROM(); } }; ArduinoFakeContext* getArduinoFakeContext(); + +// clang-format on \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b83017b..3b0e460 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,3 +3,5 @@ aux_source_directory(./fakeit SRC_LIST) aux_source_directory(./arduino SRC_LIST) add_library(${PROJECT_NAME} SHARED ${SRC_LIST}) + +target_link_libraries(${PROJECT_NAME} fakeit) \ No newline at end of file diff --git a/src/EEPROM.h b/src/EEPROM.h new file mode 100644 index 0000000..696f914 --- /dev/null +++ b/src/EEPROM.h @@ -0,0 +1 @@ +#include "EEPROMFake.h" \ No newline at end of file diff --git a/src/EEPROMFake.cpp b/src/EEPROMFake.cpp new file mode 100644 index 0000000..faa88c6 --- /dev/null +++ b/src/EEPROMFake.cpp @@ -0,0 +1,17 @@ +// clang-format off +#include "ArduinoFake.h" +#include "EEPROMFake.h" +// clang-format on + +uint8_t EEPROMClass::read(int idx) { + return ArduinoFakeInstance(EEPROM)->read(idx); +}; +void EEPROMClass::write(int idx, uint8_t val) { + ArduinoFakeInstance(EEPROM)->write(idx, val); +}; +void EEPROMClass::update(int idx, uint8_t val) { + ArduinoFakeInstance(EEPROM)->update(idx, val); +}; +uint16_t EEPROMClass::length() { return ArduinoFakeInstance(EEPROM)->length(); } + +EEPROMClass EEPROM = EEPROMFakeProxy(ArduinoFakeInstance(EEPROM)); diff --git a/src/EEPROMFake.h b/src/EEPROMFake.h new file mode 100644 index 0000000..bcb1b7a --- /dev/null +++ b/src/EEPROMFake.h @@ -0,0 +1,21 @@ +#pragma once + +#include "ArduinoFake.h" +#include "arduino/EEPROM.h" + +struct EEPROMFake { + virtual uint8_t read(int idx) = 0; + virtual void write(int idx, uint8_t val) = 0; + virtual void update(int idx, uint8_t val) = 0; + virtual uint16_t length() = 0; +}; + +class EEPROMFakeProxy : public EEPROMClass { +private: + EEPROMFake *eepromFake; + +public: + EEPROMFakeProxy(EEPROMFake *fake) { eepromFake = fake; } + + EEPROMFake *getEEPROMFake() { return eepromFake; } +}; diff --git a/src/Function.h b/src/Function.h new file mode 100644 index 0000000..6d17965 --- /dev/null +++ b/src/Function.h @@ -0,0 +1 @@ +#include "FunctionFake.h" diff --git a/src/FunctionFake.cpp b/src/FunctionFake.cpp index 0fa76d0..7b7c6ad 100644 --- a/src/FunctionFake.cpp +++ b/src/FunctionFake.cpp @@ -31,6 +31,11 @@ void analogReference(uint8_t mode) ArduinoFakeInstance(Function)->analogReference(mode); } +void analogReadResolution(uint8_t mode) +{ + ArduinoFakeInstance(Function)->analogReadResolution(mode); +} + unsigned long millis(void) { return ArduinoFakeInstance(Function)->millis(); diff --git a/src/FunctionFake.h b/src/FunctionFake.h index c13469c..c9d9047 100644 --- a/src/FunctionFake.h +++ b/src/FunctionFake.h @@ -1,6 +1,6 @@ #pragma once -#include "fakeit/fakeit.hpp" +#include "fakeit.hpp" struct FunctionFake { @@ -14,6 +14,7 @@ struct FunctionFake virtual int analogRead(uint8_t) = 0; virtual void analogReference(uint8_t) = 0; + virtual void analogReadResolution(uint8_t) = 0; virtual void analogWrite(uint8_t, int) = 0; virtual unsigned long millis(void) = 0; diff --git a/src/Print.h b/src/Print.h new file mode 100644 index 0000000..458f70b --- /dev/null +++ b/src/Print.h @@ -0,0 +1 @@ +#include "PrintFake.h" diff --git a/src/SPI.h b/src/SPI.h new file mode 100644 index 0000000..026d1a5 --- /dev/null +++ b/src/SPI.h @@ -0,0 +1 @@ +#include "SPIFake.h" \ No newline at end of file diff --git a/src/SPIFake.cpp b/src/SPIFake.cpp new file mode 100644 index 0000000..23ebbc3 --- /dev/null +++ b/src/SPIFake.cpp @@ -0,0 +1,28 @@ +#include "ArduinoFake.h" +#include "SPIFake.h" + +void SPIClass::begin() { ArduinoFakeInstance(SPI)->begin(); }; + +void SPIClass::end() { ArduinoFakeInstance(SPI)->end(); }; + +void SPIClass::beginTransaction(SPISettings settings) { + ArduinoFakeInstance(SPI)->beginTransaction(settings); +}; + +void SPIClass::endTransaction(void) { + ArduinoFakeInstance(SPI)->endTransaction(); +}; + +uint8_t SPIClass::transfer(uint8_t data) { + return ArduinoFakeInstance(SPI)->transfer(data); +}; + +uint16_t SPIClass::transfer16(uint16_t data) { + return ArduinoFakeInstance(SPI)->transfer16(data); +}; + +void SPIClass::transfer(void *buf, size_t count) { + return ArduinoFakeInstance(SPI)->transfer(buf, count); +}; + +SPIClass SPI = SPIFakeProxy(ArduinoFakeInstance(SPI)); diff --git a/src/SPIFake.h b/src/SPIFake.h new file mode 100644 index 0000000..9e90f9a --- /dev/null +++ b/src/SPIFake.h @@ -0,0 +1,26 @@ +#pragma once + +#include "ArduinoFake.h" +#include "arduino/SPI.h" + +struct SPIFake { + virtual uint8_t transfer(uint8_t data) = 0; + virtual uint16_t transfer16(uint16_t data) = 0; + virtual void transfer(void *buf, size_t count) = 0; + + virtual void beginTransaction(SPISettings settings) = 0; + virtual void endTransaction(void) = 0; + + virtual void begin() = 0; + virtual void end() = 0; +}; + +class SPIFakeProxy : public SPIClass { + private: + SPIFake *spiFake; + + public: + SPIFakeProxy(SPIFake *fake) { spiFake = fake; } + + SPIFake *getSPIFake() { return spiFake; } +}; diff --git a/src/Serial.h b/src/Serial.h new file mode 100644 index 0000000..851d0e7 --- /dev/null +++ b/src/Serial.h @@ -0,0 +1 @@ +#include "SerialFake.h" diff --git a/src/Stream.h b/src/Stream.h new file mode 100644 index 0000000..06f153b --- /dev/null +++ b/src/Stream.h @@ -0,0 +1 @@ +#include "StreamFake.h" diff --git a/src/WString.h b/src/WString.h new file mode 100644 index 0000000..e48b819 --- /dev/null +++ b/src/WString.h @@ -0,0 +1,2 @@ +#pragma once +#include "arduino/WString.h" \ No newline at end of file diff --git a/src/Wire.h b/src/Wire.h new file mode 100644 index 0000000..7ca50ad --- /dev/null +++ b/src/Wire.h @@ -0,0 +1 @@ +#include "WireFake.h" \ No newline at end of file diff --git a/src/arduino/Arduino.h b/src/arduino/Arduino.h index a61468f..42156d0 100644 --- a/src/arduino/Arduino.h +++ b/src/arduino/Arduino.h @@ -139,6 +139,7 @@ void digitalWrite(uint8_t, uint8_t); int digitalRead(uint8_t); int analogRead(uint8_t); void analogReference(uint8_t mode); +void analogReadResolution(uint8_t mode); void analogWrite(uint8_t, int); unsigned long millis(void); diff --git a/src/arduino/EEPROM.h b/src/arduino/EEPROM.h new file mode 100644 index 0000000..4e86c9a --- /dev/null +++ b/src/arduino/EEPROM.h @@ -0,0 +1,20 @@ +#pragma once +#include + +struct EEPROMClass { + virtual uint8_t read(int idx); + virtual void write(int idx, uint8_t val); + virtual void update(int idx, uint8_t val); + virtual uint16_t length(); + /* + EERef operator[](const int idx); + + // TODO: How to implement this functionality?? + // https://docs.arduino.cc/learn/built-in-libraries/eeprom + template T &get(int idx, T &t); + + template const T &put(int idx, const T &t); + */ +}; + +extern EEPROMClass EEPROM; \ No newline at end of file diff --git a/src/arduino/SPI.h b/src/arduino/SPI.h new file mode 100644 index 0000000..a1efca5 --- /dev/null +++ b/src/arduino/SPI.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2010 by Cristian Maglie + * Copyright (c) 2014 by Paul Stoffregen (Transaction API) + * Copyright (c) 2014 by Matthijs Kooijman (SPISettings AVR) + * Copyright (c) 2014 by Andrew J. Kroll (atomicity fixes) + * SPI Master library for arduino. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#pragma once +#include +#include +#include + +// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(), +// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode) +#define SPI_HAS_TRANSACTION 1 + +// SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method +#define SPI_HAS_NOTUSINGINTERRUPT 1 + +// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version. +// This way when there is a bug fix you can check this define to alert users +// of your code if it uses better version of this library. +// This also implies everything that SPI_HAS_TRANSACTION as documented above is +// available too. +#define SPI_ATOMIC_VERSION 1 + +// Uncomment this line to add detection of mismatched begin/end transactions. +// A mismatch occurs if other libraries fail to use SPI.endTransaction() for +// each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn +// on if any mismatch is ever detected. +// #define SPI_TRANSACTION_MISMATCH_LED 5 + +#ifndef LSBFIRST +#define LSBFIRST 0 +#endif +#ifndef MSBFIRST +#define MSBFIRST 1 +#endif + +#define SPI_CLOCK_DIV4 0x00 +#define SPI_CLOCK_DIV16 0x01 +#define SPI_CLOCK_DIV64 0x02 +#define SPI_CLOCK_DIV128 0x03 +#define SPI_CLOCK_DIV2 0x04 +#define SPI_CLOCK_DIV8 0x05 +#define SPI_CLOCK_DIV32 0x06 + +#define SPI_MODE0 0x00 +#define SPI_MODE1 0x04 +#define SPI_MODE2 0x08 +#define SPI_MODE3 0x0C + +#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR +#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR +#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR + +// define SPI_AVR_EIMSK for AVR boards with external interrupt pins +#if defined(EIMSK) +#define SPI_AVR_EIMSK EIMSK +#elif defined(GICR) +#define SPI_AVR_EIMSK GICR +#elif defined(GIMSK) +#define SPI_AVR_EIMSK GIMSK +#endif + +class SPISettings { + private: + uint32_t clock; + uint8_t bitOrder; + uint8_t dataMode; + + public: + SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode): clock(clock), bitOrder(bitOrder), dataMode(dataMode) {} + SPISettings() { SPISettings(4000000, MSBFIRST, SPI_MODE0); } + friend class SPIClass; + + bool operator==(const SPISettings &other) const { + return (clock == other.clock) && (bitOrder == other.bitOrder) && + (dataMode == other.dataMode); + } +}; + +class SPIClass { + public: + // Initialize the SPI library + virtual void begin(); + virtual void end(); + + // Before using SPI.transfer() or asserting chip select pins, + // this function is used to gain exclusive access to the SPI bus + // and configure the correct settings. + virtual void beginTransaction(SPISettings settings); + + // Write to the SPI bus (MOSI pin) and also receive (MISO pin) + virtual uint8_t transfer(uint8_t data); + virtual uint16_t transfer16(uint16_t data); + virtual void transfer(void *buf, size_t count); + + // After performing a group of transfers and releasing the chip select + // signal, this function allows others to access the SPI bus + virtual void endTransaction(void); + + // virtual ~SPIClass(); + + private: +}; + +extern SPIClass SPI; \ No newline at end of file diff --git a/src/fakeit/fakeit.hpp b/src/fakeit.hpp similarity index 78% rename from src/fakeit/fakeit.hpp rename to src/fakeit.hpp index 6a2884e..3fbd299 100644 --- a/src/fakeit/fakeit.hpp +++ b/src/fakeit.hpp @@ -2,7 +2,7 @@ /* * FakeIt - A Simplified C++ Mocking Framework * Copyright (c) Eran Pe'er 2013 - * Generated: 2017-05-07 09:27:35.559271 + * Generated: 2023-04-17 21:28:52.363853 * Distributed under the MIT License. Please refer to the LICENSE file at: * https://github.com/eranpeer/FakeIt */ @@ -17,11 +17,23 @@ #include #include #if defined (__GNUG__) || _MSC_VER >= 1900 -#define THROWS noexcept(false) -#define NO_THROWS noexcept(true) +# define FAKEIT_THROWS noexcept(false) +# define FAKEIT_NO_THROWS noexcept(true) #elif defined (_MSC_VER) -#define THROWS throw(...) -#define NO_THROWS +# define FAKEIT_THROWS throw(...) +# define FAKEIT_NO_THROWS +#endif + +#ifdef _MSVC_LANG +# define FAKEIT_CPLUSPLUS _MSVC_LANG +#else +# define FAKEIT_CPLUSPLUS __cplusplus +#endif + +#ifdef __GNUG__ +# define FAKEIT_DISARM_UBSAN __attribute__((no_sanitize("undefined"))) +#else +# define FAKEIT_DISARM_UBSAN #endif #include #include @@ -34,6 +46,14 @@ namespace fakeit { + template + using fk_void_t = void; + + template struct bool_pack; + + template + using all_true = std::is_same, bool_pack>; + template struct naked_type { typedef typename std::remove_cv::type>::type type; @@ -61,11 +81,11 @@ namespace fakeit { class is_ostreamable { struct no {}; #if defined(_MSC_VER) && _MSC_VER < 1900 - template - static decltype(operator<<(std::declval(), std::declval())) test(std::ostream &s, const T1 &t); + template + static decltype(operator<<(std::declval(), std::declval())) test(std::ostream &s, const Type1 &t); #else - template - static auto test(std::ostream &s, const T1 &t) -> decltype(s << t); + template + static auto test(std::ostream &s, const Type1 &t) -> decltype(s << t); #endif static no test(...); public: @@ -104,6 +124,15 @@ namespace fakeit { typedef R(__thiscall *type)(void *, arglist...); #endif }; + + templateclass test, typename T> + struct smart_test : test {}; + + templateclass test, typename T, typename A> + struct smart_test > : smart_test < test, T> {}; + + template + using smart_is_copy_constructible = smart_test < std::is_copy_constructible, T >; } #include #include @@ -118,7 +147,7 @@ namespace fakeit { template struct MockObject { - virtual ~MockObject() THROWS { }; + virtual ~MockObject() FAKEIT_THROWS { }; virtual C &get() = 0; @@ -180,7 +209,7 @@ namespace fakeit { struct Matcher { - virtual ~Matcher() THROWS { + virtual ~Matcher() FAKEIT_THROWS { } virtual bool matches(Invocation &invocation) = 0; @@ -252,6 +281,35 @@ namespace fakeit { } }; + template <> + struct Formatter + { + static std::string format(char const* const &val) + { + std::string s; + if(val != nullptr) + { + s += '"'; + s += val; + s += '"'; + } + else + { + s = "[nullptr]"; + } + return s; + } + }; + + template <> + struct Formatter + { + static std::string format(char* const &val) + { + return Formatter::format( val ); + } + }; + template struct Formatter::value>::type> { static std::string format(C const &) @@ -377,13 +435,13 @@ namespace fakeit { struct ActualInvocationsContainer { virtual void clear() = 0; - virtual ~ActualInvocationsContainer() NO_THROWS { } + virtual ~ActualInvocationsContainer() FAKEIT_NO_THROWS { } }; struct ActualInvocationsSource { virtual void getActualInvocations(std::unordered_set &into) const = 0; - virtual ~ActualInvocationsSource() NO_THROWS { } + virtual ~ActualInvocationsSource() FAKEIT_NO_THROWS { } }; struct InvocationsSourceProxy : public ActualInvocationsSource { @@ -460,7 +518,7 @@ namespace fakeit { Sequence() { } - virtual ~Sequence() THROWS { + virtual ~Sequence() FAKEIT_THROWS { } public: @@ -741,6 +799,9 @@ namespace fakeit { }; } +#ifdef FAKEIT_ASSERT_ON_UNEXPECTED_METHOD_INVOCATION +#include +#endif namespace fakeit { @@ -751,6 +812,9 @@ namespace fakeit { void handle(const UnexpectedMethodCallEvent &e) override { fireEvent(e); auto &eh = getTestingFrameworkAdapter(); + #ifdef FAKEIT_ASSERT_ON_UNEXPECTED_METHOD_INVOCATION + assert(!"Unexpected method invocation"); + #endif eh.handle(e); } @@ -827,7 +891,7 @@ namespace fakeit { out << "Unexpected method invocation: "; out << e.getInvocation().format() << std::endl; if (UnexpectedType::Unmatched == e.getUnexpectedType()) { - out << " Could not find Any recorded behavior to support this method call."; + out << " Could not find any recorded behavior to support this method call."; } else { out << " An unmocked method was invoked. All used virtual methods must be stubbed!"; } @@ -864,11 +928,22 @@ namespace fakeit { virtual std::string format(const NoMoreInvocationsVerificationEvent &e) override { std::ostringstream out; out << "Verification error" << std::endl; - out << "Expected no more invocations!! But the following unverified invocations were found:" << std::endl; + out << "Expected no more invocations!! but the following unverified invocations were found:" << std::endl; formatInvocationList(out, e.unverifedIvocations()); return out.str(); } + static std::string formatExpectedPattern(const std::vector &expectedPattern) { + std::string expectedPatternStr; + for (unsigned int i = 0; i < expectedPattern.size(); i++) { + Sequence *s = expectedPattern[i]; + expectedPatternStr += formatSequence(*s); + if (i < expectedPattern.size() - 1) + expectedPatternStr += " ... "; + } + return expectedPatternStr; + } + private: static std::string formatSequence(const Sequence &val) { @@ -900,8 +975,8 @@ namespace fakeit { static void formatInvocationList(std::ostream &out, const std::vector &actualSequence) { size_t max_size = actualSequence.size(); - if (max_size > 5) - max_size = 5; + if (max_size > 50) + max_size = 50; for (unsigned int i = 0; i < max_size; i++) { out << " "; @@ -934,20 +1009,22 @@ namespace fakeit { out << " * " << val.getTimes(); return out.str(); } - - static std::string formatExpectedPattern(const std::vector &expectedPattern) { - std::string expectedPatternStr; - for (unsigned int i = 0; i < expectedPattern.size(); i++) { - Sequence *s = expectedPattern[i]; - expectedPatternStr += formatSequence(*s); - if (i < expectedPattern.size() - 1) - expectedPatternStr += " ... "; - } - return expectedPatternStr; - } }; } +#include + + + namespace fakeit { +#if FAKEIT_CPLUSPLUS >= 201703L || defined(__cpp_lib_uncaught_exceptions) + inline bool UncaughtException () { + return std::uncaught_exceptions() >= 1; + } +#else + inline bool UncaughtException () { + return std::uncaught_exception(); + } +#endif struct FakeitException { std::exception err; @@ -1069,11 +1146,25 @@ namespace fakeit { }; } +#include +#include +#include + +namespace fakeit { + + template + static std::string to_string(const T &n) { + std::ostringstream stm; + stm << n; + return stm.str(); + } + +} namespace fakeit { struct VerificationException : public std::exception { - virtual ~VerificationException() NO_THROWS{}; + virtual ~VerificationException() FAKEIT_NO_THROWS{}; VerificationException(std::string format) : _format(format) { @@ -1100,7 +1191,7 @@ namespace fakeit { return _callingMethod; } - const char* what() const NO_THROWS override{ + const char* what() const FAKEIT_NO_THROWS override{ return _format.c_str(); } private: @@ -1126,9 +1217,9 @@ namespace fakeit { std::string formatLineNumner(std::string file, int num){ #ifndef __GNUG__ - return file + std::string("(") + std::to_string(num) + std::string(")"); + return file + std::string("(") + fakeit::to_string(num) + std::string(")"); #else - return file + std::string(":") + std::to_string(num); + return file + std::string(":") + fakeit::to_string(num); #endif } @@ -1194,11 +1285,13 @@ static fakeit::DefaultFakeit& Fakeit = fakeit::StandaloneFakeit::getInstance(); #include #include +#undef max #include #include #include #include #include +#include #include #include @@ -5222,14 +5315,21 @@ namespace fakeit { }; } +#if defined(__GNUG__) && !defined(__clang__) +#define FAKEIT_NO_DEVIRTUALIZE_ATTR [[gnu::optimize("no-devirtualize")]] +#else +#define FAKEIT_NO_DEVIRTUALIZE_ATTR +#endif + namespace fakeit { - template - TARGET union_cast(SOURCE source) { + template + FAKEIT_NO_DEVIRTUALIZE_ATTR + TargetType union_cast(SourceType source) { union { - SOURCE source; - TARGET target; + SourceType source; + TargetType target; } u; u.source = source; return u.target; @@ -5238,20 +5338,30 @@ namespace fakeit { } namespace fakeit { - class NoVirtualDtor { + class NoVirtualDtor : public std::runtime_error { + public: + NoVirtualDtor() :std::runtime_error("Can't mock the destructor. No virtual destructor was found") {} }; class VTUtils { public: +#if defined(__GNUG__) && !defined(__clang__) && __GNUC__ >= 8 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif template static unsigned int getOffset(R (C::*vMethod)(arglist...)) { auto sMethod = reinterpret_cast(vMethod); VirtualOffsetSelector offsetSelctor; return (offsetSelctor.*sMethod)(0); } +#if defined(__GNUG__) && !defined(__clang__) && __GNUC__ >= 8 +#pragma GCC diagnostic pop +#endif template + FAKEIT_DISARM_UBSAN static typename std::enable_if::value, unsigned int>::type getDestructorOffset() { VirtualOffsetSelector offsetSelctor; @@ -5265,6 +5375,18 @@ namespace fakeit { throw NoVirtualDtor(); } + template + static typename std::enable_if::value, bool>::type + hasVirtualDestructor() { + return true; + } + + template + static typename std::enable_if::value, bool>::type + hasVirtualDestructor() { + return false; + } + template static unsigned int getVTSize() { struct Derrived : public C { @@ -5282,7 +5404,7 @@ namespace fakeit { #ifdef _MSC_VER namespace fakeit { - typedef unsigned long DWORD; + typedef unsigned long dword_; struct TypeDescriptor { TypeDescriptor() : @@ -5295,11 +5417,11 @@ namespace fakeit { } char *ptrToVTable; - DWORD spare; + dword_ spare; char name[8]; }; - struct PMD { + struct PmdInfo { @@ -5308,7 +5430,7 @@ namespace fakeit { int pdisp; int vdisp; - PMD() : + PmdInfo() : mdisp(0), pdisp(-1), vdisp(0) { } }; @@ -5319,9 +5441,9 @@ namespace fakeit { } const std::type_info *pTypeDescriptor; - DWORD numContainedBases; - struct PMD where; - DWORD attributes; + dword_ numContainedBases; + struct PmdInfo where; + dword_ attributes; }; template @@ -5343,9 +5465,9 @@ namespace fakeit { delete[] pBaseClassArray; } - DWORD signature; - DWORD attributes; - DWORD numBaseClasses; + dword_ signature; + dword_ attributes; + dword_ numBaseClasses; RTTIBaseClassDescriptor **pBaseClassArray; template @@ -5360,11 +5482,11 @@ namespace fakeit { numBaseClasses++; } - template + template void addBaseClass() { - static_assert(std::is_base_of::value, "invalid inheritance list"); + static_assert(std::is_base_of::value, "invalid inheritance list"); addBaseClass(); - addBaseClass(); + addBaseClass(); } }; @@ -5376,13 +5498,14 @@ namespace fakeit { signature(0), offset(0), cdOffset(0), typeDescriptorOffset(0), classDescriptorOffset(0) { + (void)unused; } - DWORD signature; - DWORD offset; - DWORD cdOffset; - DWORD typeDescriptorOffset; - DWORD classDescriptorOffset; + dword_ signature; + dword_ offset; + dword_ cdOffset; + dword_ typeDescriptorOffset; + dword_ classDescriptorOffset; #else RTTICompleteObjectLocator(const std::type_info &info) : signature(0), offset(0), cdOffset(0), @@ -5394,9 +5517,9 @@ namespace fakeit { delete pClassDescriptor; } - DWORD signature; - DWORD offset; - DWORD cdOffset; + dword_ signature; + dword_ offset; + dword_ cdOffset; const std::type_info *pTypeDescriptor; struct RTTIClassHierarchyDescriptor *pClassDescriptor; #endif @@ -5461,6 +5584,8 @@ namespace fakeit { for (unsigned int i = 0; i < size; i++) { _firstMethod[i] = from.getMethod(i); } + if (VTUtils::hasVirtualDestructor()) + setCookie(dtorCookieIndex, from.getCookie(dtorCookieIndex)); } VirtualTable() : VirtualTable(buildVTArray()) { @@ -5483,7 +5608,7 @@ namespace fakeit { C *c = (C *) this; C &cRef = *c; auto vt = VirtualTable::getVTable(cRef); - void *dtorPtr = vt.getCookie(numOfCookies - 1); + void *dtorPtr = vt.getCookie(dtorCookieIndex); void(*method)(C *) = reinterpret_cast(dtorPtr); method(c); return 0; @@ -5498,7 +5623,7 @@ namespace fakeit { void *dtorPtr = union_cast(&VirtualTable::dtor); unsigned int index = VTUtils::getDestructorOffset(); _firstMethod[index] = dtorPtr; - setCookie(numOfCookies - 1, method); + setCookie(dtorCookieIndex, method); } unsigned int getSize() { @@ -5525,6 +5650,7 @@ namespace fakeit { static_assert(sizeof(unsigned int (SimpleType::*)()) == sizeof(unsigned int (C::*)()), "Can't mock a type with multiple inheritance or with non-polymorphic base class"); static const unsigned int numOfCookies = 3; + static const unsigned int dtorCookieIndex = numOfCookies - 1; static void **buildVTArray() { int vtSize = VTUtils::getVTSize(); @@ -5547,17 +5673,17 @@ namespace fakeit { #include namespace fakeit { - template + template class has_one_base { }; - template - class has_one_base> : public std::false_type { + template + class has_one_base> : public std::false_type { }; - template - class has_one_base> - : public has_one_base::type> { + template + class has_one_base> + : public has_one_base::type> { }; template<> @@ -5725,73 +5851,104 @@ namespace fakeit { } #include -namespace fakeit { - -#ifdef __GNUG__ -#ifndef __clang__ -#pragma GCC diagnostic ignored "-Wpedantic" -#endif -#endif - - -#ifdef _MSC_VER -#pragma warning( push ) -#pragma warning( disable : 4200 ) -#endif +namespace fakeit +{ + namespace details + { + template + class FakeObjectImpl + { + public: + void initializeDataMembersArea() + { + for (size_t i = 0; i < instanceAreaSize; ++i) + { + instanceArea[i] = (char) 0; + } + } - template - class FakeObject { + protected: + VirtualTable vtable; + char instanceArea[instanceAreaSize]; + }; - VirtualTable vtable; + template + class FakeObjectImpl<0, C, BaseClasses...> + { + public: + void initializeDataMembersArea() + {} - static const size_t SIZE = sizeof(C) - sizeof(VirtualTable); - char instanceArea[SIZE ? SIZE : 0]; + protected: + VirtualTable vtable; + }; + } - FakeObject(FakeObject const &) = delete; - FakeObject &operator=(FakeObject const &) = delete; + template + class FakeObject + : public details::FakeObjectImpl), C, BaseClasses...> + { + FakeObject(FakeObject const&) = delete; + FakeObject& operator=(FakeObject const&) = delete; public: - - FakeObject() : vtable() { - initializeDataMembersArea(); - } - - ~FakeObject() { - vtable.dispose(); + FakeObject() + { + this->initializeDataMembersArea(); } - void initializeDataMembersArea() { - for (size_t i = 0; i < SIZE; ++i) instanceArea[i] = (char) 0; + ~FakeObject() + { + this->vtable.dispose(); } - void setMethod(unsigned int index, void *method) { - vtable.setMethod(index, method); + void setMethod(unsigned int index, void* method) + { + this->vtable.setMethod(index, method); } - VirtualTable &getVirtualTable() { - return vtable; + VirtualTable& getVirtualTable() + { + return this->vtable; } - void setVirtualTable(VirtualTable &t) { - vtable = t; + void setVirtualTable(VirtualTable& t) + { + this->vtable = t; } - void setDtor(void *dtor) { - vtable.setDtor(dtor); + void setDtor(void* dtor) + { + this->vtable.setDtor(dtor); } }; +} +#include -#ifdef _MSC_VER -#pragma warning( pop ) -#endif +namespace fakeit { -#ifdef __GNUG__ -#ifndef __clang__ -#pragma GCC diagnostic pop -#endif -#endif + class Finally { + private: + std::function _finallyClause; + + Finally(const Finally &) = delete; + + Finally &operator=(const Finally &) = delete; + + public: + explicit Finally(std::function f) : + _finallyClause(f) { + } + + Finally(Finally&& other) { + _finallyClause.swap(other._finallyClause); + } + ~Finally() { + _finallyClause(); + } + }; } namespace fakeit { @@ -5827,14 +5984,14 @@ namespace fakeit { namespace fakeit { struct InvocationHandlerCollection { - static const unsigned int VT_COOKIE_INDEX = 0; + static const unsigned int VtCookieIndex = 0; virtual Destructible *getInvocatoinHandlerPtrById(unsigned int index) = 0; static InvocationHandlerCollection *getInvocationHandlerCollection(void *instance) { VirtualTableBase &vt = VirtualTableBase::getVTable(instance); InvocationHandlerCollection *invocationHandlerCollection = (InvocationHandlerCollection *) vt.getCookie( - InvocationHandlerCollection::VT_COOKIE_INDEX); + InvocationHandlerCollection::VtCookieIndex); return invocationHandlerCollection; } }; @@ -5852,6 +6009,11 @@ namespace fakeit { return MethodProxy(id, offset, union_cast(&MethodProxyCreator::methodProxyX < id > )); } + template + MethodProxy createMethodProxyStatic(unsigned int offset) { + return MethodProxy(id, offset, union_cast(&MethodProxyCreator::methodProxyXStatic < id > )); + } + protected: R methodProxy(unsigned int id, const typename fakeit::production_arg::type... args) { @@ -5867,6 +6029,20 @@ namespace fakeit { R methodProxyX(arglist ... args) { return methodProxy(id, std::forward::type>(args)...); } + + static R methodProxyStatic(void* instance, unsigned int id, const typename fakeit::production_arg::type... args) { + InvocationHandlerCollection *invocationHandlerCollection = InvocationHandlerCollection::getInvocationHandlerCollection( + instance); + MethodInvocationHandler *invocationHandler = + (MethodInvocationHandler *) invocationHandlerCollection->getInvocatoinHandlerPtrById( + id); + return invocationHandler->handleMethodInvocation(std::forward::type>(args)...); + } + + template + static R methodProxyXStatic(void* instance, arglist ... args) { + return methodProxyStatic(instance, id, std::forward::type>(args)...); + } }; } @@ -5892,6 +6068,10 @@ namespace fakeit { std::vector> &methodMocks, std::vector &offsets) : _methodMocks(methodMocks), _offsets(offsets) { + for (std::vector::iterator it = _offsets.begin(); it != _offsets.end(); ++it) + { + *it = std::numeric_limits::max(); + } } Destructible *getInvocatoinHandlerPtrById(unsigned int id) override { @@ -5914,7 +6094,7 @@ namespace fakeit { _offsets(VTUtils::getVTSize()), _invocationHandlers(_methodMocks, _offsets) { _cloneVt.copyFrom(originalVtHandle.restore()); - _cloneVt.setCookie(InvocationHandlerCollection::VT_COOKIE_INDEX, &_invocationHandlers); + _cloneVt.setCookie(InvocationHandlerCollection::VtCookieIndex, &_invocationHandlers); getFake().setVirtualTable(_cloneVt); } @@ -5953,7 +6133,17 @@ namespace fakeit { void stubDtor(MethodInvocationHandler *methodInvocationHandler) { auto offset = VTUtils::getDestructorOffset(); MethodProxyCreator creator; + + + + + + +#ifdef _MSC_VER + bindDtor(creator.createMethodProxyStatic<0>(offset), methodInvocationHandler); +#else bindDtor(creator.createMethodProxy<0>(offset), methodInvocationHandler); +#endif } template @@ -5980,21 +6170,21 @@ namespace fakeit { return ptr.get(); } - template - void stubDataMember(DATA_TYPE C::*member, const arglist &... initargs) { - DATA_TYPE C::*theMember = (DATA_TYPE C::*) member; + template + void stubDataMember(DataType C::*member, const arglist &... initargs) { + DataType C::*theMember = (DataType C::*) member; C &mock = get(); - DATA_TYPE *memberPtr = &(mock.*theMember); + DataType *memberPtr = &(mock.*theMember); _members.push_back( - std::shared_ptr > - {new DataMemeberWrapper < DATA_TYPE, arglist...>(memberPtr, + std::shared_ptr > + {new DataMemeberWrapper < DataType, arglist...>(memberPtr, initargs...)}); } - template - void getMethodMocks(std::vector &into) const { + template + void getMethodMocks(std::vector &into) const { for (std::shared_ptr ptr : _methodMocks) { - DATA_TYPE p = dynamic_cast(ptr.get()); + DataType p = dynamic_cast(ptr.get()); if (p) { into.push_back(p); } @@ -6006,21 +6196,33 @@ namespace fakeit { return vt; } + template + Finally createRaiiMethodSwapper(R(C::*vMethod)(arglist...)) { + auto offset = VTUtils::getOffset(vMethod); + auto fakeMethod = getFake().getVirtualTable().getMethod(offset); + auto originalMethod = getOriginalVT().getMethod(offset); + + getFake().setMethod(offset, originalMethod); + return Finally{[&, offset, fakeMethod](){ + getFake().setMethod(offset, fakeMethod); + }}; + } + private: - template + template class DataMemeberWrapper : public Destructible { private: - DATA_TYPE *dataMember; + DataType *dataMember; public: - DataMemeberWrapper(DATA_TYPE *dataMem, const arglist &... initargs) : + DataMemeberWrapper(DataType *dataMem, const arglist &... initargs) : dataMember(dataMem) { - new(dataMember) DATA_TYPE{initargs ...}; + new(dataMember) DataType{initargs ...}; } ~DataMemeberWrapper() override { - dataMember->~DATA_TYPE(); + dataMember->~DataType(); } }; @@ -6051,10 +6253,10 @@ namespace fakeit { _offsets[methodProxy.getOffset()] = methodProxy.getId(); } - template - DATA_TYPE getMethodMock(unsigned int offset) { + template + DataType getMethodMock(unsigned int offset) { std::shared_ptr ptr = _methodMocks[offset]; - return dynamic_cast(ptr.get()); + return dynamic_cast(ptr.get()); } template @@ -6089,31 +6291,31 @@ namespace fakeit { template struct apply_func { - template - static R applyTuple(std::function f, std::tuple &t, Args &... args) { - return apply_func::template applyTuple(f, t, std::get(t), args...); + template + static R applyTuple(FunctionType&& f, std::tuple &t, Args &... args) { + return apply_func::template applyTuple(std::forward(f), t, std::get(t), args...); } }; template<> struct apply_func < 0 > { - template - static R applyTuple(std::function f, std::tuple & , Args &... args) { - return f(args...); + template + static R applyTuple(FunctionType&& f, std::tuple & , Args &... args) { + return std::forward(f)(args...); } }; struct TupleDispatcher { - template - static R applyTuple(std::function f, std::tuple &t) { - return apply_func::template applyTuple(f, t); + template + static R applyTuple(FunctionType&& f, std::tuple &t) { + return apply_func::template applyTuple(std::forward(f), t); } - template - static R invoke(std::function func, const std::tuple &arguments) { + template + static R invoke(FunctionType&& func, const std::tuple &arguments) { std::tuple &args = const_cast &>(arguments); - return applyTuple(func, args); + return applyTuple(std::forward(func), args); } template @@ -6304,6 +6506,10 @@ namespace fakeit { }; } +#include +#include + + namespace fakeit { struct IMatcher : Destructible { @@ -6311,281 +6517,584 @@ namespace fakeit { virtual std::string format() const = 0; }; - template + template struct TypedMatcher : IMatcher { - virtual bool matches(const T &actual) const = 0; + virtual bool matches(const ActualT &actual) const = 0; }; - template - struct TypedMatcherCreator { + template + struct ComparisonMatcherCreatorBase { + using ExpectedT = typename naked_type::type; - virtual ~TypedMatcherCreator() = default; + ExpectedTRef _expectedRef; - virtual TypedMatcher *createMatcher() const = 0; - }; + template + ComparisonMatcherCreatorBase(T &&expectedRef) + : _expectedRef(std::forward(expectedRef)) { + } - template - struct ComparisonMatcherCreator : public TypedMatcherCreator { + template + struct MatcherBase : public TypedMatcher { + const ExpectedT _expected; - virtual ~ComparisonMatcherCreator() = default; + MatcherBase(ExpectedTRef expected) + : _expected{std::forward(expected)} { + } + }; - ComparisonMatcherCreator(const T &arg) - : _expected(arg) { - } + template + struct MatcherBase::value && std::is_array::value>::type> : public TypedMatcher { + ExpectedT _expected; - struct Matcher : public TypedMatcher { - Matcher(const T &expected) - : _expected(expected) { + MatcherBase(ExpectedTRef expected) { + std::memcpy(_expected, expected, sizeof(_expected)); } - - const T _expected; }; - - const T &_expected; }; namespace internal { - template - struct TypedAnyMatcher : public TypedMatcherCreator { - - virtual ~TypedAnyMatcher() = default; - - TypedAnyMatcher() { - } - - struct Matcher : public TypedMatcher { - virtual bool matches(const T &) const override { - return true; - } + struct AnyMatcherCreator{ + template + struct IsTypeCompatible : std::true_type {}; + + template + TypedMatcher *createMatcher() const { + struct Matcher : public TypedMatcher { + bool matches(const ActualT &) const override { + return true; + } - virtual std::string format() const override { - return "Any"; - } - }; + std::string format() const override { + return "Any"; + } + }; - virtual TypedMatcher *createMatcher() const override { return new Matcher(); } - }; - template - struct EqMatcherCreator : public ComparisonMatcherCreator { + template + struct EqMatcherCreator : public ComparisonMatcherCreatorBase { + using ExpectedT = typename ComparisonMatcherCreatorBase::ExpectedT; - virtual ~EqMatcherCreator() = default; + template + struct IsTypeCompatible : std::false_type {}; - EqMatcherCreator(const T &expected) - : ComparisonMatcherCreator(expected) { - } + template + struct IsTypeCompatible() == std::declval())>> : std::true_type {}; - struct Matcher : public ComparisonMatcherCreator::Matcher { - Matcher(const T &expected) - : ComparisonMatcherCreator::Matcher(expected) { - } + using ComparisonMatcherCreatorBase::ComparisonMatcherCreatorBase; - virtual std::string format() const override { - return TypeFormatter::format(this->_expected); - } + template + TypedMatcher *createMatcher() const { + struct Matcher : public ComparisonMatcherCreatorBase::template MatcherBase { + using ComparisonMatcherCreatorBase::template MatcherBase::MatcherBase; - virtual bool matches(const T &actual) const override { - return actual == this->_expected; - } - }; + virtual std::string format() const override { + return TypeFormatter::format(this->_expected); + } - virtual TypedMatcher *createMatcher() const { - return new Matcher(this->_expected); - } + virtual bool matches(const ActualT &actual) const override { + return actual == this->_expected; + } + }; + return new Matcher(std::forward(this->_expectedRef)); + } }; - template - struct GtMatcherCreator : public ComparisonMatcherCreator { + template + struct GtMatcherCreator : public ComparisonMatcherCreatorBase { + using ExpectedT = typename ComparisonMatcherCreatorBase::ExpectedT; - virtual ~GtMatcherCreator() = default; + template + struct IsTypeCompatible : std::false_type {}; - GtMatcherCreator(const T &expected) - : ComparisonMatcherCreator(expected) { - } + template + struct IsTypeCompatible() > std::declval())>> : std::true_type {}; - struct Matcher : public ComparisonMatcherCreator::Matcher { - Matcher(const T &expected) - : ComparisonMatcherCreator::Matcher(expected) { - } + using ComparisonMatcherCreatorBase::ComparisonMatcherCreatorBase; - virtual bool matches(const T &actual) const override { - return actual > this->_expected; - } + template + TypedMatcher *createMatcher() const { + struct Matcher : public ComparisonMatcherCreatorBase::template MatcherBase { + using ComparisonMatcherCreatorBase::template MatcherBase::MatcherBase; - virtual std::string format() const override { - return std::string(">") + TypeFormatter::format(this->_expected); - } - }; + virtual std::string format() const override { + return std::string(">") + TypeFormatter::format(this->_expected); + } + + virtual bool matches(const ActualT &actual) const override { + return actual > this->_expected; + } + }; - virtual TypedMatcher *createMatcher() const override { - return new Matcher(this->_expected); + return new Matcher(std::forward(this->_expectedRef)); } }; - template - struct GeMatcherCreator : public ComparisonMatcherCreator { + template + struct GeMatcherCreator : public ComparisonMatcherCreatorBase { + using ExpectedT = typename ComparisonMatcherCreatorBase::ExpectedT; - virtual ~GeMatcherCreator() = default; + template + struct IsTypeCompatible : std::false_type {}; - GeMatcherCreator(const T &expected) - : ComparisonMatcherCreator(expected) { - } + template + struct IsTypeCompatible() >= std::declval())>> : std::true_type {}; - struct Matcher : public ComparisonMatcherCreator::Matcher { - Matcher(const T &expected) - : ComparisonMatcherCreator::Matcher(expected) { - } + using ComparisonMatcherCreatorBase::ComparisonMatcherCreatorBase; - virtual bool matches(const T &actual) const override { - return actual >= this->_expected; - } + template + TypedMatcher *createMatcher() const { + struct Matcher : public ComparisonMatcherCreatorBase::template MatcherBase { + using ComparisonMatcherCreatorBase::template MatcherBase::MatcherBase; - virtual std::string format() const override { - return std::string(">=") + TypeFormatter::format(this->_expected); - } - }; + virtual std::string format() const override { + return std::string(">=") + TypeFormatter::format(this->_expected); + } - virtual TypedMatcher *createMatcher() const override { - return new Matcher(this->_expected); + virtual bool matches(const ActualT &actual) const override { + return actual >= this->_expected; + } + }; + + return new Matcher(std::forward(this->_expectedRef)); } }; - template - struct LtMatcherCreator : public ComparisonMatcherCreator { + template + struct LtMatcherCreator : public ComparisonMatcherCreatorBase { + using ExpectedT = typename ComparisonMatcherCreatorBase::ExpectedT; - virtual ~LtMatcherCreator() = default; + template + struct IsTypeCompatible : std::false_type {}; - LtMatcherCreator(const T &expected) - : ComparisonMatcherCreator(expected) { - } + template + struct IsTypeCompatible() < std::declval())>> : std::true_type {}; - struct Matcher : public ComparisonMatcherCreator::Matcher { - Matcher(const T &expected) - : ComparisonMatcherCreator::Matcher(expected) { - } + using ComparisonMatcherCreatorBase::ComparisonMatcherCreatorBase; - virtual bool matches(const T &actual) const override { - return actual < this->_expected; - } + template + TypedMatcher *createMatcher() const { + struct Matcher : public ComparisonMatcherCreatorBase::template MatcherBase { + using ComparisonMatcherCreatorBase::template MatcherBase::MatcherBase; - virtual std::string format() const override { - return std::string("<") + TypeFormatter::format(this->_expected); - } - }; + virtual std::string format() const override { + return std::string("<") + TypeFormatter::format(this->_expected); + } - virtual TypedMatcher *createMatcher() const override { - return new Matcher(this->_expected); - } + virtual bool matches(const ActualT &actual) const override { + return actual < this->_expected; + } + }; + return new Matcher(std::forward(this->_expectedRef)); + } }; - template - struct LeMatcherCreator : public ComparisonMatcherCreator { + template + struct LeMatcherCreator : public ComparisonMatcherCreatorBase { + using ExpectedT = typename ComparisonMatcherCreatorBase::ExpectedT; - virtual ~LeMatcherCreator() = default; + template + struct IsTypeCompatible : std::false_type {}; - LeMatcherCreator(const T &expected) - : ComparisonMatcherCreator(expected) { - } + template + struct IsTypeCompatible() <= std::declval())>> : std::true_type {}; - struct Matcher : public ComparisonMatcherCreator::Matcher { - Matcher(const T &expected) - : ComparisonMatcherCreator::Matcher(expected) { - } + using ComparisonMatcherCreatorBase::ComparisonMatcherCreatorBase; - virtual bool matches(const T &actual) const override { - return actual <= this->_expected; - } + template + TypedMatcher *createMatcher() const { + struct Matcher : public ComparisonMatcherCreatorBase::template MatcherBase { + using ComparisonMatcherCreatorBase::template MatcherBase::MatcherBase; - virtual std::string format() const override { - return std::string("<=") + TypeFormatter::format(this->_expected); - } - }; + virtual std::string format() const override { + return std::string("<=") + TypeFormatter::format(this->_expected); + } - virtual TypedMatcher *createMatcher() const override { - return new Matcher(this->_expected); - } + virtual bool matches(const ActualT &actual) const override { + return actual <= this->_expected; + } + }; + return new Matcher(std::forward(this->_expectedRef)); + } }; - template - struct NeMatcherCreator : public ComparisonMatcherCreator { + template + struct NeMatcherCreator : public ComparisonMatcherCreatorBase { + using ExpectedT = typename ComparisonMatcherCreatorBase::ExpectedT; - virtual ~NeMatcherCreator() = default; + template + struct IsTypeCompatible : std::false_type {}; - NeMatcherCreator(const T &expected) - : ComparisonMatcherCreator(expected) { - } + template + struct IsTypeCompatible() != std::declval())>> : std::true_type {}; - struct Matcher : public ComparisonMatcherCreator::Matcher { - Matcher(const T &expected) - : ComparisonMatcherCreator::Matcher(expected) { - } + using ComparisonMatcherCreatorBase::ComparisonMatcherCreatorBase; - virtual bool matches(const T &actual) const override { - return actual != this->_expected; - } + template + TypedMatcher *createMatcher() const { + struct Matcher : public ComparisonMatcherCreatorBase::template MatcherBase { + using ComparisonMatcherCreatorBase::template MatcherBase::MatcherBase; - virtual std::string format() const override { - return std::string("!=") + TypeFormatter::format(this->_expected); - } + virtual std::string format() const override { + return std::string("!=") + TypeFormatter::format(this->_expected); + } - }; + virtual bool matches(const ActualT &actual) const override { + return actual != this->_expected; + } + }; + + return new Matcher(std::forward(this->_expectedRef)); + } + }; + + template + struct StrEqMatcherCreator : public ComparisonMatcherCreatorBase { + using ExpectedT = typename ComparisonMatcherCreatorBase::ExpectedT; + + template + struct IsTypeCompatible : std::false_type {}; + + template + struct IsTypeCompatible(), std::declval()))>> : std::true_type {}; + + using ComparisonMatcherCreatorBase::ComparisonMatcherCreatorBase; + + template + TypedMatcher *createMatcher() const { + struct Matcher : public ComparisonMatcherCreatorBase::template MatcherBase { + using ComparisonMatcherCreatorBase::template MatcherBase::MatcherBase; + + virtual std::string format() const override { + return TypeFormatter::format(this->_expected); + } + + virtual bool matches(const ActualT &actual) const override { + return std::strcmp(actual, this->_expected.c_str()) == 0; + } + }; + + return new Matcher(std::forward(this->_expectedRef)); + } + }; + + template + struct StrGtMatcherCreator : public ComparisonMatcherCreatorBase { + using ExpectedT = typename ComparisonMatcherCreatorBase::ExpectedT; + + template + struct IsTypeCompatible : std::false_type {}; + + template + struct IsTypeCompatible(), std::declval()))>> : std::true_type {}; + + using ComparisonMatcherCreatorBase::ComparisonMatcherCreatorBase; + + template + TypedMatcher *createMatcher() const { + struct Matcher : public ComparisonMatcherCreatorBase::template MatcherBase { + using ComparisonMatcherCreatorBase::template MatcherBase::MatcherBase; + + virtual std::string format() const override { + return std::string(">") + TypeFormatter::format(this->_expected); + } + + virtual bool matches(const ActualT &actual) const override { + return std::strcmp(actual, this->_expected.c_str()) > 0; + } + }; + + return new Matcher(std::forward(this->_expectedRef)); + } + }; + + template + struct StrGeMatcherCreator : public ComparisonMatcherCreatorBase { + using ExpectedT = typename ComparisonMatcherCreatorBase::ExpectedT; + + template + struct IsTypeCompatible : std::false_type {}; + + template + struct IsTypeCompatible(), std::declval()))>> : std::true_type {}; + + using ComparisonMatcherCreatorBase::ComparisonMatcherCreatorBase; + + template + TypedMatcher *createMatcher() const { + struct Matcher : public ComparisonMatcherCreatorBase::template MatcherBase { + using ComparisonMatcherCreatorBase::template MatcherBase::MatcherBase; + + virtual std::string format() const override { + return std::string(">=") + TypeFormatter::format(this->_expected); + } + + virtual bool matches(const ActualT &actual) const override { + return std::strcmp(actual, this->_expected.c_str()) >= 0; + } + }; + + return new Matcher(std::forward(this->_expectedRef)); + } + }; + + template + struct StrLtMatcherCreator : public ComparisonMatcherCreatorBase { + using ExpectedT = typename ComparisonMatcherCreatorBase::ExpectedT; + + template + struct IsTypeCompatible : std::false_type {}; + + template + struct IsTypeCompatible(), std::declval()))>> : std::true_type {}; + + using ComparisonMatcherCreatorBase::ComparisonMatcherCreatorBase; + + template + TypedMatcher *createMatcher() const { + struct Matcher : public ComparisonMatcherCreatorBase::template MatcherBase { + using ComparisonMatcherCreatorBase::template MatcherBase::MatcherBase; + + virtual std::string format() const override { + return std::string("<") + TypeFormatter::format(this->_expected); + } + + virtual bool matches(const ActualT &actual) const override { + return std::strcmp(actual, this->_expected.c_str()) < 0; + } + }; + + return new Matcher(std::forward(this->_expectedRef)); + } + }; + + template + struct StrLeMatcherCreator : public ComparisonMatcherCreatorBase { + using ExpectedT = typename ComparisonMatcherCreatorBase::ExpectedT; + + template + struct IsTypeCompatible : std::false_type {}; + + template + struct IsTypeCompatible(), std::declval()))>> : std::true_type {}; + + using ComparisonMatcherCreatorBase::ComparisonMatcherCreatorBase; + + template + TypedMatcher *createMatcher() const { + struct Matcher : public ComparisonMatcherCreatorBase::template MatcherBase { + using ComparisonMatcherCreatorBase::template MatcherBase::MatcherBase; + + virtual std::string format() const override { + return std::string("<=") + TypeFormatter::format(this->_expected); + } + + virtual bool matches(const ActualT &actual) const override { + return std::strcmp(actual, this->_expected.c_str()) <= 0; + } + }; + + return new Matcher(std::forward(this->_expectedRef)); + } + }; + + template + struct StrNeMatcherCreator : public ComparisonMatcherCreatorBase { + using ExpectedT = typename ComparisonMatcherCreatorBase::ExpectedT; + + template + struct IsTypeCompatible : std::false_type {}; + + template + struct IsTypeCompatible(), std::declval()))>> : std::true_type {}; + + using ComparisonMatcherCreatorBase::ComparisonMatcherCreatorBase; + + template + TypedMatcher *createMatcher() const { + struct Matcher : public ComparisonMatcherCreatorBase::template MatcherBase { + using ComparisonMatcherCreatorBase::template MatcherBase::MatcherBase; + + virtual std::string format() const override { + return std::string("!=") + TypeFormatter::format(this->_expected); + } + + virtual bool matches(const ActualT &actual) const override { + return std::strcmp(actual, this->_expected.c_str()) != 0; + } + }; - virtual TypedMatcher *createMatcher() const override { - return new Matcher(this->_expected); + return new Matcher(std::forward(this->_expectedRef)); } + }; + + template + struct ApproxEqCreator { + using ExpectedT = typename naked_type::type; + using ExpectedMarginT = typename naked_type::type; + + template + struct IsTypeCompatible : std::false_type {}; + + template + struct IsTypeCompatible() - std::declval()) <= std::declval())>> : std::true_type {}; + + ExpectedTRef _expectedRef; + ExpectedMarginTRef _expectedMarginRef; + + template + ApproxEqCreator(T &&expectedRef, U &&expectedMarginRef) + : _expectedRef(std::forward(expectedRef)) + , _expectedMarginRef(std::forward(expectedMarginRef)) { + } + + template + TypedMatcher *createMatcher() const { + struct Matcher : public TypedMatcher { + const ExpectedT _expected; + const ExpectedMarginT _expectedMargin; + + Matcher(ExpectedTRef expected, ExpectedMarginTRef expectedMargin) + : _expected{std::forward(expected)} + , _expectedMargin{std::forward(expectedMargin)} { + } + + virtual std::string format() const override { + return TypeFormatter::format(this->_expected) + std::string("+/-") + TypeFormatter::format(this->_expectedMargin); + } + + virtual bool matches(const ActualT &actual) const override { + return std::abs(actual - this->_expected) <= this->_expectedMargin; + } + }; + return new Matcher(std::forward(this->_expectedRef), std::forward(this->_expectedMarginRef)); + } }; } struct AnyMatcher { } static _; - template - internal::TypedAnyMatcher Any() { - internal::TypedAnyMatcher rv; - return rv; + template + internal::AnyMatcherCreator Any() { + static_assert(sizeof(T) >= 0, "To maintain backward compatibility, this function takes an useless template argument."); + internal::AnyMatcherCreator mc; + return mc; + } + + inline internal::AnyMatcherCreator Any() { + internal::AnyMatcherCreator mc; + return mc; } template - internal::EqMatcherCreator Eq(const T &arg) { - internal::EqMatcherCreator rv(arg); - return rv; + internal::EqMatcherCreator Eq(T &&arg) { + internal::EqMatcherCreator mc(std::forward(arg)); + return mc; } template - internal::GtMatcherCreator Gt(const T &arg) { - internal::GtMatcherCreator rv(arg); - return rv; + internal::GtMatcherCreator Gt(T &&arg) { + internal::GtMatcherCreator mc(std::forward(arg)); + return mc; } template - internal::GeMatcherCreator Ge(const T &arg) { - internal::GeMatcherCreator rv(arg); - return rv; + internal::GeMatcherCreator Ge(T &&arg) { + internal::GeMatcherCreator mc(std::forward(arg)); + return mc; } template - internal::LtMatcherCreator Lt(const T &arg) { - internal::LtMatcherCreator rv(arg); - return rv; + internal::LtMatcherCreator Lt(T &&arg) { + internal::LtMatcherCreator mc(std::forward(arg)); + return mc; } template - internal::LeMatcherCreator Le(const T &arg) { - internal::LeMatcherCreator rv(arg); - return rv; + internal::LeMatcherCreator Le(T &&arg) { + internal::LeMatcherCreator mc(std::forward(arg)); + return mc; } template - internal::NeMatcherCreator Ne(const T &arg) { - internal::NeMatcherCreator rv(arg); - return rv; + internal::NeMatcherCreator Ne(T &&arg) { + internal::NeMatcherCreator mc(std::forward(arg)); + return mc; + } + + inline internal::StrEqMatcherCreator StrEq(std::string&& arg) { + internal::StrEqMatcherCreator mc(std::move(arg)); + return mc; + } + + inline internal::StrEqMatcherCreator StrEq(const std::string& arg) { + internal::StrEqMatcherCreator mc(arg); + return mc; + } + + inline internal::StrGtMatcherCreator StrGt(std::string&& arg) { + internal::StrGtMatcherCreator mc(std::move(arg)); + return mc; + } + + inline internal::StrGtMatcherCreator StrGt(const std::string& arg) { + internal::StrGtMatcherCreator mc(arg); + return mc; + } + + inline internal::StrGeMatcherCreator StrGe(std::string&& arg) { + internal::StrGeMatcherCreator mc(std::move(arg)); + return mc; + } + + inline internal::StrGeMatcherCreator StrGe(const std::string& arg) { + internal::StrGeMatcherCreator mc(arg); + return mc; + } + + inline internal::StrLtMatcherCreator StrLt(std::string&& arg) { + internal::StrLtMatcherCreator mc(std::move(arg)); + return mc; + } + + inline internal::StrLtMatcherCreator StrLt(const std::string& arg) { + internal::StrLtMatcherCreator mc(arg); + return mc; + } + + inline internal::StrLeMatcherCreator StrLe(std::string&& arg) { + internal::StrLeMatcherCreator mc(std::move(arg)); + return mc; + } + + inline internal::StrLeMatcherCreator StrLe(const std::string& arg) { + internal::StrLeMatcherCreator mc(arg); + return mc; + } + + inline internal::StrNeMatcherCreator StrNe(std::string&& arg) { + internal::StrNeMatcherCreator mc(std::move(arg)); + return mc; + } + + inline internal::StrNeMatcherCreator StrNe(const std::string& arg) { + internal::StrNeMatcherCreator mc(arg); + return mc; + } + + template::type>::value, int>::type = 0, + typename std::enable_if::type>::value, int>::type = 0> + internal::ApproxEqCreator ApproxEq(T &&expected, U &&margin) { + internal::ApproxEqCreator mc(std::forward(expected), std::forward(margin)); + return mc; } } @@ -6690,7 +7199,7 @@ namespace fakeit { struct UserDefinedInvocationMatcher : ActualInvocation::Matcher { virtual ~UserDefinedInvocationMatcher() = default; - UserDefinedInvocationMatcher(std::function match) + UserDefinedInvocationMatcher(const std::function& match) : matcher{match} { } @@ -6810,7 +7319,7 @@ namespace fakeit { RecordedMethodBody(FakeitContext &fakeit, std::string name) : _fakeit(fakeit), _method{MethodInfo::nextMethodOrdinal(), name} { } - virtual ~RecordedMethodBody() NO_THROWS { + virtual ~RecordedMethodBody() FAKEIT_NO_THROWS { } MethodInfo &getMethod() { @@ -6933,7 +7442,7 @@ namespace fakeit { template struct Times : public Quantity { - Times() : Quantity(q) { } + Times() : Quantity(q) { } template static Quantifier of(const R &value) { @@ -7064,10 +7573,28 @@ namespace fakeit { namespace fakeit { + namespace helper + { + template + struct ArgValue; + + template + struct ArgValidator; + + template + static void + Assign(std::tuple...> arg_vals, current_arg &&p, arglist &&... args); + + template + struct ParamWalker; + + } + + template struct MethodStubbingProgress { - virtual ~MethodStubbingProgress() THROWS { + virtual ~MethodStubbingProgress() FAKEIT_THROWS { } template @@ -7082,6 +7609,15 @@ namespace fakeit { return Do([&r](const typename fakeit::test_arg::type...) -> R { return r; }); } + template + typename std::enable_if::value, MethodStubbingProgress&>::type + Return(R&& r) { + auto store = std::make_shared(std::move(r)); + return Do([store](const typename fakeit::test_arg::type...) mutable -> R { + return std::move(*store); + }); + } + MethodStubbingProgress & Return(const Quantifier &q) { const R &value = q.value; @@ -7143,6 +7679,19 @@ namespace fakeit { return AlwaysDo([e](const typename fakeit::test_arg::type...) -> R { throw e; }); } + template + MethodStubbingProgress & + ReturnAndSet(R &&r, valuelist &&... arg_vals) { + return Do(GetAssigner(std::forward(r), + std::forward(arg_vals)...)); + } + + template + void AlwaysReturnAndSet(R &&r, valuelist &&... arg_vals) { + AlwaysDo(GetAssigner(std::forward(r), + std::forward(arg_vals)...)); + } + virtual MethodStubbingProgress & Do(std::function::type...)> method) { return DoImpl(new Repeat(method)); @@ -7171,13 +7720,66 @@ namespace fakeit { private: MethodStubbingProgress &operator=(const MethodStubbingProgress &other) = delete; + + template +#if FAKEIT_CPLUSPLUS >= 201402L + auto +#else + std::function::type...)> +#endif + GetAssigner(R &&r, valuelist &&... arg_vals) { + class Lambda { + public: + Lambda(R &&r, valuelist &&... arg_vals) + : vals_tuple{std::forward(r), std::forward(arg_vals)...} {} + + R operator()(typename fakeit::test_arg::type... args) { + helper::ParamWalker::Assign(vals_tuple, + std::forward(args)...); + return std::get<0>(vals_tuple); + } + + private: + ArgumentsTuple vals_tuple; + }; + + return Lambda(std::forward(r), std::forward(arg_vals)...); + } + + template +#if FAKEIT_CPLUSPLUS >= 201402L + auto +#else + std::function::type...)> +#endif + GetAssigner(R &&r, helper::ArgValue... arg_vals) { + class Lambda { + public: + Lambda(R &&r, helper::ArgValue... arg_vals) + : ret{std::forward(r)} + , vals_tuple{std::forward>(arg_vals)...} {} + + R operator()(typename fakeit::test_arg::type... args) { + helper::ArgValidator::CheckPositions(vals_tuple); + helper::Assign<1>(vals_tuple, std::forward(args)...); + return std::get<0>(ret); + } + + private: + std::tuple ret; + ArgumentsTuple...> vals_tuple; + }; + + return Lambda(std::forward(r), std::forward>(arg_vals)...); + } + }; template struct MethodStubbingProgress { - virtual ~MethodStubbingProgress() THROWS { + virtual ~MethodStubbingProgress() FAKEIT_THROWS { } MethodStubbingProgress &Return() { @@ -7228,7 +7830,18 @@ namespace fakeit { return AlwaysDo([e](const typename fakeit::test_arg::type...) -> void { throw e; }); } - template + template + MethodStubbingProgress & + ReturnAndSet(valuelist &&... arg_vals) { + return Do(GetAssigner(std::forward(arg_vals)...)); + } + + template + void AlwaysReturnAndSet(valuelist &&... arg_vals) { + AlwaysDo(GetAssigner(std::forward(arg_vals)...)); + } + + template MethodStubbingProgress & Do(const Quantifier &q) { return DoImpl(new Repeat(q.value, q.quantity)); @@ -7251,33 +7864,197 @@ namespace fakeit { private: MethodStubbingProgress &operator=(const MethodStubbingProgress &other) = delete; + + template +#if FAKEIT_CPLUSPLUS >= 201402L + auto +#else + std::function::type...)> +#endif + GetAssigner(valuelist &&... arg_vals) { + class Lambda { + public: + Lambda(valuelist &&... arg_vals) + : vals_tuple{std::forward(arg_vals)...} {} + + void operator()(typename fakeit::test_arg::type... args) { + helper::ParamWalker::Assign(vals_tuple, + std::forward(args)...); + } + + private: + ArgumentsTuple vals_tuple; + }; + + return Lambda(std::forward(arg_vals)...); + } + + template +#if FAKEIT_CPLUSPLUS >= 201402L + auto +#else + std::function::type...)> +#endif + GetAssigner(helper::ArgValue... arg_vals) { + class Lambda { + public: + Lambda(helper::ArgValue... arg_vals) + : vals_tuple{std::forward>(arg_vals)...} {} + + void operator()(typename fakeit::test_arg::type... args) { + helper::ArgValidator::CheckPositions(vals_tuple); + helper::Assign<1>(vals_tuple, std::forward(args)...); + } + + private: + ArgumentsTuple...> vals_tuple; + }; + + return Lambda(std::forward>(arg_vals)...); + } + }; -} -#include -#include + namespace helper + { + template + struct ArgValue + { + ArgValue(T &&v): value ( std::forward(v) ) {} + constexpr static int pos = N; + T value; + }; -namespace fakeit { + template + struct ArgValidator + { + template + static void CheckPositions(const std::tuple...> arg_vals) + { +#if FAKEIT_CPLUSPLUS >= 201402L && !defined(_WIN32) + static_assert(std::get(arg_vals).pos <= max_index, + "Argument index out of range"); + ArgValidator::CheckPositions(arg_vals); +#else + (void)arg_vals; +#endif + } + }; - class Finally { - private: - std::function _finallyClause; + template + struct ArgValidator + { + template + static void CheckPositions(T) {} + }; - Finally(const Finally &); + template + typename std::enable_if::value, + typename std::remove_pointer::type &>::type + GetArg(current_arg &&t) + { + return *t; + } - Finally &operator=(const Finally &); + template + typename std::enable_if::value, current_arg>::type + GetArg(current_arg &&t) + { + return std::forward(t); + } - public: - explicit Finally(std::function f) : - _finallyClause(f) { + template + struct ParamWalker { + template + static void + Assign(ArgumentsTuple arg_vals, current_arg &&p, arglist&&... args) { + ParamWalker::template Assign(arg_vals, std::forward(args)...); + GetArg(std::forward(p)) = std::get(arg_vals); + } + }; + + template<> + struct ParamWalker<0> { + template + static void Assign(ArgumentsTuple, arglist... ) {} + }; + + template + struct ArgLocator { + template + static void AssignArg(current_arg &&p, std::tuple...> arg_vals) { +#if FAKEIT_CPLUSPLUS >= 201703L && !defined (_WIN32) + if constexpr (std::get(arg_vals).pos == arg_index) + GetArg(std::forward(p)) = std::get(arg_vals).value; +#else + if (std::get(arg_vals).pos == arg_index) + Set(std::forward(p), std::get(arg_vals).value); +#endif + else if (check_index > 0) + ArgLocator::AssignArg(std::forward(p), arg_vals); + } + +#if FAKEIT_CPLUSPLUS < 201703L || defined (_WIN32) + private: + template + static + typename std::enable_if())), U>::value, void>::type + Set(T &&p, U &&v) + { + GetArg(std::forward(p)) = v; + } + + template + static + typename std::enable_if())), U>::value, void>::type + Set(T &&, U &&) + { + throw std::logic_error("ReturnAndSet(): Invalid value type"); + } +#endif + + }; + + template + struct ArgLocator { + template + static void AssignArg(current_arg, T) { + } + }; + + template + static void + Assign(std::tuple...> arg_vals, current_arg &&p, arglist &&... args) { + ArgLocator::AssignArg(std::forward(p), arg_vals); + Assign(arg_vals, std::forward(args)...); } - ~Finally() { - _finallyClause(); + template + static void Assign(std::tuple) {} + + } + + + namespace placeholders + { + using namespace std::placeholders; + + template (std::is_placeholder::value), bool>::type = true> + helper::ArgValue::value> + operator<=(PlaceHolder, ArgType &&arg) + { + return { std::forward(arg) }; } - }; + + } + + using placeholders::operator <=; } +#include + + namespace fakeit { @@ -7300,7 +8077,10 @@ namespace fakeit { Action &action = dynamic_cast &>(destructable); std::function finallyClause = [&]() -> void { if (action.isDone()) + { _recordedActions.erase(_recordedActions.begin()); + _usedActions.push_back(destructablePtr); + } }; Finally onExit(finallyClause); return action.invoke(args); @@ -7332,18 +8112,20 @@ namespace fakeit { void clear() { _recordedActions.clear(); + _usedActions.clear(); auto actionPtr = std::shared_ptr {new NoMoreRecordedAction()}; _recordedActions.push_back(actionPtr); } std::vector> _recordedActions; + std::vector> _usedActions; }; } namespace fakeit { - template + template class DataMemberStubbingRoot { private: @@ -7352,7 +8134,7 @@ namespace fakeit { DataMemberStubbingRoot() = default; - void operator=(const DATA_TYPE&) { + void operator=(const DataType&) { } }; @@ -7381,7 +8163,8 @@ namespace fakeit { struct SpyingContext : Xaction { virtual void appendAction(Action *action) = 0; - virtual std::function getOriginalMethod() = 0; + virtual std::function getOriginalMethodCopyArgs() = 0; + virtual std::function getOriginalMethodForwardArgs() = 0; }; } namespace fakeit { @@ -7416,8 +8199,11 @@ namespace fakeit { template using NakedArgType = typename naked_type>::type; - template - using ArgMatcherCreatorType = decltype(std::declval>>()); + template + struct IsMatcherCreatorTypeCompatible : std::false_type {}; + + template + struct IsMatcherCreatorTypeCompatible>::value, void>::type> : std::true_type {}; MatchersCollector(std::vector &matchers) : _matchers(matchers) { @@ -7428,56 +8214,36 @@ namespace fakeit { template typename std::enable_if< - std::is_constructible, Head>::value, void> - ::type CollectMatchers(const Head &value) { + !std::is_same::type>::value && + !IsMatcherCreatorTypeCompatible::type>::value && + std::is_constructible, Head&&>::value, void> + ::type CollectMatchers(Head &&value) { - TypedMatcher> *d = Eq>(value).createMatcher(); + TypedMatcher> *d = Eq(std::forward(value)).template createMatcher>(); _matchers.push_back(d); } - template - typename std::enable_if< - std::is_constructible, Head>::value - , void> - ::type CollectMatchers(const Head &head, const Tail &... tail) { - CollectMatchers(head); - MatchersCollector c(_matchers); - c.CollectMatchers(tail...); - } - template typename std::enable_if< - std::is_base_of>, Head>::value, void> - ::type CollectMatchers(const Head &creator) { - TypedMatcher> *d = creator.createMatcher(); + IsMatcherCreatorTypeCompatible::type>::value, void> + ::type CollectMatchers(Head &&creator) { + TypedMatcher> *d = creator.template createMatcher>(); _matchers.push_back(d); } - template - - typename std::enable_if< - std::is_base_of>, Head>::value, void> - ::type CollectMatchers(const Head &head, const Tail &... tail) { - CollectMatchers(head); - MatchersCollector c(_matchers); - c.CollectMatchers(tail...); - } - template typename std::enable_if< - std::is_same::value, void> - ::type CollectMatchers(const Head &) { - TypedMatcher> *d = Any>().createMatcher(); + std::is_same::type>::value, void> + ::type CollectMatchers(Head &&) { + TypedMatcher> *d = Any().template createMatcher>(); _matchers.push_back(d); } template - typename std::enable_if< - std::is_same::value, void> - ::type CollectMatchers(const Head &head, const Tail &... tail) { - CollectMatchers(head); + void CollectMatchers(Head &&head, Tail &&... tail) { + CollectMatchers(std::forward(head)); MatchersCollector c(_matchers); - c.CollectMatchers(tail...); + c.CollectMatchers(std::forward(tail)...); } }; @@ -7498,7 +8264,8 @@ namespace fakeit { struct Context : Destructible { - virtual typename std::function getOriginalMethod() = 0; + virtual typename std::function getOriginalMethodCopyArgs() = 0; + virtual typename std::function getOriginalMethodForwardArgs() = 0; virtual std::string getMethodName() = 0; @@ -7597,8 +8364,12 @@ namespace fakeit { into.push_back(&getStubbingContext().getInvolvedMock()); } - typename std::function getOriginalMethod() { - return getStubbingContext().getOriginalMethod(); + typename std::function getOriginalMethodCopyArgs() { + return getStubbingContext().getOriginalMethodCopyArgs(); + } + + typename std::function getOriginalMethodForwardArgs() { + return getStubbingContext().getOriginalMethodForwardArgs(); } void setInvocationMatcher(typename ActualInvocation::Matcher *matcher) { @@ -7613,7 +8384,7 @@ namespace fakeit { : _impl{new Implementation(stubbingContext)} { } - MethodMockingContext(MethodMockingContext &) = default; + MethodMockingContext(const MethodMockingContext &) = default; @@ -7621,7 +8392,7 @@ namespace fakeit { : _impl(std::move(other._impl)) { } - virtual ~MethodMockingContext() NO_THROWS { } + virtual ~MethodMockingContext() FAKEIT_NO_THROWS { } std::string format() const override { return _impl->format(); @@ -7660,13 +8431,13 @@ namespace fakeit { _impl->setMethodDetails(mockName, methodName); } - void setMatchingCriteria(std::function predicate) { + void setMatchingCriteria(const std::function& predicate) { typename ActualInvocation::Matcher *matcher{ new UserDefinedInvocationMatcher(predicate)}; _impl->setInvocationMatcher(matcher); } - void setMatchingCriteria(const std::vector &matchers) { + void setMatchingCriteria(std::vector &matchers) { typename ActualInvocation::Matcher *matcher{ new ArgumentsMatcherInvocationMatcher(matchers)}; _impl->setInvocationMatcher(matcher); @@ -7681,21 +8452,26 @@ namespace fakeit { _impl->setMethodBodyByAssignment(method); } - template::type> - void setMatchingCriteria(const matcherCreators &... matcherCreator) { + template + typename std::enable_if< + sizeof...(matcherCreators) == sizeof...(arglist), void> + ::type setMatchingCriteria(matcherCreators &&... matcherCreator) { std::vector matchers; MatchersCollector<0, arglist...> c(matchers); - c.CollectMatchers(matcherCreator...); + c.CollectMatchers(std::forward(matcherCreator)...); MethodMockingContext::setMatchingCriteria(matchers); } private: - typename std::function getOriginalMethod() override { - return _impl->getOriginalMethod(); + typename std::function getOriginalMethodCopyArgs() override { + return _impl->getOriginalMethodCopyArgs(); + } + + typename std::function getOriginalMethodForwardArgs() override { + return _impl->getOriginalMethodForwardArgs(); } std::shared_ptr _impl; @@ -7712,7 +8488,7 @@ namespace fakeit { : MethodMockingContext(stubbingContext) { } - MockingContext(MockingContext &) = default; + MockingContext(const MockingContext &) = default; MockingContext(MockingContext &&other) : MethodMockingContext(std::move(other)) { @@ -7723,18 +8499,13 @@ namespace fakeit { return *this; } - MockingContext &Using(const arglist &... args) { - MethodMockingContext::setMatchingCriteria(args...); - return *this; - } - template - MockingContext &Using(const arg_matcher &... arg_matchers) { - MethodMockingContext::setMatchingCriteria(arg_matchers...); + MockingContext &Using(arg_matcher &&... arg_matchers) { + MethodMockingContext::setMatchingCriteria(std::forward(arg_matchers)...); return *this; } - MockingContext &Matching(std::function matcher) { + MockingContext &Matching(const std::function& matcher) { MethodMockingContext::setMatchingCriteria(matcher); return *this; } @@ -7744,7 +8515,7 @@ namespace fakeit { return *this; } - MockingContext &operator()(std::function matcher) { + MockingContext &operator()(const std::function& matcher) { MethodMockingContext::setMatchingCriteria(matcher); return *this; } @@ -7777,7 +8548,7 @@ namespace fakeit { : MethodMockingContext(stubbingContext) { } - MockingContext(MockingContext &) = default; + MockingContext(const MockingContext &) = default; MockingContext(MockingContext &&other) : MethodMockingContext(std::move(other)) { @@ -7788,18 +8559,13 @@ namespace fakeit { return *this; } - MockingContext &Using(const arglist &... args) { - MethodMockingContext::setMatchingCriteria(args...); - return *this; - } - template - MockingContext &Using(const arg_matcher &... arg_matchers) { - MethodMockingContext::setMatchingCriteria(arg_matchers...); + MockingContext &Using(arg_matcher &&... arg_matchers) { + MethodMockingContext::setMatchingCriteria(std::forward(arg_matchers)...); return *this; } - MockingContext &Matching(std::function matcher) { + MockingContext &Matching(const std::function& matcher) { MethodMockingContext::setMatchingCriteria(matcher); return *this; } @@ -7809,7 +8575,7 @@ namespace fakeit { return *this; } - MockingContext &operator()(std::function matcher) { + MockingContext &operator()(const std::function& matcher) { MethodMockingContext::setMatchingCriteria(matcher); return *this; } @@ -7827,7 +8593,7 @@ namespace fakeit { : MethodMockingContext(stubbingContext) { } - DtorMockingContext(DtorMockingContext &other) : MethodMockingContext(other) { + DtorMockingContext(const DtorMockingContext &other) : MethodMockingContext(other) { } DtorMockingContext(DtorMockingContext &&other) : MethodMockingContext(std::move(other)) { @@ -7857,21 +8623,12 @@ namespace fakeit { } MockImpl(FakeitContext &fakeit) - : MockImpl(fakeit, *(createFakeInstance()), false) { - FakeObject *fake = reinterpret_cast *>(_instance); + : MockImpl(fakeit, *(createFakeInstance()), false){ + FakeObject *fake = asFakeObject(_instanceOwner.get()); fake->getVirtualTable().setCookie(1, this); } - virtual ~MockImpl() NO_THROWS { - _proxy.detach(); - if (_isOwner) { - FakeObject *fake = reinterpret_cast *>(_instance); - delete fake; - } - } - - void detach() { - _isOwner = false; + virtual ~MockImpl() FAKEIT_NO_THROWS { _proxy.detach(); } @@ -7886,8 +8643,8 @@ namespace fakeit { void initDataMembersIfOwner() { - if (_isOwner) { - FakeObject *fake = reinterpret_cast *>(_instance); + if (isOwner()) { + FakeObject *fake = asFakeObject(_instanceOwner.get()); fake->initializeDataMembersArea(); } } @@ -7915,10 +8672,10 @@ namespace fakeit { return _fakeit; } - template::value>::type> - DataMemberStubbingRoot stubDataMember(DATA_TYPE T::*member, const arglist &... ctorargs) { + template::value>::type> + DataMemberStubbingRoot stubDataMember(DataType T::*member, const arglist &... ctorargs) { _proxy.stubDataMember(member, ctorargs...); - return DataMemberStubbingRoot(); + return DataMemberStubbingRoot(); } template::value>::type> @@ -7931,12 +8688,35 @@ namespace fakeit { return DtorMockingContext(new DtorMockingContextImpl(*this)); } + + + + + + private: - DynamicProxy _proxy; - C *_instance; - bool _isOwner; + + + + + + + + + + std::shared_ptr> _instanceOwner; + DynamicProxy _proxy; FakeitContext &_fakeit; + MockImpl(FakeitContext &fakeit, C &obj, bool isSpy) + : _instanceOwner(isSpy ? nullptr : asFakeObject(&obj)) + , _proxy{obj} + , _fakeit(fakeit) {} + + static FakeObject* asFakeObject(void* instance){ + return reinterpret_cast *>(instance); + } + template class MethodMockingContextBase : public MethodMockingContext::Context { protected: @@ -7989,13 +8769,35 @@ namespace fakeit { : MethodMockingContextBase(mock), _vMethod(vMethod) { } + template::value...>::value, int>::type = 0> + std::function getOriginalMethodCopyArgsInternal(int) { + auto mPtr = _vMethod; + auto& mock = MethodMockingContextBase::_mock; + C * instance = &(MethodMockingContextBase::_mock.get()); + return [=, &mock](arglist&... args) -> R { + auto methodSwapper = mock.createRaiiMethodSwapper(mPtr); + return (instance->*mPtr)(args...); + }; + } + + + template + [[noreturn]] std::function getOriginalMethodCopyArgsInternal(long) { + std::abort(); + } + + + std::function getOriginalMethodCopyArgs() override { + return getOriginalMethodCopyArgsInternal(0); + } - virtual std::function getOriginalMethod() override { - void *mPtr = MethodMockingContextBase::_mock.getOriginalMethod(_vMethod); + std::function getOriginalMethodForwardArgs() override { + auto mPtr = _vMethod; + auto& mock = MethodMockingContextBase::_mock; C * instance = &(MethodMockingContextBase::_mock.get()); - return [=](arglist&... args) -> R { - auto m = union_cast::type>(mPtr); - return m(instance, std::forward(args)...); + return [=, &mock](arglist&... args) -> R { + auto methodSwapper = mock.createRaiiMethodSwapper(mPtr); + return (instance->*mPtr)(std::forward(args)...); }; } }; @@ -8034,21 +8836,29 @@ namespace fakeit { : MethodMockingContextBase(mock) { } - virtual std::function getOriginalMethod() override { - C &instance = MethodMockingContextBase::_mock.get(); - return [=, &instance]() -> void { + std::function getOriginalMethodCopyArgs() override { + return [=]() -> void { + }; + } + + std::function getOriginalMethodForwardArgs() override { + return [=]() -> void { }; } }; static MockImpl *getMockImpl(void *instance) { - FakeObject *fake = reinterpret_cast *>(instance); + FakeObject *fake = asFakeObject(instance); MockImpl *mock = reinterpret_cast *>(fake->getVirtualTable().getCookie( 1)); return mock; } + bool isOwner(){ return _instanceOwner != nullptr;} + + void unmockedDtor() {} + void unmocked() { ActualInvocation<> invocation(Invocation::nextInvocationOrdinal(), UnknownMethod::instance()); UnexpectedMethodCallEvent event(UnexpectedType::Unmocked, invocation); @@ -8063,8 +8873,16 @@ namespace fakeit { static C *createFakeInstance() { FakeObject *fake = new FakeObject(); void *unmockedMethodStubPtr = union_cast(&MockImpl::unmocked); - fake->getVirtualTable().initAll(unmockedMethodStubPtr); - return reinterpret_cast(fake); + void *unmockedDtorStubPtr = union_cast(&MockImpl::unmockedDtor); + fake->getVirtualTable().initAll(unmockedMethodStubPtr); + if (VTUtils::hasVirtualDestructor()) + fake->setDtor(unmockedDtorStubPtr); + return reinterpret_cast(fake); + } + + template + Finally createRaiiMethodSwapper(R(C::*vMethod)(arglist...)) { + return _proxy.createRaiiMethodSwapper(vMethod); } template @@ -8102,10 +8920,6 @@ namespace fakeit { return *dtorMock; } - MockImpl(FakeitContext &fakeit, C &obj, bool isSpy) - : _proxy{obj}, _instance(&obj), _isOwner(!isSpy), _fakeit(fakeit) { - } - template static RecordedMethodBody *createRecordedMethodBody(MockObject &mock, R(C::*vMethod)(arglist...)) { @@ -8115,7 +8929,6 @@ namespace fakeit { static RecordedMethodBody *createRecordedDtorBody(MockObject &mock) { return new RecordedMethodBody(mock.getFakeIt(), "dtor"); } - }; } namespace fakeit { @@ -8126,21 +8939,37 @@ namespace fakeit { template struct Prototype { - typedef R Type(Args...); - - typedef R ConstType(Args...) const; - template struct MemberType { - typedef Type(C::*type); - typedef ConstType(C::*cosntType); + using Type = R (C::*)(Args...); + using ConstType = R (C::*)(Args...) const; + using RefType = R (C::*)(Args...) &; + using ConstRefType = R (C::*)(Args...) const&; + using RValRefType = R (C::*)(Args...) &&; + using ConstRValRefType = R (C::*)(Args...) const&&; + + static Type get(Type t) { + return t; + } + + static ConstType getConst(ConstType t) { + return t; + } + + static RefType getRef(RefType t) { + return t; + } + + static ConstRefType getConstRef(ConstRefType t) { + return t; + } - static type get(type t) { + static RValRefType getRValRef(RValRefType t) { return t; } - static cosntType getconst(cosntType t) { + static ConstRValRefType getConstRValRef(ConstRValRefType t) { return t; } @@ -8165,12 +8994,25 @@ namespace fakeit { } - namespace fakeit { namespace internal { + template + struct WithCommonVoid { + using type = T; + }; + + + + + + template + struct WithCommonVoid::value, void>::type> { + using type = void; + }; + + template + using WithCommonVoid_t = typename WithCommonVoid::type; } - using namespace fakeit; - using namespace fakeit::internal; template class Mock : public ActualInvocationsSource { @@ -8190,7 +9032,11 @@ namespace fakeit { return impl.get(); } - C &operator()() { + + + + + C &operator()() { return get(); } @@ -8202,64 +9048,73 @@ namespace fakeit { impl.clear(); } - template::value>::type> - DataMemberStubbingRoot Stub(DATA_TYPE C::* member, const arglist &... ctorargs) { + template::value>::type> + DataMemberStubbingRoot Stub(DataType C::* member, const arglist &... ctorargs) { return impl.stubDataMember(member, ctorargs...); } + template::value && std::is_base_of::value>::type> - MockingContext stub(R (T::*vMethod)(arglist...) const) { - auto methodWithoutConstVolatile = reinterpret_cast(vMethod); + std::is_base_of::value>::type> + MockingContext, arglist...> stub(R (T::*vMethod)(arglist...) const) { + auto methodWithoutConstVolatile = reinterpret_cast (T::*)(arglist...)>(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } + template::value && std::is_base_of::value>::type> - MockingContext stub(R(T::*vMethod)(arglist...) volatile) { - auto methodWithoutConstVolatile = reinterpret_cast(vMethod); + std::is_base_of::value>::type> + MockingContext, arglist...> stub(R(T::*vMethod)(arglist...) volatile) { + auto methodWithoutConstVolatile = reinterpret_cast(T::*)(arglist...)>(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } + template::value && std::is_base_of::value>::type> - MockingContext stub(R(T::*vMethod)(arglist...) const volatile) { - auto methodWithoutConstVolatile = reinterpret_cast(vMethod); + std::is_base_of::value>::type> + MockingContext, arglist...> stub(R(T::*vMethod)(arglist...) const volatile) { + auto methodWithoutConstVolatile = reinterpret_cast(T::*)(arglist...)>(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } + template::value && std::is_base_of::value>::type> - MockingContext stub(R(T::*vMethod)(arglist...)) { - return impl.template stubMethod(vMethod); + std::is_base_of::value>::type> + MockingContext, arglist...> stub(R(T::*vMethod)(arglist...)) { + auto methodWithoutConstVolatile = reinterpret_cast(T::*)(arglist...)>(vMethod); + return impl.template stubMethod(methodWithoutConstVolatile); } + template::value && std::is_base_of::value>::type> - MockingContext stub(R(T::*vMethod)(arglist...) const) { - auto methodWithoutConstVolatile = reinterpret_cast(vMethod); + std::is_base_of::value>::type> + MockingContext, arglist...> stub(R(T::*vMethod)(arglist...) &) { + auto methodWithoutConstVolatile = reinterpret_cast(T::*)(arglist...)>(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } + template::value && std::is_base_of::value>::type> - MockingContext stub(R(T::*vMethod)(arglist...) volatile) { - auto methodWithoutConstVolatile = reinterpret_cast(vMethod); + std::is_base_of::value>::type> + MockingContext, arglist...> stub(R(T::*vMethod)(arglist...) const&) { + auto methodWithoutConstVolatile = reinterpret_cast(T::*)(arglist...)>(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } + template::value && std::is_base_of::value>::type> - MockingContext stub(R(T::*vMethod)(arglist...) const volatile) { - auto methodWithoutConstVolatile = reinterpret_cast(vMethod); + std::is_base_of::value>::type> + MockingContext, arglist...> stub(R(T::*vMethod)(arglist...) &&) { + auto methodWithoutConstVolatile = reinterpret_cast(T::*)(arglist...)>(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } + template::value && std::is_base_of::value>::type> - MockingContext stub(R(T::*vMethod)(arglist...)) { - auto methodWithoutConstVolatile = reinterpret_cast(vMethod); + std::is_base_of::value>::type> + MockingContext, arglist...> stub(R(T::*vMethod)(arglist...) const&&) { + auto methodWithoutConstVolatile = reinterpret_cast(T::*)(arglist...)>(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } @@ -8314,7 +9169,7 @@ namespace fakeit { reference->AddRef(); } - ~smart_ptr() THROWS { + ~smart_ptr() FAKEIT_THROWS { if (reference->Release() == 0) { delete reference; delete pData; @@ -8358,16 +9213,16 @@ namespace fakeit { friend class WhenFunctor; - virtual ~StubbingChange() THROWS { + virtual ~StubbingChange() FAKEIT_THROWS { - if (std::uncaught_exception()) { + if (UncaughtException()) { return; } _xaction.commit(); } - StubbingChange(StubbingChange &other) : + StubbingChange(const StubbingChange &other) : _xaction(other._xaction) { } @@ -8389,7 +9244,7 @@ namespace fakeit { virtual ~MethodProgress() override = default; - MethodProgress(MethodProgress &other) : + MethodProgress(const MethodProgress &other) : _progress(other._progress), _context(other._context) { } @@ -8619,8 +9474,8 @@ namespace fakeit { friend class SequenceVerificationProgress; - ~SequenceVerificationExpectation() THROWS { - if (std::uncaught_exception()) { + ~SequenceVerificationExpectation() FAKEIT_THROWS { + if (UncaughtException()) { return; } VerifyExpectation(_fakeit); @@ -8634,6 +9489,10 @@ namespace fakeit { _expectedCount = count; } + void expectAnything() { + _expectAnything = true; + } + void setFileInfo(const char * file, int line, const char * callingMethod) { _file = file; _line = line; @@ -8646,6 +9505,7 @@ namespace fakeit { InvocationsSourceProxy _involvedInvocationSources; std::vector _expectedPattern; int _expectedCount; + bool _expectAnything; const char * _file; int _line; @@ -8660,6 +9520,7 @@ namespace fakeit { _involvedInvocationSources(mocks), _expectedPattern(expectedPattern), _expectedCount(-1), + _expectAnything(false), _line(0), _isVerified(false) { } @@ -8673,12 +9534,14 @@ namespace fakeit { MatchAnalysis ma; ma.run(_involvedInvocationSources, _expectedPattern); - if (isAtLeastVerification() && atLeastLimitNotReached(ma.count)) { - return handleAtLeastVerificationEvent(verificationErrorHandler, ma.actualSequence, ma.count); - } + if (isNotAnythingVerification()) { + if (isAtLeastVerification() && atLeastLimitNotReached(ma.count)) { + return handleAtLeastVerificationEvent(verificationErrorHandler, ma.actualSequence, ma.count); + } - if (isExactVerification() && exactLimitNotMatched(ma.count)) { - return handleExactVerificationEvent(verificationErrorHandler, ma.actualSequence, ma.count); + if (isExactVerification() && exactLimitNotMatched(ma.count)) { + return handleExactVerificationEvent(verificationErrorHandler, ma.actualSequence, ma.count); + } } markAsVerified(ma.matchedInvocations); @@ -8702,6 +9565,10 @@ namespace fakeit { } } + bool isNotAnythingVerification() { + return !_expectAnything; + } + bool isAtLeastVerification() { return _expectedCount < 0; @@ -8711,12 +9578,12 @@ namespace fakeit { return !isAtLeastVerification(); } - bool atLeastLimitNotReached(int count) { - return count < -_expectedCount; + bool atLeastLimitNotReached(int actualCount) { + return actualCount < -_expectedCount; } - bool exactLimitNotMatched(int count) { - return count != _expectedCount; + bool exactLimitNotMatched(int actualCount) { + return actualCount != _expectedCount; } void handleExactVerificationEvent(VerificationEventHandler &verificationErrorHandler, @@ -8750,20 +9617,6 @@ namespace fakeit { } }; } -#include -#include -#include - -namespace fakeit { - - template - static std::string to_string(const T &n) { - std::ostringstream stm; - stm << n; - return stm.str(); - } - -} namespace fakeit { @@ -8820,14 +9673,19 @@ namespace fakeit { public: - ~SequenceVerificationProgress() THROWS { }; + ~SequenceVerificationProgress() FAKEIT_THROWS { }; - operator bool() { + operator bool() const { return Terminator(_expectationPtr); } bool operator!() const { return !Terminator(_expectationPtr); } + Terminator Any() { + _expectationPtr->expectAnything(); + return Terminator(_expectationPtr); + } + Terminator Never() { Exactly(0); return Terminator(_expectationPtr); @@ -8981,8 +9839,8 @@ namespace fakeit { friend class VerifyNoOtherInvocationsVerificationProgress; - ~VerifyNoOtherInvocationsExpectation() THROWS { - if (std::uncaught_exception()) { + ~VerifyNoOtherInvocationsExpectation() FAKEIT_THROWS { + if (UncaughtException()) { return; } @@ -9013,7 +9871,7 @@ namespace fakeit { _isVerified(false) { } - VerifyNoOtherInvocationsExpectation(VerifyNoOtherInvocationsExpectation &other) = default; + VerifyNoOtherInvocationsExpectation(const VerifyNoOtherInvocationsExpectation &other) = default; void VerifyExpectation(VerificationEventHandler &verificationErrorHandler) { if (_isVerified) @@ -9068,7 +9926,7 @@ namespace fakeit { public: - ~VerifyNoOtherInvocationsVerificationProgress() THROWS { + ~VerifyNoOtherInvocationsVerificationProgress() FAKEIT_THROWS { }; VerifyNoOtherInvocationsVerificationProgress setFileInfo(const char * file, int line, @@ -9077,8 +9935,8 @@ namespace fakeit { return *this; } - operator bool() { - return toBool(); + operator bool() const { + return const_cast(this)->toBool(); } bool operator!() const { return !const_cast(this)->toBool(); } @@ -9112,15 +9970,51 @@ namespace fakeit { }; } +#include + + namespace fakeit { class SpyFunctor { + private: + + template::value...>::value, int>::type = 0> + void spy(const SpyingContext &root, int) { + SpyingContext &rootWithoutConst = const_cast &>(root); + auto methodFromOriginalVT = rootWithoutConst.getOriginalMethodCopyArgs(); + rootWithoutConst.appendAction(new ReturnDelegateValue(methodFromOriginalVT)); + rootWithoutConst.commit(); + } + + template + void spy(const SpyingContext &, long) { + static_assert(!std::is_same::value, "Spy() cannot accept move-only args, use SpyWithoutVerify() instead which is able to forward these args but then they won't be available for Verify()."); + } + + void operator()() { + } + + public: + + template + void operator()(const H &head, const M &... tail) { + spy(head, 0); + this->operator()(tail...); + } + + }; + +} + +namespace fakeit { + + class SpyWithoutVerifyFunctor { private: template void spy(const SpyingContext &root) { SpyingContext &rootWithoutConst = const_cast &>(root); - auto methodFromOriginalVT = rootWithoutConst.getOriginalMethod(); + auto methodFromOriginalVT = rootWithoutConst.getOriginalMethodForwardArgs(); rootWithoutConst.appendAction(new ReturnDelegateValue(methodFromOriginalVT)); rootWithoutConst.commit(); } @@ -9139,7 +10033,6 @@ namespace fakeit { }; } - #include #include @@ -9209,6 +10102,7 @@ namespace fakeit { static VerifyNoOtherInvocationsFunctor VerifyNoOtherInvocations(Fakeit); static UnverifiedFunctor Unverified(Fakeit); static SpyFunctor Spy; + static SpyWithoutVerifyFunctor SpyWithoutVerify; static FakeFunctor Fake; static WhenFunctor When; @@ -9222,6 +10116,7 @@ namespace fakeit { use(&Fake); use(&When); use(&Spy); + use(&SpyWithoutVerify); use(&Using); use(&Verify); use(&VerifyNoOtherInvocations); @@ -9235,25 +10130,49 @@ namespace fakeit { #endif #define MOCK_TYPE(mock) \ - std::remove_reference::type + std::remove_reference::type #define OVERLOADED_METHOD_PTR(mock, method, prototype) \ - fakeit::Prototype::MemberType::get(&MOCK_TYPE(mock)::method) + fakeit::Prototype::template MemberType::get(&MOCK_TYPE(mock)::method) #define CONST_OVERLOADED_METHOD_PTR(mock, method, prototype) \ - fakeit::Prototype::MemberType::getconst(&MOCK_TYPE(mock)::method) + fakeit::Prototype::template MemberType::getConst(&MOCK_TYPE(mock)::method) + +#define REF_OVERLOADED_METHOD_PTR(mock, method, prototype) \ + fakeit::Prototype::MemberType::getRef(&MOCK_TYPE(mock)::method) + +#define CONST_REF_OVERLOADED_METHOD_PTR(mock, method, prototype) \ + fakeit::Prototype::MemberType::getConstRef(&MOCK_TYPE(mock)::method) + +#define R_VAL_REF_OVERLOADED_METHOD_PTR(mock, method, prototype) \ + fakeit::Prototype::MemberType::getRValRef(&MOCK_TYPE(mock)::method) + +#define CONST_R_VAL_REF_OVERLOADED_METHOD_PTR(mock, method, prototype) \ + fakeit::Prototype::MemberType::getConstRValRef(&MOCK_TYPE(mock)::method) #define Dtor(mock) \ - mock.dtor().setMethodDetails(#mock,"destructor") + (mock).dtor().setMethodDetails(#mock,"destructor") #define Method(mock, method) \ - mock.template stub<__COUNTER__>(&MOCK_TYPE(mock)::method).setMethodDetails(#mock,#method) + (mock).template stub<__COUNTER__>(&MOCK_TYPE(mock)::method).setMethodDetails(#mock,#method) #define OverloadedMethod(mock, method, prototype) \ - mock.template stub<__COUNTER__>(OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) + (mock).template stub<__COUNTER__>(OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) #define ConstOverloadedMethod(mock, method, prototype) \ - mock.template stub<__COUNTER__>(CONST_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) + (mock).template stub<__COUNTER__>(CONST_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) + +#define RefOverloadedMethod(mock, method, prototype) \ + (mock).template stub<__COUNTER__>(REF_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) + +#define ConstRefOverloadedMethod(mock, method, prototype) \ + (mock).template stub<__COUNTER__>(CONST_REF_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) + +#define RValRefOverloadedMethod(mock, method, prototype) \ + (mock).template stub<__COUNTER__>(R_VAL_REF_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) + +#define ConstRValRefOverloadedMethod(mock, method, prototype) \ + (mock).template stub<__COUNTER__>(CONST_R_VAL_REF_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) #define Verify(...) \ Verify( __VA_ARGS__ ).setFileInfo(__FILE__, __LINE__, __func__) @@ -9269,4 +10188,3 @@ namespace fakeit { #define When(call) \ When(call) - diff --git a/src/fakeit/README.md b/src/fakeit/README.md deleted file mode 100644 index 8e01fa0..0000000 --- a/src/fakeit/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# FakeIt - -Files present in this directory were extracted from [FakeIt](https://github.com/eranpeer/FakeIt) - -This directory should not be here, FakeIt should be a dependency and the headers should be linked. \ No newline at end of file diff --git a/test/main.cpp b/test/main.cpp index ffad5f3..a308066 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -1,3 +1,4 @@ +// clang-format off #include #include #include @@ -10,6 +11,8 @@ using namespace fakeit; #include "test_stream.h" #include "test_serial.h" #include "test_wire.h" +#include "test_spi.h" +#include "test_eeprom.h" #include "test_client.h" #include "test_arduino_string.h" #include "test_include.h" @@ -38,6 +41,8 @@ int main(int argc, char **argv) RUN_TEST_GROUP(StreamTest); RUN_TEST_GROUP(SerialTest); RUN_TEST_GROUP(WireTest); + RUN_TEST_GROUP(SpiTest); + RUN_TEST_GROUP(EEPROMTest); RUN_TEST_GROUP(ClientTest); RUN_TEST_GROUP(IncludeTest); @@ -47,3 +52,4 @@ int main(int argc, char **argv) } #endif +// clang-format on \ No newline at end of file diff --git a/test/test_client.h b/test/test_client.h index 532a228..dd8d544 100644 --- a/test/test_client.h +++ b/test/test_client.h @@ -1,7 +1,11 @@ +const char * host = "localhost"; + #ifdef UNIT_TEST namespace ClientTest { + const char * localhost = "localhost"; + class MyService { public: @@ -30,7 +34,7 @@ namespace ClientTest Client* client = ArduinoFakeMock(Client); TEST_ASSERT_EQUAL(0, client->connected()); - TEST_ASSERT_EQUAL(1, client->connect("localhost", 8080)); + TEST_ASSERT_EQUAL(1, client->connect(localhost, 8080)); TEST_ASSERT_EQUAL(1, client->connected()); TEST_ASSERT_EQUAL(2, client->peek()); @@ -41,7 +45,7 @@ namespace ClientTest Verify(Method(ArduinoFake(Client), peek)).Once(); Verify(Method(ArduinoFake(Client), flush)).Once(); Verify(Method(ArduinoFake(Client), connected)).Exactly(2_Times); - Verify(OverloadedMethod(ArduinoFake(Client), connect, int(const char*, uint16_t)).Using("localhost", 8080)).Once(); + Verify(OverloadedMethod(ArduinoFake(Client), connect, int(const char*, uint16_t)).Using(localhost, 8080)).Once(); } void test_connect(void) @@ -54,14 +58,14 @@ namespace ClientTest Client* client = ArduinoFakeMock(Client); - TEST_ASSERT_EQUAL(1, client->connect("localhost", 8080)); - TEST_ASSERT_EQUAL(0, client->connect("localhost", 80)); + TEST_ASSERT_EQUAL(1, client->connect(localhost, 8080)); + TEST_ASSERT_EQUAL(0, client->connect(localhost, 80)); TEST_ASSERT_EQUAL(0, client->connect(ipAddress1, 8080)); TEST_ASSERT_EQUAL(1, client->connect(ipAddress2, 8080)); - Verify(OverloadedMethod(ArduinoFake(Client), connect, int(const char*, uint16_t)).Using("localhost", 8080)).Once(); - Verify(OverloadedMethod(ArduinoFake(Client), connect, int(const char*, uint16_t)).Using("localhost", 80)).Once(); + Verify(OverloadedMethod(ArduinoFake(Client), connect, int(const char*, uint16_t)).Using(localhost, 8080)).Once(); + Verify(OverloadedMethod(ArduinoFake(Client), connect, int(const char*, uint16_t)).Using(localhost, 80)).Once(); Verify(OverloadedMethod(ArduinoFake(Client), connect, int(IPAddress, uint16_t)).Using(ipAddress1, 8080)).Once(); Verify(OverloadedMethod(ArduinoFake(Client), connect, int(IPAddress, uint16_t)).Using(ipAddress2, 8080)).Once(); @@ -147,3 +151,4 @@ namespace ClientTest } #endif + diff --git a/test/test_eeprom.h b/test/test_eeprom.h new file mode 100644 index 0000000..4e372c2 --- /dev/null +++ b/test/test_eeprom.h @@ -0,0 +1,33 @@ +#ifdef UNIT_TEST + +namespace EEPROMTest { + +#include "arduino/EEPROM.h" + +void test_basics(void) { + When(OverloadedMethod(ArduinoFake(EEPROM), read, uint8_t(int))) + .AlwaysReturn(); + When(OverloadedMethod(ArduinoFake(EEPROM), write, void(int, uint8_t))) + .AlwaysReturn(); + When(OverloadedMethod(ArduinoFake(EEPROM), update, void(int, uint8_t))) + .AlwaysReturn(); + When(OverloadedMethod(ArduinoFake(EEPROM), length, uint16_t(void))) + .AlwaysReturn(); + + EEPROM.read(1); + EEPROM.write(1, 1); + EEPROM.update(1, 2); + EEPROM.length(); + + Verify(OverloadedMethod(ArduinoFake(EEPROM), read, uint8_t(int))).Once(); + Verify(OverloadedMethod(ArduinoFake(EEPROM), write, void(int, uint8_t))) + .Once(); + Verify(OverloadedMethod(ArduinoFake(EEPROM), update, void(int, uint8_t))) + .Once(); + Verify(OverloadedMethod(ArduinoFake(EEPROM), length, uint16_t(void))).Once(); +} + +void run_tests() { RUN_TEST(EEPROMTest::test_basics); } +} // namespace EEPROMTest + +#endif \ No newline at end of file diff --git a/test/test_function.h b/test/test_function.h index ebfbdaa..5362aa2 100644 --- a/test/test_function.h +++ b/test/test_function.h @@ -49,6 +49,15 @@ namespace FunctionTest Verify(Method(ArduinoFake(), analogRead).Using(4)).Once(); } + void test_analog_read_resolution(void) + { + When(Method(ArduinoFake(), analogReadResolution)).AlwaysReturn(); + + analogReadResolution(12); + + Verify(Method(ArduinoFake(), analogReadResolution).Using(12)).Once(); + } + void test_yield(void) { When(Method(ArduinoFake(), yield)).AlwaysReturn(); @@ -188,6 +197,7 @@ namespace FunctionTest RUN_TEST(FunctionTest::test_pin_mode); RUN_TEST(FunctionTest::test_digital_pin); RUN_TEST(FunctionTest::test_analog_pin); + RUN_TEST(FunctionTest::test_analog_read_resolution); RUN_TEST(FunctionTest::test_delay); RUN_TEST(FunctionTest::test_detach); RUN_TEST(FunctionTest::test_attach); diff --git a/test/test_print.h b/test/test_print.h index 984afca..6f56946 100644 --- a/test/test_print.h +++ b/test/test_print.h @@ -5,8 +5,8 @@ namespace PrintTest void test_print_variables(void) { char char_var = 'A'; + const char * char_array_var = "char_array_var"; unsigned char unsigned_char_var = 'B'; - const char char_array_var[] = "char_array_var"; int int_var = 123; long long_var = 12345678; @@ -15,7 +15,7 @@ namespace PrintTest unsigned long unsigned_long_var = 87654321; When(OverloadedMethod(ArduinoFake(Print), print, size_t(char))).AlwaysReturn(); - When(OverloadedMethod(ArduinoFake(Print), print, size_t(const char[]))).AlwaysReturn(); + When(OverloadedMethod(ArduinoFake(Print), print, size_t(const char *))).AlwaysReturn(); When(OverloadedMethod(ArduinoFake(Print), print, size_t(unsigned char, int))).AlwaysReturn(); When(OverloadedMethod(ArduinoFake(Print), print, size_t(int, int))).AlwaysReturn(); @@ -37,7 +37,7 @@ namespace PrintTest print->print(unsigned_long_var, DEC); Verify(OverloadedMethod(ArduinoFake(Print), print, size_t(char)).Using(char_var)).Once(); - Verify(OverloadedMethod(ArduinoFake(Print), print, size_t(const char[])).Using(char_array_var)).Once(); + Verify(OverloadedMethod(ArduinoFake(Print), print, size_t(const char *)).Using(char_array_var)).Once(); Verify(OverloadedMethod(ArduinoFake(Print), print, size_t(unsigned char, int)).Using(unsigned_char_var, DEC)).Once(); Verify(OverloadedMethod(ArduinoFake(Print), print, size_t(int, int)).Using(int_var, DEC)).Once(); @@ -51,7 +51,7 @@ namespace PrintTest { char char_var = 'A'; unsigned char unsigned_char_var = 'B'; - const char char_array_var[] = "char_array_var"; + const char * char_array_var = "char_array_var"; int int_var = 123; long long_var = 12345678; @@ -61,7 +61,7 @@ namespace PrintTest When(OverloadedMethod(ArduinoFake(Print), println, size_t())).AlwaysReturn(); When(OverloadedMethod(ArduinoFake(Print), println, size_t(char))).AlwaysReturn(); - When(OverloadedMethod(ArduinoFake(Print), println, size_t(const char[]))).AlwaysReturn(); + When(OverloadedMethod(ArduinoFake(Print), println, size_t(const char *))).AlwaysReturn(); When(OverloadedMethod(ArduinoFake(Print), println, size_t(unsigned char, int))).AlwaysReturn(); When(OverloadedMethod(ArduinoFake(Print), println, size_t(int, int))).AlwaysReturn(); @@ -85,7 +85,7 @@ namespace PrintTest Verify(OverloadedMethod(ArduinoFake(Print), println, size_t())).Once(); Verify(OverloadedMethod(ArduinoFake(Print), println, size_t(char)).Using(char_var)).Once(); - Verify(OverloadedMethod(ArduinoFake(Print), println, size_t(const char[])).Using(char_array_var)).Once(); + Verify(OverloadedMethod(ArduinoFake(Print), println, size_t(const char *)).Using(char_array_var)).Once(); Verify(OverloadedMethod(ArduinoFake(Print), println, size_t(unsigned char, int)).Using(unsigned_char_var, DEC)).Once(); Verify(OverloadedMethod(ArduinoFake(Print), println, size_t(int, int)).Using(int_var, DEC)).Once(); diff --git a/test/test_spi.h b/test/test_spi.h new file mode 100644 index 0000000..3bcdf98 --- /dev/null +++ b/test/test_spi.h @@ -0,0 +1,42 @@ +#ifdef UNIT_TEST + +namespace SpiTest { + +#include "arduino/SPI.h" + +void test_basics(void) { + SPISettings settings(4000000, MSBFIRST, SPI_MODE0); + uint8_t data = 0x01; + uint16_t data16 = 0x1234; + uint8_t buffer[] = {0x02, 0x03, 0x04}; + uint8_t *ptr = buffer; + + When(OverloadedMethod(ArduinoFake(SPI), begin, void(void))).AlwaysReturn(); + When(OverloadedMethod(ArduinoFake(SPI), end, void(void))).AlwaysReturn(); + When(OverloadedMethod(ArduinoFake(SPI), beginTransaction, void(SPISettings)).Using(settings)).AlwaysReturn(); + When(OverloadedMethod(ArduinoFake(SPI), endTransaction, void(void))).AlwaysReturn(); + When(OverloadedMethod(ArduinoFake(SPI), transfer, uint8_t(uint8_t)).Using(data)).AlwaysReturn(); + When(OverloadedMethod(ArduinoFake(SPI), transfer16, uint16_t(uint16_t)).Using(data16)).AlwaysReturn(); + When(OverloadedMethod(ArduinoFake(SPI), transfer, void(void*, size_t)).Using(ptr, sizeof(buffer))).AlwaysReturn(); + + SPI.begin(); + SPI.beginTransaction(settings); + SPI.transfer(data); + SPI.transfer16(data16); + SPI.transfer(buffer, sizeof(buffer)); + SPI.endTransaction(); + SPI.end(); + + Verify(OverloadedMethod(ArduinoFake(SPI), begin, void(void))).Once(); + Verify(OverloadedMethod(ArduinoFake(SPI), end, void(void))).Once(); + Verify(OverloadedMethod(ArduinoFake(SPI), beginTransaction, void(SPISettings))).Once(); + Verify(OverloadedMethod(ArduinoFake(SPI), endTransaction, void(void))).Once(); + Verify(OverloadedMethod(ArduinoFake(SPI), transfer, uint8_t(uint8_t))).Once(); + Verify(OverloadedMethod(ArduinoFake(SPI), transfer16, uint16_t(uint16_t))).Once(); + Verify(OverloadedMethod(ArduinoFake(SPI), transfer, void(void*, size_t))).Once(); +} + +void run_tests() { RUN_TEST(SpiTest::test_basics); } +} // namespace SpiTest + +#endif \ No newline at end of file