Each of the header files contains a description of the problem you are tasked to solve. The makefile contains rules to build each of the problems' final test executable. The makefile also contains rules to run cpplint on the files.
employee.h
#include < string >
namespace exam3 {
namespace problem1 {
// The Demographic class provides a base for people in the system. It will be
// extended by other classes, such as Employee.
//
// The class provides a constructor, a virtual destructor, and three accessor
// methods for the class members passed into the constructor.
class Demographic {
public:
Demographic(const std::string& first_name,
const std::string& last_name,
const std::string& date_of_birth);
// not necessarily pure
virtual ~Demographic();
// accessors
const std::string first_name() const;
const std::string last_name() const;
const std::string date_of_birth() const;
private:
std::string _first_name;
std::string _last_name;
std::string _date_of_birth;
};
// Employee extends the Demographic class, adding an employee id and relevant
// constructor and accessor
class Employee : public Demographic {
public:
// Additional parameter employee_id stored by the Employee class
Employee(const std::string& first_name,
const std::string& last_name,
const std::string& date_of_birth,
const std::string& employee_id);
// additional accessor
const std::string employee_id() const;
// Must be defined by child
// Returns the payment unit of a child class, i.e. salary or hourly rate
virtual double pay_rate() const = 0;
// Must be defined by child
// Calculates and returns the payment based on child class behavior.
virtual double CalculatePay(double) const = 0;
private:
std::string _employee_id;
};
// HourlyEmplyee extends the Employee class and provides the following methods:
// - Constructor: accepts 4 const pass-by-reference strings, representing
// first_name, last_name, date_of_birth, employee_id, and a double
// representing the instance's hourly_rate.
//
// - pay_rate: access for the hourly_rate parameter above
// - CalculatePay: accepts number of hours worked and returns the pay for the
// hourly rate based on hours worked.
class HourlyEmployee : public Employee {
public:
// Additional parameter hourly_rate is stored privately in HourlyEmployee
HourlyEmployee(const std::string& first_name,
const std::string& last_name,
const std::string& date_of_birth,
const std::string& employee_id,
double hourly_rate);
// accessor for hourly rate
double pay_rate() const;
// Calculates payment based on the employee's hourly_rate and the
// hours_worked.
double CalculatePay(double hours_worked) const;
private:
double _hourly_rate;
};
// SalaryEmplyee extends the Employee class and provides the following methods:
// - Constructor: accepts 4 const pass-by-reference strings, representing
// first_name, last_name, date_of_birth, employee_id, and a double
// representing the instance's salary.
//
// - pay_rate: accessor for the salary parameter above
// - CalculatePay: accepts a double representing the percentage of the year for
// which the salaried employee is paid, e.g. a week is 1/52 of a year ~1.923%.
class SalaryEmployee : public Employee {
public:
// Additional parameter salary is stored privately in SalaryEmployee
SalaryEmployee(const std::string& first_name,
const std::string& last_name,
const std::string& date_of_birth,
const std::string& employee_id,
double salary);
// accessor for salary
double pay_rate() const;
// Calculates payment based on the worker's salary and the percentage of the
// year for which payment is made e.g. a week payment is ~1.923% (1/52).
double CalculatePay(double annual_percentage) const;
private:
double _salary;
};
} // namespace problem1
} // namespace exam3
test_employee.h
#ifndef EXAM3_INC_TEST_EMPLOYEE_H_
#define EXAM3_INC_TEST_EMPLOYEE_H_
#include < exam3/inc/employee.h >
#include < cmath > // fabs
#include < cstddef > // size_t
#include < iostream >
#include < string >
#include < utility > // pair
#include < vector >
bool TestDemographicFirstName();
bool TestDemographicLastName();
bool TestDemographicDateOfBirth();
bool TestEmployeeEmployeeId();
bool TestHourlyEmployeePayRate();
bool TestHourlyEmployeeCalculatePay();
bool TestSalaryEmployeePayRate();
bool TestSalaryEmployeeCalculatePay();
// Test values
const char *kFirst_name = "Jackson";
const char *kLast_name = "Seller";
const char *kDate_of_birth = "1999 10 14";
const char *kEmployee_id = "911911";
const double kHourly_rate = 17.25;
const double kHours_worked = 37.50;
const double kSalary = 68525.01;
const double kAnnual_percentage = 1.0/24.0;
// close enough for floating point equality
const double kAbs_diff = 1e-6;
#endif // EXAM3_INC_TEST_EMPLOYEE_H_
smart_appliance.h
#include < string >
namespace exam3 {
namespace problem2 {
// SmartAppliance represents a class of objects with the following
// characteristics:
// - They have a low power state in which they are inactive
// - They must be activated via Activate() before any internal state may be
// changed.
// - They define a Set method which is used to set an internal state.
// Note: binary internal states may be represented via a 0 for off and 1
// for on. See SmartAppliance class for SmartAppliance::OFF and
// SmartAppliance::ON and below for usage with binary state device--a
// light.
// - The Activate, Deactivate, and Set methods return a status string each
// time they are called.
//
// USAGE:
// SmartLight light;
// std::cout << light.Activate() << 'n';
// std::cout << light.Set(SmartAppliance::ON) << 'n';
//
// SmartAppliance *appliance = &light;
// std::cout << appliance->Set(SmartAppliance::OFF) << 'n';
// std::cout << appliance->Deactivate() << std::endl;
//
// SmartThermostat thermo;
// std::cout << thermostat.Activate() << 'n';
// std::cout << thermostat.Set(70) << 'n';
//
// SmartAppliance *appliance = &thermostat;
// std::cout << appliance->Set(25) << 'n';
// std::cout << appliance->Deactivate() << std::endl;
class SmartAppliance {
public:
static const unsigned int ON = 0;
static const unsigned int OFF = 1;
// not necessarily pure
virtual ~SmartAppliance();
virtual const std::string Activate() = 0;
virtual const std::string Deactivate() = 0;
virtual const std::string Set(unsigned int setting) = 0;
};
// SmartLight
// Extends the SmartAppliance. A light is off when deactivated and remains so
// until set using the Set method.
//
// Activate: (1) Object is inactive, activates light and returns the string
// { "active": true, "previous": false };
// (2) Object is active, returns the string
// { "active": true, "previous": true };
//
// Deactivate: (1) Object is inactive, does nothing and returns the string
// { "active": false, "previous": false }
// (2) Object is active, deactivates light and returns string
// { "active": false, "previous": true };
//
// Set: (1) Object is inactive, setting parameter is ignored and returns the
// string
// { "active": false }
// (2) Object is active:
// (a) Setting parameter is 1(ON) and light is off, turns light on
// and returns string:
// { "active": true, "on": true, "previous": false }
// (b) Setting parameter is 1(ON) and light is on, returns string:
// { "active": true, "on": true, "previous": true }
// (c) Setting parameter is 0(OFF) and light is on, turns light off
// and returns string:
// { "active": true, "on": false, "previous": true }
// (d) When setting parameter is 0(OFF) and light is off, returns
// string:
// { "active": true, "on": false, "previous": false }
//
class SmartLight :
public SmartAppliance
{
public:
SmartLight();
const std::string Activate();
const std::string Deactivate();
const std::string Set(unsigned int setting);
private:
bool _active;
unsigned int _state;
};
// SmartThermostat
// Extends the SmartAppliance. A thermostat object has "no temperature" when it
// is deactivated and remains so until set using the Set method. You may
// represent this however you choose, but the value is returned as the literal
// null
//
// A thermostat receives it setting as a value in [0, 100]. A thermostat has a
// temperature range between 40 and 90 degrees Fahrenheight---a range of 50
// degrees. Use the 0 to 100 as the percent of the range to set the
// temperature,
// i.e. setting 0(%) => 40, setting 50(%) => 65, setting 100(%) => 90, etc.
// You should round to one decimal place.
//
// Activate: (1) Object is inactive, activates light and returns the string
// { "active": true, "previous": false };
// (2) Object is active, returns the string
// { "active": true, "previous": true };
//
// Deactivate: (1) Object is inactive, does nothing and returns the string
// { "active": false, "previous": false }
// (2) Object is active, deactivates light and returns string
// { "active": false, "previous": true };
//
// Set: (1) object is inactive, setting parameter is ignored and returns the
// string
// { "active": false }
// (2) object is active:
// (a) Current temperature is not set, updates temperature using
// setting parameter accordingly and returns the string:
// { "active": true, "temp": 75, "previous": null }
// (b) Setting parameter is not equal to the current temperature,
// returns the string:
// { "active": true, "temp": 75, "previous": 75 }
// (b) Setting parameter is equal to current temperature, updates
// temperature accordingly and returns the string:
// { "active": true, "temp": 75, "previous": 73 }
//
class SmartThermostat
: public SmartAppliance
{
public:
SmartThermostat();
const std::string Activate();
const std::string Deactivate();
const std::string Set(unsigned int setting);
private:
bool _active;
int _temp;
};
} // namespace problem2
} // namespace exam3
test_smart_appliance.h
#ifndef EXAM3_INC_TEST_SMART_APPLIANCE_H_
#define EXAM3_INC_TEST_SMART_APPLIANCE_H_
#include < exam3/inc/smart_appliance.h >
#include < cctype > // isspace
#include < cstddef > // size_t
#include < cstdlib > // atoi
#include < algorithm >
#include < iostream >
#include < string >
// Active devices behave differently from inactive ones
enum class TestType {
ACTIVE,
INACTIVE
};
// PARAMETERS:
// test determines inactive vs active devices
// name is printed type of smart device---Thermostat or Light
// expected is expected return string from method
// appliance is the device being tested---a child of SmartAppliance
bool TestSmartApplianceActivate(TestType test,
const char* name,
const std::string& expected,
exam3::problem2::SmartAppliance* appliance);
// PARAMETERS:
// test determines inactive vs active devices
// name is printed type of smart device---Thermostat or Light
// expected is expected return string from method
// appliance is the device being tested---a child of SmartAppliance
bool TestSmartApplianceDeactivate(TestType test,
const char* name,
const std::string& expected,
exam3::problem2::SmartAppliance* appliance);
// PARAMETERS:
// test determines inactive vs active devices
// name is printed type of smart device---Thermostat or Light
// input is character string representation of curr
// prev is any previous value to which device should be set
// curr is value passed to test method
// expected is expected return string from method
// appliance is the device being tested---a child of SmartAppliance
bool TestSmartApplianceSet(TestType test,
const char* name,
const char* input,
int prev,
unsigned int curr,
const std::string&& expected,
exam3::problem2::SmartAppliance* appliance);
//////////////////////////////////////////////////////////////////////////////
// //
// DEFINITIONS SHARED BY BOTH TEST FILES //
// //
//////////////////////////////////////////////////////////////////////////////
inline const std::string RemoveWhiteSpace(const std::string& string) {
std::string tmp(string);
tmp.erase(std::remove_if(tmp.begin(), tmp.end(), isspace), tmp.end());
return tmp;
}
bool TestSmartApplianceActivate(TestType test,
const char* name,
const std::string& expected,
exam3::problem2::SmartAppliance* appliance) {
std::cout << " Smart" << name << "::Activate : ";
if (test == TestType::ACTIVE) // preset active when indicated
appliance->Activate();
const std::string kActual = appliance->Activate();
if (RemoveWhiteSpace(kActual) == expected)
std::cout << "PASSED" << std::endl;
else
std::cout << "FAILED" << std::endl
<< " Expected: " << expected << std::endl
<< " Actual: " << RemoveWhiteSpace(kActual) << std::endl;
return RemoveWhiteSpace(kActual) == expected;
}
bool TestSmartApplianceDeactivate(TestType test,
const char* name,
const std::string& expected,
exam3::problem2::SmartAppliance* appliance) {
std::cout << " Smart" << name << "::Activate : ";
if (test == TestType::ACTIVE) // preset active when indicated
appliance->Activate();
const std::string kActual = appliance->Deactivate();
if (RemoveWhiteSpace(kActual) == expected)
std::cout << "PASSED" << std::endl;
else
std::cout << "FAILED" << std::endl
<< " Expected: " << expected << std::endl
<< " Actual: " << kActual << std::endl;
return RemoveWhiteSpace(kActual) == expected;
}
bool TestSmartApplianceSet(TestType test,
const char* name,
const char* input,
int prev,
unsigned int curr,
const std::string&& expected,
exam3::problem2::SmartAppliance* appliance) {
std::cout << " Smart" << name << "::Set(" << input << "): ";
if (test == TestType::ACTIVE) // preset active when indicated
appliance->Activate();
if (prev > -1)
appliance->Set(static_cast< unsigned int >(prev));
const std::string kActual = appliance->Set(curr);
if (RemoveWhiteSpace(kActual) == expected)
std::cout << "PASSED" << std::endl;
else
std::cout << "FAILED" << std::endl
<< " Expected: " << expected << std::endl
<< " Actual: " << kActual << std::endl;
return RemoveWhiteSpace(kActual) == expected;
}
#endif // EXAM3_INC_TEST_SMART_APPLIANCE_H_
makefile
CC = g++ # use g++ compiler
root = .. # use parent dir for project root
FLAGS = -std=c++17 # use C++ 17 standard
FLAGS += -Wall # emit all warnings
FLAGS += -I $(root) # update preprocessor #include path
FLAGS += -g # add gdb instrumentation
LINK = $(CC) $(FLAGS) -o # final linked build to binary executable
COMPILE = $(CC) $(FLAGS) -c # compilation to intermediary .o files
test: test-employee test-smart-light test-smart-thermostat
@./test-employee && ./test-smart-light && ./test-smart-thermostat
style: src/employee.cc inc/employee.h \
src/smart_appliance.cc inc/smart_appliance.h
cpplint --root=$(root) $^
# PROBLEM 1: Employee Inheritance
#
test-employee: bin/employee.o bin/test-employee.o
$(LINK) $@ $^
test-employee-style: src/employee.cc inc/employee.h
cpplint --root=$(root) $^
bin/test-employee.o : src/test_employee.cc inc/test_employee.h inc/employee.h
$(COMPILE) -o $@ $<
bin/employee.o : src/employee.cc inc/employee.h
$(COMPILE) -o $@ $<
# PROBLEM 2: Smart Appliance
#
test-smart-appliance : test-smart-light test-smart-thermostat
@./test-smart-light && ./test-smart-thermostat
test-smart-light: bin/smart-appliance.o bin/test-smart-light.o
$(LINK) $@ $^
test-smart-thermostat: bin/smart-appliance.o bin/test-smart-thermostat.o
$(LINK) $@ $^
test-smart-appliance-style: src/smart_appliance.cc inc/smart_appliance.h
cpplint --root=$(root) $^
bin/test-smart-light.o : src/test_smart_light.cc \
inc/test_smart_appliance.h \
inc/smart_appliance.h
$(COMPILE) -o $@ $<
bin/test-smart-thermostat.o : src/test_smart_thermostat.cc \
inc/test_smart_appliance.h \
inc/smart_appliance.h
$(COMPILE) -o $@ $<
bin/smart-appliance.o : src/smart_appliance.cc inc/smart_appliance.h
$(COMPILE) -o $@ $<
# UTILITY: removes intermediary files and executables
clean:
rm -f bin/* test-employee test-smart-light test-smart-thermostat