verbose(ENV['verbose'] == '1')
DEBUG = ENV['debug'] == '1'
+TESTING = ENV['testing'] == '1'
def pop_path(path)
Pathname(path).each_filename.to_a[1..-1]
# include a defaults file if present
load 'rakefile.defaults' if File.exists?('rakefile.defaults')
+if TESTING
+ BUILDTYPE= 'Testing'
-if DEBUG
+elsif DEBUG
BUILDTYPE= 'Debug'
ENABLE_DEBUG_MONITOR= '0'
end
DEFAULT_SERIAL_BAUD_RATE= ENV['BAUDRATE'] || '115200' unless defined? DEFAULT_SERIAL_BAUD_RATE
# set to true to eliminate all the network code
-NONETWORK= false unless defined? NONETWORK
+unless defined? NONETWORK
+ NONETWORK= false || TESTING
+end
# list of modules to exclude, include directory it is in
EXCLUDE_MODULES= %w(tools/touchprobe) unless defined? EXCLUDE_MODULES
nonetwork= false
end
-SRC = FileList['src/**/*.{c,cpp}'].exclude(/#{excludes.join('|')}/)
-
-puts "WARNING Excluding modules: #{EXCLUDE_MODULES.join(' ')}" unless exclude_defines.empty?
+if TESTING
+ # add modules to be tested here
+ TESTMODULES= %w(tools/temperatureswitch)
+ puts "Modules under test: #{TESTMODULES}"
+ excludes << %w(Kernel.cpp main.cpp) # we replace these with mock versions in testframework
+ testmodules= FileList['src/testframework/*.{c,cpp}', 'src/testframework/easyunit/*.{c,cpp}', 'src/modules/communication/SerialConsole.cpp', 'src/modules/communication/utils/Gcode.cpp'].include(TESTMODULES.collect { |e| "src/modules/#{e}/**/*.{c,cpp}"}).include(TESTMODULES.collect { |e| "src/testframework/unittests/#{e}/*.{c,cpp}"})
+ SRC = FileList['src/libs/**/*.{c,cpp}'].exclude(/#{excludes.join('|')}/) + testmodules
+else
+ excludes << %w(testframework)
+ SRC = FileList['src/**/*.{c,cpp}'].exclude(/#{excludes.join('|')}/)
+ puts "WARNING Excluding modules: #{EXCLUDE_MODULES.join(' ')}" unless exclude_defines.empty?
+end
OBJDIR = 'OBJ'
OBJ = SRC.collect { |fn| File.join(OBJDIR, pop_path(File.dirname(fn)), File.basename(fn).ext('o')) } +
OPTIMIZATION = 2
MRI_ENABLE = 1
MRI_SEMIHOST_STDIO = 1 unless defined? MRI_SEMIHOST_STDIO
+when 'testing'
+ OPTIMIZATION = 0
+ MRI_ENABLE = 1
+ MRI_SEMIHOST_STDIO = 0 unless defined? MRI_SEMIHOST_STDIO
end
MRI_ENABLE = 1 unless defined? MRI_ENABLE # set to 0 to disable MRI
# Compiler flags used to enable creation of header dependencies.
DEPFLAGS = '-MMD '
-CFLAGS = DEPFLAGS + "-Wall -Wextra -Wno-unused-parameter -Wcast-align -Wpointer-arith -Wredundant-decls -Wcast-qual -Wcast-align -O#{OPTIMIZATION} -g3 -mcpu=cortex-m3 -mthumb -mthumb-interwork -ffunction-sections -fdata-sections -fno-exceptions -fno-delete-null-pointer-checks"
-CPPFLAGS = CFLAGS + ' -fno-rtti -std=gnu++11'
+CFLAGS = DEPFLAGS + "-Wall -Wextra -Wno-unused-parameter -Wcast-align -Wpointer-arith -Wredundant-decls -Wcast-qual -Wcast-align -O#{OPTIMIZATION} -g3 -mcpu=cortex-m3 -mthumb -mthumb-interwork -ffunction-sections -fdata-sections -fno-delete-null-pointer-checks"
+CPPFLAGS = CFLAGS + ' -fno-rtti -std=gnu++11 -fno-exceptions'
+CXXFLAGS = CFLAGS + ' -fno-rtti -std=gnu++11 -fexceptions' # used for a .cxx file that needs to be compiled with exceptions
MRI_WRAPS = MRI_ENABLE == 1 ? ',--wrap=_read,--wrap=_write,--wrap=semihost_connected' : ''
end
file "#{OBJDIR}/mbed_custom.o" => ['./build/mbed_custom.cpp'] do |t|
- puts "Compiling #{t.source}"
+ puts "Compiling mbed_custom.cpp"
sh "#{CCPP} #{CPPFLAGS} #{INCLUDE} #{DEFINES} -c -o #{t.name} #{t.prerequisites[0]}"
end
sh "#{CCPP} #{CPPFLAGS} #{INCLUDE} #{DEFINES} #{VERSION} -c -o #{t.name} #{t.source}"
end
+rule '.o' => lambda{ |objfile| obj2src(objfile, 'cxx') } do |t|
+ puts "Compiling #{t.source}"
+ sh "#{CCPP} #{CXXFLAGS} #{INCLUDE} #{DEFINES} #{VERSION} -c -o #{t.name} #{t.source}"
+end
+
rule '.o' => lambda{ |objfile| obj2src(objfile, 'c') } do |t|
puts "Compiling #{t.source}"
sh "#{CC} #{CFLAGS} #{INCLUDE} #{DEFINES} #{VERSION} -c -o #{t.name} #{t.source}"
CSRCS1 = $(wildcard $(SRC)/*.c $(SRC)/*/*.c $(SRC)/*/*/*.c $(SRC)/*/*/*/*.c $(SRC)/*/*/*/*/*.c $(SRC)/*/*/*/*/*/*.c)
# Totally exclude network if NONETWORK is defined
ifeq "$(NONETWORK)" "1"
-CSRCS = $(filter-out $(SRC)/libs/Network/%,$(CSRCS1))
+CSRCS2 = $(filter-out $(SRC)/libs/Network/%,$(CSRCS1))
DEFINES += -DNONETWORK
else
-CSRCS = $(CSRCS1)
+CSRCS2 = $(CSRCS1)
endif
+# do not compile the src/testframework as that can only be done with rake
+CSRCS = $(filter-out $(SRC)/testframework/%,$(CSRCS2))
+
ifeq "$(DISABLEMSD)" "1"
DEFINES += -DDISABLEMSD
endif
# uppercase function
uc = $(subst a,A,$(subst b,B,$(subst c,C,$(subst d,D,$(subst e,E,$(subst f,F,$(subst g,G,$(subst h,H,$(subst i,I,$(subst j,J,$(subst k,K,$(subst l,L,$(subst m,M,$(subst n,N,$(subst o,O,$(subst p,P,$(subst q,Q,$(subst r,R,$(subst s,S,$(subst t,T,$(subst u,U,$(subst v,V,$(subst w,W,$(subst x,X,$(subst y,Y,$(subst z,Z,$1))))))))))))))))))))))))))
EXL = $(patsubst %,$(SRC)/modules/%/%,$(EXCLUDED_MODULES))
-CPPSRCS = $(filter-out $(EXL),$(CPPSRCS2))
+CPPSRCS3 = $(filter-out $(EXL),$(CPPSRCS2))
DEFINES += $(call uc, $(subst /,_,$(patsubst %,-DNO_%,$(EXCLUDED_MODULES))))
+# do not compile the src/testframework as that can only be done with rake
+CPPSRCS = $(filter-out $(SRC)/testframework/%,$(CPPSRCS3))
+
# List of the objects files to be compiled/assembled
OBJECTS = $(patsubst %.c,$(OUTDIR)/%.o,$(CSRCS)) $(patsubst %.s,$(OUTDIR)/%.o,$(patsubst %.S,$(OUTDIR)/%.o,$(ASRCS))) $(patsubst %.cpp,$(OUTDIR)/%.o,$(CPPSRCS))
this->config_sources.push_back( fcs );
}
+Config::Config(ConfigSource *cs)
+{
+ this->config_cache = NULL;
+ this->config_sources.push_back( cs );
+}
+
+Config::~Config()
+{
+ config_cache_clear();
+ for(auto i : this->config_sources) {
+ delete i;
+ }
+}
+
void Config::on_module_loaded() {}
void Config::on_console_line_received( void *argument ) {}
class Config : public Module {
public:
Config();
+ Config(ConfigSource*);
+ ~Config();
void on_module_loaded();
void on_console_line_received( void* argument );
class ConfigSource {
public:
ConfigSource(){}
+ virtual ~ConfigSource(){}
// Read each value, and append it as a ConfigValue to the config_cache we were passed
virtual void transfer_values_to_cache( ConfigCache* ) = 0;
extern char _binary_config_default_start;
extern char _binary_config_default_end;
-
FirmConfigSource::FirmConfigSource(const char* name){
this->name_checksum = get_checksum(name);
+ this->start= &_binary_config_default_start;
+ this->end= &_binary_config_default_end;
+}
+
+FirmConfigSource::FirmConfigSource(const char* name, const char *start, const char *end){
+ this->name_checksum = get_checksum(name);
+ this->start= start;
+ this->end= end;
}
// Transfer all values found in the file to the passed cache
void FirmConfigSource::transfer_values_to_cache( ConfigCache* cache ){
- char* p = &_binary_config_default_start;
+ const char* p = this->start;
// For each line
- while( p < &_binary_config_default_end ){
+ while( p < this->end ){
// find eol
- char *eol= p;
- while(eol < &_binary_config_default_end) {
+ const char *eol= p;
+ while(eol < this->end) {
if(*eol++ == '\n') break;
}
string line(p, eol-p);
string value = "";
- char* p = &_binary_config_default_start;
+ const char* p = this->start;
// For each line
- while( p < &_binary_config_default_end ){
+ while( p < this->end ){
// find eol
- char *eol= p;
- while(eol < &_binary_config_default_end) {
+ const char *eol= p;
+ while(eol < this->end) {
if(*eol++ == '\n') break;
}
string line(p, eol-p);
using namespace std;
#include <string>
-class FirmConfigSource : public ConfigSource {
- public:
- FirmConfigSource(const char* name);
- void transfer_values_to_cache( ConfigCache* cache );
- bool is_named( uint16_t check_sum );
- bool write( string setting, string value );
- string read( uint16_t check_sums[3] );
-
+class FirmConfigSource : public ConfigSource
+{
+public:
+ FirmConfigSource(const char *name);
+ FirmConfigSource(const char* name, const char *start, const char *end);
+
+ void transfer_values_to_cache( ConfigCache *cache );
+ bool is_named( uint16_t check_sum );
+ bool write( string setting, string value );
+ string read( uint16_t check_sums[3] );
+
+private:
+ const char *start, *end;
};
this->hooks[id_event].push_back(mod);
}
-// Call a specific event without arguments
-void Kernel::call_event(_EVENT_ENUM id_event){
+// Call a specific event with an argument
+void Kernel::call_event(_EVENT_ENUM id_event, void * argument){
for (auto m : hooks[id_event]) {
- (m->*kernel_callback_functions[id_event])(this);
+ (m->*kernel_callback_functions[id_event])(argument);
}
}
-// Call a specific event with an argument
-void Kernel::call_event(_EVENT_ENUM id_event, void * argument){
+// These are used by tests to test for various things. basically mocks
+bool Kernel::kernel_has_event(_EVENT_ENUM id_event, Module *mod)
+{
for (auto m : hooks[id_event]) {
- (m->*kernel_callback_functions[id_event])(argument);
+ if(m == mod) return true;
}
+ return false;
}
+
+void Kernel::unregister_for_event(_EVENT_ENUM id_event, Module *mod)
+{
+ for (auto i = hooks[id_event].begin(); i != hooks[id_event].end(); ++i) {
+ if(*i == mod) {
+ hooks[id_event].erase(i);
+ return;
+ }
+ }
+}
+
void add_module(Module* module);
void register_for_event(_EVENT_ENUM id_event, Module *module);
- void call_event(_EVENT_ENUM id_event);
- void call_event(_EVENT_ENUM id_event, void * argument);
+ void call_event(_EVENT_ENUM id_event, void * argument= nullptr);
+
+ bool kernel_has_event(_EVENT_ENUM id_event, Module *mod);
+ void unregister_for_event(_EVENT_ENUM id_event, Module *module);
// These modules are available to all other modules
SerialConsole* serial;
#include "PublicData.h"
#include "StreamOutputPool.h"
#include "TemperatureControlPool.h"
+#include "mri.h"
#define temperatureswitch_checksum CHECKSUM("temperatureswitch")
#define enable_checksum CHECKSUM("enable")
{
}
+TemperatureSwitch::~TemperatureSwitch()
+{
+ THEKERNEL->unregister_for_event(ON_SECOND_TICK, this);
+ THEKERNEL->unregister_for_event(ON_GCODE_RECEIVED, this);
+}
+
// Load module
void TemperatureSwitch::on_module_loaded()
{
delete this;
}
-
-bool TemperatureSwitch::load_config(uint16_t modcs)
+TemperatureSwitch* TemperatureSwitch::load_config(uint16_t modcs)
{
// see if enabled
if (!THEKERNEL->config->value(temperatureswitch_checksum, modcs, enable_checksum)->by_default(false)->as_bool()) {
- return false;
+ return nullptr;
}
// create a temperature control and load settings
designator= s[0];
}
- if(designator == 0) return false; // no designator then not valid
+ if(designator == 0) return nullptr; // no designator then not valid
// create a new temperature switch module
TemperatureSwitch *ts= new TemperatureSwitch();
+ //__debugbreak();
+
// make a list of temperature controls with matching designators with the same first letter
// the list is added t the controllers vector given below
- std::vector<struct pad_temperature> controllers;
- bool ok = PublicData::get_value(temperature_control_checksum, poll_controls_checksum, &controllers);
- if (ok) {
- for (auto &c : controllers) {
- if (c.designator[0] == designator) {
- ts->temp_controllers.push_back(c.id);
+ {
+ std::vector<struct pad_temperature> controllers;
+ bool ok = PublicData::get_value(temperature_control_checksum, poll_controls_checksum, &controllers);
+ if (ok) {
+ for (auto &c : controllers) {
+ if (c.designator[0] == designator) {
+ ts->temp_controllers.push_back(c.id);
+ }
}
}
}
// if we don't have any matching controllers, then not valid
if (ts->temp_controllers.empty()) {
delete ts;
- return false;
+ return nullptr;
}
// load settings from config file
if(s.empty()) {
// no switch specified so invalid entry
delete this;
- return false;
+ return nullptr;
}
}
if(this->arm_mcode != 0) {
ts->register_for_event(ON_GCODE_RECEIVED);
}
- return true;
+ return ts;
}
void TemperatureSwitch::on_gcode_received(void *argument)
{
public:
TemperatureSwitch();
+ ~TemperatureSwitch();
void on_module_loaded();
void on_second_tick(void *argument);
void on_gcode_received(void *argument);
+ TemperatureSwitch* load_config(uint16_t modcs);
+
+ bool is_armed() const { return armed; }
private:
enum TRIGGER_TYPE {LEVEL, RISING, FALLING};
enum STATE {NONE, HIGH_TEMP, LOW_TEMP};
- bool load_config(uint16_t modcs);
-
// get the highest temperature from the set of configured temperature controllers
float get_highest_temperature();
--- /dev/null
+/*
+ This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+ Smoothie is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ Smoothie is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+This is aprt of the Smoothie test framework, it generates a Mockable Kernl so kernel calls can be tested for
+*/
+
+#include "libs/Kernel.h"
+#include "libs/Module.h"
+#include "libs/Config.h"
+#include "libs/nuts_bolts.h"
+#include "libs/SlowTicker.h"
+#include "libs/Adc.h"
+#include "libs/StreamOutputPool.h"
+#include <mri.h>
+#include "checksumm.h"
+#include "ConfigValue.h"
+
+#include "libs/StepTicker.h"
+#include "libs/PublicData.h"
+#include "modules/communication/SerialConsole.h"
+#include "modules/communication/GcodeDispatch.h"
+#include "modules/robot/Planner.h"
+#include "modules/robot/Robot.h"
+#include "modules/robot/Stepper.h"
+#include "modules/robot/Conveyor.h"
+#include "modules/robot/Pauser.h"
+
+#include "Config.h"
+#include "FirmConfigSource.h"
+
+#include <malloc.h>
+#include <array>
+#include <functional>
+#include <map>
+
+Kernel* Kernel::instance;
+
+// The kernel is the central point in Smoothie : it stores modules, and handles event calls
+Kernel::Kernel(){
+ instance= this; // setup the Singleton instance of the kernel
+
+ // serial first at fixed baud rate (DEFAULT_SERIAL_BAUD_RATE) so config can report errors to serial
+ // Set to UART0, this will be changed to use the same UART as MRI if it's enabled
+ this->serial = new SerialConsole(USBTX, USBRX, DEFAULT_SERIAL_BAUD_RATE);
+
+ // Config next, but does not load cache yet
+ // loads config from in memory source for test framework must be loaded by test
+ this->config = nullptr;
+
+ this->streams = new StreamOutputPool();
+ this->streams->append_stream(this->serial);
+
+ this->current_path = "/";
+
+ // Configure UART depending on MRI config
+ // Match up the SerialConsole to MRI UART. This makes it easy to use only one UART for both debug and actual commands.
+ NVIC_SetPriorityGrouping(0);
+ NVIC_SetPriority(UART0_IRQn, 5);
+}
+
+// Add a module to Kernel. We don't actually hold a list of modules we just call its on_module_loaded
+void Kernel::add_module(Module* module){
+ module->on_module_loaded();
+}
+
+// Adds a hook for a given module and event
+void Kernel::register_for_event(_EVENT_ENUM id_event, Module *mod){
+ this->hooks[id_event].push_back(mod);
+}
+
+static std::map<_EVENT_ENUM, std::function<void(void*)> > event_callbacks;
+
+// Call a specific event with an argument
+void Kernel::call_event(_EVENT_ENUM id_event, void * argument){
+ for (auto m : hooks[id_event]) {
+ (m->*kernel_callback_functions[id_event])(argument);
+ }
+ if(event_callbacks.find(id_event) != event_callbacks.end()){
+ event_callbacks[id_event](argument);
+ }else{
+ printf("call_event for event: %d not handled\n", id_event);
+ }
+}
+
+// These are used by tests to test for various things. basically mocks
+bool Kernel::kernel_has_event(_EVENT_ENUM id_event, Module *mod)
+{
+ for (auto m : hooks[id_event]) {
+ if(m == mod) return true;
+ }
+ return false;
+}
+
+void Kernel::unregister_for_event(_EVENT_ENUM id_event, Module *mod)
+{
+ for (auto i = hooks[id_event].begin(); i != hooks[id_event].end(); ++i) {
+ if(*i == mod) {
+ hooks[id_event].erase(i);
+ return;
+ }
+ }
+}
+
+void test_kernel_setup_config(const char* start, const char* end)
+{
+ THEKERNEL->config= new Config(new FirmConfigSource("rom", start, end) );
+ // Pre-load the config cache
+ THEKERNEL->config->config_cache_load();
+}
+
+void test_kernel_teardown()
+{
+ delete THEKERNEL->config;
+ THEKERNEL->config= nullptr;
+ event_callbacks.clear();
+}
+
+void test_kernel_trap_event(_EVENT_ENUM id_event, std::function<void(void*)> fnc)
+{
+ event_callbacks[id_event]= fnc;
+}
+
+void test_kernel_untrap_event(_EVENT_ENUM id_event)
+{
+ event_callbacks.erase(id_event);
+}
--- /dev/null
+#pragma once
+
+#include "Module.h"
+#include <functional>
+
+void test_kernel_setup_config(const char* start, const char* end);
+void test_kernel_teardown();
+void test_kernel_trap_event(_EVENT_ENUM id_event, std::function<void(void*)> fnc);
+void test_kernel_untrap_event(_EVENT_ENUM id_event);
--- /dev/null
+#include <vector>
+#include <string>
+#include <iostream>
+
+#include "utils.h"
+#include "SerialConsole.h"
+#include "gpio.h"
+
+GPIO leds[5] = {
+ GPIO(P1_18),
+ GPIO(P1_19),
+ GPIO(P1_20),
+ GPIO(P1_21),
+ GPIO(P4_28)
+};
+
+#include "easyunit/testharness.h"
+#include "easyunit/test.h"
+
+int main( )
+{
+ Kernel* kernel = new Kernel();
+
+ printf("Starting tests...\n");
+
+ TestRegistry::runAndPrint();
+
+ kernel->serial->printf("Done\n");
+
+ // drop back into DFU upload
+ kernel->serial->printf("Entering DFU flash mode...\n");
+ system_reset(true);
+
+ for(;;) {}
+}
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#include "defaulttestprinter.h"\r
+\r
+#include "testpartresult.h"\r
+\r
+#include <stdio.h>\r
+\r
+\r
+DefaultTestPrinter::DefaultTestPrinter()\r
+: testsTotal_(0),testFailuresTotal_(0),failuresTotal_(0),\r
+ level_(normal), showSuccessDetail_(false), output_(stdout)\r
+{\r
+}\r
+\r
+DefaultTestPrinter::~DefaultTestPrinter()\r
+{\r
+}\r
+\r
+void DefaultTestPrinter::print(const TestResult *testResult)\r
+{\r
+ int failures;\r
+ int successes;\r
+ int errors;\r
+ SimpleString state;\r
+ SimpleString name;\r
+ TestCase *testCase = testResult->getTestCases();\r
+ int size = testResult->getTestCaseCount();\r
+\r
+ printHeader(testResult);\r
+\r
+ if (testResult->getTestCaseRanCount() == 0) {\r
+ fprintf(output_,"\nNo test ran\n");\r
+ }\r
+\r
+ for (int i=0;i<size;i++) {\r
+\r
+ if (testCase->ran()) {\r
+\r
+ name = testCase->getName();\r
+ failures = testCase->getFailuresCount();\r
+ successes = testCase->getSuccessesCount();\r
+ errors = testCase->getErrorsCount();\r
+\r
+ if (failures > 0 || errors > 0) {\r
+ state = "FAILED";\r
+ }\r
+ else {\r
+ state = "SUCCEEDED";\r
+ }\r
+\r
+ fprintf(output_, "\n\nTest case \"%s\" %s with %d error(s), %d failure(s) and %d success(es): \n",name.asCharString(),state.asCharString(),errors,failures,successes);\r
+\r
+ printTests(testCase);\r
+ }\r
+\r
+ testCase = testCase->getNext();\r
+ }\r
+}\r
+\r
+void DefaultTestPrinter::setHeaderLevel(headerLevel level)\r
+{\r
+ level_ = level;\r
+}\r
+\r
+void DefaultTestPrinter::showSuccessDetail(bool show)\r
+{\r
+ showSuccessDetail_ = show;\r
+}\r
+\r
+void DefaultTestPrinter::setOutput(FILE *output)\r
+{\r
+ output_ = output;\r
+}\r
+\r
+void DefaultTestPrinter::printHeader(const TestResult *testResult)\r
+{\r
+ fprintf(output_ , "-- EasyUnit Results --\n");\r
+\r
+ if (level_ != off) {\r
+ fprintf(output_ , "\nSUMMARY\n\n");\r
+ fprintf(output_ , "Test summary: ");\r
+\r
+ if (testResult->getErrors() > 0 || testResult->getFailures() > 0) {\r
+ fprintf(output_ , "FAIL\n");\r
+ }\r
+ else {\r
+ fprintf(output_ , "SUCCESS\n");\r
+ }\r
+\r
+ if (level_ == normal) {\r
+ printNormalHeader(testResult);\r
+ }\r
+ else {\r
+ printCompleteHeader(testResult);\r
+ }\r
+ }\r
+\r
+ fprintf(output_ , "\n");\r
+ fprintf(output_ , "\nDETAILS");\r
+}\r
+\r
+void DefaultTestPrinter::printCompleteHeader(const TestResult *testResult)\r
+{\r
+ fprintf(output_ , "Number of test cases: %d\n",testResult->getTestCaseCount());\r
+ fprintf(output_ , "Number of test cases ran: %d\n",testResult->getTestCaseRanCount());\r
+ fprintf(output_ , "Test cases that succeeded: %d\n",testResult->getSuccesses());\r
+ fprintf(output_ , "Test cases with errors: %d\n",testResult->getErrors());\r
+ fprintf(output_ , "Test cases that failed: %d\n",testResult->getFailures());\r
+ fprintf(output_ , "Number of tests ran: %d\n",testResult->getTestRanCount());\r
+ fprintf(output_ , "Tests that succeeded: %d\n",testResult->getTotalSuccesses());\r
+ fprintf(output_ , "Tests with errors: %d\n",testResult->getTotalErrors());\r
+ fprintf(output_ , "Tests that failed: %d\n",testResult->getTotalFailures());\r
+\r
+}\r
+\r
+void DefaultTestPrinter::printNormalHeader(const TestResult *testResult)\r
+{\r
+ fprintf(output_ , "Number of test cases ran: %d\n",testResult->getTestCaseRanCount());\r
+ fprintf(output_ , "Test cases that succeeded: %d\n",testResult->getSuccesses());\r
+ fprintf(output_ , "Test cases with errors: %d\n",testResult->getErrors());\r
+ fprintf(output_ , "Test cases that failed: %d\n",testResult->getFailures());\r
+}\r
+\r
+void DefaultTestPrinter::printTests(TestCase *testCase)\r
+{\r
+ const char *indent = " ";\r
+ Test *test = testCase->getTests();\r
+ int size = testCase->getTestsCount();\r
+ SimpleString state;\r
+\r
+\r
+\r
+ for (int i=0;i<size;i++) {\r
+ if (test->getFailuresCount() > 0 || test->getErrorsCount() > 0) {\r
+ state = "FAILED :";\r
+ }\r
+ else {\r
+ state = "SUCCEEDED!";\r
+ }\r
+\r
+ fprintf(output_, "%s Test \"%s\" %s\n",indent,test->getTestName().asCharString(),state.asCharString());\r
+ printResults(test);\r
+ test = test->getNext();\r
+ }\r
+}\r
+\r
+void DefaultTestPrinter::printResults(Test *test)\r
+{\r
+ const char *indent = " ";\r
+ TestPartResult *testPR = test->getTestPartResult();\r
+ int size = test->getFailuresCount() + test->getSuccessesCount() + test->getErrorsCount();\r
+ int type;\r
+\r
+ for (int i=0;i<size;i++) {\r
+\r
+ type = testPR->getType();\r
+\r
+ if (type == failure) {\r
+ fprintf (output_, "%s%s%s%s%s%ld%s%s\n",\r
+ indent,\r
+ "Failure: \"",\r
+ testPR->getMessage().asCharString (),\r
+ "\" " ,\r
+ "line ",\r
+ testPR->getLineNumber(),\r
+ " in ",\r
+ testPR->getFileName().asCharString ());\r
+ }\r
+ else if (type == error) {\r
+ fprintf (output_, "%s%s%s%s%s%s\n",\r
+ indent,\r
+ "Error in ",\r
+ test->getTestName().asCharString(),\r
+ ": \"",\r
+ testPR->getMessage().asCharString (),\r
+ "\"");\r
+ }\r
+ else if (type == success && showSuccessDetail_) {\r
+ fprintf (output_, "%s%s%s%s%s%ld%s%s\n",\r
+ indent,\r
+ "Success: \"",\r
+ testPR->getMessage().asCharString (),\r
+ "\" " ,\r
+ "line ",\r
+ testPR->getLineNumber(),\r
+ " in ",\r
+ testPR->getFileName().asCharString ());\r
+ }\r
+ testPR = testPR->getNext();\r
+ }\r
+}\r
+\r
+\r
+\r
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#ifndef DEFAULTTESTPRINTER_H\r
+#define DEFAULTTESTPRINTER_H\r
+\r
+#include "testprinter.h"\r
+#include "testcase.h"\r
+#include "test.h"\r
+#include "testresult.h"\r
+#include <stdio.h>\r
+\r
+\r
+/**\r
+ * Complete header level means that a header will be printed\r
+ * before the test details with all information available in\r
+ * the test result.\r
+ * \r
+ * Normal header level means that a header will be printed\r
+ * before the test details with the most useful information\r
+ * available in the test result.\r
+ *\r
+ * Off header level means that no header will be printed\r
+ * before the test details.\r
+ * \r
+ * Whatever the level, there will always be a clear indication\r
+ * telling if there was a failure/error or not at the global\r
+ * level.\r
+ */\r
+enum headerLevel {complete,normal,off};\r
+\r
+/**\r
+ * This is the default testprinter used by easyunit testregistry\r
+ * when the user calls the runAndPrint() method without specifying\r
+ * a testprinter.\r
+ *\r
+ * This testprinter writes plain text result to any supplied file.\r
+ * The default file is the standard output.\r
+ *\r
+ * You may customize the outpur format by specifying the header level\r
+ * and if you wish the testprinter to print details about each success.\r
+ *\r
+ * The default header level is normal and by default, the testprinter\r
+ * does not print details about each success.\r
+ */\r
+class DefaultTestPrinter : public TestPrinter\r
+{\r
+ public:\r
+ \r
+ /**\r
+ * Default constructor that sets the header level\r
+ * to normal and the output source to the standard\r
+ * output.\r
+ */\r
+ DefaultTestPrinter();\r
+ \r
+ /**\r
+ * Empty destructor.\r
+ */\r
+ virtual ~DefaultTestPrinter();\r
+ /**\r
+ * Prints a header depending of the header level and\r
+ * details about each test to the output_.\r
+ *\r
+ * @param testResult Results of all tests that were ran.\r
+ */\r
+ virtual void print(const TestResult *testResult); \r
+ \r
+ /**\r
+ * Set the header level of the printer.\r
+ *\r
+ * @param level Header level that will be used during print()\r
+ */\r
+ void setHeaderLevel(headerLevel level);\r
+ \r
+ /**\r
+ * Set whether or not the printer should display the details\r
+ * of test that succeeded.\r
+ *\r
+ * @param show Set to true to display details about success\r
+ */\r
+ void showSuccessDetail(bool show);\r
+ \r
+ /**\r
+ * Set the output to which the printer will print results.\r
+ *\r
+ * @param output Output used to print the results\r
+ */\r
+ void setOutput(FILE *output);\r
+ \r
+ protected:\r
+ virtual void printHeader(const TestResult *testResult);\r
+ virtual void printTests(TestCase *testCase);\r
+ virtual void printResults(Test *test);\r
+ virtual void printCompleteHeader(const TestResult *testResult);\r
+ virtual void printNormalHeader(const TestResult *testResult);\r
+ int testsTotal_;\r
+ int testFailuresTotal_;\r
+ int failuresTotal_;\r
+ headerLevel level_;\r
+ bool showSuccessDetail_;\r
+ FILE *output_;\r
+};\r
+\r
+#endif // DEFAULTTESTPRINTER_H\r
+\r
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#include "simplestring.h"\r
+#include <string.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+\r
+static const int DEFAULT_SIZE = 20;\r
+\r
+SimpleString::SimpleString ()\r
+: buffer(new char [1])\r
+{\r
+ buffer [0] = '\0';\r
+}\r
+\r
+\r
+SimpleString::SimpleString (const char *otherBuffer)\r
+: buffer (new char [strlen (otherBuffer) + 1])\r
+{\r
+ strcpy (buffer, otherBuffer);\r
+}\r
+\r
+SimpleString::SimpleString (const SimpleString& other)\r
+{\r
+ buffer = new char [other.size() + 1];\r
+ strcpy(buffer, other.buffer);\r
+}\r
+\r
+\r
+SimpleString SimpleString::operator= (const SimpleString& other)\r
+{\r
+ delete buffer;\r
+ buffer = new char [other.size() + 1];\r
+ strcpy(buffer, other.buffer); \r
+ return *this;\r
+}\r
+\r
+SimpleString SimpleString::operator+ (const SimpleString& other)\r
+{\r
+ SimpleString newS;\r
+ delete [] newS.buffer;\r
+ newS.buffer = new char[this->size()+other.size()+1];\r
+ strcpy(newS.buffer,this->asCharString());\r
+ newS.buffer= strcat(newS.buffer,other.asCharString());\r
+ return newS;\r
+}\r
+\r
+char *SimpleString::asCharString () const\r
+{\r
+ return buffer;\r
+}\r
+\r
+int SimpleString::size() const\r
+{\r
+ return strlen (buffer);\r
+}\r
+\r
+SimpleString::~SimpleString ()\r
+{\r
+ delete [] buffer;\r
+}\r
+\r
+bool operator== (const SimpleString& left, const SimpleString& right)\r
+{\r
+ return !strcmp (left.asCharString (), right.asCharString ());\r
+}\r
+\r
+bool operator!= (const SimpleString& left, const SimpleString& right)\r
+{\r
+ return !(left == right);\r
+}\r
+\r
+SimpleString StringFrom (bool value)\r
+{\r
+ char buffer [sizeof ("false") + 1];\r
+ sprintf (buffer, "%s", value ? "true" : "false");\r
+ return SimpleString(buffer);\r
+}\r
+\r
+SimpleString StringFrom (const char *value)\r
+{\r
+ return SimpleString(value);\r
+}\r
+\r
+SimpleString StringFrom (long value)\r
+{\r
+ char buffer [DEFAULT_SIZE];\r
+ sprintf (buffer, "%ld", value);\r
+\r
+ return SimpleString(buffer);\r
+}\r
+\r
+SimpleString StringFrom (int value)\r
+{\r
+ char buffer [DEFAULT_SIZE];\r
+ sprintf (buffer, "%d", value);\r
+\r
+ return SimpleString(buffer);\r
+}\r
+\r
+SimpleString StringFrom (double value)\r
+{\r
+ char buffer [DEFAULT_SIZE];\r
+ sprintf (buffer, "%lf", value);\r
+\r
+ return SimpleString(buffer);\r
+}\r
+\r
+SimpleString StringFrom (const SimpleString& value)\r
+{\r
+ return SimpleString(value);\r
+}\r
+\r
+\r
+\r
+\r
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+\r
+This class was originally created by Michael Feathers and was modified\r
+by Barthelemy Dagenais.\r
+*/\r
+\r
+\r
+#ifndef SIMPLE_STRING\r
+#define SIMPLE_STRING\r
+\r
+\r
+/**\r
+ * SimpleString is a simple implementation of the std class String and is\r
+ * provided to ease the manipulation of strings without using any other\r
+ * libraries.\r
+ */\r
+class SimpleString\r
+{\r
+ friend bool operator== (const SimpleString& left, const SimpleString& right);\r
+\r
+ friend bool operator!= (const SimpleString& left, const SimpleString& right);\r
+\r
+ public:\r
+ SimpleString ();\r
+ SimpleString (const char *value);\r
+ SimpleString (const SimpleString& other);\r
+ ~SimpleString ();\r
+\r
+ SimpleString operator= (const SimpleString& other);\r
+ \r
+ SimpleString operator+ (const SimpleString& other);\r
+ \r
+ char *asCharString () const;\r
+ int size() const;\r
+\r
+ private:\r
+ char *buffer;\r
+};\r
+\r
+// Those functions are provided to ease the conversion between\r
+// primary datatypes and SimpleString. Feel free to extend this list\r
+// to support your own datatype.\r
+SimpleString StringFrom (bool value);\r
+SimpleString StringFrom (const char *value);\r
+SimpleString StringFrom (long value);\r
+SimpleString StringFrom (int value);\r
+SimpleString StringFrom (double value);\r
+SimpleString StringFrom (const SimpleString& other);\r
+\r
+#endif\r
+\r
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#include "test.h"\r
+#include "testregistry.h"\r
+\r
+\r
+Test::Test(const SimpleString& testCaseName, const SimpleString& testName)\r
+: testCaseName_(testCaseName), testName_(testName), testPartResult_(0), nextTest_(0), failuresCount_(0),\r
+ successesCount_(0)\r
+{\r
+ TestRegistry::addTest(this);\r
+}\r
+\r
+Test::~Test() {\r
+ TestPartResult *tmp;\r
+ int size = failuresCount_ + successesCount_;\r
+\r
+ for (int i = 0; i<size; i++) {\r
+ tmp = testPartResult_;\r
+ testPartResult_ = testPartResult_->getNext();\r
+ delete tmp;\r
+ }\r
+}\r
+\r
+void Test::setUp()\r
+{\r
+}\r
+\r
+void Test::tearDown()\r
+{\r
+}\r
+\r
+void Test::run()\r
+{\r
+}\r
+\r
+\r
+TestCase* Test::getTestCase() const\r
+{\r
+ return testCase_;\r
+}\r
+\r
+\r
+void Test::setTestCase(TestCase *testCase)\r
+{\r
+ testCase_ = testCase;\r
+}\r
+\r
+void Test::addTestPartResult(TestPartResult *testPartResult)\r
+{\r
+ TestPartResult *tmp;\r
+ int type = testPartResult->getType();\r
+\r
+ if (testPartResult_ == 0) {\r
+ testPartResult_ = testPartResult;\r
+ testPartResult_->setNext(testPartResult_);\r
+ }\r
+ else {\r
+ tmp = testPartResult_;\r
+ testPartResult_ = testPartResult;\r
+ testPartResult_->setNext(tmp->getNext());\r
+ tmp->setNext(testPartResult_);\r
+ }\r
+\r
+ if (type == failure) {\r
+ failuresCount_++;\r
+ }\r
+ else if (type == error) {\r
+ errorsCount_++;\r
+ }\r
+ else {\r
+ successesCount_++;\r
+ }\r
+}\r
+\r
+TestPartResult* Test::getTestPartResult() const\r
+{\r
+ TestPartResult *tpr = testPartResult_;\r
+\r
+ if (tpr != 0) {\r
+ tpr = tpr->getNext();\r
+ }\r
+\r
+ return tpr;\r
+}\r
+\r
+int Test::getFailuresCount() const\r
+{\r
+ return failuresCount_;\r
+}\r
+\r
+int Test::getSuccessesCount() const\r
+{\r
+ return successesCount_;\r
+}\r
+\r
+int Test::getErrorsCount() const\r
+{\r
+ return errorsCount_;\r
+}\r
+\r
+void Test::setNext(Test *nextTest)\r
+{\r
+ nextTest_ = nextTest;\r
+}\r
+\r
+\r
+Test* Test::getNext() const\r
+{\r
+ return nextTest_;\r
+}\r
+\r
+const SimpleString& Test::getTestName() const\r
+{\r
+ return testName_;\r
+}\r
+\r
+const SimpleString& Test::getTestCaseName() const\r
+{\r
+ return testCaseName_;\r
+}\r
+\r
+\r
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#ifndef TEST_H\r
+#define TEST_H\r
+\r
+#include "testcase.h"\r
+#include "testpartresult.h"\r
+\r
+\r
+\r
+\r
+\r
+/**\r
+ * EasyUnit namespace.\r
+ * This is the namespace containing all easyunit classes.\r
+ */\r
+\r
+/**\r
+ * Test class containing all macros to do unit testing.\r
+ * A test object represents a test that will be executed. Once it has been\r
+ * executed, it reports all results in the testPartResult linked list.\r
+ *\r
+ * A failure occurs when a test fails (condition is false).\r
+ * An error occurs when an exception is thrown during a test.\r
+ * A success occurs if a test succeed (condition is true).\r
+ */\r
+class Test\r
+{\r
+ public:\r
+\r
+ /**\r
+ * Main Test constructor. Used to create a test that will register itself\r
+ * with TestRegistry and with its test case.\r
+ * @param testCaseName Name of the test case this test belongs to\r
+ * @param testName Name of this test\r
+ */\r
+ Test(const SimpleString& testCaseName, const SimpleString& testName);\r
+\r
+ /**\r
+ * Main Test desctructor\r
+ * Delete the testPartResult linked list. This is why the user should\r
+ * only use the macro provided by easyunit to report a test result.\r
+ */\r
+ virtual ~Test();\r
+\r
+ /**\r
+ * Fixtures that will be called after run().\r
+ */\r
+ virtual void tearDown();\r
+\r
+ /**\r
+ * Fixtures that will be called before run().\r
+ */\r
+ virtual void setUp();\r
+\r
+ /**\r
+ * Test code should be in this method.\r
+ * run() will be called by the Test's TestCase, hence subclasses of Test\r
+ * should override this method.\r
+ */\r
+ virtual void run();\r
+\r
+ /**\r
+ * Set the TestCase this test belongs to.\r
+ *\r
+ * @param testCase The TestCase this test belongs to\r
+ */\r
+ void setTestCase(TestCase *testCase);\r
+\r
+ /**\r
+ * Get the TestCase this test belongs to. A test always belongs to\r
+ * only one TestCase. This is the TestCase identified by the first\r
+ * parameter of the test declaration. For example, if there is a\r
+ * test declared as TEST(TESTCASE1, TEST1), this test will be\r
+ * associated with the TestCase TESTCASE1.\r
+ *\r
+ * @return The TestCase this test belongs to\r
+ */\r
+ TestCase* getTestCase() const;\r
+\r
+ /**\r
+ * Add a testpartresult to the testpartresult list of this test.\r
+ * This method is used by the assertion macros to report success,\r
+ * failure or error.\r
+ *\r
+ * @param testPartResult The testpartresult to be added to the list\r
+ */\r
+ virtual void addTestPartResult(TestPartResult *testPartResult);\r
+\r
+ /**\r
+ * Get the testpartresult list of this test. If assertion macros\r
+ * and TEST and TESTF macros are used, there may be more than\r
+ * one successful testpartresult and no more than one error or failure.\r
+ *\r
+ * @return testPartResult The list of testpartresults of this test\r
+ */\r
+ TestPartResult* getTestPartResult() const;\r
+\r
+ /**\r
+ * Returns number of failures found in this test.\r
+ * If macro TEST or TESTF is used, failuresCount <= 1.\r
+ * If Test class is extended and ASSERT macros are used in different\r
+ * test methods, than failuresCount may be more than 1.\r
+ *\r
+ * @return Number of failures in this test\r
+ */\r
+ int getFailuresCount() const;\r
+\r
+ /**\r
+ * Returns number of successes found in this test.\r
+ * There may be more than one success since each ASSERT macro\r
+ * that succeeded generate a success.\r
+ *\r
+ * @return Number of successes in this test\r
+ */\r
+ int getSuccessesCount() const;\r
+\r
+ /**\r
+ * Returns number of errors found in this test.\r
+ * ErrorsCount <= 1, since exception are caught\r
+ * for the whole run() method.\r
+ *\r
+ * @return Number of errors in this test\r
+ */\r
+ int getErrorsCount() const;\r
+\r
+\r
+ /**\r
+ * Set the next test in the linked list.\r
+ *\r
+ * @param nextTest Next test in the linked list\r
+ */\r
+ void setNext(Test *nextTest);\r
+\r
+ /**\r
+ * Get the next test in the linked list.\r
+ *\r
+ * @return The next test in the linked list\r
+ */\r
+ Test* getNext() const;\r
+\r
+ /**\r
+ * Get the name of the TestCase this test belongs to. The name of the\r
+ * TestCase is the first parameter of the test declaration. For example,\r
+ * if a test is declared as TEST(TESTCASE1, TEST1), this method will return\r
+ * "TESTCASE1".\r
+ *\r
+ * @return The TestCase name of this test\r
+ */\r
+ const SimpleString& getTestCaseName() const;\r
+\r
+ /**\r
+ * Get the name of this test. The name of the test is the second\r
+ * parameter of the test declaration. For example,\r
+ * if a test is declared as TEST(TESTCASE1, TEST1), this method will return\r
+ * "TEST1".\r
+ *\r
+ * @return The name of this test.\r
+ */\r
+ const SimpleString& getTestName() const;\r
+\r
+ protected:\r
+ SimpleString testCaseName_;\r
+ SimpleString testName_;\r
+ TestCase *testCase_;\r
+ TestPartResult *testPartResult_;\r
+ Test *nextTest_;\r
+ int failuresCount_;\r
+ int successesCount_;\r
+ int errorsCount_;\r
+};\r
+\r
+\r
+\r
+\r
+/*\r
+ * Helper macros\r
+ */\r
+\r
+#define EQUALS_DELTA(expected,actual,delta)\\r
+ (actual - expected) <= delta && actual >= expected || (expected - actual) <= delta && expected >= actual\r
+\r
+#define TO_STRING_EQUALS_F(expected,actual)\\r
+ StringFrom("Expected : ") + StringFrom(expected) + StringFrom(" but Actual : ") + StringFrom(actual)\r
+\r
+#define TO_STRING_EQUALS_S(expected,actual)\\r
+ StringFrom(expected) + StringFrom(" == ") + StringFrom(actual)\r
+\r
+#define TO_S_E_DELTA_F(expected,actual,delta)\\r
+ StringFrom("Expected : ") + StringFrom(expected) + StringFrom(" but Actual : ") + StringFrom(actual) + StringFrom(" with delta = ") + StringFrom(delta)\r
+\r
+#define TO_S_E_DELTA_S(expected,actual,delta)\\r
+ StringFrom(expected) + StringFrom(" == ") + StringFrom(actual) + StringFrom(" with delta = ") + StringFrom(delta)\r
+\r
+/**\r
+ * Asserts that a condition is true.\r
+ * If the condition is not true, a failure is generated.\r
+ * @param condition Condition to fullfill for the assertion to pass\r
+ */\r
+#define ASSERT_TRUE(condition)\\r
+ { if (condition) {\\r
+ addTestPartResult(new TestPartResult(this, __FILE__,__LINE__,#condition,success));\\r
+ } else {\\r
+ addTestPartResult(new TestPartResult(this, __FILE__,__LINE__, #condition,failure)); return;\\r
+ }}\r
+\r
+/**\r
+ * Asserts that a condition is true.\r
+ * If the condition is not true, a failure is generated.\r
+ * @param condition Condition to fullfill for the assertion to pass\r
+ * @param message Message that will be displayed if this assertion fails\r
+ */\r
+#define ASSERT_TRUE_M(condition,message)\\r
+ { if (condition) {\\r
+ addTestPartResult(new TestPartResult(this, __FILE__,__LINE__,#condition,success));\\r
+ } else {\\r
+ addTestPartResult(new TestPartResult(this, __FILE__,__LINE__, message,failure)); return;\\r
+ }}\r
+\r
+/**\r
+ * Asserts that the two parameters are equals. Operator == must be defined.\r
+ * If the two parameters are not equals, a failure is generated.\r
+ * @param expected Expected value\r
+ * @param actual Actual value to be compared\r
+ */\r
+#define ASSERT_EQUALS(expected,actual)\\r
+{ if (expected == actual) {\\r
+ addTestPartResult(new TestPartResult(this, __FILE__,__LINE__,TO_STRING_EQUALS_S(#expected,#actual),success));\\r
+ } else {\\r
+ addTestPartResult(new TestPartResult(this, __FILE__,__LINE__,TO_STRING_EQUALS_F(#expected,#actual),failure)); return;\\r
+ }}\r
+\r
+/**\r
+ * Asserts that the two parameters are equals. Operator == must be defined.\r
+ * If the two parameters are not equals, a failure is generated.\r
+ *\r
+ * Parameters must be primitive data types or StringFrom (custom type) must\r
+ * be overloaded.\r
+ *\r
+ * @see SimpleString\r
+ * @param expected Expected value\r
+ * @param actual Actual value to be compared\r
+ */\r
+#define ASSERT_EQUALS_V(expected,actual)\\r
+{ if (expected == actual) {\\r
+ addTestPartResult(new TestPartResult(this, __FILE__,__LINE__,TO_STRING_EQUALS_S(expected,actual),success));\\r
+ } else {\\r
+ addTestPartResult(new TestPartResult(this, __FILE__,__LINE__,TO_STRING_EQUALS_F(expected,actual),failure)); return;\\r
+ }}\r
+\r
+/**\r
+ * Asserts that the two parameters are equals. Operator == must be defined.\r
+ * If the two parameters are not equals, a failure is generated.\r
+ * @param expected Expected value\r
+ * @param actual Actual value to be compared\r
+ * @param message Message that will be displayed if this assertion fails\r
+ */\r
+#define ASSERT_EQUALS_M(expected,actual,message)\\r
+{ if (expected == actual) {\\r
+ addTestPartResult(new TestPartResult(this, __FILE__,__LINE__,#expected,success));\\r
+ } else {\\r
+ addTestPartResult(new TestPartResult(this, __FILE__,__LINE__,message,failure)); return;\\r
+ }}\r
+\r
+/**\r
+ * Asserts that the two parameters are equals within a delta. Operators == and - must be defined.\r
+ * If the two parameters are not equals, a failure is generated.\r
+ * @param expected Expected value\r
+ * @param actual Actual value to be compared\r
+ * @param delta Delta accepted between the two values\r
+ */\r
+#define ASSERT_EQUALS_DELTA(expected,actual,delta)\\r
+{ if (EQUALS_DELTA(expected,actual,delta) ) {\\r
+ addTestPartResult(new TestPartResult(this, __FILE__,__LINE__,TO_S_E_DELTA_S(#expected,#actual,#delta),success));\\r
+ } else {\\r
+ addTestPartResult(new TestPartResult(this, __FILE__,__LINE__,TO_S_E_DELTA_F(#expected,#actual,#delta),failure)); return;\\r
+ }}\r
+\r
+/**\r
+ * Asserts that the two parameters are equals within a delta. Operators == and - must be defined.\r
+ * If the two parameters are not equals, a failure is generated.\r
+ * @param expected Expected value\r
+ * @param actual Actual value to be compared\r
+ * @param delta Delta accepted between the two values\r
+ * @param message Message that will be displayed if this assertion fails\r
+ */\r
+#define ASSERT_EQUALS_DELTA_M(expected,actual,delta,message)\\r
+{ if (EQUALS_DELTA(expected,actual,delta)) {\\r
+ addTestPartResult(new TestPartResult(this, __FILE__,__LINE__,#expected,success));\\r
+ } else {\\r
+ addTestPartResult(new TestPartResult(this, __FILE__,__LINE__,message,failure)); return;\\r
+ }}\r
+\r
+/**\r
+ * Asserts that the two parameters are equals within a delta. Operators == and - must be defined.\r
+ * If the two parameters are not equals, a failure is generated.\r
+ *\r
+ * Parameters must be primitive data types or StringFrom (custom type) must\r
+ * be overloaded.\r
+ *\r
+ * @see SimpleString\r
+ * @param expected Expected value\r
+ * @param actual Actual value to be compared\r
+ * @param delta Delta accepted between the two values\r
+ */\r
+#define ASSERT_EQUALS_DELTA_V(expected,actual,delta)\\r
+{ if (EQUALS_DELTA(expected,actual,delta)) {\\r
+ addTestPartResult(new TestPartResult(this, __FILE__,__LINE__,TO_S_E_DELTA_S(expected,actual,delta),success));\\r
+ } else {\\r
+ addTestPartResult(new TestPartResult(this, __FILE__,__LINE__,TO_S_E_DELTA_F(expected,actual,delta),failure)); return;\\r
+ }}\r
+\r
+\r
+/**\r
+ * Make a test fails.\r
+ */\r
+#define FAIL()\\r
+ { addTestPartResult(new TestPartResult(this, __FILE__, __LINE__,("Test failed."),failure)); return; }\r
+\r
+/**\r
+ * Make a test fails with the given message.\r
+ * @param text Failure message\r
+ */\r
+#define FAIL_M(text)\\r
+ { addTestPartResult(new TestPartResult(this, __FILE__, __LINE__,text,failure)); return; }\r
+\r
+\r
+/**\r
+ * Define a test in a TestCase.\r
+ * User should put his test code between brackets after using this macro.\r
+ * @param testCaseName TestCase name where the test belongs to\r
+ * @param testName Unique test name\r
+ */\r
+#define TEST(testCaseName, testName)\\r
+ class testCaseName##testName##Test : public Test \\r
+ { public: testCaseName##testName##Test() : Test (#testCaseName , #testName) {} \\r
+ void run(); } \\r
+ testCaseName##testName##Instance; \\r
+ void testCaseName##testName##Test::run ()\r
+\r
+\r
+/**\r
+ * Define a test in a TestCase using test fixtures.\r
+ * User should put his test code between brackets after using this macro.\r
+ *\r
+ * This macro should only be used if test fixtures were declared earlier in\r
+ * this order: DECLARE, SETUP, TEARDOWN.\r
+ * @param testCaseName TestCase name where the test belongs to. Should be\r
+ * the same name of DECLARE, SETUP and TEARDOWN.\r
+ * @param testName Unique test name.\r
+ */\r
+#define TESTF(testCaseName, testName)\\r
+ class testCaseName##testName##Test : public testCaseName##Declare##Test \\r
+ { public: testCaseName##testName##Test() : testCaseName##Declare##Test (#testCaseName , #testName) {} \\r
+ void run(); } \\r
+ testCaseName##testName##Instance; \\r
+ void testCaseName##testName##Test::run ()\r
+\r
+\r
+/**\r
+ * Setup code for test fixtures.\r
+ * This code is executed before each TESTF.\r
+ *\r
+ * User should put his setup code between brackets after using this macro.\r
+ *\r
+ * @param testCaseName TestCase name of the fixtures.\r
+ */\r
+#define SETUP(testCaseName)\\r
+ void testCaseName##Declare##Test::setUp ()\r
+\r
+\r
+/**\r
+ * Teardown code for test fixtures.\r
+ * This code is executed after each TESTF.\r
+ *\r
+ * User should put his setup code between brackets after using this macro.\r
+ *\r
+ * @param testCaseName TestCase name of the fixtures.\r
+ */\r
+#define TEARDOWN(testCaseName)\\r
+ void testCaseName##Declare##Test::tearDown ()\r
+\r
+\r
+/**\r
+ * Location to declare variables and objets.\r
+ * This is where user should declare members accessible by TESTF,\r
+ * SETUP and TEARDOWN.\r
+ *\r
+ * User should not use brackets after using this macro. User should\r
+ * not initialize any members here.\r
+ *\r
+ * @param testCaseName TestCase name of the fixtures\r
+ * @see END_DECLARE for more information.\r
+ */\r
+#define DECLARE(testCaseName)\\r
+ class testCaseName##Declare##Test : public Test \\r
+ { public: testCaseName##Declare##Test(const SimpleString& testCaseName, const SimpleString& testName) : Test (testCaseName , testName) {} \\r
+ virtual void run() = 0; void setUp(); void tearDown(); \\r
+ protected:\r
+\r
+\r
+/**\r
+ * Ending macro used after DECLARE.\r
+ *\r
+ * User should use this macro after declaring members with\r
+ * DECLARE macro.\r
+ */\r
+#define END_DECLARE \\r
+ };\r
+\r
+#endif // TEST_H\r
+\r
+\r
--- /dev/null
+#define ECPP\r
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#include "testcase.h"\r
+#include "test.h"\r
+#include "testresult.h"\r
+\r
+#ifndef ECPP\r
+#include <exception>\r
+#endif\r
+\r
+\r
+TestCase::TestCase(const SimpleString& name, TestResult *testResult)\r
+: name_(name), testResult_(testResult)\r
+{\r
+}\r
+\r
+TestCase::~TestCase()\r
+{\r
+}\r
+\r
+void TestCase::addTest(Test *test)\r
+{\r
+ Test *tmp;\r
+\r
+ if (tests_ == 0) {\r
+ tests_ = test;\r
+ tests_->setNext(tests_);\r
+ }\r
+ else {\r
+ tmp = tests_;\r
+ tests_ = test;\r
+ tests_->setNext(tmp->getNext());\r
+ tmp->setNext(tests_);\r
+ }\r
+\r
+ testsCount_++;\r
+}\r
+\r
+Test* TestCase::getTests() const\r
+{\r
+ Test *test = tests_;\r
+\r
+ if (test != 0) {\r
+ test = test->getNext();\r
+ }\r
+\r
+ return test;\r
+}\r
+\r
+void TestCase::run()\r
+{\r
+ Test *test = tests_->getNext();\r
+\r
+ runTests(test);\r
+\r
+ ran_ = true;\r
+\r
+ testResult_->addResult(this);\r
+}\r
+\r
+int TestCase::getTestsCount() const\r
+{\r
+ return testsCount_;\r
+}\r
+\r
+int TestCase::getFailuresCount() const\r
+{\r
+ return failuresCount_;\r
+}\r
+\r
+int TestCase::getSuccessesCount() const\r
+{\r
+ return successesCount_;\r
+}\r
+\r
+int TestCase::getErrorsCount() const\r
+{\r
+ return errorsCount_;\r
+}\r
+\r
+bool TestCase::ran() const\r
+{\r
+ return ran_;\r
+}\r
+\r
+const SimpleString& TestCase::getName() const\r
+{\r
+ return name_;\r
+}\r
+\r
+void TestCase::updateCount(Test *test)\r
+{\r
+ if (test->getErrorsCount() > 0) {\r
+ errorsCount_++;\r
+ }\r
+ else if (test->getFailuresCount() > 0) {\r
+ failuresCount_++;\r
+ }\r
+ else {\r
+ successesCount_++;\r
+ }\r
+}\r
+\r
+TestCase* TestCase::getNext() const\r
+{\r
+ return nextTestCase_;\r
+}\r
+\r
+void TestCase::setNext(TestCase *testCase)\r
+{\r
+ nextTestCase_ = testCase;\r
+}\r
+\r
+void TestCase::runTests(Test *test)\r
+{\r
+\r
+ for (int i = 0; i<testsCount_; i++) {\r
+ test->setUp();\r
+ runTest(test);\r
+ test->tearDown();\r
+ updateCount(test);\r
+ test = test->getNext();\r
+ }\r
+\r
+}\r
+\r
+#ifdef ECPP\r
+\r
+void TestCase::runTest(Test *test)\r
+{\r
+ test->run();\r
+}\r
+\r
+#else\r
+\r
+void TestCase::runTest(Test *test)\r
+{\r
+ try {\r
+ test->run();\r
+ }\r
+ catch (std::exception &e) {\r
+ test->addTestPartResult(new TestPartResult(test,"",-1,e.what(),error));\r
+ }\r
+ catch (...) {\r
+ test->addTestPartResult(new TestPartResult(test,"",-1,"Unexpected error occured",error));\r
+ }\r
+}\r
+#endif\r
+\r
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#include "simplestring.h"\r
+\r
+#ifndef TESTCASE_H\r
+#define TESTCASE_H\r
+\r
+\r
+class Test;\r
+class TestResult;\r
+\r
+/**\r
+ * A TestCase is a collection of unit tests (instance of Test) and is\r
+ * always specified by the first parameter of a Test declaration.\r
+ */\r
+class TestCase\r
+{\r
+ public:\r
+\r
+ /**\r
+ * Main TestCase constructor.\r
+ *\r
+ * @param name TestCase name\r
+ * @param testResult Pointer to the TestResult used to report results\r
+ * of executed Test\r
+ */\r
+ TestCase(const SimpleString& name, TestResult *testResult);\r
+\r
+ virtual ~TestCase();\r
+\r
+ /**\r
+ * Add a Test to the Test list. This method is used by TestRegistry.\r
+ *\r
+ * @param test Test instance to add to the Test list.\r
+ */\r
+ void addTest(Test *test);\r
+\r
+ /**\r
+ * Get the Test list.\r
+ *\r
+ * @return Test list\r
+ */\r
+ Test* getTests() const;\r
+\r
+ /**\r
+ * Execute all Tests in the Test list of this TestCase. In fact, it calls\r
+ * the run() method of all Tests.\r
+ */\r
+ void run();\r
+\r
+ /**\r
+ * Get the Test list size (number of Tests in this TestCase).\r
+ *\r
+ * @return The Test list size\r
+ */\r
+ int getTestsCount() const;\r
+\r
+ /**\r
+ * Get the total number of failures reported by all Tests.\r
+ *\r
+ * @return The total number of failures reported by all Tests. 0\r
+ * if no test were run or if no failures were reported.\r
+ */\r
+ int getFailuresCount() const;\r
+\r
+ /**\r
+ * Get the total number of successes reported by all Tests.\r
+ *\r
+ * @return The total number of successes reported by all Tests. 0\r
+ * if no test were run or if no successes were reported.\r
+ */\r
+ int getSuccessesCount() const;\r
+\r
+ /**\r
+ * Get the total number of errors reported by all Tests.\r
+ *\r
+ * @return The total number of errors reported by all Tests. 0\r
+ * if no test were run, if this is the embedded version or if\r
+ * no errors were reported.\r
+ */\r
+ int getErrorsCount() const;\r
+\r
+ /**\r
+ * Indicates whether or not this TestCase was executed.\r
+ *\r
+ * @return true if the method run() of this TestCase was called. false\r
+ * otherwise\r
+ */\r
+ bool ran() const;\r
+\r
+ /**\r
+ * Get the TestCase name. This name is specified by the first parameter\r
+ * of the Test declaration. For example, if a test was declared as\r
+ * TEST(TESTCASE1, TEST1), the TestCase name would be "TESTCASE1".\r
+ *\r
+ * @return The name of the TestCase\r
+ */\r
+ const SimpleString& getName() const;\r
+\r
+ /**\r
+ * Get the next TestCase in the list.\r
+ *\r
+ * @return The next TestCase in the TestCase linked list\r
+ */\r
+ TestCase* getNext() const;\r
+\r
+ /**\r
+ * Set the next TestCase in the list.\r
+ *\r
+ * @return The next TestCase in the TestCase linked list\r
+ */\r
+ void setNext(TestCase *testCase);\r
+\r
+ protected:\r
+ int failuresCount_{0};\r
+ int successesCount_{0};\r
+ int errorsCount_{0};\r
+ int testsCount_{0};\r
+ Test *tests_{0};\r
+ SimpleString name_;\r
+ TestCase *nextTestCase_{0};\r
+ TestResult *testResult_;\r
+\r
+ private:\r
+ void updateCount(Test *test);\r
+ void runTests(Test *test);\r
+ void runTest(Test *test);\r
+ bool ran_{false};\r
+\r
+};\r
+\r
+#endif // TESTCASE_H\r
+\r
+\r
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#ifndef TESTHARNESS_H\r
+#define TESTHARNESS_H\r
+\r
+#include "test.h"\r
+#include "testcase.h"\r
+#include "testpartresult.h"\r
+#include "testregistry.h"\r
+#include "simplestring.h"\r
+#include "testprinter.h"\r
+#include "testresult.h"\r
+#include "testrunner.h"\r
+#include "defaulttestprinter.h"\r
+\r
+#endif\r
+\r
+\r
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#include "testpartresult.h"\r
+#include "test.h"\r
+\r
+\r
+TestPartResult::TestPartResult (Test *test,\r
+ const SimpleString& fileName, \r
+ long lineNumber,\r
+ const SimpleString& message,\r
+ testType type) \r
+ : message_ (message), \r
+ test_ (test), \r
+ fileName_ (fileName), \r
+ lineNumber_ (lineNumber),\r
+ type_ (type)\r
+{\r
+}\r
+\r
+void TestPartResult::setNext(TestPartResult *next) {\r
+ next_ = next;\r
+} \r
+\r
+TestPartResult* TestPartResult::getNext() const {\r
+ return next_;\r
+} \r
+\r
+testType TestPartResult::getType() const {\r
+ return type_; \r
+} \r
+\r
+const SimpleString& TestPartResult::getMessage() const {\r
+ return message_;\r
+}\r
+ \r
+Test* TestPartResult::getTest() const {\r
+ return test_;\r
+}\r
+ \r
+const SimpleString& TestPartResult::getFileName() const {\r
+ return fileName_;\r
+}\r
+ \r
+long TestPartResult::getLineNumber() const {\r
+ return lineNumber_;\r
+}\r
+\r
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#ifndef TESTPARTRESULT_H\r
+#define TESTPARTRESULT_H\r
+\r
+#include "simplestring.h"\r
+\r
+\r
+/**\r
+ * This enumeration contains the three states a TestPartResult can take.\r
+ *\r
+ * A failure means that an assertion failed during the test.\r
+ *\r
+ * A success means that all assertion succeeded during the test.\r
+ *\r
+ * An error means that an exception was thrown during the test.\r
+ */\r
+enum testType {failure,success,error};\r
+\r
+class Test;\r
+\r
+/**\r
+ * This class contains details about assertion processed during the\r
+ * execution of a Test. It contains the line and the file of the assertion, \r
+ * the result (success, failure or error), the condition (or message), and\r
+ * the Test class where the assertion was processed.\r
+ */ \r
+class TestPartResult\r
+{\r
+ public:\r
+ /**\r
+ * Main constructor used to initialize all details about the result\r
+ * of an assertion.\r
+ *\r
+ * @param test The test where the assertion was processed\r
+ * @param fileName The file name where the assertion is located\r
+ * @param lineNumber The line number where the assertion is located\r
+ * @param message The assertion condition or message\r
+ * @param type The result of the assertion (failure, success or error)\r
+ */\r
+ TestPartResult (Test *test,\r
+ const SimpleString& fileName, \r
+ long lineNumber,\r
+ const SimpleString& message,\r
+ testType type);\r
+\r
+ /**\r
+ * Set the next TestPartResult in the list.\r
+ *\r
+ * @param next The next TestPartResult in the linked list\r
+ */\r
+ void setNext(TestPartResult* next);\r
+ \r
+ /**\r
+ * Get the next TestPartResult in the list.\r
+ *\r
+ * @return The next TestPartResult in the linked list\r
+ */\r
+ TestPartResult* getNext() const;\r
+\r
+ /**\r
+ * Get the type of the TestPartResult. This represents the result\r
+ * of the assertion.\r
+ *\r
+ * @return The type of the TestPartResult (failure, success or error)\r
+ */\r
+ testType getType() const;\r
+ \r
+ /**\r
+ * Get the message (or condition) of the assertion.\r
+ *\r
+ * @return The message (or condition) of the assertion\r
+ */\r
+ const SimpleString& getMessage() const;\r
+ \r
+ /**\r
+ * Get the Test where the assertion is located.\r
+ *\r
+ * @return The Test where the assertion is located\r
+ */\r
+ Test* getTest() const;\r
+ \r
+ /**\r
+ * Get the file name where the assertion is located.\r
+ *\r
+ * @return The file name where the assertion is located\r
+ */\r
+ const SimpleString& getFileName() const;\r
+ \r
+ /**\r
+ * Get the line number where the assertion is located.\r
+ *\r
+ * @return The line number where the assertion is located\r
+ */\r
+ long getLineNumber() const;\r
+ \r
+ \r
+ protected:\r
+ SimpleString message_;\r
+ Test *test_;\r
+ SimpleString fileName_;\r
+ long lineNumber_;\r
+\r
+ private:\r
+ TestPartResult *next_;\r
+ testType type_; \r
+};\r
+\r
+#endif // TESTPARTRESULT_H\r
+\r
+\r
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#ifndef TESTPRINTER_H\r
+#define TESTPRINTER_H\r
+\r
+#include "testresult.h"\r
+\r
+\r
+/**\r
+ * A TestPrinter is a class used by the TestRegistry to print results\r
+ * of executed TestCases. This is an abstract class, so no default behavior\r
+ * for the print method is provided.\r
+ *\r
+ * @see DefaultTestPrinter\r
+ */\r
+class TestPrinter\r
+{\r
+ public:\r
+ virtual ~TestPrinter(){};\r
+ /**\r
+ * Print the details of a given TestResult instance. This\r
+ * method must be overridden by subclasses since it is\r
+ * abstract.\r
+ *\r
+ * @param testResult TestResult instance that the user wish to print\r
+ */\r
+ virtual void print(const TestResult *testResult) = 0;\r
+};\r
+\r
+#endif // TESTPRINTER_H\r
+\r
+\r
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#include "testregistry.h"\r
+#include "defaulttestprinter.h"\r
+\r
+\r
+int TestRegistry::nextName = 0;\r
+\r
+TestRegistry::TestRegistry()\r
+: currentTC_(0), defaultPrinter_(new DefaultTestPrinter()),testCaseCount_(0),\r
+ defaultRunner_(new TestRunner())\r
+{\r
+} \r
+\r
+TestRegistry::~TestRegistry()\r
+{\r
+ TestCase *tmp;\r
+ for (int i = 0; i<testCaseCount_; i++) {\r
+ tmp = currentTC_;\r
+ currentTC_ = currentTC_->getNext();\r
+ delete tmp;\r
+ }\r
+ \r
+ delete defaultPrinter_;\r
+ delete defaultRunner_;\r
+}\r
+\r
+void TestRegistry::addTest(Test *test)\r
+{\r
+ instance().add(test);\r
+} \r
+\r
+const TestResult* TestRegistry::run()\r
+{\r
+ return instance().runTests(instance().defaultRunner_);\r
+}\r
+\r
+const TestResult* TestRegistry::run(TestRunner *runner)\r
+{\r
+ return instance().runTests(runner);\r
+}\r
+\r
+const TestResult* TestRegistry::runAndPrint()\r
+{\r
+ return runAndPrint(instance().defaultPrinter_,instance().defaultRunner_);\r
+}\r
+\r
+const TestResult* TestRegistry::runAndPrint(TestRunner *runner)\r
+{\r
+ return runAndPrint(instance().defaultPrinter_,runner);\r
+}\r
+\r
+const TestResult* TestRegistry::runAndPrint(TestPrinter *printer)\r
+{\r
+ return runAndPrint(printer,instance().defaultRunner_);\r
+}\r
+\r
+\r
+const TestResult* TestRegistry::runAndPrint(TestPrinter *printer, TestRunner *runner)\r
+{\r
+ const TestResult *testResult = instance().runTests(runner);\r
+ printer->print(testResult);\r
+ return testResult;\r
+}\r
+\r
+ \r
+TestRegistry& TestRegistry::instance()\r
+{\r
+ static TestRegistry registry;\r
+ return registry;\r
+} \r
+\r
+void TestRegistry::add(Test *test)\r
+{\r
+ const SimpleString tcName = test->getTestCaseName();\r
+ const SimpleString tName = test->getTestName();\r
+ \r
+ if ((currentTC_ == 0) || (currentTC_->getName() != tcName)) {\r
+ addTestCase(new TestCase(tcName,&testResult_));\r
+ }\r
+ \r
+ currentTC_->addTest(test);\r
+ \r
+}\r
+\r
+const TestResult* TestRegistry::runTests(TestRunner *runner)\r
+{\r
+ TestCase *tc = currentTC_;\r
+ \r
+ if (tc != 0) {\r
+ tc = tc->getNext();\r
+ runner->run(tc,testCaseCount_);\r
+ }\r
+ \r
+ testResult_.setTestCases(tc,testCaseCount_);\r
+ \r
+ return &testResult_;\r
+} \r
+\r
+\r
+\r
+void TestRegistry::addTestCase(TestCase *testCase)\r
+{\r
+ TestCase *tmp;\r
+ \r
+ if (currentTC_ == 0) {\r
+ currentTC_ = testCase;\r
+ currentTC_->setNext(currentTC_);\r
+ }\r
+ else {\r
+ tmp = currentTC_;\r
+ currentTC_ = testCase;\r
+ currentTC_->setNext(tmp->getNext());\r
+ tmp->setNext(currentTC_);\r
+ }\r
+ \r
+ testCaseCount_++;\r
+} \r
+\r
+\r
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#ifndef TESTREGISTRY_H\r
+#define TESTREGISTRY_H\r
+\r
+#include "test.h"\r
+#include "testcase.h"\r
+#include "testprinter.h"\r
+#include "simplestring.h"\r
+#include "testrunner.h"\r
+#include "testresult.h"\r
+\r
+\r
+/**\r
+ * The TestRegistry is the main class used to register all tests,\r
+ * and create appropriate TestCase. It can then be used to run\r
+ * tests and print results. All methods that should be used by\r
+ * the user are static.\r
+ */\r
+class TestRegistry\r
+{\r
+ public:\r
+ TestRegistry();\r
+ ~TestRegistry();\r
+\r
+ /**\r
+ * Add a test in the registry. If the previous TestCase was not the same\r
+ * as the one of the current test, a new TestCase is created.\r
+ *\r
+ * @param test Test to be added\r
+ */\r
+ static void addTest (Test *test);\r
+\r
+ /**\r
+ * Run all tests in the registry (default test runner) and return\r
+ * the test results.\r
+ *\r
+ * @return The test results\r
+ */\r
+ static const TestResult* run();\r
+\r
+ /**\r
+ * Pass all tests in the registry to the TestRunner runner and\r
+ * return the results of all tests ran.\r
+ *\r
+ * @param runner The custom runner used to decided which test to run\r
+ * @return The test results of all tests ran\r
+ */\r
+ static const TestResult* run(TestRunner *runner);\r
+\r
+ /**\r
+ * Run all tests in the registry (default test runner) and return\r
+ * the test results. This will also print the results using the\r
+ * default test printer (normal level of details and to the standard\r
+ * output).\r
+ *\r
+ * @return The test results\r
+ */\r
+ static const TestResult* runAndPrint();\r
+\r
+ /**\r
+ * Pass all tests in the registry to the TestRunner runner and\r
+ * return the results of all tests ran. This will also print the results\r
+ * using the default test printer (normal level of details and to the\r
+ * standard output).\r
+ *\r
+ * @param runner The custom runner used to decided which test to run\r
+ * @return The test results\r
+ */\r
+ static const TestResult* runAndPrint(TestRunner *runner);\r
+\r
+ /**\r
+ * Run all tests in the registry (default test runner) and return\r
+ * the test results. Results will also be given to\r
+ * to the TestPrinter printer.\r
+ *\r
+ * @param printer The custom printer used to print the test results\r
+ * @return The test results\r
+ */\r
+ static const TestResult* runAndPrint(TestPrinter *printer);\r
+\r
+ /**\r
+ * Pass all tests in the registry to the TestRunner runner and\r
+ * return the results of all tests ran. Results will also be given to\r
+ * to the TestPrinter printer.\r
+ *\r
+ * @param printer The custom printer used to print the test results\r
+ * @param runner The custom runner used to decided which test to run\r
+ * @return The test results\r
+ */\r
+ static const TestResult* runAndPrint(TestPrinter *printer, TestRunner *runner);\r
+\r
+ private:\r
+ static TestRegistry& instance();\r
+ static int nextName;\r
+ void add(Test *test);\r
+ void addTestCase(TestCase *testCase);\r
+ const TestResult* runTests(TestRunner *runner);\r
+ TestCase *currentTC_;\r
+ TestPrinter *defaultPrinter_;\r
+ int testCaseCount_;\r
+ TestRunner *defaultRunner_;\r
+ TestResult testResult_;\r
+};\r
+\r
+#endif // TESTREGISTRY_H\r
+\r
+\r
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#include "testresult.h"\r
+\r
+\r
+TestResult::TestResult()\r
+{\r
+}\r
+\r
+\r
+TestResult::~TestResult()\r
+{\r
+}\r
+\r
+int TestResult::getTotalSuccesses() const\r
+{\r
+ return totalSuccesses_;\r
+}\r
+\r
+int TestResult::getTotalErrors() const\r
+{\r
+ return totalErrors_;\r
+}\r
+\r
+int TestResult::getTotalFailures() const\r
+{\r
+ return totalFailures_;\r
+}\r
+\r
+\r
+int TestResult::getSuccesses() const\r
+{\r
+ return successes_;\r
+}\r
+\r
+int TestResult::getFailures() const\r
+{\r
+ return failures_;\r
+}\r
+\r
+int TestResult::getErrors() const\r
+{\r
+ return errors_;\r
+}\r
+\r
+int TestResult::getTestCaseCount() const\r
+{\r
+ return testCaseCount_;\r
+}\r
+\r
+int TestResult::getTestRanCount() const\r
+{\r
+ return testRanCount_;\r
+}\r
+\r
+int TestResult::getTestCaseRanCount() const\r
+{\r
+ return testCaseRanCount_;\r
+}\r
+\r
+TestCase* TestResult::getTestCases() const\r
+{\r
+ return testCases_;\r
+}\r
+\r
+void TestResult::setTestCases(TestCase *testCases, int testCaseCount)\r
+{\r
+ testCases_ = testCases;\r
+ testCaseCount_ = testCaseCount;\r
+}\r
+\r
+void TestResult::addResult(TestCase *testCase)\r
+{\r
+ int tcSuccesses = testCase->getSuccessesCount();\r
+ int tcErrors = testCase->getErrorsCount();\r
+ int tcFailures = testCase->getFailuresCount();\r
+\r
+ testCaseRanCount_++;\r
+\r
+ totalSuccesses_ += tcSuccesses;\r
+ totalErrors_ += tcErrors;\r
+ totalFailures_ += tcFailures;\r
+ testRanCount_ += testCase->getTestsCount();\r
+\r
+ if (tcErrors == 0 && tcFailures == 0) {\r
+ successes_++;\r
+ }\r
+ else if (tcErrors > 0) {\r
+ errors_++;\r
+ }\r
+ else {\r
+ failures_++;\r
+ }\r
+}\r
+\r
+\r
+\r
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#ifndef testresult_H\r
+#define testresult_H\r
+\r
+#include "testcase.h"\r
+\r
+\r
+class TestResult\r
+{\r
+public:\r
+ TestResult();\r
+ virtual ~TestResult();\r
+\r
+\r
+ /**\r
+ * Get the total number of successes registered by all\r
+ * test cases ran. This is the sum of all TestCase->getSuccessesCount().\r
+ *\r
+ *@return The number of successes registered by all testcases.\r
+ */\r
+ int getTotalSuccesses() const;\r
+\r
+ /**\r
+ * Get the total number of errors registered by all\r
+ * test cases ran. This is the sum of all TestCase->getErrorsCount().\r
+ *\r
+ *@return The number of errors registered by all testcases.\r
+ */\r
+ int getTotalErrors() const;\r
+\r
+ /**\r
+ * Get the total number of failures registered by all\r
+ * test cases ran. This is the sum of all TestCase->getFailuresCount().\r
+ *\r
+ * @return The number of failures registered by all testcases.\r
+ */\r
+ int getTotalFailures() const;\r
+\r
+ /**\r
+ * Get the number of testcases ran that succeeded.\r
+ *\r
+ * @return The number of testcases ran that succeeded.\r
+ */\r
+ int getSuccesses() const;\r
+\r
+ /**\r
+ * Get the number of testcases ran that failed.\r
+ *\r
+ * @return The number of testcases ran that failed.\r
+ */\r
+ int getFailures() const;\r
+\r
+ /**\r
+ * Get the number of testcases ran that reported an error.\r
+ *\r
+ * @return The number of testcases ran that reported an error.\r
+ */\r
+ int getErrors() const;\r
+\r
+ /**\r
+ * Get the number of testcases in the TestCase list.\r
+ *\r
+ * @return The size of the TestCase list\r
+ */\r
+ int getTestCaseCount() const;\r
+\r
+ /**\r
+ * Get the number of tests\r
+ *\r
+ * @return The number of tests ran that succeeded\r
+ */\r
+ int getTestRanCount() const;\r
+\r
+ /**\r
+ * Get the number of testcases ran.\r
+ *\r
+ * @return The number of testcases ran\r
+ */\r
+ int getTestCaseRanCount() const;\r
+\r
+ /**\r
+ * Get the TestCase list. This list contains all TestCase registered and\r
+ * not only those that were ran.\r
+ *\r
+ * @return The TestCase list\r
+ */\r
+ TestCase* getTestCases() const;\r
+\r
+ /**\r
+ * Set the TestCase list and the size of the list.\r
+ *\r
+ * @param testCases TestCase list\r
+ * @param testCaseCount size of the TestCase list\r
+ */\r
+ void setTestCases(TestCase *testCases, int testCaseCount);\r
+\r
+ /**\r
+ * Add a TestCase result. This is used by a TestCase after it has\r
+ * completed.\r
+ *\r
+ * @param testCase TestCase that ran and contains results to add to\r
+ * global results\r
+ */\r
+ virtual void addResult(TestCase *testCase);\r
+\r
+protected:\r
+ int testCaseCount_{0};\r
+ int testRanCount_{0};\r
+ int testCaseRanCount_{0};\r
+\r
+ int totalSuccesses_{0};\r
+ int totalErrors_{0};\r
+ int totalFailures_{0};\r
+\r
+ int successes_{0};\r
+ int errors_{0};\r
+ int failures_{0};\r
+\r
+ TestCase* testCases_{0};\r
+\r
+};\r
+\r
+\r
+#endif // testresult_H\r
+\r
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#include "testrunner.h"\r
+\r
+\r
+TestRunner::TestRunner()\r
+{\r
+}\r
+\r
+\r
+TestRunner::~TestRunner()\r
+{\r
+}\r
+\r
+void TestRunner::run(TestCase *testCase, int size)\r
+{\r
+ for (int i=0; i<size; i++) {\r
+ testCase->run();\r
+ testCase = testCase->getNext();\r
+ }\r
+}\r
+\r
+\r
+\r
+\r
--- /dev/null
+/*\r
+EasyUnit : Simple C++ Unit testing framework\r
+Copyright (C) 2004 Barthelemy Dagenais\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+Barthelemy Dagenais\r
+barthelemy@prologique.com\r
+*/\r
+\r
+#ifndef TestRunner_H\r
+#define TestRunner_H\r
+\r
+#include "testcase.h"\r
+\r
+\r
+\r
+/**\r
+ * Test runner used to determine which test to run.\r
+ * \r
+ * User may extends this class to provide a custom test runner\r
+ * to TestRegistry.\r
+ */\r
+class TestRunner\r
+{\r
+public:\r
+ TestRunner();\r
+ virtual ~TestRunner();\r
+ \r
+ /**\r
+ * Method used to run testcases by TestRegistry.\r
+ * \r
+ * User should override this method in order to provide custom\r
+ * behavior.\r
+ *\r
+ * @param testCase Linked list of testcases\r
+ * @param size Size of the linked list\r
+ */\r
+ virtual void run(TestCase *testCase, int size);\r
+\r
+};\r
+\r
+\r
+#endif // TestRunner_H\r
+\r
--- /dev/null
+// Copyright Louis Delacroix 2010 - 2014.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+// A pretty printing library for C++
+//
+// Usage:
+// Include this header, and operator<< will "just work".
+
+#ifndef H_PRETTY_PRINT
+#define H_PRETTY_PRINT
+
+#include <cstddef>
+#include <iterator>
+#include <memory>
+#include <ostream>
+#include <set>
+#include <tuple>
+#include <type_traits>
+#include <unordered_set>
+#include <utility>
+#include <valarray>
+
+namespace pretty_print
+{
+ namespace detail
+ {
+ // SFINAE type trait to detect whether T::const_iterator exists.
+
+ struct sfinae_base
+ {
+ using yes = char;
+ using no = yes[2];
+ };
+
+ template <typename T>
+ struct has_const_iterator : private sfinae_base
+ {
+ private:
+ template <typename C> static yes & test(typename C::const_iterator*);
+ template <typename C> static no & test(...);
+ public:
+ static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
+ using type = T;
+ };
+
+ template <typename T>
+ struct has_begin_end : private sfinae_base
+ {
+ private:
+ template <typename C>
+ static yes & f(typename std::enable_if<
+ std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::begin)),
+ typename C::const_iterator(C::*)() const>::value>::type *);
+
+ template <typename C> static no & f(...);
+
+ template <typename C>
+ static yes & g(typename std::enable_if<
+ std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::end)),
+ typename C::const_iterator(C::*)() const>::value, void>::type*);
+
+ template <typename C> static no & g(...);
+
+ public:
+ static bool const beg_value = sizeof(f<T>(nullptr)) == sizeof(yes);
+ static bool const end_value = sizeof(g<T>(nullptr)) == sizeof(yes);
+ };
+
+ } // namespace detail
+
+
+ // Holds the delimiter values for a specific character type
+
+ template <typename TChar>
+ struct delimiters_values
+ {
+ using char_type = TChar;
+ const char_type * prefix;
+ const char_type * delimiter;
+ const char_type * postfix;
+ };
+
+
+ // Defines the delimiter values for a specific container and character type
+
+ template <typename T, typename TChar>
+ struct delimiters
+ {
+ using type = delimiters_values<TChar>;
+ static const type values;
+ };
+
+
+ // Functor to print containers. You can use this directly if you want
+ // to specificy a non-default delimiters type. The printing logic can
+ // be customized by specializing the nested template.
+
+ template <typename T,
+ typename TChar = char,
+ typename TCharTraits = ::std::char_traits<TChar>,
+ typename TDelimiters = delimiters<T, TChar>>
+ struct print_container_helper
+ {
+ using delimiters_type = TDelimiters;
+ using ostream_type = std::basic_ostream<TChar, TCharTraits>;
+
+ template <typename U>
+ struct printer
+ {
+ static void print_body(const U & c, ostream_type & stream)
+ {
+ using std::begin;
+ using std::end;
+
+ auto it = begin(c);
+ const auto the_end = end(c);
+
+ if (it != the_end)
+ {
+ for ( ; ; )
+ {
+ stream << *it;
+
+ if (++it == the_end) break;
+
+ if (delimiters_type::values.delimiter != NULL)
+ stream << delimiters_type::values.delimiter;
+ }
+ }
+ }
+ };
+
+ print_container_helper(const T & container)
+ : container_(container)
+ { }
+
+ inline void operator()(ostream_type & stream) const
+ {
+ if (delimiters_type::values.prefix != NULL)
+ stream << delimiters_type::values.prefix;
+
+ printer<T>::print_body(container_, stream);
+
+ if (delimiters_type::values.postfix != NULL)
+ stream << delimiters_type::values.postfix;
+ }
+
+ private:
+ const T & container_;
+ };
+
+ // Specialization for pairs
+
+ template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
+ template <typename T1, typename T2>
+ struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::pair<T1, T2>>
+ {
+ using ostream_type = print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
+
+ static void print_body(const std::pair<T1, T2> & c, ostream_type & stream)
+ {
+ stream << c.first;
+ if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL)
+ stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter;
+ stream << c.second;
+ }
+ };
+
+ // Specialization for tuples
+
+ template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
+ template <typename ...Args>
+ struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::tuple<Args...>>
+ {
+ using ostream_type = print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
+ using element_type = std::tuple<Args...>;
+
+ template <std::size_t I> struct Int { };
+
+ static void print_body(const element_type & c, ostream_type & stream)
+ {
+ tuple_print(c, stream, Int<0>());
+ }
+
+ static void tuple_print(const element_type &, ostream_type &, Int<sizeof...(Args)>)
+ {
+ }
+
+ static void tuple_print(const element_type & c, ostream_type & stream,
+ typename std::conditional<sizeof...(Args) != 0, Int<0>, std::nullptr_t>::type)
+ {
+ stream << std::get<0>(c);
+ tuple_print(c, stream, Int<1>());
+ }
+
+ template <std::size_t N>
+ static void tuple_print(const element_type & c, ostream_type & stream, Int<N>)
+ {
+ if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL)
+ stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter;
+
+ stream << std::get<N>(c);
+
+ tuple_print(c, stream, Int<N + 1>());
+ }
+ };
+
+ // Prints a print_container_helper to the specified stream.
+
+ template<typename T, typename TChar, typename TCharTraits, typename TDelimiters>
+ inline std::basic_ostream<TChar, TCharTraits> & operator<<(
+ std::basic_ostream<TChar, TCharTraits> & stream,
+ const print_container_helper<T, TChar, TCharTraits, TDelimiters> & helper)
+ {
+ helper(stream);
+ return stream;
+ }
+
+
+ // Basic is_container template; specialize to derive from std::true_type for all desired container types
+
+ template <typename T>
+ struct is_container : public std::integral_constant<bool,
+ detail::has_const_iterator<T>::value &&
+ detail::has_begin_end<T>::beg_value &&
+ detail::has_begin_end<T>::end_value> { };
+
+ template <typename T, std::size_t N>
+ struct is_container<T[N]> : std::true_type { };
+
+ template <std::size_t N>
+ struct is_container<char[N]> : std::false_type { };
+
+ template <typename T>
+ struct is_container<std::valarray<T>> : std::true_type { };
+
+ template <typename T1, typename T2>
+ struct is_container<std::pair<T1, T2>> : std::true_type { };
+
+ template <typename ...Args>
+ struct is_container<std::tuple<Args...>> : std::true_type { };
+
+
+ // Default delimiters
+
+ template <typename T> struct delimiters<T, char> { static const delimiters_values<char> values; };
+ template <typename T> const delimiters_values<char> delimiters<T, char>::values = { "[", ", ", "]" };
+ template <typename T> struct delimiters<T, wchar_t> { static const delimiters_values<wchar_t> values; };
+ template <typename T> const delimiters_values<wchar_t> delimiters<T, wchar_t>::values = { L"[", L", ", L"]" };
+
+
+ // Delimiters for (multi)set and unordered_(multi)set
+
+ template <typename T, typename TComp, typename TAllocator>
+ struct delimiters< ::std::set<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
+
+ template <typename T, typename TComp, typename TAllocator>
+ const delimiters_values<char> delimiters< ::std::set<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
+
+ template <typename T, typename TComp, typename TAllocator>
+ struct delimiters< ::std::set<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
+
+ template <typename T, typename TComp, typename TAllocator>
+ const delimiters_values<wchar_t> delimiters< ::std::set<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
+
+ template <typename T, typename TComp, typename TAllocator>
+ struct delimiters< ::std::multiset<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
+
+ template <typename T, typename TComp, typename TAllocator>
+ const delimiters_values<char> delimiters< ::std::multiset<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
+
+ template <typename T, typename TComp, typename TAllocator>
+ struct delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
+
+ template <typename T, typename TComp, typename TAllocator>
+ const delimiters_values<wchar_t> delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
+
+ template <typename T, typename THash, typename TEqual, typename TAllocator>
+ struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
+
+ template <typename T, typename THash, typename TEqual, typename TAllocator>
+ const delimiters_values<char> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
+
+ template <typename T, typename THash, typename TEqual, typename TAllocator>
+ struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
+
+ template <typename T, typename THash, typename TEqual, typename TAllocator>
+ const delimiters_values<wchar_t> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
+
+ template <typename T, typename THash, typename TEqual, typename TAllocator>
+ struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
+
+ template <typename T, typename THash, typename TEqual, typename TAllocator>
+ const delimiters_values<char> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
+
+ template <typename T, typename THash, typename TEqual, typename TAllocator>
+ struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
+
+ template <typename T, typename THash, typename TEqual, typename TAllocator>
+ const delimiters_values<wchar_t> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
+
+
+ // Delimiters for pair and tuple
+
+ template <typename T1, typename T2> struct delimiters<std::pair<T1, T2>, char> { static const delimiters_values<char> values; };
+ template <typename T1, typename T2> const delimiters_values<char> delimiters<std::pair<T1, T2>, char>::values = { "(", ", ", ")" };
+ template <typename T1, typename T2> struct delimiters< ::std::pair<T1, T2>, wchar_t> { static const delimiters_values<wchar_t> values; };
+ template <typename T1, typename T2> const delimiters_values<wchar_t> delimiters< ::std::pair<T1, T2>, wchar_t>::values = { L"(", L", ", L")" };
+
+ template <typename ...Args> struct delimiters<std::tuple<Args...>, char> { static const delimiters_values<char> values; };
+ template <typename ...Args> const delimiters_values<char> delimiters<std::tuple<Args...>, char>::values = { "(", ", ", ")" };
+ template <typename ...Args> struct delimiters< ::std::tuple<Args...>, wchar_t> { static const delimiters_values<wchar_t> values; };
+ template <typename ...Args> const delimiters_values<wchar_t> delimiters< ::std::tuple<Args...>, wchar_t>::values = { L"(", L", ", L")" };
+
+
+ // Type-erasing helper class for easy use of custom delimiters.
+ // Requires TCharTraits = std::char_traits<TChar> and TChar = char or wchar_t, and MyDelims needs to be defined for TChar.
+ // Usage: "cout << pretty_print::custom_delims<MyDelims>(x)".
+
+ struct custom_delims_base
+ {
+ virtual ~custom_delims_base() { }
+ virtual std::ostream & stream(::std::ostream &) = 0;
+ virtual std::wostream & stream(::std::wostream &) = 0;
+ };
+
+ template <typename T, typename Delims>
+ struct custom_delims_wrapper : custom_delims_base
+ {
+ custom_delims_wrapper(const T & t_) : t(t_) { }
+
+ std::ostream & stream(std::ostream & s)
+ {
+ return s << print_container_helper<T, char, std::char_traits<char>, Delims>(t);
+ }
+
+ std::wostream & stream(std::wostream & s)
+ {
+ return s << print_container_helper<T, wchar_t, std::char_traits<wchar_t>, Delims>(t);
+ }
+
+ private:
+ const T & t;
+ };
+
+ template <typename Delims>
+ struct custom_delims
+ {
+ template <typename Container>
+ custom_delims(const Container & c) : base(new custom_delims_wrapper<Container, Delims>(c)) { }
+
+ std::unique_ptr<custom_delims_base> base;
+ };
+
+ template <typename TChar, typename TCharTraits, typename Delims>
+ inline std::basic_ostream<TChar, TCharTraits> & operator<<(std::basic_ostream<TChar, TCharTraits> & s, const custom_delims<Delims> & p)
+ {
+ return p.base->stream(s);
+ }
+
+
+ // A wrapper for a C-style array given as pointer-plus-size.
+ // Usage: std::cout << pretty_print_array(arr, n) << std::endl;
+
+ template<typename T>
+ struct array_wrapper_n
+ {
+ typedef const T * const_iterator;
+ typedef T value_type;
+
+ array_wrapper_n(const T * const a, size_t n) : _array(a), _n(n) { }
+ inline const_iterator begin() const { return _array; }
+ inline const_iterator end() const { return _array + _n; }
+
+ private:
+ const T * const _array;
+ size_t _n;
+ };
+
+
+ // A wrapper for hash-table based containers that offer local iterators to each bucket.
+ // Usage: std::cout << bucket_print(m, 4) << std::endl; (Prints bucket 5 of container m.)
+
+ template <typename T>
+ struct bucket_print_wrapper
+ {
+ typedef typename T::const_local_iterator const_iterator;
+ typedef typename T::size_type size_type;
+
+ const_iterator begin() const
+ {
+ return m_map.cbegin(n);
+ }
+
+ const_iterator end() const
+ {
+ return m_map.cend(n);
+ }
+
+ bucket_print_wrapper(const T & m, size_type bucket) : m_map(m), n(bucket) { }
+
+ private:
+ const T & m_map;
+ const size_type n;
+ };
+
+} // namespace pretty_print
+
+
+// Global accessor functions for the convenience wrappers
+
+template<typename T>
+inline pretty_print::array_wrapper_n<T> pretty_print_array(const T * const a, size_t n)
+{
+ return pretty_print::array_wrapper_n<T>(a, n);
+}
+
+template <typename T> pretty_print::bucket_print_wrapper<T>
+bucket_print(const T & m, typename T::size_type n)
+{
+ return pretty_print::bucket_print_wrapper<T>(m, n);
+}
+
+
+// Main magic entry point: An overload snuck into namespace std.
+// Can we do better?
+
+namespace std
+{
+ // Prints a container to the stream using default delimiters
+
+ template<typename T, typename TChar, typename TCharTraits>
+ inline typename enable_if< ::pretty_print::is_container<T>::value,
+ basic_ostream<TChar, TCharTraits> &>::type
+ operator<<(basic_ostream<TChar, TCharTraits> & stream, const T & container)
+ {
+ return stream << ::pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
+ }
+}
+
+
+
+#endif // H_PRETTY_PRINT
--- /dev/null
+#include "utils.h"
+
+#include <vector>
+#include <stdio.h>
+
+#include "easyunit/test.h"
+
+TEST(UtilsTest,split)
+{
+ const char *s= "one two three";
+ std::vector<std::string> v= split(s, ' ');
+ ASSERT_TRUE(v.size() == 3);
+ ASSERT_TRUE(v[0] == "one");
+ ASSERT_TRUE(v[1] == "two");
+ ASSERT_TRUE(v[2] == "three");
+}
+
+TEST(UtilsTest,split_empty_string)
+{
+ const char *s= "";
+ std::vector<std::string> v= split(s, ' ');
+
+ ASSERT_TRUE(v.size() == 1);
+ ASSERT_TRUE(v[0].empty());
+ ASSERT_TRUE(v[0] == "");
+}
+
+TEST(UtilsTest,parse_number_list)
+{
+ const char *s= "1.1,2.2,3.3";
+ std::vector<float> v= parse_number_list(s);
+ ASSERT_TRUE(v.size() == 3);
+ ASSERT_TRUE(v[0] == 1.1F);
+ ASSERT_TRUE(v[1] == 2.2F);
+ ASSERT_TRUE(v[2] == 3.3F);
+}
--- /dev/null
+#include "TemperatureSwitch.h"
+#include "Kernel.h"
+#include "checksumm.h"
+#include "utils.h"
+#include "Test_kernel.h"
+#include "PublicDataRequest.h"
+#include "PublicData.h"
+#include "TemperatureControlPublicAccess.h"
+#include "SwitchPublicAccess.h"
+#include "Gcode.h"
+
+#include <stdio.h>
+#include <memory>
+
+#include "easyunit/test.h"
+
+DECLARE(TemperatureSwitch)
+ TemperatureSwitch *ts;
+END_DECLARE
+
+SETUP(TemperatureSwitch)
+{
+ ts = new TemperatureSwitch();
+ //printf("...Setup TemperatureSwitch\n");
+}
+
+TEARDOWN(TemperatureSwitch)
+{
+ delete ts;
+ test_kernel_teardown();
+
+ //printf("...Teardown TemperatureSwitch\n");
+}
+
+const static char edge_low_config[]= "\
+temperatureswitch.psu_off.enable true \n\
+temperatureswitch.psu_off.designator T \n\
+temperatureswitch.psu_off.switch fan \n\
+temperatureswitch.psu_off.threshold_temp 50.0 \n\
+temperatureswitch.psu_off.heatup_poll 5 \n\
+temperatureswitch.psu_off.cooldown_poll 5 \n\
+temperatureswitch.psu_off.arm_mcode 1100 \n\
+temperatureswitch.psu_off.trigger falling \n\
+temperatureswitch.psu_off.inverted false \n\
+";
+
+const static char level_config[]= "\
+temperatureswitch.psu_off.enable true \n\
+temperatureswitch.psu_off.designator T \n\
+temperatureswitch.psu_off.switch fan \n\
+temperatureswitch.psu_off.threshold_temp 50.0 \n\
+temperatureswitch.psu_off.heatup_poll 5 \n\
+temperatureswitch.psu_off.cooldown_poll 5 \n\
+";
+
+// handle mock call to temperature control
+static void on_get_public_data_tc1(void *argument)
+{
+ PublicDataRequest *pdr = static_cast<PublicDataRequest *>(argument);
+
+ if(!pdr->starts_with(temperature_control_checksum)) return;
+ if(!pdr->second_element_is(poll_controls_checksum)) return;
+
+ std::vector<struct pad_temperature> *v= static_cast<std::vector<pad_temperature>*>(pdr->get_data_ptr());
+
+ struct pad_temperature t;
+ // setup data
+ t.designator= "T";
+ t.id= 123;
+ v->push_back(t);
+ pdr->set_taken();
+ pdr->clear_returned_data();
+}
+
+// Handle temperature request and switch status request
+static bool switch_state;
+static bool switch_get_hit= false;
+static int hitcnt= 0;
+static float return_current_temp= 0;
+static void on_get_public_data_tc2(void *argument)
+{
+ PublicDataRequest *pdr = static_cast<PublicDataRequest *>(argument);
+
+ if(pdr->starts_with(temperature_control_checksum)) {
+ if(!pdr->second_element_is(current_temperature_checksum)) return;
+ if(!pdr->third_element_is(123)) return;
+
+ hitcnt++;
+
+ struct pad_temperature *t= static_cast<pad_temperature*>(pdr->get_data_ptr());
+ t->current_temperature = return_current_temp;
+ t->target_temperature = 0;
+ t->pwm = 0;
+ t->designator= "T";
+ t->id= 123;
+ pdr->set_taken();
+ pdr->clear_returned_data();
+
+ } else if(pdr->starts_with(switch_checksum)){
+
+ if(!pdr->second_element_is(get_checksum("fan"))) return;
+
+ switch_get_hit= true;
+
+ static struct pad_switch pad;
+ pad.name = get_checksum("fan");
+ pad.state = switch_state;
+ pad.value = 0;
+
+ pdr->set_data_ptr(&pad);
+ pdr->set_taken();
+ }
+}
+
+static bool switch_set_hit= false;
+static void on_set_public_data_switch(void *argument)
+{
+ PublicDataRequest *pdr = static_cast<PublicDataRequest *>(argument);
+
+ if(!pdr->starts_with(switch_checksum)) return;
+ if(!pdr->second_element_is(get_checksum("fan"))) return;
+ if(!pdr->third_element_is(state_checksum)) return;
+
+ switch_set_hit= true;
+
+ bool t = *static_cast<bool *>(pdr->get_data_ptr());
+ switch_state = t;
+ pdr->set_taken();
+}
+
+
+static bool set_temp(TemperatureSwitch *nts, float t)
+{
+ // trap public data request to TemperatureControl and return a temperature
+ hitcnt= 0;
+ return_current_temp= t;
+ test_kernel_trap_event(ON_GET_PUBLIC_DATA, on_get_public_data_tc2);
+
+ // tick 5 times for 5 seconds
+ for (int i = 0; i < 5; ++i) {
+ nts->on_second_tick(nullptr);
+ }
+
+ // make sure the temp was read at least once
+ return (hitcnt > 0);
+}
+
+TESTF(TemperatureSwitch,level_low_high)
+{
+ // load config with required settings for this test
+ test_kernel_setup_config(level_config, &level_config[sizeof(level_config)]);
+
+ // trap public data request to TemperatureControl and return a mock tempcontrol
+ test_kernel_trap_event(ON_GET_PUBLIC_DATA, on_get_public_data_tc1);
+
+ // make module load the config
+ uint16_t cs= get_checksum("psu_off");
+ std::unique_ptr<TemperatureSwitch> nts(ts->load_config(cs));
+
+ if(nts.get() == nullptr) {
+ FAIL_M("load config failed");
+ }
+
+ // stop handling this event
+ test_kernel_untrap_event(ON_GET_PUBLIC_DATA);
+
+ // test it registered the event
+ ASSERT_TRUE(THEKERNEL->kernel_has_event(ON_GCODE_RECEIVED, nts.get()));
+
+ set_temp(nts.get(), 25);
+
+ // capture any call to the switch to turn it on or off
+ switch_state= false;
+ switch_set_hit= false;
+ switch_get_hit= false;
+ test_kernel_trap_event(ON_SET_PUBLIC_DATA, on_set_public_data_switch);
+
+ // increase temp low -> high
+ set_temp(nts.get(), 60);
+
+ ASSERT_TRUE(switch_get_hit);
+ // make sure switch was set
+ ASSERT_TRUE(switch_set_hit);
+
+ // and make sure it was turned on
+ ASSERT_TRUE(switch_state);
+
+ // now make sure it turns off when temp drops
+ set_temp(nts.get(), 30);
+
+ // and make sure it was turned off
+ ASSERT_TRUE(!switch_state);
+}
+
+TESTF(TemperatureSwitch,edge_high_low)
+{
+ // load config with required settings for this test
+ test_kernel_setup_config(edge_low_config, &edge_low_config[sizeof(edge_low_config)]);
+
+ // trap public data request to TemperatureControl and return a mock tempcontrol
+ test_kernel_trap_event(ON_GET_PUBLIC_DATA, on_get_public_data_tc1);
+
+ // make module load the config
+ uint16_t cs= get_checksum("psu_off");
+ std::unique_ptr<TemperatureSwitch> nts(ts->load_config(cs));
+
+ if(nts.get() == nullptr) {
+ FAIL_M("load config failed");
+ }
+
+ // stop handling this event
+ test_kernel_untrap_event(ON_GET_PUBLIC_DATA);
+
+ // test it registered the event
+ ASSERT_TRUE(THEKERNEL->kernel_has_event(ON_GCODE_RECEIVED, nts.get()));
+ ASSERT_TRUE(!nts->is_armed());
+
+ // set initial temp low
+ set_temp(nts.get(), 25);
+
+ // capture any call to the switch to turn it on or off
+ switch_state= true;
+ test_kernel_trap_event(ON_SET_PUBLIC_DATA, on_set_public_data_switch);
+
+ // increase temp low -> high
+ set_temp(nts.get(), 60);
+
+ // make sure it was not turned off
+ ASSERT_TRUE(switch_state);
+
+ // drop temp
+ set_temp(nts.get(), 30);
+
+ // and make sure it was still on
+ ASSERT_TRUE(switch_state);
+
+ // now arm it
+ Gcode gc("M1100 S1", (StreamOutput *)THEKERNEL->serial, false);
+ nts->on_gcode_received(&gc);
+
+ ASSERT_TRUE(nts->is_armed());
+
+ // increase temp low -> high
+ set_temp(nts.get(), 60);
+
+ // make sure it was not turned off
+ ASSERT_TRUE(switch_state);
+
+ // drop temp
+ set_temp(nts.get(), 30);
+
+ // and make sure it was tunred off
+ ASSERT_TRUE(!switch_state);
+
+ // make sure it is not armed anymore
+ ASSERT_TRUE(!nts->is_armed());
+}