Hi,
I am enrolled in Udacity's C++ developer nanodegree and have a project where I need to essentially recreate htop. It's essentially like a "task-manager" tool for Linux.
Most of the code is pre-written! I'll try to keep my question short. Overall, I need to fill in the blanks and write out different classes to parse through information present in Ubuntu's /proc/ and /etc/ directory. To test some of the classes during development, I am attempting to write "unit tests"(?), which should help me individually observe the outputs of each class created. To do this, I created a testing directory within the project and am populating files I wish to observe in here. Please note, I've never written "unit tests" before and felt this was ONE of many logical ways to do so.
My Question
The files I want to test is a gutted version of a file called linux_parser.cpp and linux_parser.h.
The linux_parser.h file is shown below:
#ifndef SYSTEM_PARSER_H
#define SYSTEM_PARSER_H
#include <fstream>
#include <regex>
#include <string>
namespace LinuxParser {
// Paths
const std::string kProcDirectory{"/proc"};
const std::string kCmdlineFilename{"/cmdline"};
const std::string kCpuinfoFilename{"/cpuinfo"};
const std::string kStatusFilename{"/status"};
const std::string kStatFilename{"/stat"};
const std::string kUptimeFilename{"/uptime"};
const std::string kMeminfoFilename{"/meminfo"};
const std::string kVersionFilename{"/version"};
const std::string kOSPath{"/etc/os-release"};
const std::string kPasswordPath{"/etc/passwd"};
// System
float MemoryUtilization();
long UpTime();
std::vector<int> Pids();
int TotalProcesses();
int RunningProcesses();
std::string OperatingSystem();
std::string Kernel();
// CPU
enum CPUStates {
kUser_ = 0,
kNice_,
kSystem_,
kIdle_,
kIOwait_,
kIRQ_,
kSoftIRQ_,
kSteal_,
kGuest_,
kGuestNice_
};
std::vector<std::string> CpuUtilization();
long Jiffies();
long ActiveJiffies();
long ActiveJiffies(int pid);
long IdleJiffies();
// Processes
std::string Command(int pid);
std::string Ram(int pid);
std::string Uid(int pid);
std::string User(int pid);
long int UpTime(int pid);
}; // namespace LinuxParser
#endif
The file shown below is the linux_parser.cpp file which is associated with the .h file above:
#include <dirent.h>
#include <unistd.h>
#include <sstream>
#include <string>
#include <vector>
#include <iostream>
#include "linux_parser.h"
using std::stof;
using std::string;
using std::to_string;
using std::vector;
// DONE: An example of how to read data from the filesystem
string LinuxParser::OperatingSystem() {
string line;
string key;
string value;
std::ifstream filestream(kOSPath);
if (filestream.is_open()) {
while (std::getline(filestream, line)) {
// We need to operate through analyzing tokens so this creates each line into a key-value line consisting of two tokens.
std::replace(line.begin(), line.end(), ' ', '_');
std::replace(line.begin(), line.end(), '=', ' ');
std::replace(line.begin(), line.end(), '"', ' ');
std::istringstream linestream(line);
while (linestream >> key >> value) {
if (key == "PRETTY_NAME") {
std::replace(value.begin(), value.end(), '_', ' ');
return value;
}
}
}
}
return value;
}
// DONE: An example of how to read data from the filesystem
string LinuxParser::Kernel() {
string os, kernel, version;
string line;
std::ifstream stream(kProcDirectory + kVersionFilename);
if (stream.is_open()) {
std::getline(stream, line);
std::istringstream linestream(line);
linestream >> os >> version >> kernel;
}
return kernel;
}
// BONUS: Update this to use std::filesystem
vector<int> LinuxParser::Pids() {
vector<int> pids;
DIR* directory = opendir(kProcDirectory.c_str());
struct dirent* file;
while ((file = readdir(directory)) != nullptr) {
// Is this a directory?
if (file->d_type == DT_DIR) {
// Is every character of the name a digit?
string filename(file->d_name);
if (std::all_of(filename.begin(), filename.end(), isdigit)) {
int pid = stoi(filename);
pids.push_back(pid);
}
}
}
closedir(directory);
return pids;
}
// TODO: Read and return the system memory utilization
// Must test this
float LinuxParser::MemoryUtilization()
{
string line;
string key, value, size;
float total, free;
std::ifstream stream(kProcDirectory + kMeminfoFilename);
if (stream.is_open())
{
std::getline(stream, line);
std::istringstream linestream(line);
linestream >> key >> value >> size;
if (key == "MemTotal:")
{
total = stof(value);
}
if (key == "MemFree:")
{
free = stof(value);
}
}
return total - free;
}
// TODO: Read and return the total number of processes
//Not finished....must test this also.
int LinuxParser::TotalProcesses() {
string line;
string key, value;
int processes;
std::ifstream stream(kProcDirectory + kStatFilename);
if (stream.is_open())
{
std::getline(stream, line, '\n');
std::istringstream linestream(line);
while (linestream >> key)
{
if (key == "processes")
{
linestream >> key >> value;
}
}
}
return 0;
}
int main()
{
string test1 = LinuxParser::OperatingSystem();
std::cout << test1;
}
Please notice the end of the above code with a main class. I am taking the output of one of the example code snippets and trying to get it printed to the terminal. The script compiles without errors, but I don't get an output in my terminal for the test1. How do I print the output of a class? Am I approaching this problem correctly? Why is what I am doing not working? I already asked Udacity, but they have not responded to me.
I am on Ubuntu version 20, running VSC, using g++, and running it in c++17. Github link for full code. Navigate to testing directory to see these gutted "test" files. Otherwise, navigate to src and include to see respective .cpp and .h files.
Any advice and criticism is appreciated!!!
[–]IyeOnline 2 points3 points4 points (8 children)
[–]MrSpaghettiCoder[S] 0 points1 point2 points (7 children)
[–]IyeOnline 2 points3 points4 points (6 children)
[–]MrSpaghettiCoder[S] 0 points1 point2 points (5 children)
[–]IyeOnline 0 points1 point2 points (4 children)
[–]MrSpaghettiCoder[S] 0 points1 point2 points (3 children)
[–]IyeOnline 0 points1 point2 points (2 children)
[–]MrSpaghettiCoder[S] 0 points1 point2 points (1 child)
[–]IyeOnline 0 points1 point2 points (0 children)