Lab 7 completed

parent 5dca0c1c
Pipeline #21020 passed with stages
in 2 minutes and 47 seconds
......@@ -2,3 +2,4 @@ area/area.exe
area/test.exe
.vscode/
msg.txt
lab07/build.bat
--filterNames()--
Susan Brewer
Eugene McMannon
Susan Brewer
Eugene McMannon
--sortNames()--
Eugene McMannon
Eugene McMannon
Susan Brewer
Susan Brewer
Foster, James
Aamodt, Larry
Duncan, Jonathan
Carman, Preston
File added
/*
* CPTR 245 Lab 07
*
* 1. Use dependency injection to provide a StubbedSource for canned responses
* 2. Avoid the user interface by getting the user type from the command line
* 3. Use a mock test double for the application analysis
* 4. Use fake time
*/
#include <algorithm> // std::sort
#include <chrono>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <string>
#include <thread> // std::this_thread::sleep_for
#include <vector>
using namespace std;
using namespace std::chrono;
class Clock {
public:
virtual uint64_t msSinceEpoch() = 0;
virtual void sleepMs(int ms) = 0;
};
class SystemClock : public Clock {
public:
uint64_t msSinceEpoch() {
return duration_cast<milliseconds>(system_clock::now().time_since_epoch())
.count();
}
void sleepMs(int ms) {
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}
};
// PROBLEM 4
// The instructions were a little fuzzy on this one, personally, maybe I just didn't understand it.
// Rather than use whatever the system time was, I just had it count up by increments of ten. We can
// assume that it's counting in milliseconds, so "epoch" is in units of ms.
class FakeClock : public Clock {
public:
uint64_t epoch = 0;
uint64_t msSinceEpoch(){
return epoch;
}
void sleepMs(int ms) {
epoch+=10;
}
};
class DataSource {
public:
virtual vector<string> names(int userType) = 0;
};
class FileSource : public DataSource {
public:
vector<string> names(int userType);
};
// PROBLEM 1
// Creates an almost identical DataSource that has its own implementation of names(int userType)
class StubbedSource : public DataSource {
public:
vector<string> names(int userType);
};
// PROBLEM 1
// Rather than read from a file, simply pushes random names to the vector
vector<string> StubbedSource::names(int userType) {
vector<string> names;
switch(userType) {
case 1:
names.push_back("Bob Saget");
names.push_back("Susan Brewer");
names.push_back("Eugene McMannon");
case 2:
names.push_back("Bob Saget");
names.push_back("Susan Brewer");
names.push_back("Eugene McMannon");
}
return names;
}
vector<string> FileSource::names(int userType) {
string filename;
vector<string> names;
switch (userType) {
case 1:
filename = "students.txt";
break;
case 2:
filename = "faculty.txt";
break;
default:
cerr << "Invalid userType: " << userType << endl;
exit(1);
}
ifstream inFS;
inFS.open(filename);
if (!inFS.is_open()) {
cerr << "Could not open \"" << filename << '\"' << endl;
exit(1);
}
while (!inFS.eof()) {
string name;
getline(inFS, name);
if (name.size()) {
names.push_back(name);
}
}
inFS.close();
return names;
}
class AnalysisTool {
public:
virtual vector<string> filterNames(vector<string> names) = 0;
virtual vector<string> sortNames(vector<string> names) = 0;
virtual void printNames(vector<string> names) = 0;
};
class RealAnalysisTool : public AnalysisTool {
public:
vector<string> filterNames(vector<string> names);
vector<string> sortNames(vector<string> names);
void printNames(vector<string> names);
};
vector<string> RealAnalysisTool::filterNames(vector<string> names) {
vector<string> result;
for (int i = 0; i < names.size(); ++i) {
if (names.at(i).at(0) % 2) {
result.push_back(names.at(i));
}
}
return result;
}
vector<string> RealAnalysisTool::sortNames(vector<string> names) {
vector<string> result = names;
sort(result.begin(), result.end());
return result;
}
void RealAnalysisTool::printNames(vector<string> names) {
for (int i = 0; i < names.size(); ++i) {
cout << i << ": " << names.at(i) << endl;
}
}
// PROBLEM 3
// This class runs the same operations that the RealAnalysisTool does, except that on every call, it pushes back the
// name of the function call and the results of the output.
class MockAnalysisTool : public AnalysisTool {
public:
vector<string> functionNames;
vector<string> filterNames(vector<string> names);
vector<string> sortNames(vector<string> names);
void printNames(vector<string> names);
};
vector<string> MockAnalysisTool::filterNames(vector<string> names) {
functionNames.push_back("--filterNames()--");
vector<string> result;
for (int i = 0; i < names.size(); ++i) {
if (names.at(i).at(0) % 2) {
result.push_back(names.at(i));
}
}
for (int i = 0; i < result.size(); i++){
functionNames.push_back(result.at(i));
}
return result;
}
vector<string> MockAnalysisTool::sortNames(vector<string> names) {
functionNames.push_back("--sortNames()--");
vector<string> result = names;
sort(result.begin(), result.end());
for (int i = 0; i < result.size(); i++){
functionNames.push_back(result.at(i));
}
return result;
}
void MockAnalysisTool::printNames(vector<string> names) {
string filename = "MockAnalysisTool.txt";
ofstream onFS;
onFS.open(filename);
if(!onFS.is_open()) {
ofstream file(filename);
}
for (int i = 0; i < functionNames.size(); i++){
onFS << functionNames.at(i) << "\n" << endl;
}
onFS.close();
}
class Application {
public:
Application(DataSource *dataSource) { this->dataSource = dataSource; }
int getUserInput();
vector<string> getNames(int userType);
private:
DataSource *dataSource;
};
int Application::getUserInput() {
while (true) {
int choice;
cout << "Enter user type (1 = student; 2 = faculty): ";
cin >> choice;
if (cin && 1 <= choice && choice <= 2) {
return choice;
}
cerr << "Invalid response!" << endl;
cin.clear();
cin.ignore(100, '\n');
}
}
vector<string> Application::getNames(int userType) {
return dataSource->names(userType);
}
/*
* Arguments (all optional):
* 1: DataSource subclass name (defaults to FileSource)
* 2: user type (defaults to asking user)
* 3: AnalysisTool subclass name (defaults to RealAnalysisTool)
* 4: Clock subclass name (defaults to SystemClock)
*
*/
int main(int argc, char *argv[]) {
// collect the arguments
vector<string> args(10);
for (int i = 0; i < argc; ++i) {
args.at(i) = argv[i];
}
// select the data source
DataSource *dataSource;
if (args.at(1) == "" || args.at(1) == "FileSource") {
dataSource = new FileSource();
} else if (args.at(1) == "StubbedSource"){ //Problem 1 code
dataSource = new StubbedSource();
} else {
cerr << "unrecognized data source" << endl;
exit(1);
}
// Use dependency injection for the data source
Application app(dataSource);
// Get the user type (avoid the user interface during testing)
// PROBLEM 2: Adjusted for command line testing
int userType;
if (args.at(2) == ""){
userType = app.getUserInput();
} else if (args.at(2) == "1"){
userType = 1;
} else if (args.at(2) == "2"){
userType = 2;
} else {
cerr << "Invalid user input" << endl;
}
// read from the data source
vector<string> names = app.getNames(userType);
// do analysis of the names (use a mock for testing)
if (args.at(3) == "" || args.at(3) == "RealAnalysisTool"){
AnalysisTool *tool;
tool = new RealAnalysisTool();
names = tool->filterNames(names);
names = tool->sortNames(names);
tool->printNames(names);
} else {
AnalysisTool *tool;
tool = new MockAnalysisTool();
names = tool->filterNames(names);
names = tool->sortNames(names);
tool->printNames(names);
}
Clock *clock;
// Determining, based on the args, if FakeClock or System clock is to be used
if (args.at(4) == "" || args.at(4) == "SystemClock"){
clock = new SystemClock();
} else if (args.at(4) == "FakeClock"){
clock = new FakeClock();
}
// do long-running process (faking time for testing)
uint64_t start = clock->msSinceEpoch();
cout << "start long-running process at " << start << endl;
while (clock->msSinceEpoch() < start + 2000) {
clock->sleepMs(10);
}
cout << " end long-running process at " << clock->msSinceEpoch() << endl;
return 0;
}
Tinker, Hayden
Benko, Matija
Sukachevin, Kieran
Smith, Taylor
Herbel, Caleb
Hernandez, Samuel
Jones, Julian
Taylor, Evan
Thomsen, Catherine
DePaula, Stefan
Fairchild, Kaden
Hartman, Joel
Taylor, Adam
Calvo, Eliam
Price, Quinton
Reklai, Reece
Riggs, Jason
Moody, Garrett
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment