cppunit only accept return value zero - c++

I am new to CPPUnit testing and have written test for login authentication function with various test cases. But it only accepts return value zero.
The first test case should return 1 if expected and actual are the same but it only works when I change to zero. Any advice is appreciated. Thanks.
void POSUnitTest::testAuthenticate()
{
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser","password"),1); // valid username and password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser1","password"),0); //invalid username, valid password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser","password1"),0); //valid username, invalid password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser1","password1"),0); // invalid username and password
CPPUNIT_ASSERT_EQUAL (console.Authenticate(" ","password"),0); // Empty username, valid password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser",""),0); // Valid username, empty password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("",""),0); // Empty username and password
cout << "Test 3) testAuthenticate successful.\n\n";
}
This is my Authenticate function in class POSConsole.
int POSConsole::Authenticate(string _userID, string _password)
{
bool failedLogin=false;
int returnValue=0;
_password = Encrypt (_password); //Encrypt user enter password to compare with vector
for (int index = 0; index < cashierVector.size(); index++)
{
if ( (_userID == cashierVector[index].getUserID()) &&
(_password == cashierVector[index].getPassword()))
{
returnValue=1;
system("clear");
POSMenu();
break;
}
else
{
returnValue=0;
cout << "Invalid user login information. Please try again.\n";
failCount++;
break;
}
}
return returnValue;
if (failCount == 3)
{
cout << "You have used maximum attempts to login. Your account has been locked." << endl;
exit (0);
}
}
Edited:
I think I have found the problem. My vector size shows zero when I run CPPUnit testing. I have a function to read text file data to vector. So I called the function from CPPUnit testAuthenticate function. All test cases are passed now but other unit test functions became invisible. They are not seen by the compiler if that makes senses. I have total 10 test functions but only two is being processed. I do not get any output from other test cases at all, not even fail error.
How do I solve this, please? Appreciate your help as I'm stuck in this for days now.
void POSUnitTest::testAuthenticate()
{
console.readData();
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser","password"),1); // valid username and password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser1","password"),0); //invalid username, valid password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser","password1"),0); //valid username, invalid password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser1","password1"),0); // invalid username and password
CPPUNIT_ASSERT_EQUAL (console.Authenticate(" ","password"),0); // Empty username, valid password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("testuser",""),0); // Valid username, empty password
CPPUNIT_ASSERT_EQUAL (console.Authenticate("",""),0); // Empty username and password */
cout << "Test 3) testAuthenticate successful.\n\n";
}
Here's the amended function:
int POSConsole::Authenticate(string _userID, string _password)
{
bool validUser=false;
bool failedLogin=false;
int returnValue=0;
_password = Encrypt (_password);
int vectorzie = cashierVector.size();
cout << "\nVector size" << vectorzie << endl;
for (int index = 0; index < cashierVector.size(); index++)
{
if ( (_userID == cashierVector[index].getUserID()) &&
(_password == cashierVector[index].getPassword()))
{
validUser = true;
returnValue=1;
cout << "\nOk Login Return Value: " << returnValue; //this show 1
system("clear");
POSMenu();
break;
}
}
if (validUser=false) //I have changed to this from else statement
{
failedLogin=true;
returnValue=2;
cout << "\nfail Login Return Value: " << returnValue;
cout << "\nInvalid user login information. Please try again.\n";
failCount++;
cout << "\nfail count: " << failCount << endl;
}
cout << "Final Login Return Value: " << returnValue;
if (failCount == 3)
{
cout << "You have used maximum attempts to login. Your account has been locked." << endl;
exit (0);
}
return returnValue;
}

You have a break statement for both cases of the if ... else. Therefore your loop will always end after comparing to the first element of cashierVector.
If you remove both break, then your loop will keep running even if the user was already found and returnValue will be reset to 0 again.
You need to remove the break in the else-block only. In fact your else block should only be executed if no user/password combination in cashierVector matches. So it should be placed after the loop, not in it.
The block after return returnValue will never be reached by the function, because it already has returned at that point. You need to move it before the return statement. However if you do so, then your unit test will never succeed, because after the third call to Authenticate with the wrong password (as you do in the test) the program will exit via exit(0).
On a side node: This is a use case for a map instead of a vector. If you have many users then the search will take very long. In a map this is much faster and you don't need a loop.
After your edit:
if (validUser=false). Here you assign false to validUser and then test the return, which is false. Consequently this if block will never be executed. You should change it to if(validUser==false) or better if(!valid_user). You are also missing a return statement in that block. If it is executed you don't want the following part to be executed, too.

Related

How to check if a string matches an array element?

I'm fairly new to programming, and I'm wondering if there's any way I can compare a string input to an array element? I tried the code below, and I know it's wrong, I just don't know how else to go about this.
#include <iostream>
using namespace std;
int main()
{
string Username[10] = {"name1", "name2", "name3", "name4", "name5", "name6", "name7", "name8", "name9", "name10"};
string login;
int i;
cout << "Enter username login: ";
getline(cin, login);
cout << "\n";
for (i = 0; i < 10; i++)
if (login == Username[i])
{
cout << "Loading user settings...";
}
else
cout << "Error: Wrong username entered. ";
return 0;
}
You can avoid the loop and use the std::find algorithm function.
#include <algorithm>
//...
bool exists = (std::find(std::begin(Username), std::end(Username), login)
!= std::end(Username));
I imagine what you want to see is "Loading user settings..." if there is a match, and "Error: Wrong username entered. " if there is no match. Your if-statement should look like this:
if (login == Username[i]){
cout << "Loading user settings...";
break;
}
and your else-statement should be an else-if in the form of:
else if(i==9) cout << "Error: Wrong username entered. ";
Two things:
1) break functions in a way such that, when the program sees a break, it ends the loop that it is currently using. When you find a match, you don't have to look any farther in the array, so break out of it.
2) You only want to print error if you have looked through the entire array, and that will only happen after you have checked the last element which, in this case, is at index 9. Changing the else to an else-if lets you specify this condition.
You should use an algorithm, like this:
if (std::find(Username, Username + 10, login) != (Username + 10))
cout << "Loading user settings...";
else
cout << "Error: Wrong username entered. ";
You can use a bool flag to check if the user exists or not:
Running sample
//...
bool exists = false;
//...
for (i = 0; i < 10; i++)
if (login == Username[i])
{
exists = true;
break;
}
exists ? std::cout << "Loading user settings..." : std::cout << "Error: Wrong username entered. ";
//...
On a side note, see Why is "using namespace std;" considered bad practice?

Cin is not working with array of chars

When I try to get from user a username, I make the following:
#include <iostream>
using namespace std;
void main(){
char *usrn=new char[20]; //Max username length of 20 alfanumeric characters
std::string usrn_str;
while (true){
std::cout << "Enter the username(3-20 characters): ";
cin.clear();
cin.ignore();
std::cin.getline(usrn,22);
usrn_str=usrn;
if ((usrn_str.length())<3){
cout << "Introduced username too short!" << endl;
}
else if ((usrn_str.length())>=21){
cout << "Introduced username too long!" << endl;
}
else {
cout << usrn_str.c_str() ;
}
}
}
Anyway, when introducing a larger username than the allowed one, i.e 25, it shows me the message that the introduced username is too long, but in the next loop, I can't enter again the username, because it takes as I've entered the last 5 characters in the mentioned example. Summing up, if I enter a 30 length username, it discards the first 20 and sets the last 10 ones as the username, when I want to be asking the username till I get a 3-20 length username.
How could I implement it? Any help is appreciated.
Use std::getline() to read the whole user input (user input is line based). Then do the validation checkes against the input line.
bool finished = false;
std::string name;
do
{
if (std::getline(std::cin, name))
{
// You have successfully read one line of user input.
// User input is line based so this is usually the answer to
// one question.
//
// Do your validation checks here.
// If the user entered data that checks out then set
// finished to true.
}
else
{
// There was a problem reading the line.
// You need to reset the stream to a good state
// before proceeding or exit the application.
}
}
while(!finished);

How would I have string validate just the ENTER key being hit?

void Game::validate(string& str1)
{
bool exit = false;
int strLength = str1.length();
while (exit == false)
{
for (int i = 0; i < strLength; i++)
{
if(!isalpha(str1[i]) || isspace(str1[i])) //|| str1.empty())//?
{
cout << "Not a valid name, please try again: " << endl;
getline(cin, str1);
}
else if(isalpha(str1[i]))
{
exit = true;
}
}
}
I am passing down a string,i need to output the error message
if the user hits the Enter key only*. Ive tried using '\n' but isspace should take care of that(which it dosent). When i run the program and hit ENTER only, it freezes...whats wrong with it??? All other validation works except the ENTER key
Blockquote
try and print out your string before you start checking and you'll probably
see that the string is not empty even though enter key was the only input.
before you have the user input try and flush the stream.
try std::cout<<endl;

How to make Do function only repeat password input

I finally figured out how to make the function I was looking for, however the issue I am having is I would like to have it only repeat asking for the password input, instead of both the username and password.
#include "stdafx.h"
#include <iostream> // library that contains basic input output functions
#include <string> // library for c++ strings
using namespace std;
int main()
{
//Username and Password to validate credentials
const string USERNAME = "myself";
const string PASSWORD = "stanley";
const string USERNAME2 = "otherperson";
const string PASSWORD2 = "otherpassword";
//strings in which user will enter username and password
string username, password;
int passattempts = 0;
do{
// Prompting user to input username
cout << "Enter Username : ";
cin >> username;
//Checking if username length is less than 4 characters then display an error message
if (username.length() < 4)
{
cout << "Username length must be atleast 4 characters long.";
}
else //if username length is greater than 3
{
//promprting user for password
cout << "Enter Password : ";
cin >> password;
//Checking if password length is less than 6 characters then display an error message
if (password.length() < 6)
{
cout << "Password length must be atleast 6 characters long.";
}
else //if password length is greater than 5
{
//Checking if user's entered credentials are equal to actual USERNAME and PASSWORD
if (username == USERNAME && password == PASSWORD || username == USERNAME2 && password == PASSWORD2)
{
cout << "User credentials are correct!!!" << endl;
break;
}
else
{
cout << "Invalid login details" << endl;
++passattempts;
}
}
}
} while (passattempts != 3);
system("pause");
return (0);
}
Then put the entry (and check on) the username outside the password do loop.
You can always put those inside another do loop if you want to allow the user to re-enter a username that is too short. There's no rule that says you're only allowed one loop :)
something like (pseudo code)
do
{
prompt for username
read username
} while (username invalid)
do
{
prompt for password
read password
} while (password invalid)
There's a philosophical argument to be had about whether or not you tell the user why their data is invalid. I'm not being drawn into that, security people can get a bit... intense.

C++ function runs more than intended

When I run my program the user can log in, but if the enter in a wrong user name, it runs a check username loop again, saying that they did not enter in a valid user name. This work perfectly fine except for one thing. Say they attempt to log in in three times and the third attempt is correct and the get prompted for a password. Once they input it it ask for a second password and then a third. It seems like it is completing the function for the other attempts. I can not think of a way to check for this. Any ideas.
If you look at it you can see that I am calling UserCheck inside of getNameIndex. I am almost positive this is where the error is occurring.
The Function that checks the users:
void User_Psw::UserCheck()
{
// read from the database
ifstream fin("dataBase.txt", ios::in);
if( !fin.good() )
{
cout << "Failed to open database file." << endl;
return;
}
while (fin >> username >> password)
{
Usernames.push_back(username);
Password.push_back(password);
++sizeOfDatabase; // This may or may not be needed elsewhere.
}
// rest of the program
cout << "Username: ";
cin >> username;
getNameIndex();
cout << "Password: ";
cin >> password;
if(!PasswordMatches())
{
cout << "Access denied";
}
else
{
cout << "Success! You have logged in.";
}
}
This is the username check function
void User_Psw::getNameIndex()
{
userThere = false;
for(int i=0; i < sizeOfDatabase; i++)
{
if (Usernames[i] == username)
{
index = i;
userThere = true;
}
}
if (userThere == false)
{
cout << "\nThat user name does not exsist. \n";
cout << "Please try again. \n\n";
UserCheck();
}
}
The structure of your program is wrong.
Instead of getNameIndex calling UserCheck() again, you should have getNameIndex return a bool - true on success, false on failure. Run it inside of a loop, something like this:
bool success = false;
while (!success)
{
cout << "Username: ";
cin >> username;
success = getNameIndex();
}
Also, instead of having global variables, you should pass them to the function. Something like:
success = getNameIndex(username);
and getNameIndex() shouldn't do any I/O - the function that calls getNameIndex() should also be responsible for printing the error message. Imagine if you used getNameIndex() in a different context, such as when when the program is being run by another program or in an automated way - then printing to the console would be meaningless.