<commit_before>//
//  ExecutorImplementation.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 01/05/2022.
//  Copyright © 2022 Thomas Harte. All rights reserved.
//

#ifndef InstructionSets_M68k_ExecutorImplementation_hpp
#define InstructionSets_M68k_ExecutorImplementation_hpp

#include "../Perform.hpp"
#include <cassert>

namespace InstructionSet {
namespace M68k {

template <Model model, typename BusHandler>
Executor<model, BusHandler>::Executor(BusHandler &handler) : bus_handler_(handler) {
	reset();
}

template <Model model, typename BusHandler>
void Executor<model, BusHandler>::reset() {
	// Establish: supervisor state, all interrupts blocked.
	status_.set_status(0b0010'0011'1000'0000);

	// Seed stack pointer and program counter.
	data_[7] = bus_handler_.template read<uint32_t>(0);
	program_counter_.l = bus_handler_.template read<uint32_t>(4);
}

template <Model model, typename BusHandler>
void Executor<model, BusHandler>::read(DataSize size, uint32_t address, CPU::SlicedInt32 &value) {
	switch(size) {
		case DataSize::Byte:
			value.b = bus_handler_.template read<uint8_t>(address);
		break;
		case DataSize::Word:
			value.w = bus_handler_.template read<uint16_t>(address);
		break;
		case DataSize::LongWord:
			value.l = bus_handler_.template read<uint32_t>(address);
		break;
	}
}

template <Model model, typename BusHandler>
void Executor<model, BusHandler>::write(DataSize size, uint32_t address, CPU::SlicedInt32 value) {
	switch(size) {
		case DataSize::Byte:
			 bus_handler_.template write<uint8_t>(address, value.b);
		break;
		case DataSize::Word:
			bus_handler_.template write<uint16_t>(address, value.w);
		break;
		case DataSize::LongWord:
			bus_handler_.template write<uint32_t>(address, value.l);
		break;
	}
}

template <Model model, typename BusHandler>
template <typename IntT> IntT Executor<model, BusHandler>::read_pc() {
	const IntT result = bus_handler_.template read<IntT>(program_counter_.l);

	if constexpr (sizeof(IntT) == 4) {
		program_counter_.l += 4;
	} else {
		program_counter_.l += 2;
	}

	return result;
}

template <Model model, typename BusHandler>
uint32_t Executor<model, BusHandler>::index_8bitdisplacement() {
	// TODO: if not a 68000, check bit 8 for whether this should be a full extension word;
	// also include the scale field even if not.
	const auto extension = read_pc<uint16_t>();
	const auto offset = int8_t(extension);
	const int register_index = (extension >> 11) & 7;
	const uint32_t displacement = (extension & 0x8000) ? address_[register_index].l : data_[register_index].l;
	return offset + (extension & 0x800) ? displacement : uint16_t(displacement);
}

template <Model model, typename BusHandler>
typename Executor<model, BusHandler>::EffectiveAddress Executor<model, BusHandler>::calculate_effective_address(Preinstruction instruction, uint16_t opcode, int index) {
	EffectiveAddress ea;

	switch(instruction.mode(index)) {
		case AddressingMode::None:
			// Permit an uninitialised effective address to be returned;
			// this value shouldn't be used.
		break;

		//
		// Operands that don't have effective addresses, which are returned as values.
		//
		case AddressingMode::DataRegisterDirect:
			ea.value = data_[instruction.reg(index)];
			ea.requires_fetch = false;
		break;
		case AddressingMode::AddressRegisterDirect:
			ea.value = address_[instruction.reg(index)];
			ea.requires_fetch = false;
		break;
		case AddressingMode::Quick:
			ea.value.l = quick(instruction.operation, opcode);
			ea.requires_fetch = false;
		break;
		case AddressingMode::ImmediateData:
			read(instruction.size(), program_counter_.l, ea.value.l);
			program_counter_.l += (instruction.size() == DataSize::LongWord) ? 4 : 2;
			ea.requires_fetch = false;
		break;

		//
		// Absolute addresses.
		//
		case AddressingMode::AbsoluteShort:
			ea.value.l = int16_t(read_pc<uint16_t>());
			ea.requires_fetch = true;
		break;
		case AddressingMode::AbsoluteLong:
			ea.value.l = read_pc<uint32_t>();
			ea.requires_fetch = true;
		break;

		//
		// Address register indirects.
		//
		case AddressingMode::AddressRegisterIndirect:
			ea.value.l = address_[instruction.reg(index)];
			ea.requires_fetch = true;
		break;
		case AddressingMode::AddressRegisterIndirectWithPostincrement: {
			const auto reg = instruction.reg(index);

			ea.value.l = address_[reg];
			ea.requires_fetch = true;

			switch(instruction.size()) {
				case DataSize::Byte:		address_[reg].l += byte_increments[reg];	break;
				case DataSize::Word:		address_[reg].l += 2;						break;
				case DataSize::LongWord:	address_[reg].l += 4;						break;
			}
		} break;
		case AddressingMode::AddressRegisterIndirectWithPredecrement: {
			const auto reg = instruction.reg(index);

			switch(instruction.size()) {
				case DataSize::Byte:		address_[reg].l -= byte_increments[reg];	break;
				case DataSize::Word:		address_[reg].l -= 2;						break;
				case DataSize::LongWord:	address_[reg].l -= 4;						break;
			}

			ea.value.l = address_[reg];
			ea.requires_fetch = true;
		} break;
		case AddressingMode::AddressRegisterIndirectWithDisplacement:
			ea.value.l = address_[instruction.reg(index)].l + int16_t(read_pc<uint16_t>());
			ea.requires_fetch = true;
		break;
		case AddressingMode::AddressRegisterIndirectWithIndex8bitDisplacement:
			ea.value.l = address_[instruction.reg(index)].l + index_8bitdisplacement();
			ea.requires_fetch = true;
		break;

		//
		// PC-relative addresses.
		//
		// TODO: rephrase these in terms of instruction_address_. Just for security
		// against whatever mutations the PC has been through already to get to here.
		//
		case AddressingMode::ProgramCounterIndirectWithDisplacement:
			ea.value.l = program_counter_.l + int16_t(read_pc<uint16_t>());
			ea.requires_fetch = true;
		break;
		case AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement:
			ea.value.l = program_counter_.l + index_8bitdisplacement();
			ea.requires_fetch = true;
		break;

		default:
			// TODO.
			assert(false);
		break;
	}

	return ea;
}

template <Model model, typename BusHandler>
void Executor<model, BusHandler>::run_for_instructions(int count) {
	while(count--) {
		// TODO: check interrupt level, trace flag.

		// Read the next instruction.
		instruction_address_ = program_counter_.l;
		const auto opcode = read_pc<uint16_t>();
		const Preinstruction instruction = decoder_.decode(opcode);
		program_counter_.l += 2;

		// TODO: check privilege level.

		// Temporary storage.
		CPU::SlicedInt32 operand_[2];
		EffectiveAddress effective_address_[2];

		// Calculate effective addresses; copy 'addresses' into the
		// operands by default both: (i) because they might be values,
		// rather than addresses; and (ii) then they'll be there for use
		// by LEA and PEA.
		//
		// TODO: this work should be performed by a full Decoder, so that it can be cached.
		effective_address_[0] = calculate_effective_address(instruction, opcode, 0);
		effective_address_[1] = calculate_effective_address(instruction, opcode, 1);
		operand_[0] = effective_address_[0].value;
		operand_[1] = effective_address_[1].value;

		// Obtain the appropriate sequence.
		//
		// TODO: make a decision about whether this goes into a fully-decoded Instruction.
		Sequence<model> sequence(instruction.operation);

		// Perform it.
		while(!sequence.empty()) {
			const auto step = sequence.pop_front();

			switch(step) {
				default: assert(false);	// i.e. TODO

				case Step::FetchOp1:
				case Step::FetchOp2: {
					const auto index = int(step) & 1;

					// If the operand wasn't indirect, it's already fetched.
					if(!effective_address_[index].requires_fetch) continue;

					// TODO: potential bus alignment exception.
					read(instruction.size(), effective_address_[index].value, operand_[index]);
				} break;

				case Step::Perform:
					perform<model>(instruction, operand_[0], operand_[1], status_, this);
				break;

				case Step::StoreOp1:
				case Step::StoreOp2: {
					const auto index = int(step) & 1;

					// If the operand wasn't indirect, store directly to Dn or An.
					if(!effective_address_[index].requires_fetch) {
						// This must be either address or data register indirect.
						assert(
							instruction.mode(index) == AddressingMode::DataRegisterDirect ||
							instruction.mode(index) == AddressingMode::AddressRegisterDirect);

						// TODO: is it worth holding registers as a single block to avoid this conditional?
						if(instruction.mode(index) == AddressingMode::DataRegisterDirect) {
							data_[instruction.reg(index)] = operand_[index];
						} else {
							address_[instruction.reg(index)] = operand_[index];
						}

						break;
					}

					// TODO: potential bus alignment exception.
					write(instruction.size(), effective_address_[index].value, operand_[index]);
				} break;
			}
		}
	}
}

}
}

#endif /* InstructionSets_M68k_ExecutorImplementation_hpp */
<commit_msg>Equivocate.<commit_after>//
//  ExecutorImplementation.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 01/05/2022.
//  Copyright © 2022 Thomas Harte. All rights reserved.
//

#ifndef InstructionSets_M68k_ExecutorImplementation_hpp
#define InstructionSets_M68k_ExecutorImplementation_hpp

#include "../Perform.hpp"
#include <cassert>

namespace InstructionSet {
namespace M68k {

template <Model model, typename BusHandler>
Executor<model, BusHandler>::Executor(BusHandler &handler) : bus_handler_(handler) {
	reset();
}

template <Model model, typename BusHandler>
void Executor<model, BusHandler>::reset() {
	// Establish: supervisor state, all interrupts blocked.
	status_.set_status(0b0010'0011'1000'0000);

	// Seed stack pointer and program counter.
	data_[7] = bus_handler_.template read<uint32_t>(0);
	program_counter_.l = bus_handler_.template read<uint32_t>(4);
}

template <Model model, typename BusHandler>
void Executor<model, BusHandler>::read(DataSize size, uint32_t address, CPU::SlicedInt32 &value) {
	switch(size) {
		case DataSize::Byte:
			value.b = bus_handler_.template read<uint8_t>(address);
		break;
		case DataSize::Word:
			value.w = bus_handler_.template read<uint16_t>(address);
		break;
		case DataSize::LongWord:
			value.l = bus_handler_.template read<uint32_t>(address);
		break;
	}
}

template <Model model, typename BusHandler>
void Executor<model, BusHandler>::write(DataSize size, uint32_t address, CPU::SlicedInt32 value) {
	switch(size) {
		case DataSize::Byte:
			 bus_handler_.template write<uint8_t>(address, value.b);
		break;
		case DataSize::Word:
			bus_handler_.template write<uint16_t>(address, value.w);
		break;
		case DataSize::LongWord:
			bus_handler_.template write<uint32_t>(address, value.l);
		break;
	}
}

template <Model model, typename BusHandler>
template <typename IntT> IntT Executor<model, BusHandler>::read_pc() {
	const IntT result = bus_handler_.template read<IntT>(program_counter_.l);

	if constexpr (sizeof(IntT) == 4) {
		program_counter_.l += 4;
	} else {
		program_counter_.l += 2;
	}

	return result;
}

template <Model model, typename BusHandler>
uint32_t Executor<model, BusHandler>::index_8bitdisplacement() {
	// TODO: if not a 68000, check bit 8 for whether this should be a full extension word;
	// also include the scale field even if not.
	const auto extension = read_pc<uint16_t>();
	const auto offset = int8_t(extension);
	const int register_index = (extension >> 11) & 7;
	const uint32_t displacement = (extension & 0x8000) ? address_[register_index].l : data_[register_index].l;
	return offset + (extension & 0x800) ? displacement : uint16_t(displacement);
}

template <Model model, typename BusHandler>
typename Executor<model, BusHandler>::EffectiveAddress Executor<model, BusHandler>::calculate_effective_address(Preinstruction instruction, uint16_t opcode, int index) {
	EffectiveAddress ea;

	switch(instruction.mode(index)) {
		case AddressingMode::None:
			// Permit an uninitialised effective address to be returned;
			// this value shouldn't be used.
		break;

		//
		// Operands that don't have effective addresses, which are returned as values.
		//
		case AddressingMode::DataRegisterDirect:
			ea.value = data_[instruction.reg(index)];
			ea.requires_fetch = false;
		break;
		case AddressingMode::AddressRegisterDirect:
			ea.value = address_[instruction.reg(index)];
			ea.requires_fetch = false;
		break;
		case AddressingMode::Quick:
			ea.value.l = quick(instruction.operation, opcode);
			ea.requires_fetch = false;
		break;
		case AddressingMode::ImmediateData:
			read(instruction.size(), program_counter_.l, ea.value.l);
			program_counter_.l += (instruction.size() == DataSize::LongWord) ? 4 : 2;
			ea.requires_fetch = false;
		break;

		//
		// Absolute addresses.
		//
		case AddressingMode::AbsoluteShort:
			ea.value.l = int16_t(read_pc<uint16_t>());
			ea.requires_fetch = true;
		break;
		case AddressingMode::AbsoluteLong:
			ea.value.l = read_pc<uint32_t>();
			ea.requires_fetch = true;
		break;

		//
		// Address register indirects.
		//
		case AddressingMode::AddressRegisterIndirect:
			ea.value.l = address_[instruction.reg(index)];
			ea.requires_fetch = true;
		break;
		case AddressingMode::AddressRegisterIndirectWithPostincrement: {
			const auto reg = instruction.reg(index);

			ea.value.l = address_[reg];
			ea.requires_fetch = true;

			switch(instruction.size()) {
				case DataSize::Byte:		address_[reg].l += byte_increments[reg];	break;
				case DataSize::Word:		address_[reg].l += 2;						break;
				case DataSize::LongWord:	address_[reg].l += 4;						break;
			}
		} break;
		case AddressingMode::AddressRegisterIndirectWithPredecrement: {
			const auto reg = instruction.reg(index);

			switch(instruction.size()) {
				case DataSize::Byte:		address_[reg].l -= byte_increments[reg];	break;
				case DataSize::Word:		address_[reg].l -= 2;						break;
				case DataSize::LongWord:	address_[reg].l -= 4;						break;
			}

			ea.value.l = address_[reg];
			ea.requires_fetch = true;
		} break;
		case AddressingMode::AddressRegisterIndirectWithDisplacement:
			ea.value.l = address_[instruction.reg(index)].l + int16_t(read_pc<uint16_t>());
			ea.requires_fetch = true;
		break;
		case AddressingMode::AddressRegisterIndirectWithIndex8bitDisplacement:
			ea.value.l = address_[instruction.reg(index)].l + index_8bitdisplacement();
			ea.requires_fetch = true;
		break;

		//
		// PC-relative addresses.
		//
		// TODO: rephrase these in terms of instruction_address_. Just for security
		// against whatever mutations the PC has been through already to get to here.
		//
		case AddressingMode::ProgramCounterIndirectWithDisplacement:
			ea.value.l = program_counter_.l + int16_t(read_pc<uint16_t>());
			ea.requires_fetch = true;
		break;
		case AddressingMode::ProgramCounterIndirectWithIndex8bitDisplacement:
			ea.value.l = program_counter_.l + index_8bitdisplacement();
			ea.requires_fetch = true;
		break;

		default:
			// TODO.
			assert(false);
		break;
	}

	return ea;
}

template <Model model, typename BusHandler>
void Executor<model, BusHandler>::run_for_instructions(int count) {
	while(count--) {
		// TODO: check interrupt level, trace flag.

		// Read the next instruction.
		instruction_address_ = program_counter_.l;
		const auto opcode = read_pc<uint16_t>();
		const Preinstruction instruction = decoder_.decode(opcode);
		program_counter_.l += 2;

		// TODO: check privilege level.

		// Temporary storage.
		CPU::SlicedInt32 operand_[2];
		EffectiveAddress effective_address_[2];

		// Calculate effective addresses; copy 'addresses' into the
		// operands by default both: (i) because they might be values,
		// rather than addresses; and (ii) then they'll be there for use
		// by LEA and PEA.
		//
		// TODO: much of this work should be performed by a full Decoder,
		// so that it can be cached.
		effective_address_[0] = calculate_effective_address(instruction, opcode, 0);
		effective_address_[1] = calculate_effective_address(instruction, opcode, 1);
		operand_[0] = effective_address_[0].value;
		operand_[1] = effective_address_[1].value;

		// Obtain the appropriate sequence.
		//
		// TODO: make a decision about whether this goes into a fully-decoded Instruction.
		Sequence<model> sequence(instruction.operation);

		// Perform it.
		while(!sequence.empty()) {
			const auto step = sequence.pop_front();

			switch(step) {
				default: assert(false);	// i.e. TODO

				case Step::FetchOp1:
				case Step::FetchOp2: {
					const auto index = int(step) & 1;

					// If the operand wasn't indirect, it's already fetched.
					if(!effective_address_[index].requires_fetch) continue;

					// TODO: potential bus alignment exception.
					read(instruction.size(), effective_address_[index].value, operand_[index]);
				} break;

				case Step::Perform:
					perform<model>(instruction, operand_[0], operand_[1], status_, this);
				break;

				case Step::StoreOp1:
				case Step::StoreOp2: {
					const auto index = int(step) & 1;

					// If the operand wasn't indirect, store directly to Dn or An.
					if(!effective_address_[index].requires_fetch) {
						// This must be either address or data register indirect.
						assert(
							instruction.mode(index) == AddressingMode::DataRegisterDirect ||
							instruction.mode(index) == AddressingMode::AddressRegisterDirect);

						// TODO: is it worth holding registers as a single block to avoid this conditional?
						if(instruction.mode(index) == AddressingMode::DataRegisterDirect) {
							data_[instruction.reg(index)] = operand_[index];
						} else {
							address_[instruction.reg(index)] = operand_[index];
						}

						break;
					}

					// TODO: potential bus alignment exception.
					write(instruction.size(), effective_address_[index].value, operand_[index]);
				} break;
			}
		}
	}
}

}
}

#endif /* InstructionSets_M68k_ExecutorImplementation_hpp */
<|endoftext|>


<commit_before>#include <orbsvcs/NotifyExtC.h>
#include <iostream>

#include <maciContainerImpl.h>
#include <acsContainerServices.h>

#include "acsncReconnectionCallback.h"

using namespace nc;

ReconnectionCallback::ReconnectionCallback(nc::Helper *sub):
   sub_(sub),
   id_is_valid_(false),
   root_poa_(0),
   services_(0)
{
   if (::maci::ContainerImpl::getContainer() != NULL)
      services_ = ::maci::ContainerImpl::getContainer()->getContainerServices();
}

bool ReconnectionCallback::is_alive()
{
   return true;
}

void ReconnectionCallback::reconnect(::CORBA::Object_ptr new_connection)
{
   ecf_ = NotifyMonitoringExt::EventChannelFactory::_narrow(new_connection);
   if(!::CORBA::is_nil(ecf_))
      sub_->reconnect(ecf_);
}

void ReconnectionCallback::init( CORBA::ORB_ptr orb_mp,
      NotifyMonitoringExt::EventChannelFactory_ptr ecf)
{
   if (::CORBA::is_nil(ecf)){
	  std::cout << "-- ECF is nil :( --" << std::endl;
      return;
   }

   ecf_ =  NotifyMonitoringExt::EventChannelFactory::_duplicate(ecf);
   NotifyExt::ReconnectionCallback_var callback;

   if (!::CORBA::is_nil(orb_mp)){
        ::CORBA::Object_ptr poa = orb_mp->resolve_initial_references("RootPOA");
        root_poa_ = PortableServer::POA::_narrow (poa);
        callback_obj_id_ = root_poa_->activate_object(this);

        CORBA::Object_var obj =
        root_poa_->id_to_reference(callback_obj_id_.in());
        callback = NotifyExt::ReconnectionCallback::_narrow(obj);
   }
   else if (services_ != NULL){
      callback = NotifyExt::ReconnectionCallback::_narrow(
            services_->activateOffShoot(this));
   }
   else
      return;

   if (::CORBA::is_nil(callback))
      std::cout << "Callback not initializated" << std::endl;

   NotifyExt::ReconnectionRegistry_var registry =
      NotifyExt::ReconnectionRegistry::_narrow(ecf_);

   callback_id_ = registry->register_callback(callback);
   id_is_valid_ = true;

}

void ReconnectionCallback::disconnect()
{
   if (id_is_valid_){
      NotifyExt::ReconnectionRegistry_var registry =
         NotifyExt::ReconnectionRegistry::_narrow(ecf_);
      registry->unregister_callback(callback_id_);
      if (!::CORBA::is_nil(root_poa_))
         root_poa_->deactivate_object(callback_obj_id_);
      else
        services_->deactivateOffShoot(this);
      id_is_valid_ = false;
   }
}

ReconnectionCallback::~ReconnectionCallback()
{
}
<commit_msg>ICTJ:ICT-4935: Fix memory leak in C++ callback<commit_after>#include <orbsvcs/NotifyExtC.h>
#include <iostream>

#include <maciContainerImpl.h>
#include <acsContainerServices.h>

#include "acsncReconnectionCallback.h"

using namespace nc;

ReconnectionCallback::ReconnectionCallback(nc::Helper *sub):
   sub_(sub),
   id_is_valid_(false),
   root_poa_(0),
   services_(0)
{
   if (::maci::ContainerImpl::getContainer() != NULL)
      services_ = ::maci::ContainerImpl::getContainer()->getContainerServices();
}

bool ReconnectionCallback::is_alive()
{
   return true;
}

void ReconnectionCallback::reconnect(::CORBA::Object_ptr new_connection)
{
   ecf_ = NotifyMonitoringExt::EventChannelFactory::_narrow(new_connection);
   if(!::CORBA::is_nil(ecf_))
      sub_->reconnect(ecf_);
}

void ReconnectionCallback::init( CORBA::ORB_ptr orb_mp,
      NotifyMonitoringExt::EventChannelFactory_ptr ecf)
{
   if (::CORBA::is_nil(ecf)){
	  std::cout << "-- ECF is nil :( --" << std::endl;
      return;
   }

   ecf_ =  NotifyMonitoringExt::EventChannelFactory::_duplicate(ecf);
   NotifyExt::ReconnectionCallback_var callback;

   if (!::CORBA::is_nil(orb_mp)){
        ::CORBA::Object_ptr poa = orb_mp->resolve_initial_references("RootPOA");
        root_poa_ = PortableServer::POA::_narrow (poa);
        callback_obj_id_ = root_poa_->activate_object(this);

        CORBA::Object_var obj =
        root_poa_->id_to_reference(callback_obj_id_.in());
        callback = NotifyExt::ReconnectionCallback::_narrow(obj);
   }
   else if (services_ != NULL){
      ACS::OffShoot_var shoot = services_->activateOffShoot(this);
      callback = NotifyExt::ReconnectionCallback::_narrow(shoot.in());
   }
   else
      return;

   if (::CORBA::is_nil(callback))
      std::cout << "Callback not initializated" << std::endl;

   NotifyExt::ReconnectionRegistry_var registry =
      NotifyExt::ReconnectionRegistry::_narrow(ecf_);

   callback_id_ = registry->register_callback(callback);
   id_is_valid_ = true;

}

void ReconnectionCallback::disconnect()
{
   if (id_is_valid_){
      NotifyExt::ReconnectionRegistry_var registry =
         NotifyExt::ReconnectionRegistry::_narrow(ecf_);
      registry->unregister_callback(callback_id_);
      if (!::CORBA::is_nil(root_poa_))
         root_poa_->deactivate_object(callback_obj_id_);
      else
        services_->deactivateOffShoot(this);
      id_is_valid_ = false;
   }
}

ReconnectionCallback::~ReconnectionCallback()
{
}
<|endoftext|>


<commit_before>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "QmitkTrackingDeviceConfigurationWidget.h"

#include "mitkNDIPolarisTypeInformation.h"

#include <QSettings>

const std::string QmitkTrackingDeviceConfigurationWidget::VIEW_ID = "org.mitk.views.trackingdeviceconfigurationwidget";

QmitkTrackingDeviceConfigurationWidget::QmitkTrackingDeviceConfigurationWidget(QWidget* parent, Qt::WindowFlags f)
  : QWidget(parent, f)
  , m_Controls(nullptr)
  , m_TrackingDevice(nullptr)
  , m_DeviceToWidgetIndexMap()
{
  //initializations
  CreateQtPartControl(this);
  CreateConnections();

  RefreshTrackingDeviceCollection();

  //initialize a few UI elements
  AddOutput("
First Element selected"); //Order from Collection List

  //reset a few things
  ResetOutput();

  //restore old UI settings
  LoadUISettings();
}

QmitkTrackingDeviceConfigurationWidget::~QmitkTrackingDeviceConfigurationWidget()
{
  StoreUISettings();
  delete m_Controls;
  m_TrackingDevice = nullptr;
}

void QmitkTrackingDeviceConfigurationWidget::CreateQtPartControl(QWidget *parent)
{
  if (!m_Controls)
  {
    // create GUI widgets
    m_Controls = new Ui::QmitkTrackingDeviceConfigurationWidgetControls;
    m_Controls->setupUi(parent);
  }
}

void QmitkTrackingDeviceConfigurationWidget::CreateConnections()
{
  if (m_Controls)
  {
    connect((QObject*)(m_Controls->m_TrackingDeviceChooser), SIGNAL(currentIndexChanged(int)), this, SLOT(TrackingDeviceChanged()));
  }
}

void QmitkTrackingDeviceConfigurationWidget::TrackingDeviceChanged()
{
  const std::string currentDevice = this->GetCurrentDeviceName();

  //show the correspondig widget
  m_Controls->m_TrackingSystemWidget->setCurrentIndex(m_DeviceToWidgetIndexMap[currentDevice]);

  //reset output
  ResetOutput();

  AddOutput("
");
  AddOutput(currentDevice);
  AddOutput(" selected");

  QmitkAbstractTrackingDeviceWidget* widget = GetWidget(currentDevice);

  if (widget == nullptr || !widget->IsDeviceInstalled())
  {
    AddOutput("
ERROR: not installed!");
  }

  emit TrackingDeviceSelectionChanged();
}

void QmitkTrackingDeviceConfigurationWidget::RefreshTrackingDeviceCollection()
{
  // clean-up of stacked widget, drop-down box and map
  for (auto& item : m_DeviceToWidgetIndexMap)
  {
    m_Controls->m_TrackingSystemWidget->removeWidget(m_Controls->m_TrackingSystemWidget->widget(item.second));
    MITK_INFO << "removing widget for device '" << item.first << "'";
  }

  m_Controls->m_TrackingDeviceChooser->clear();

  m_DeviceToWidgetIndexMap.clear();

  // get tracking device type service references
  us::ModuleContext* context = us::GetModuleContext();
  std::vector<us::ServiceReference<mitk::TrackingDeviceTypeCollection> > deviceRefs =
    context->GetServiceReferences<mitk::TrackingDeviceTypeCollection>();

  if (deviceRefs.empty())
  {
    MITK_ERROR << "No tracking device type service found!";
    return;
  }

  // get tracking device configuration widget service references
  std::vector<us::ServiceReference<mitk::TrackingDeviceWidgetCollection> > widgetRefs =
    context->GetServiceReferences<mitk::TrackingDeviceWidgetCollection>();

  if (widgetRefs.empty())
  {
    MITK_ERROR << "No tracking device configuration widget service found!";
    return;
  }

  const us::ServiceReference<mitk::TrackingDeviceTypeCollection>& deviceServiceReference = deviceRefs.front();
  const us::ServiceReference<mitk::TrackingDeviceWidgetCollection>& widgetServiceReference = widgetRefs.front();

  mitk::TrackingDeviceTypeCollection* deviceTypeCollection =
    context->GetService<mitk::TrackingDeviceTypeCollection>(deviceServiceReference);

  mitk::TrackingDeviceWidgetCollection* deviceWidgetCollection =
    context->GetService<mitk::TrackingDeviceWidgetCollection>(widgetServiceReference);

  for (auto name : deviceTypeCollection->GetTrackingDeviceTypeNames())
  {
    // if the device is not included yet, add name to comboBox and widget to stackedWidget
    if (m_Controls->m_TrackingDeviceChooser->findText(QString::fromStdString(name)) == -1)
    {
      m_Controls->m_TrackingDeviceChooser->addItem(QString::fromStdString(name));
      QWidget* current = deviceWidgetCollection->GetTrackingDeviceWidgetClone(name);
      if (current == nullptr)
      {
        MITK_WARN << "No widget for tracking device type " << name << " available. Please implement and register it!";
        current = new QWidget();
      }

      m_DeviceToWidgetIndexMap[name] = m_Controls->m_TrackingSystemWidget->addWidget(current);
    }
  }

  if (!m_DeviceToWidgetIndexMap.empty())
  {
    m_Controls->m_TrackingDeviceChooser->setCurrentIndex(0);
    m_Controls->m_TrackingSystemWidget->setCurrentIndex(0);
  }

  context->UngetService(deviceServiceReference);
  context->UngetService(widgetServiceReference);
}

//######################### internal help methods #######################################
void QmitkTrackingDeviceConfigurationWidget::ResetOutput()
{
  QmitkAbstractTrackingDeviceWidget* currentWidget = this->GetWidget(this->GetCurrentDeviceName());

  if (currentWidget == nullptr)
  {
    return;
  }

  currentWidget->ResetOutput();
  currentWidget->repaint();
}

void QmitkTrackingDeviceConfigurationWidget::AddOutput(std::string s)
{
  QmitkAbstractTrackingDeviceWidget* currentWidget = this->GetWidget(this->GetCurrentDeviceName());

  if (currentWidget == nullptr)
  {
    return;
  }

  currentWidget->AddOutput(s);
  currentWidget->repaint();
}

mitk::TrackingDevice::Pointer QmitkTrackingDeviceConfigurationWidget::ConstructTrackingDevice()
{
  QmitkAbstractTrackingDeviceWidget* currentWidget = this->GetWidget(this->GetCurrentDeviceName());

  if (currentWidget == nullptr)
  {
    return nullptr;
  }

  return currentWidget->ConstructTrackingDevice();
}

mitk::TrackingDevice::Pointer QmitkTrackingDeviceConfigurationWidget::GetTrackingDevice()
{
  m_TrackingDevice = ConstructTrackingDevice();
  if (m_TrackingDevice.IsNull() || !m_TrackingDevice->IsDeviceInstalled()) return nullptr;
  else return this->m_TrackingDevice;
}

void QmitkTrackingDeviceConfigurationWidget::StoreUISettings()
{
  std::string id = "org.mitk.modules.igt.ui.trackingdeviceconfigurationwidget";

  std::string selectedDevice = this->GetCurrentDeviceName();

  //Save settings for every widget
  //Don't use m_DeviceTypeCollection here, it's already unregistered, when deconstructor is called...
  for (int index = 0; index < m_Controls->m_TrackingSystemWidget->count(); index++)
  {
    QmitkAbstractTrackingDeviceWidget* widget = dynamic_cast<QmitkAbstractTrackingDeviceWidget*>(m_Controls->m_TrackingSystemWidget->widget(index));

    if (widget != nullptr)
    {
      widget->StoreUISettings();
    }
  }

  if (this->GetPersistenceService()) // now save the settings using the persistence service
  {
    mitk::PropertyList::Pointer propList = this->GetPersistenceService()->GetPropertyList(id);
    propList->Set("SelectedDevice", selectedDevice);
  }
  else // QSettings as a fallback if the persistence service is not available
  {
    QSettings settings;
    settings.beginGroup(QString::fromStdString(id));
    settings.setValue("trackingDeviceChooser", QVariant(QString::fromStdString(selectedDevice)));
    settings.endGroup();
  }
}

/**
 * @brief QmitkTrackingDeviceConfigurationWidget::LoadUISettings
 *
 * Precondition:
 * Make sure that QStackedWidget is already initialized,
 * e.g. by calling RefreshTrackingDeviceCollection() before.
 */
void QmitkTrackingDeviceConfigurationWidget::LoadUISettings()
{
  //Load settings for every widget
  for (int index = 0; index < m_Controls->m_TrackingSystemWidget->count(); index++)
  {
    QmitkAbstractTrackingDeviceWidget* widget = dynamic_cast<QmitkAbstractTrackingDeviceWidget*>(m_Controls->m_TrackingSystemWidget->widget(index));

    if (widget != nullptr)
    {
      widget->LoadUISettings();
    }
  }

  std::string id = "org.mitk.modules.igt.ui.trackingdeviceconfigurationwidget";
  std::string selectedDevice;
  if (this->GetPersistenceService())
  {
    mitk::PropertyList::Pointer propList = this->GetPersistenceService()->GetPropertyList(id);
    if (propList.IsNull())
    {
      MITK_ERROR << "Property list for this UI (" << id << ") is not available, could not load UI settings!"; return;
    }

    propList->Get("SelectedDevice", selectedDevice);

    if (selectedDevice.empty())
    {
      MITK_ERROR << "Loaded data from persistence service is invalid (SelectedDevice:" << selectedDevice << "): aborted to restore data!";
      return;
    }

    MITK_INFO << "Successfully restored UI settings";
  }
  else
  {
    // QSettings as a fallback if the persistence service is not available
    QSettings settings;
    settings.beginGroup(QString::fromStdString(id));

    selectedDevice = settings.value("trackingDeviceChooser", "").toString().toStdString();

    settings.endGroup();
  }

  // The selected device requires some checks because a device that is not installed should not be restored to avoid bugs.
  // Use NDI Polaris as default if there's no widget registered for selected device or there's a widget for it but no device installed.

  const auto& deviceIterator = m_DeviceToWidgetIndexMap.find(selectedDevice);

  if (deviceIterator != m_DeviceToWidgetIndexMap.end())
  {
    QmitkAbstractTrackingDeviceWidget* widget =
      dynamic_cast<QmitkAbstractTrackingDeviceWidget*>(m_Controls->m_TrackingSystemWidget->widget(deviceIterator->second));

    if (widget == nullptr || (widget != nullptr && !widget->IsDeviceInstalled()))
    {
      selectedDevice = mitk::NDIPolarisTypeInformation::GetTrackingDeviceName();
    }
  }
  else
  {
    selectedDevice = mitk::NDIPolarisTypeInformation::GetTrackingDeviceName();
  }

  const int index = m_Controls->m_TrackingDeviceChooser->findText(QString::fromStdString(selectedDevice));

  if (index >= 0)
  {
    m_Controls->m_TrackingDeviceChooser->setCurrentIndex(index);
  }
  else
  {
    MITK_ERROR << "Failed to load UI setting for tracking device configuration";
    return;
  }

  m_Controls->m_TrackingSystemWidget->setCurrentIndex(m_DeviceToWidgetIndexMap[selectedDevice]);
}

std::string QmitkTrackingDeviceConfigurationWidget::GetCurrentDeviceName(void) const
{
  return m_Controls->m_TrackingDeviceChooser->currentText().toStdString();
}

QmitkAbstractTrackingDeviceWidget* QmitkTrackingDeviceConfigurationWidget::GetWidget(const std::string& deviceName) const
{
  const auto& deviceIterator = m_DeviceToWidgetIndexMap.find(deviceName);

  if (deviceIterator != m_DeviceToWidgetIndexMap.end())
  {
    QWidget* widget = m_Controls->m_TrackingSystemWidget->widget(deviceIterator->second);

    return dynamic_cast<QmitkAbstractTrackingDeviceWidget*>(widget);
  }

  return nullptr;
}
<commit_msg>Only construct TrackingDevices if necessary!<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "QmitkTrackingDeviceConfigurationWidget.h"

#include "mitkNDIPolarisTypeInformation.h"

#include <QSettings>

const std::string QmitkTrackingDeviceConfigurationWidget::VIEW_ID = "org.mitk.views.trackingdeviceconfigurationwidget";

QmitkTrackingDeviceConfigurationWidget::QmitkTrackingDeviceConfigurationWidget(QWidget* parent, Qt::WindowFlags f)
  : QWidget(parent, f)
  , m_Controls(nullptr)
  , m_TrackingDevice(nullptr)
  , m_DeviceToWidgetIndexMap()
{
  //initializations
  CreateQtPartControl(this);
  CreateConnections();

  RefreshTrackingDeviceCollection();

  //initialize a few UI elements
  AddOutput("
First Element selected"); //Order from Collection List

  //reset a few things
  ResetOutput();

  //restore old UI settings
  LoadUISettings();
}

QmitkTrackingDeviceConfigurationWidget::~QmitkTrackingDeviceConfigurationWidget()
{
  StoreUISettings();
  delete m_Controls;
  m_TrackingDevice = nullptr;
}

void QmitkTrackingDeviceConfigurationWidget::CreateQtPartControl(QWidget *parent)
{
  if (!m_Controls)
  {
    // create GUI widgets
    m_Controls = new Ui::QmitkTrackingDeviceConfigurationWidgetControls;
    m_Controls->setupUi(parent);
  }
}

void QmitkTrackingDeviceConfigurationWidget::CreateConnections()
{
  if (m_Controls)
  {
    connect((QObject*)(m_Controls->m_TrackingDeviceChooser), SIGNAL(currentIndexChanged(int)), this, SLOT(TrackingDeviceChanged()));
  }
}

void QmitkTrackingDeviceConfigurationWidget::TrackingDeviceChanged()
{
  const std::string currentDevice = this->GetCurrentDeviceName();

  //show the correspondig widget
  m_Controls->m_TrackingSystemWidget->setCurrentIndex(m_DeviceToWidgetIndexMap[currentDevice]);

  //reset output
  ResetOutput();

  AddOutput("
");
  AddOutput(currentDevice);
  AddOutput(" selected");

  QmitkAbstractTrackingDeviceWidget* widget = GetWidget(currentDevice);

  if (widget == nullptr || !widget->IsDeviceInstalled())
  {
    AddOutput("
ERROR: not installed!");
  }

  emit TrackingDeviceSelectionChanged();
}

void QmitkTrackingDeviceConfigurationWidget::RefreshTrackingDeviceCollection()
{
  // clean-up of stacked widget, drop-down box and map
  for (auto& item : m_DeviceToWidgetIndexMap)
  {
    m_Controls->m_TrackingSystemWidget->removeWidget(m_Controls->m_TrackingSystemWidget->widget(item.second));
    MITK_INFO << "removing widget for device '" << item.first << "'";
  }

  m_Controls->m_TrackingDeviceChooser->clear();

  m_DeviceToWidgetIndexMap.clear();

  // get tracking device type service references
  us::ModuleContext* context = us::GetModuleContext();
  std::vector<us::ServiceReference<mitk::TrackingDeviceTypeCollection> > deviceRefs =
    context->GetServiceReferences<mitk::TrackingDeviceTypeCollection>();

  if (deviceRefs.empty())
  {
    MITK_ERROR << "No tracking device type service found!";
    return;
  }

  // get tracking device configuration widget service references
  std::vector<us::ServiceReference<mitk::TrackingDeviceWidgetCollection> > widgetRefs =
    context->GetServiceReferences<mitk::TrackingDeviceWidgetCollection>();

  if (widgetRefs.empty())
  {
    MITK_ERROR << "No tracking device configuration widget service found!";
    return;
  }

  const us::ServiceReference<mitk::TrackingDeviceTypeCollection>& deviceServiceReference = deviceRefs.front();
  const us::ServiceReference<mitk::TrackingDeviceWidgetCollection>& widgetServiceReference = widgetRefs.front();

  mitk::TrackingDeviceTypeCollection* deviceTypeCollection =
    context->GetService<mitk::TrackingDeviceTypeCollection>(deviceServiceReference);

  mitk::TrackingDeviceWidgetCollection* deviceWidgetCollection =
    context->GetService<mitk::TrackingDeviceWidgetCollection>(widgetServiceReference);

  for (auto name : deviceTypeCollection->GetTrackingDeviceTypeNames())
  {
    // if the device is not included yet, add name to comboBox and widget to stackedWidget
    if (m_Controls->m_TrackingDeviceChooser->findText(QString::fromStdString(name)) == -1)
    {
      m_Controls->m_TrackingDeviceChooser->addItem(QString::fromStdString(name));
      QWidget* current = deviceWidgetCollection->GetTrackingDeviceWidgetClone(name);
      if (current == nullptr)
      {
        MITK_WARN << "No widget for tracking device type " << name << " available. Please implement and register it!";
        current = new QWidget();
      }

      m_DeviceToWidgetIndexMap[name] = m_Controls->m_TrackingSystemWidget->addWidget(current);
    }
  }

  if (!m_DeviceToWidgetIndexMap.empty())
  {
    m_Controls->m_TrackingDeviceChooser->setCurrentIndex(0);
    m_Controls->m_TrackingSystemWidget->setCurrentIndex(0);
  }

  context->UngetService(deviceServiceReference);
  context->UngetService(widgetServiceReference);
}

//######################### internal help methods #######################################
void QmitkTrackingDeviceConfigurationWidget::ResetOutput()
{
  QmitkAbstractTrackingDeviceWidget* currentWidget = this->GetWidget(this->GetCurrentDeviceName());

  if (currentWidget == nullptr)
  {
    return;
  }

  currentWidget->ResetOutput();
  currentWidget->repaint();
}

void QmitkTrackingDeviceConfigurationWidget::AddOutput(std::string s)
{
  QmitkAbstractTrackingDeviceWidget* currentWidget = this->GetWidget(this->GetCurrentDeviceName());

  if (currentWidget == nullptr)
  {
    return;
  }

  currentWidget->AddOutput(s);
  currentWidget->repaint();
}

mitk::TrackingDevice::Pointer QmitkTrackingDeviceConfigurationWidget::ConstructTrackingDevice()
{
  QmitkAbstractTrackingDeviceWidget* currentWidget = this->GetWidget(this->GetCurrentDeviceName());

  if (currentWidget == nullptr)
  {
    return nullptr;
  }

  return currentWidget->ConstructTrackingDevice();
}

mitk::TrackingDevice::Pointer QmitkTrackingDeviceConfigurationWidget::GetTrackingDevice()
{
  //Only create a new device, if we don't have one yet or if the device selection in the widget has changed.
  //otherwise, hundered of devices will be created each time someone calls Get...
  if (m_TrackingDevice.IsNull() || m_TrackingDevice->GetTrackingDeviceName() != this->GetCurrentDeviceName())
    m_TrackingDevice = ConstructTrackingDevice();

  if (m_TrackingDevice.IsNull() || !m_TrackingDevice->IsDeviceInstalled()) return nullptr;
  else return this->m_TrackingDevice;
}

void QmitkTrackingDeviceConfigurationWidget::StoreUISettings()
{
  std::string id = "org.mitk.modules.igt.ui.trackingdeviceconfigurationwidget";

  std::string selectedDevice = this->GetCurrentDeviceName();

  //Save settings for every widget
  //Don't use m_DeviceTypeCollection here, it's already unregistered, when deconstructor is called...
  for (int index = 0; index < m_Controls->m_TrackingSystemWidget->count(); index++)
  {
    QmitkAbstractTrackingDeviceWidget* widget = dynamic_cast<QmitkAbstractTrackingDeviceWidget*>(m_Controls->m_TrackingSystemWidget->widget(index));

    if (widget != nullptr)
    {
      widget->StoreUISettings();
    }
  }

  if (this->GetPersistenceService()) // now save the settings using the persistence service
  {
    mitk::PropertyList::Pointer propList = this->GetPersistenceService()->GetPropertyList(id);
    propList->Set("SelectedDevice", selectedDevice);
  }
  else // QSettings as a fallback if the persistence service is not available
  {
    QSettings settings;
    settings.beginGroup(QString::fromStdString(id));
    settings.setValue("trackingDeviceChooser", QVariant(QString::fromStdString(selectedDevice)));
    settings.endGroup();
  }
}

/**
 * @brief QmitkTrackingDeviceConfigurationWidget::LoadUISettings
 *
 * Precondition:
 * Make sure that QStackedWidget is already initialized,
 * e.g. by calling RefreshTrackingDeviceCollection() before.
 */
void QmitkTrackingDeviceConfigurationWidget::LoadUISettings()
{
  //Load settings for every widget
  for (int index = 0; index < m_Controls->m_TrackingSystemWidget->count(); index++)
  {
    QmitkAbstractTrackingDeviceWidget* widget = dynamic_cast<QmitkAbstractTrackingDeviceWidget*>(m_Controls->m_TrackingSystemWidget->widget(index));

    if (widget != nullptr)
    {
      widget->LoadUISettings();
    }
  }

  std::string id = "org.mitk.modules.igt.ui.trackingdeviceconfigurationwidget";
  std::string selectedDevice;
  if (this->GetPersistenceService())
  {
    mitk::PropertyList::Pointer propList = this->GetPersistenceService()->GetPropertyList(id);
    if (propList.IsNull())
    {
      MITK_ERROR << "Property list for this UI (" << id << ") is not available, could not load UI settings!"; return;
    }

    propList->Get("SelectedDevice", selectedDevice);

    if (selectedDevice.empty())
    {
      MITK_ERROR << "Loaded data from persistence service is invalid (SelectedDevice:" << selectedDevice << "): aborted to restore data!";
      return;
    }

    MITK_INFO << "Successfully restored UI settings";
  }
  else
  {
    // QSettings as a fallback if the persistence service is not available
    QSettings settings;
    settings.beginGroup(QString::fromStdString(id));

    selectedDevice = settings.value("trackingDeviceChooser", "").toString().toStdString();

    settings.endGroup();
  }

  // The selected device requires some checks because a device that is not installed should not be restored to avoid bugs.
  // Use NDI Polaris as default if there's no widget registered for selected device or there's a widget for it but no device installed.

  const auto& deviceIterator = m_DeviceToWidgetIndexMap.find(selectedDevice);

  if (deviceIterator != m_DeviceToWidgetIndexMap.end())
  {
    QmitkAbstractTrackingDeviceWidget* widget =
      dynamic_cast<QmitkAbstractTrackingDeviceWidget*>(m_Controls->m_TrackingSystemWidget->widget(deviceIterator->second));

    if (widget == nullptr || (widget != nullptr && !widget->IsDeviceInstalled()))
    {
      selectedDevice = mitk::NDIPolarisTypeInformation::GetTrackingDeviceName();
    }
  }
  else
  {
    selectedDevice = mitk::NDIPolarisTypeInformation::GetTrackingDeviceName();
  }

  const int index = m_Controls->m_TrackingDeviceChooser->findText(QString::fromStdString(selectedDevice));

  if (index >= 0)
  {
    m_Controls->m_TrackingDeviceChooser->setCurrentIndex(index);
  }
  else
  {
    MITK_ERROR << "Failed to load UI setting for tracking device configuration";
    return;
  }

  m_Controls->m_TrackingSystemWidget->setCurrentIndex(m_DeviceToWidgetIndexMap[selectedDevice]);
}

std::string QmitkTrackingDeviceConfigurationWidget::GetCurrentDeviceName(void) const
{
  return m_Controls->m_TrackingDeviceChooser->currentText().toStdString();
}

QmitkAbstractTrackingDeviceWidget* QmitkTrackingDeviceConfigurationWidget::GetWidget(const std::string& deviceName) const
{
  const auto& deviceIterator = m_DeviceToWidgetIndexMap.find(deviceName);

  if (deviceIterator != m_DeviceToWidgetIndexMap.end())
  {
    QWidget* widget = m_Controls->m_TrackingSystemWidget->widget(deviceIterator->second);

    return dynamic_cast<QmitkAbstractTrackingDeviceWidget*>(widget);
  }

  return nullptr;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "CppUTest/TestHarness.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/TestTestingFixture.h"
#include "CppUTest/PlatformSpecificFunctions.h"

TEST_GROUP(UtestShell)
{
    TestTestingFixture fixture;
};

static void _failMethod()
{
    FAIL("This test fails");
}

static void _passingTestMethod()
{
    CHECK(true);
}

static void _passingCheckEqualTestMethod()
{
    CHECK_EQUAL(1, 1);
}

static void _exitTestMethod()
{
    TEST_EXIT;
    FAIL("Should not get here");
}

static volatile double zero = 0.0;

TEST(UtestShell, compareDoubles)
{
    double not_a_number = zero / zero;
    double infinity = 1 / zero;
    CHECK(doubles_equal(1.0, 1.001, 0.01));
    CHECK(!doubles_equal(not_a_number, 1.001, 0.01));
    CHECK(!doubles_equal(1.0, not_a_number, 0.01));
    CHECK(!doubles_equal(1.0, 1.001, not_a_number));
    CHECK(!doubles_equal(1.0, 1.1, 0.05));
    CHECK(!doubles_equal(infinity, 1.0, 0.01));
    CHECK(!doubles_equal(1.0, infinity, 0.01));
    CHECK(doubles_equal(1.0, -1.0, infinity));
    CHECK(doubles_equal(infinity, infinity, 0.01));
    CHECK(doubles_equal(infinity, infinity, infinity));
    double a = 1.2345678;
    CHECK(doubles_equal(a, a, 0.000000001));
}

TEST(UtestShell, FailWillIncreaseTheAmountOfChecks)
{
    fixture.setTestFunction(_failMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getCheckCount());
}

TEST(UtestShell, PassedCheckEqualWillIncreaseTheAmountOfChecks)
{
    fixture.setTestFunction(_passingCheckEqualTestMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getCheckCount());
}

IGNORE_TEST(UtestShell, IgnoreTestAccessingFixture)
{
    CHECK(&fixture != NULLPTR);
}

TEST(UtestShell, MacrosUsedInSetup)
{
    IGNORE_ALL_LEAKS_IN_TEST();
    fixture.setSetup(_failMethod);
    fixture.setTestFunction(_passingTestMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getFailureCount());
}

TEST(UtestShell, MacrosUsedInTearDown)
{
    IGNORE_ALL_LEAKS_IN_TEST();
    fixture.setTeardown(_failMethod);
    fixture.setTestFunction(_passingTestMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getFailureCount());
}

TEST(UtestShell, ExitLeavesQuietly)
{
    fixture.setTestFunction(_exitTestMethod);
    fixture.runAllTests();
    LONGS_EQUAL(0, fixture.getFailureCount());
}

static int teardownCalled = 0;

static void _teardownMethod()
{
    teardownCalled++;
}

TEST(UtestShell, TeardownCalledAfterTestFailure)
{
    teardownCalled = 0;
    IGNORE_ALL_LEAKS_IN_TEST();
    fixture.setTeardown(_teardownMethod);
    fixture.setTestFunction(_failMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getFailureCount());
    LONGS_EQUAL(1, teardownCalled);
}

static int stopAfterFailure = 0;
static void _stopAfterFailureMethod()
{
    FAIL("fail");
    stopAfterFailure++;
}

TEST(UtestShell, TestStopsAfterTestFailure)
{
    IGNORE_ALL_LEAKS_IN_TEST();
    stopAfterFailure = 0;
    fixture.setTestFunction(_stopAfterFailureMethod);
    fixture.runAllTests();
    CHECK(fixture.hasTestFailed());
    LONGS_EQUAL(1, fixture.getFailureCount());
    LONGS_EQUAL(0, stopAfterFailure);
}

TEST(UtestShell, TestStopsAfterSetupFailure)
{
    stopAfterFailure = 0;
    fixture.setSetup(_stopAfterFailureMethod);
    fixture.setTeardown(_stopAfterFailureMethod);
    fixture.setTestFunction(_failMethod);
    fixture.runAllTests();
    LONGS_EQUAL(2, fixture.getFailureCount());
    LONGS_EQUAL(0, stopAfterFailure);
}

class defaultUtestShell: public UtestShell
{
};

TEST(UtestShell, this_test_covers_the_UtestShell_createTest_and_Utest_testBody_methods)
{
    defaultUtestShell shell;
    fixture.addTest(&shell);
    fixture.runAllTests();
    LONGS_EQUAL(2, fixture.result_->getTestCount());
}

static void StubPlatformSpecificRunTestInASeperateProcess(UtestShell* shell, TestPlugin*, TestResult* result)
{
    result->addFailure(TestFailure(shell, "Failed in separate process"));
}

TEST(UtestShell, RunInSeparateProcessTest)
{
    UT_PTR_SET(PlatformSpecificRunTestInASeperateProcess, StubPlatformSpecificRunTestInASeperateProcess);
    fixture.registry_->setRunTestsInSeperateProcess();
    fixture.runAllTests();
    fixture.assertPrintContains("Failed in separate process");
}

#ifndef CPPUTEST_HAVE_FORK

IGNORE_TEST(UtestShell, TestDefaultCrashMethodInSeparateProcessTest) {}

#else

TEST(UtestShell, TestDefaultCrashMethodInSeparateProcessTest)
{
    fixture.setTestFunction(UtestShell::crash);
    fixture.registry_->setRunTestsInSeperateProcess();
    fixture.runAllTests();
    fixture.assertPrintContains("Failed in separate process - killed by signal");

    /* Signal 11 usually happens, but with clang3.7 on Linux, it produced signal 4 */
    CHECK(fixture.getOutput().contains("signal 11") || fixture.getOutput().contains("signal 4"));
}

#endif

#if CPPUTEST_USE_STD_CPP_LIB

static bool destructorWasCalledOnFailedTest = false;

static void _destructorCalledForLocalObjects()
{
    SetBooleanOnDestructorCall pleaseCallTheDestructor(destructorWasCalledOnFailedTest);
    destructorWasCalledOnFailedTest = false;
    FAIL("fail");
}

TEST(UtestShell, DestructorIsCalledForLocalObjectsWhenTheTestFails)
{
    fixture.setTestFunction(_destructorCalledForLocalObjects);
    fixture.runAllTests();
    CHECK(destructorWasCalledOnFailedTest);
}

#endif

TEST_GROUP(IgnoredUtestShell)
{
    TestTestingFixture fixture;
    IgnoredUtestShell ignoredTest;
    ExecFunctionTestShell normalUtestShell;

    void setup() _override
    {
        fixture.addTest(&ignoredTest);
        fixture.addTest(&normalUtestShell);
    }
};

TEST(IgnoredUtestShell, doesIgnoreCount)
{
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getIgnoreCount());
}

TEST(IgnoredUtestShell, printsIGNORE_TESTwhenVerbose)
{
    fixture.output_->verbose();
    fixture.runAllTests();
    fixture.assertPrintContains("IGNORE_TEST");
}

TEST(IgnoredUtestShell, runIgnoredOptionSpecifiedThenIncreaseRunCount)
{
    ignoredTest.setRunIgnored();
    fixture.runAllTests();
    LONGS_EQUAL(3, fixture.getRunCount());
    LONGS_EQUAL(0, fixture.getIgnoreCount());
}

TEST(IgnoredUtestShell, runIgnoredOptionNotSpecifiedThenIncreaseIgnoredCount)
{
    fixture.runAllTests();
    LONGS_EQUAL(2, fixture.getRunCount());
    LONGS_EQUAL(1, fixture.getIgnoreCount());
}

TEST(IgnoredUtestShell, runIgnoredOptionSpecifiedWillNotInfluenceNormalTestCount)
{
    normalUtestShell.setRunIgnored();
    fixture.runAllTests();
    LONGS_EQUAL(2, fixture.getRunCount());
    LONGS_EQUAL(1, fixture.getIgnoreCount());
}

TEST(IgnoredUtestShell, runIgnoredOptionSpecifiedThenReturnTESTInFormattedName)
{
    ignoredTest.setGroupName("TestGroup");
    ignoredTest.setTestName("TestName");
    ignoredTest.setRunIgnored();
    fixture.runAllTests();
    STRCMP_EQUAL("TEST(TestGroup, TestName)", ignoredTest.getFormattedName().asCharString());
}

TEST(IgnoredUtestShell, runIgnoredOptionNotSpecifiedThenReturnIGNORETESTInFormattedName)
{
    ignoredTest.setGroupName("TestGroup");
    ignoredTest.setTestName("TestName");
    fixture.runAllTests();
    STRCMP_EQUAL("IGNORE_TEST(TestGroup, TestName)", ignoredTest.getFormattedName().asCharString());
}

TEST(IgnoredUtestShell, runIgnoredOptionNotSpecifiedThenWillRunReturnFalse)
{
    CHECK_FALSE(ignoredTest.willRun());
}

TEST(IgnoredUtestShell, runIgnoredOptionSpecifiedThenWillRunReturnTrue)
{
    ignoredTest.setRunIgnored();
    CHECK_TRUE(ignoredTest.willRun());
}

TEST_BASE(MyOwnTest)
{
    MyOwnTest() :
        inTest(false)
    {
    }
    bool inTest;

    void setup()
    {
        CHECK(!inTest);
        inTest = true;
    }
    void teardown()
    {
        CHECK(inTest);
        inTest = false;
    }
};

TEST_GROUP_BASE(UtestMyOwn, MyOwnTest)
{
};

TEST(UtestMyOwn, test)
{
    CHECK(inTest);
}

class NullParameterTest: public UtestShell
{
};

TEST(UtestMyOwn, NullParameters)
{
    NullParameterTest nullTest; /* Bug fix tests for creating a test without a name, fix in SimpleString */
    TestFilter emptyFilter;
    CHECK(nullTest.shouldRun(&emptyFilter, &emptyFilter));
}

class AllocateAndDeallocateInConstructorAndDestructor
{
    char* memory_;
    char* morememory_;
public:
    AllocateAndDeallocateInConstructorAndDestructor()
    {
        memory_ = new char[100];
        morememory_ = NULLPTR;
    }
    void allocateMoreMemory()
    {
        morememory_ = new char[123];
    }

    ~AllocateAndDeallocateInConstructorAndDestructor()
    {
        delete [] memory_;
        delete [] morememory_;
    }
};

TEST_GROUP(CanHaveMemberVariablesInTestGroupThatAllocateMemoryWithoutCausingMemoryLeaks)
{
    AllocateAndDeallocateInConstructorAndDestructor dummy;
};

TEST(CanHaveMemberVariablesInTestGroupThatAllocateMemoryWithoutCausingMemoryLeaks, testInTestGroupName)
{
    dummy.allocateMoreMemory();
}

static int getZero()
{
    return 0;
}

static int getOne()
{
    return 1;
}

TEST_GROUP(UtestShellPointerArrayTest)
{
    UtestShell* test0;
    UtestShell* test1;
    UtestShell* test2;

    void setup()
    {
        test0 = new IgnoredUtestShell();
        test1 = new IgnoredUtestShell();
        test2 = new IgnoredUtestShell();

        test0->addTest(test1);
        test1->addTest(test2);
    }

    void teardown()
    {
        delete test0;
        delete test1;
        delete test2;
    }
};

TEST(UtestShellPointerArrayTest, empty)
{
    UtestShellPointerArray tests(NULLPTR);
    tests.shuffle(0);
    CHECK(NULL == tests.getFirstTest());
}

TEST(UtestShellPointerArrayTest, testsAreInOrder)
{
    UtestShellPointerArray tests(test0);
    CHECK(tests.get(0) == test0);
    CHECK(tests.get(1) == test1);
    CHECK(tests.get(2) == test2);
}

TEST(UtestShellPointerArrayTest, relinkingTestsWillKeepThemTheSameWhenNothingWasDone)
{
    UtestShellPointerArray tests(test0);
    tests.relinkTestsInOrder();
    CHECK(tests.get(0) == test0);
    CHECK(tests.get(1) == test1);
    CHECK(tests.get(2) == test2);
}

TEST(UtestShellPointerArrayTest, firstTestisNotTheFirstTestWithSeed1234)
{
    UtestShellPointerArray tests(test0);
    tests.shuffle(1234);
    CHECK(tests.getFirstTest() != test0);
}

TEST(UtestShellPointerArrayTest, ShuffleListTestWithRandomAlwaysReturningZero)
{
    UT_PTR_SET(PlatformSpecificRand, getZero);

    UtestShellPointerArray tests(test0);
    tests.shuffle(3);
    CHECK(tests.get(0) == test1);
    CHECK(tests.get(1) == test2);
    CHECK(tests.get(2) == test0);
}

// swaps with 4 mod 3 (1) then 4 mod 2 (0): 1, [2], [0] --> [1], [0], 2 --> 0, 1, 2
TEST(UtestShellPointerArrayTest, ShuffleListTestWithRandomAlwaysReturningOne)
{
    UT_PTR_SET(PlatformSpecificRand, getOne);

    UtestShellPointerArray tests(test0);
    tests.shuffle(3);
    CHECK(tests.get(0) == test0);
    CHECK(tests.get(1) == test2);
    CHECK(tests.get(2) == test1);
}

TEST(UtestShellPointerArrayTest, reverse)
{
    UT_PTR_SET(PlatformSpecificRand, getOne);

    UtestShellPointerArray tests(test0);
    tests.reverse();
    CHECK(tests.get(0) == test2);
    CHECK(tests.get(1) == test1);
    CHECK(tests.get(2) == test0);
}

<commit_msg>Not use ifndef but use if<commit_after>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "CppUTest/TestHarness.h"
#include "CppUTest/TestOutput.h"
#include "CppUTest/TestTestingFixture.h"
#include "CppUTest/PlatformSpecificFunctions.h"

TEST_GROUP(UtestShell)
{
    TestTestingFixture fixture;
};

static void _failMethod()
{
    FAIL("This test fails");
}

static void _passingTestMethod()
{
    CHECK(true);
}

static void _passingCheckEqualTestMethod()
{
    CHECK_EQUAL(1, 1);
}

static void _exitTestMethod()
{
    TEST_EXIT;
    FAIL("Should not get here");
}

static volatile double zero = 0.0;

TEST(UtestShell, compareDoubles)
{
    double not_a_number = zero / zero;
    double infinity = 1 / zero;
    CHECK(doubles_equal(1.0, 1.001, 0.01));
    CHECK(!doubles_equal(not_a_number, 1.001, 0.01));
    CHECK(!doubles_equal(1.0, not_a_number, 0.01));
    CHECK(!doubles_equal(1.0, 1.001, not_a_number));
    CHECK(!doubles_equal(1.0, 1.1, 0.05));
    CHECK(!doubles_equal(infinity, 1.0, 0.01));
    CHECK(!doubles_equal(1.0, infinity, 0.01));
    CHECK(doubles_equal(1.0, -1.0, infinity));
    CHECK(doubles_equal(infinity, infinity, 0.01));
    CHECK(doubles_equal(infinity, infinity, infinity));
    double a = 1.2345678;
    CHECK(doubles_equal(a, a, 0.000000001));
}

TEST(UtestShell, FailWillIncreaseTheAmountOfChecks)
{
    fixture.setTestFunction(_failMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getCheckCount());
}

TEST(UtestShell, PassedCheckEqualWillIncreaseTheAmountOfChecks)
{
    fixture.setTestFunction(_passingCheckEqualTestMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getCheckCount());
}

IGNORE_TEST(UtestShell, IgnoreTestAccessingFixture)
{
    CHECK(&fixture != NULLPTR);
}

TEST(UtestShell, MacrosUsedInSetup)
{
    IGNORE_ALL_LEAKS_IN_TEST();
    fixture.setSetup(_failMethod);
    fixture.setTestFunction(_passingTestMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getFailureCount());
}

TEST(UtestShell, MacrosUsedInTearDown)
{
    IGNORE_ALL_LEAKS_IN_TEST();
    fixture.setTeardown(_failMethod);
    fixture.setTestFunction(_passingTestMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getFailureCount());
}

TEST(UtestShell, ExitLeavesQuietly)
{
    fixture.setTestFunction(_exitTestMethod);
    fixture.runAllTests();
    LONGS_EQUAL(0, fixture.getFailureCount());
}

static int teardownCalled = 0;

static void _teardownMethod()
{
    teardownCalled++;
}

TEST(UtestShell, TeardownCalledAfterTestFailure)
{
    teardownCalled = 0;
    IGNORE_ALL_LEAKS_IN_TEST();
    fixture.setTeardown(_teardownMethod);
    fixture.setTestFunction(_failMethod);
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getFailureCount());
    LONGS_EQUAL(1, teardownCalled);
}

static int stopAfterFailure = 0;
static void _stopAfterFailureMethod()
{
    FAIL("fail");
    stopAfterFailure++;
}

TEST(UtestShell, TestStopsAfterTestFailure)
{
    IGNORE_ALL_LEAKS_IN_TEST();
    stopAfterFailure = 0;
    fixture.setTestFunction(_stopAfterFailureMethod);
    fixture.runAllTests();
    CHECK(fixture.hasTestFailed());
    LONGS_EQUAL(1, fixture.getFailureCount());
    LONGS_EQUAL(0, stopAfterFailure);
}

TEST(UtestShell, TestStopsAfterSetupFailure)
{
    stopAfterFailure = 0;
    fixture.setSetup(_stopAfterFailureMethod);
    fixture.setTeardown(_stopAfterFailureMethod);
    fixture.setTestFunction(_failMethod);
    fixture.runAllTests();
    LONGS_EQUAL(2, fixture.getFailureCount());
    LONGS_EQUAL(0, stopAfterFailure);
}

class defaultUtestShell: public UtestShell
{
};

TEST(UtestShell, this_test_covers_the_UtestShell_createTest_and_Utest_testBody_methods)
{
    defaultUtestShell shell;
    fixture.addTest(&shell);
    fixture.runAllTests();
    LONGS_EQUAL(2, fixture.result_->getTestCount());
}

static void StubPlatformSpecificRunTestInASeperateProcess(UtestShell* shell, TestPlugin*, TestResult* result)
{
    result->addFailure(TestFailure(shell, "Failed in separate process"));
}

TEST(UtestShell, RunInSeparateProcessTest)
{
    UT_PTR_SET(PlatformSpecificRunTestInASeperateProcess, StubPlatformSpecificRunTestInASeperateProcess);
    fixture.registry_->setRunTestsInSeperateProcess();
    fixture.runAllTests();
    fixture.assertPrintContains("Failed in separate process");
}

#if !CPPUTEST_HAVE_FORK

IGNORE_TEST(UtestShell, TestDefaultCrashMethodInSeparateProcessTest) {}

#else

TEST(UtestShell, TestDefaultCrashMethodInSeparateProcessTest)
{
    fixture.setTestFunction(UtestShell::crash);
    fixture.registry_->setRunTestsInSeperateProcess();
    fixture.runAllTests();
    fixture.assertPrintContains("Failed in separate process - killed by signal");

    /* Signal 11 usually happens, but with clang3.7 on Linux, it produced signal 4 */
    CHECK(fixture.getOutput().contains("signal 11") || fixture.getOutput().contains("signal 4"));
}

#endif

#if CPPUTEST_USE_STD_CPP_LIB

static bool destructorWasCalledOnFailedTest = false;

static void _destructorCalledForLocalObjects()
{
    SetBooleanOnDestructorCall pleaseCallTheDestructor(destructorWasCalledOnFailedTest);
    destructorWasCalledOnFailedTest = false;
    FAIL("fail");
}

TEST(UtestShell, DestructorIsCalledForLocalObjectsWhenTheTestFails)
{
    fixture.setTestFunction(_destructorCalledForLocalObjects);
    fixture.runAllTests();
    CHECK(destructorWasCalledOnFailedTest);
}

#endif

TEST_GROUP(IgnoredUtestShell)
{
    TestTestingFixture fixture;
    IgnoredUtestShell ignoredTest;
    ExecFunctionTestShell normalUtestShell;

    void setup() _override
    {
        fixture.addTest(&ignoredTest);
        fixture.addTest(&normalUtestShell);
    }
};

TEST(IgnoredUtestShell, doesIgnoreCount)
{
    fixture.runAllTests();
    LONGS_EQUAL(1, fixture.getIgnoreCount());
}

TEST(IgnoredUtestShell, printsIGNORE_TESTwhenVerbose)
{
    fixture.output_->verbose();
    fixture.runAllTests();
    fixture.assertPrintContains("IGNORE_TEST");
}

TEST(IgnoredUtestShell, runIgnoredOptionSpecifiedThenIncreaseRunCount)
{
    ignoredTest.setRunIgnored();
    fixture.runAllTests();
    LONGS_EQUAL(3, fixture.getRunCount());
    LONGS_EQUAL(0, fixture.getIgnoreCount());
}

TEST(IgnoredUtestShell, runIgnoredOptionNotSpecifiedThenIncreaseIgnoredCount)
{
    fixture.runAllTests();
    LONGS_EQUAL(2, fixture.getRunCount());
    LONGS_EQUAL(1, fixture.getIgnoreCount());
}

TEST(IgnoredUtestShell, runIgnoredOptionSpecifiedWillNotInfluenceNormalTestCount)
{
    normalUtestShell.setRunIgnored();
    fixture.runAllTests();
    LONGS_EQUAL(2, fixture.getRunCount());
    LONGS_EQUAL(1, fixture.getIgnoreCount());
}

TEST(IgnoredUtestShell, runIgnoredOptionSpecifiedThenReturnTESTInFormattedName)
{
    ignoredTest.setGroupName("TestGroup");
    ignoredTest.setTestName("TestName");
    ignoredTest.setRunIgnored();
    fixture.runAllTests();
    STRCMP_EQUAL("TEST(TestGroup, TestName)", ignoredTest.getFormattedName().asCharString());
}

TEST(IgnoredUtestShell, runIgnoredOptionNotSpecifiedThenReturnIGNORETESTInFormattedName)
{
    ignoredTest.setGroupName("TestGroup");
    ignoredTest.setTestName("TestName");
    fixture.runAllTests();
    STRCMP_EQUAL("IGNORE_TEST(TestGroup, TestName)", ignoredTest.getFormattedName().asCharString());
}

TEST(IgnoredUtestShell, runIgnoredOptionNotSpecifiedThenWillRunReturnFalse)
{
    CHECK_FALSE(ignoredTest.willRun());
}

TEST(IgnoredUtestShell, runIgnoredOptionSpecifiedThenWillRunReturnTrue)
{
    ignoredTest.setRunIgnored();
    CHECK_TRUE(ignoredTest.willRun());
}

TEST_BASE(MyOwnTest)
{
    MyOwnTest() :
        inTest(false)
    {
    }
    bool inTest;

    void setup()
    {
        CHECK(!inTest);
        inTest = true;
    }
    void teardown()
    {
        CHECK(inTest);
        inTest = false;
    }
};

TEST_GROUP_BASE(UtestMyOwn, MyOwnTest)
{
};

TEST(UtestMyOwn, test)
{
    CHECK(inTest);
}

class NullParameterTest: public UtestShell
{
};

TEST(UtestMyOwn, NullParameters)
{
    NullParameterTest nullTest; /* Bug fix tests for creating a test without a name, fix in SimpleString */
    TestFilter emptyFilter;
    CHECK(nullTest.shouldRun(&emptyFilter, &emptyFilter));
}

class AllocateAndDeallocateInConstructorAndDestructor
{
    char* memory_;
    char* morememory_;
public:
    AllocateAndDeallocateInConstructorAndDestructor()
    {
        memory_ = new char[100];
        morememory_ = NULLPTR;
    }
    void allocateMoreMemory()
    {
        morememory_ = new char[123];
    }

    ~AllocateAndDeallocateInConstructorAndDestructor()
    {
        delete [] memory_;
        delete [] morememory_;
    }
};

TEST_GROUP(CanHaveMemberVariablesInTestGroupThatAllocateMemoryWithoutCausingMemoryLeaks)
{
    AllocateAndDeallocateInConstructorAndDestructor dummy;
};

TEST(CanHaveMemberVariablesInTestGroupThatAllocateMemoryWithoutCausingMemoryLeaks, testInTestGroupName)
{
    dummy.allocateMoreMemory();
}

static int getZero()
{
    return 0;
}

static int getOne()
{
    return 1;
}

TEST_GROUP(UtestShellPointerArrayTest)
{
    UtestShell* test0;
    UtestShell* test1;
    UtestShell* test2;

    void setup()
    {
        test0 = new IgnoredUtestShell();
        test1 = new IgnoredUtestShell();
        test2 = new IgnoredUtestShell();

        test0->addTest(test1);
        test1->addTest(test2);
    }

    void teardown()
    {
        delete test0;
        delete test1;
        delete test2;
    }
};

TEST(UtestShellPointerArrayTest, empty)
{
    UtestShellPointerArray tests(NULLPTR);
    tests.shuffle(0);
    CHECK(NULL == tests.getFirstTest());
}

TEST(UtestShellPointerArrayTest, testsAreInOrder)
{
    UtestShellPointerArray tests(test0);
    CHECK(tests.get(0) == test0);
    CHECK(tests.get(1) == test1);
    CHECK(tests.get(2) == test2);
}

TEST(UtestShellPointerArrayTest, relinkingTestsWillKeepThemTheSameWhenNothingWasDone)
{
    UtestShellPointerArray tests(test0);
    tests.relinkTestsInOrder();
    CHECK(tests.get(0) == test0);
    CHECK(tests.get(1) == test1);
    CHECK(tests.get(2) == test2);
}

TEST(UtestShellPointerArrayTest, firstTestisNotTheFirstTestWithSeed1234)
{
    UtestShellPointerArray tests(test0);
    tests.shuffle(1234);
    CHECK(tests.getFirstTest() != test0);
}

TEST(UtestShellPointerArrayTest, ShuffleListTestWithRandomAlwaysReturningZero)
{
    UT_PTR_SET(PlatformSpecificRand, getZero);

    UtestShellPointerArray tests(test0);
    tests.shuffle(3);
    CHECK(tests.get(0) == test1);
    CHECK(tests.get(1) == test2);
    CHECK(tests.get(2) == test0);
}

// swaps with 4 mod 3 (1) then 4 mod 2 (0): 1, [2], [0] --> [1], [0], 2 --> 0, 1, 2
TEST(UtestShellPointerArrayTest, ShuffleListTestWithRandomAlwaysReturningOne)
{
    UT_PTR_SET(PlatformSpecificRand, getOne);

    UtestShellPointerArray tests(test0);
    tests.shuffle(3);
    CHECK(tests.get(0) == test0);
    CHECK(tests.get(1) == test2);
    CHECK(tests.get(2) == test1);
}

TEST(UtestShellPointerArrayTest, reverse)
{
    UT_PTR_SET(PlatformSpecificRand, getOne);

    UtestShellPointerArray tests(test0);
    tests.reverse();
    CHECK(tests.get(0) == test2);
    CHECK(tests.get(1) == test1);
    CHECK(tests.get(2) == test0);
}

<|endoftext|>