How to unit test an if else statement - c#

I have the following method. How can I write a unit test for this function to make sure the machine is added to the repairs list?
public void AddMachineToRepairsList()
{
Console.WriteLine("Would you like to add this Machine to the repairs list?");
var addToRepairs = Console.ReadLine().ToLower();
if (addToRepairs == "yes")
{
int cost = 0;
int hoursWorked = 0;
var machine = new Repair(cost, hoursWorked);
Repairs.Add(machine);
Console.WriteLine("Machine successfully added!");
}
else
{
Console.WriteLine("Please enter machine information again");
this.Run();
}
}

You will need to pass addToRepairs as parameter to the method and call like
Console.WriteLine("Would you like to add this Machine to the repairs list?");
var addToRepairs = Console.ReadLine().ToLower();
while(AddMachineToRepairsList(addToRepairs)==false)
{
Console.WriteLine("Please enter machine information again");
this.Run();
}
Definition would be
public bool AddMachineToRepairsList(string option)
{
string addToRepairs = "";
if (addToRepairs == "yes")
{
int cost = 0;
int hoursWorked = 0;
var machine = new Repair(cost, hoursWorked);
Repairs.Add(machine);
Console.WriteLine("Machine successfully added!");
return true;
}
else
{
return false;
}
}
Now one unit tests will be with value "yes" and one with "no" . you
can write unit test and assert the return value is true/false based on option passed

Related

How to unit test code that requires user input c#

its my first time doing unit tests/integration tests and I have a question. So I started doing unit tests for my code, but I have a method, which is actually the logic of the whole application, where multiple methods are called, and user input is required. How can I test that method? Here is the method:
public async Task RunAsync()
{
var watch = System.Diagnostics.Stopwatch.StartNew();
var playAgain = 'y';
do
{
var attempts = 1;
var foundNumber = false;
while (attempts < 10 && foundNumber == false)
{
try
{
var inputNumber = int.Parse(GetInput());
if (inputNumber == _randomNumber)
{
foundNumber = true;
OnSuccesfulGuess(watch, attempts);
}
else if (attempts < 10)
{
OnWrongGuessWithinAttempts(inputNumber);
}
else
{
Console.WriteLine("Oops, maybe next time.");
}
}
catch (Exception ex)
{
Console.WriteLine("Please enter a number");
}
attempts++;
}
playAgain = PlayAgain(playAgain);
_randomNumber = await GetRandomNumber(1, 100);
Log.Information("User wants to play again");
}
while (playAgain == 'y' || playAgain == 'Y');
}
This is the method where i run in my Program class in order to start the application.
Your code is essentially untestable.
The method does too much work. It should be splitted into several smaller ones that can be tested separately.
You should get rid of static methods. Because you can't get them fake.
Getting data over the network (I see using WebSocket), as well as from the database or file system, should be brought out. You should pass ready-made data to this method.
Here is the modified code, broken down into small methods. Logging and events are removed from the code so as not to complicate the explanation.
public class App
{
private readonly Random _random = new Random();
private Task<int> GetRandomNumber(int min, int max)
{
return Task.FromResult(_random.Next(min, max));
}
internal int GetInput()
{
Console.WriteLine("Please guess a number between 1 and 100");
int value;
while (true)
{
string input = Console.ReadLine();
bool result = int.TryParse(input, out value);
if (!result)
Console.WriteLine("Not a number");
else if (value < 1 || value > 100)
Console.WriteLine("Must be between 1 and 100");
else
break;
}
return value;
}
internal bool PlayAgain()
{
Console.WriteLine("Do you want to play again?");
string input = Console.ReadLine();
return input == "Y" || input == "y";
}
internal void Guessing(int randomNumber)
{
int attempts = 1;
while (attempts < 10)
{
var inputNumber = GetInput();
// logging
if (inputNumber == randomNumber)
{
// OnSuccesfulGuess
return;
}
else
{
// OnWrongGuessWithinAttempts
}
attempts++;
}
Console.WriteLine("Oops, maybe next time.");
// logging
}
public async Task RunAsync()
{
do
{
int randomNumber = await GetRandomNumber(1, 100);
Guessing(randomNumber);
}
while (PlayAgain());
}
}
Now we have the ability to test individual methods.
I use MSTest.
[DataTestMethod]
[DataRow("Y")]
[DataRow("y")]
public void PlayAgain_InputY_ReturnsTrue(string value)
{
using (var reader = new StringReader(value))
{
Console.SetIn(reader);
var app = new App();
bool result = app.PlayAgain();
Assert.IsTrue(result);
}
}
[DataTestMethod]
[DataRow("N")]
[DataRow("boo")]
[DataRow("")]
public void PlayAgain_InputNotY_ReturnsFalse(string value)
{
using (var reader = new StringReader(value))
{
Console.SetIn(reader);
var app = new App();
bool result = app.PlayAgain();
Assert.IsFalse(result);
}
}
We do the same with the other methods.
Here are the tests for the GetInput method.
Since there is a loop inside that runs indefinitely when incorrect values are entered, we must interrupt it by entering the correct value. This is done by passing two values via a line feed: "0\n50". Entering an incorrect value is a test of the output string, then interrupting the loop with the correct value.
[DataTestMethod]
[DataRow("1")]
[DataRow("50")]
[DataRow("100")]
public void GetInput_InputCorrectString_ReturnsNumber(string value)
{
using (var reader = new StringReader(value))
{
Console.SetIn(reader);
var app = new App();
int actual = app.GetInput();
int expected = int.Parse(value);
Assert.AreEqual(expected, actual);
}
}
[DataTestMethod]
[DataRow("0\n50")]
[DataRow("101\n50")]
public void GetInput_InputSmallerOrGreaterValue_WritesMessage(string value)
{
using (var reader = new StringReader(value))
using (var writer = new StringWriter())
{
Console.SetIn(reader);
Console.SetOut(writer);
var app = new App();
_ = app.GetInput();
string actualMessage = writer.ToString();
string expectedMessage = "Must be between 1 and 100";
Assert.IsTrue(actualMessage.Contains(expectedMessage));
}
}
[DataTestMethod]
[DataRow("x\n50")]
[DataRow("qwerty\n50")]
public void GetInput_InputNotNumber_WritesMessage(string value)
{
using (var reader = new StringReader(value))
using (var writer = new StringWriter())
{
Console.SetIn(reader);
Console.SetOut(writer);
var app = new App();
_ = app.GetInput();
string actualMessage = writer.ToString();
string expectedMessage = "Not a number";
Assert.IsTrue(actualMessage.Contains(expectedMessage));
}
}
Normally the unit testing methods are made regarding the different results that may return. You can create an interface to handle this method and communicate giving values depending of the output expected (Mocking). Check this post maybe would help!:
How do I apply unit testing to C# function which requires user input dynamically?

Checking whether string is empty, contains int or is an integer

I need to ask the user for his name, surname and other details and I wan't to verify them, basically checking if the string is empty, is an integer, or contains an integer. The problem with this code is let's say I type in "a" it works. And if I type in a2 it shows the correct error message but when I go to type in "a" on its own it keeps repeating the same error message. Any help would be appreciated and a cleaner way to write this would also be appreciated as I have to do this for the surname, email and other fields.
bool check = true;
Console.Write("Enter your name:");
string name = Console.ReadLine();
bool isEmpty = string.IsNullOrEmpty(name);
bool isIntString = name.All(char.IsDigit);
bool containsInt = name.Any(char.IsDigit);
while (check == true) {
if (isEmpty)
{
Console.WriteLine("Name cannot be empty");
Console.Write("Enter your name: ");
name = Console.ReadLine();
}
else if(isIntString)
{
Console.WriteLine("Your name cannot be made up of numbers");
Console.Write("Enter your name: ");
name = Console.ReadLine();
}
else if (containsInt)
{
Console.WriteLine("Your name cannot contain numbers");
Console.Write("Enter your name: ");
name = Console.ReadLine();
}
else if(!isEmpty && !isIntString && !containsInt)
{
check = false;
Console.WriteLine("Name filled");
}
}
Console.WriteLine("Your name is: " + name);
Console.ReadKey();
After reading the input, you are checking for null/empty/integers.
bool isEmpty = string.IsNullOrEmpty(name);
bool isIntString = name.All(char.IsDigit);
bool containsInt = name.Any(char.IsDigit);
However, these checks are placed outside the loop. Once evaluated, the 3 verification variables never changes, even after new input has been read.
For fixing the same, you need to place the checks within the loop.
while (check == true) {
bool isEmpty = string.IsNullOrEmpty(name);
bool isIntString = name.All(char.IsDigit);
bool containsInt = name.Any(char.IsDigit);
// rest of code
To clean up code, you could refactor out the expressions and reading input to create a pattern, which could be reused for other inputs. For example,
void Main()
{
bool check = true;
var name = ReadInput("Enter your name:",ValidationExpressionsForName);
// var surname = ReadInput("Enter your SurName :",ValidationExpressionsForSurName);
// so on
Console.WriteLine("Your name is: " + name);
}
public string ReadInput(string inputMessage,Func<string,IEnumerable<EvaluationExpression>> evaluationExpression)
{
while (true)
{
Console.Write(inputMessage);
string term = Console.ReadLine();
if(evaluationExpression(term).Any(x=>x.Expression()))
{
Console.WriteLine(evaluationExpression(term).First(x=>x.Expression()).Message);
}
else
return term;
}
}
public IEnumerable<EvaluationExpression> ValidationExpressionsForName(string message) => new EvaluationExpression[]
{
new EvaluationExpression{ Expression = ()=>String.IsNullOrWhiteSpace(message), Message= "Name cannot be empty"},
new EvaluationExpression{ Expression = ()=>message.All(char.IsDigit),Message ="Your name cannot be made up of numbers"},
new EvaluationExpression{ Expression = ()=>message.Any(char.IsDigit),Message="Your name cannot contain numbers"}
};
public class EvaluationExpression
{
public Func<bool> Expression{get;set;}
public string Message{get;set;}
}
Checking if a string is Null, Empty or WhiteSpace is relatively easy:
https://learn.microsoft.com/en-us/dotnet/api/system.string.isnullorwhitespace
Checking if it is a Number can be done. Just feed it to Int32.TryParse() and see if it can make sense of the input.
If it contains a anumber? Checkable, but not easily. You could itterate over all Characters in the string and check if any of them parse to Int. Note that this cheeck would supersede/make unessesary the previous check too. I made it into a simple function:
public bool IsValidName(String input){
if(String.IsNullOrWhiteSpace(input)){
return false;
}
foreach (char current in input){
int ignore;
//TryPrase will not take Chars, but turning it into a string should be this easy
String currentString = current.ToString();
if(Int32.TryParse(currentString, out ignore))
return false;
}
//You only get here if none of hte false cases was trigerred
return true;
}
All of this might be solveable with a single Regular Expression too, but I am not that good at Regex.
With small changes to your code:
string name;
while (true)
{
Console.Write("Enter your name:");
name = Console.ReadLine();
bool isEmpty = string.IsNullOrEmpty(name);
bool isIntString = name.All(char.IsDigit);
bool containsInt = name.Any(char.IsDigit);
if (isEmpty)
{
Console.WriteLine("Name cannot be empty");
}
else if (isIntString)
{
Console.WriteLine("Your name cannot be made up of numbers");
}
else if (containsInt)
{
Console.WriteLine("Your name cannot contain numbers");
}
else
{
Console.WriteLine("Name filled");
break;
}
}
Console.WriteLine("Your name is: " + name);
Console.ReadKey();
With variable term:
static string GetUserInput(string term)
{
string name;
while (true)
{
Console.Write($"Enter your {term}:");
name = Console.ReadLine();
bool isEmpty = string.IsNullOrEmpty(name);
bool isIntString = name.All(char.IsDigit);
bool containsInt = name.Any(char.IsDigit);
if (isEmpty)
{
Console.WriteLine("Cannot be empty");
}
else if (isIntString)
{
Console.WriteLine("Cannot be made up of numbers");
}
else if (containsInt)
{
Console.WriteLine("Cannot contain numbers");
}
else
{
Console.WriteLine($"Your {term} filled");
break;
}
}
Console.WriteLine($"Your {term} is: {name}");
return name;
}
Your code fails here. It goes into this else block displays the error message and then reads from the console again. while check still being true and isIntString still true it again lands up in this block. You need to correct it for all the three checks you have placed on the the string.
else if(isIntString)
{
Console.WriteLine("Your name cannot be made up of numbers");
isIntString = false; // to prevent going into this block again
Console.Write("Enter your name: ");
name = Console.ReadLine();
}

C# how to set a conditional statement to except user input?

I have a simple console App that converts pounds to kilograms and vice-versa. What I'm attempting to do is if the user enters lb then run the function to convert pounds to kilograms, else if the user enters kg, then run the function to convert kilograms to pounds.
During the setup part of the condition in main, I get an error "Use of unassigned local variable 'lb'
...The Code (snippets):
//method to convert KG to Lbs
public void ConvertKg()
{
Console.WriteLine("C# KG to LB program\n");
Console.Write("Enter a number in KG: ");
double kilograms = Convert.ToDouble(Console.ReadLine());
double pounds = kilograms * 2.20462262185;
Console.WriteLine(kilograms + " kilograms is " + pounds + " pounds");
}
//method to convert Lbs to KG
public void ConvertLb()
{
Console.WriteLine("C# LB to KG program\n");
Console.Write("Enter a number in lbs:");
double pounds_userEntry = Convert.ToDouble(Console.ReadLine());
double kilogram_userEntry = pounds_userEntry * 0.453592;
Console.WriteLine(kilogram_userEntry + " kilograms is " + pounds_userEntry + " pounds");
}
...main:
string lb, kg;
string userInput = "";
Console.Write("Enter either lb or kg:");
if(userInput == lb) // where the error occurs
{
var k = new ConvertNumber();
k.ConvertLb();
}
else
{
var l = new ConvertNumber();
l.ConvertKg();
}
Console.ReadLine();
...the problem seems to be within the approach I'm using to set up the conditional statement to accept the user's input. ...could I get some help as to what I'm doing wrong?
There is no need to do string lb, kg;, so you can leave it out.
userInput is assigned to "", but it should probably contain something from the user.
Replace
string userInput = "";
with
Console.Write("Enter either kg or lb: ");
string userInput = Console.ReadLine() // Console.ReadLine enables the user to type some text and returns it
Because
Console.Write("Enter either kg or lb");
has been done now, you can leave it out afterwards.
Now you can compare userInput with "lb" and "kg".
Replace
if(userInput == lb)
{
var k = new ConvertNumber();
k.ConvertLb();
}
else
{
var l = new ConvertNumber();
l.ConvertKg();
}
Console.ReadLine();
with
if (userInput == "lb") {
ConvertLb();
} else if (userInput == "kg") {
ConvertKg();
} else {
Console.WriteLine("Your input was neither lb nor kg");
}
Final code (main):
Console.Write("Enter either kg or lb: ");
string userInput = Console.ReadLine() // Console.ReadLine enables the user to type some text and returns it
if (userInput == "lb") { // The user typed "lb"
ConvertLb();
} else if (userInput == "kg") { // The user typed "kg"
ConvertKg();
} else { // The user typed neither "lb" nor "kg"
Console.WriteLine("Your input was neither lb nor kg");
}
As the comments are mentioning, you have to either initialize the lb variable with "lb" or to compare the userInput directly to the string "lb" as Rakesh is writing in comments.
Also I've seen that you don't read the user input.
Below I've created a quick sample code that should do the job that you expect and should be easy to understand.
class Program
{
public const string Lb = "lb"; //User options as constants
public const string Kg = "kg";
static void Main(string[] args)
{
string userInput = GetUserInput();
try
{
ConvertUserInput(userInput);
}
catch (ArgumentException ex)
{
Console.WriteLine(ex.Message); // Show error message
userInput = GetUserInput(); // Get user input again
ConvertUserInput(userInput);
}
Console.ReadLine();
}
private static string GetUserInput()
{
Console.Write("Enter either lb or kg:");
string userInput = Console.ReadLine();
return userInput;
}
private static void ConvertUserInput(string userInput)
{
// Guard for throwing an error when the user enters another value
if (!IsValidUserInput(userInput))
throw new ArgumentException("Input value is not lb or kg");
if (ConvertFromPoundsToKg(userInput)) // where the error occurs
{
var k = new ConvertNumber();
k.ConvertLb();
}
else
{
var l = new ConvertNumber();
l.ConvertKg();
}
}
/// <summary>
/// userInput is either "lb" or "kg"
/// </summary>
/// <param name="userInput"></param>
/// <returns></returns>
private static bool IsValidUserInput(string userInput)
{
return ConvertFromPoundsToKg(userInput) || (ConvertFromKgToPounds(userInput));
}
private static bool ConvertFromKgToPounds(string userInput)
{
return userInput == Kg;
}
private static bool ConvertFromPoundsToKg(string userInput)
{
return userInput == Lb;
}
}
The problem is that the variable lb is not initialized. It doesn't have a value that you could compare against. I've changed your code to solve this problem. Next steps would be to get the "number" the user entered before the unit and pass it to a unit coversion function and output it to the user again. This will be left for you to do ;)
class Program
{
static void Main(string[] args)
{
//string lb, kg;
//string userInput = "";
Console.Write("Enter either lb or kg:");
string input = Console.ReadLine();
string unit = input.Substring(input.Length-2);
if (unit == "lb") // where the error occurs
{
int k = ConvertNumber();
Console.WriteLine(k + "kg");
//k.ConvertLb();
}
else if (unit == "kg")
{
int l = ConvertNumber();
Console.WriteLine(l + "lb");
//l.ConvertKg();
}
else
{
Console.WriteLine("invalid unit");
}
Console.ReadLine();
}
static int ConvertNumber()
{
Console.WriteLine("convert");
return 123;
}
}

Not all code paths return a value when they should

Trying to complete a stock system in a console application and thus I am stuck on this part, to make sure that a user can't have a duplicate 8 digit long ID number, my issue is as follows.
Basically I am unsure why this code will not work, I'm probably missing a very obvious piece of code here, help would be appreciated, have tried changing values around already so have more than likely overlooked a value.
static int checkIDNumber(int ID)
{
// Check the number passed in & then loop through all the lines...
// If number is taken then output error, because id exists already
// Else allow the value to be used in the stock system.
int IDNumber = ID;
using (StreamReader sr = new StreamReader("Stockfile.txt"))
{
string lineValues;
while (sr.EndOfStream == false)
{
lineValues = sr.ReadLine();
if (lineValues.Contains(IDNumber.ToString()))
{
Console.WriteLine("Id number is currently already taken.");
}
else
{
return IDNumber;
}
}
}
}
I pass in my value from this line in another procedure where it is defined in the local scope.
stockID = checkIDNumber(stockID);
Here is the full code:
class Program
{
static void Main(string[] args)
{
char menuOption = '0';
while (menuOption != '3')
{
DisplayMenuOption();
menuOption = GetMenuOption();
switch (menuOption)
{
case '1':
AddStock();
break;
case '2':
CheckStock();
break;
case '3':
Console.WriteLine("Goodbye");
break;
default:
Console.WriteLine("That is not a valid option");
break;
}
}
// Keep it all happy for a screenshot ;)
Console.ReadLine();
}
static void DisplayMenuOption()
{
Console.WriteLine("Do you wish to Add Stock(1) or Check Stock(2) or Exit(3)?");
}
static void DisplayStockOption()
{
Console.WriteLine("Do you want to search by ID(1) or by Name(2), Delete current stock(3) or Exit(4)?");
}
static char GetMenuOption()
{
char userChoice = '0';
userChoice = Convert.ToChar(Console.ReadLine());
return userChoice;
}
static void CheckStock()
{
char menuOption = 'a';
while (menuOption != '4')
{
DisplayStockOption();
menuOption = GetMenuOption();
switch (menuOption)
{
case '1':
SearchID();
break;
case '2':
SearchName();
break;
case '3':
RemoveStock();
break;
case '4':
Console.WriteLine("Goodbye");
break;
default:
Console.WriteLine("That is not a valid option");
break;
}
}
}
static void RemoveStock()
{
List<string> tempList = new List<string>();
string lineValues = "";
bool found = false;
int ID = 0;
using (StreamReader sr = new StreamReader("Stockfile.txt"))
{
Console.Write("Please enter the ID number to delete: ");
ID = Convert.ToInt32(Console.ReadLine());
while (sr.EndOfStream == false)
{
lineValues = sr.ReadLine();
if (lineValues.Contains(ID.ToString()) == false)
{
tempList.Add(lineValues);
}
else
{
found = true;
}
}
}
if (found == true)
{
using (StreamWriter sw = new StreamWriter("Stockfile.txt", false))
{
for (int i=0; i < tempList.Count; i++)
{
sw.Write(tempList[i]);
sw.WriteLine();
}
}
}
}
static void SearchName()
{
using (StreamReader sr = new StreamReader("Stockfile.txt"))
{
string name;
Console.Write("Please enter the name: ");
name = Console.ReadLine();
while (sr.EndOfStream == false)
{
string lineValues = sr.ReadLine();
if (lineValues.Contains(name))
{
Console.WriteLine("{0}", lineValues);
}
else
{
Console.WriteLine("{0} does not exist in this stock system!",name); // Could try to match a similar string incase of spelling errors here, although after looking at it it may be a bit far for what is being required now, but in the real world application this would be a must else people would mistype words thus not having an exact match.
}
}
}
}
static void SearchID()
{
using (StreamReader sr = new StreamReader("Stockfile.txt"))
{
int IDNumber;
string lineValues;
Console.Write("Please enter the ID number: ");
IDNumber = Convert.ToInt32(Console.ReadLine());
while (sr.EndOfStream == false)
{
lineValues = sr.ReadLine();
if (lineValues.Contains(IDNumber.ToString()))
{
Console.WriteLine("{0}", lineValues);
}
else
{
Console.WriteLine("{0} does not exist in this stock system!", IDNumber); // Could try to match a similar string incase of spelling errors here, although after looking at it it may be a bit far for what is being required now, but in the real world application this would be a must else people would mistype words thus not having an exact match.
}
}
}
}
static int checkIDNumber(int ID)
{
// Check the number passed in & then loop through all the lines...
// If number is taken then output error, becuase id exists already
// Else allow the value to be used in the stock system.
using (StreamReader sr = new StreamReader("Stockfile.txt"))
{
int IDNumber;
string lineValues;
Console.Write("Please enter the ID number: ");
IDNumber = Convert.ToInt32(Console.ReadLine());
while (sr.EndOfStream == false)
{
lineValues = sr.ReadLine();
if (lineValues.Contains(IDNumber.ToString()))
{
Console.WriteLine("Id number is currently already taken.");
}
else
{
ID = IDNumber;
return ID;
}
}
}
}
static void AddStock(int IDNumber)
{
using (StreamWriter sw = new StreamWriter("Stockfile.txt", true))
{
int stockID = 0;
int stockQuantity = 0;
double stockPrice = 0.00;
string stockName = "";
string s = ""; // Being Lazy here, to convert to when needed.
while (stockID.ToString().Length != 8)
{
Console.Write("Please enter the stock ID number: ");
stockID = Convert.ToInt32(Console.ReadLine());
}
s = stockID.ToString();
sw.Write(s + "\t"); // Will only accept an 8 figure digit so is safe to have a single value here.
while (stockName.Length <= 2) // No fancy brands here......
{
Console.Write("Please enter the name of the stock: ");
stockName = Console.ReadLine();
}
s = stockName;
sw.Write(s + "\t");
while (stockQuantity < 1) // Running a small shop here...
{
Console.Write("Please enter the quanity of stock: ");
stockQuantity = Convert.ToInt32(Console.ReadLine());
}
s = stockQuantity.ToString();
sw.Write(s + "\t");
while (stockPrice < 0.01) // Running a very small shop....
{
Console.Write("Please enter the price of the stock: ");
stockPrice = Convert.ToDouble(Console.ReadLine());
}
s = stockPrice.ToString();
sw.Write(s + "\t");
sw.WriteLine(); // TO create the new line.....
}
}
}
}
The problem is that you're only returning a value from inside the else block.
Your method needs to return a value regardless of which path the program takes through your code. You can fix this in any number of ways, depending on your requirements. For instance, you can have a "catch-all" return value at the bottom of the method so that if it passes through all your tests (i.e. if blocks) and reaches the bottom, as long as that's a meaningful result, it will return the catch-all value.
Alternatively, you could just make sure you put a return statement inside each of the code paths. For that, you'd need to add a return in the if portion of your if block, but you'd likely also still need a return outside of your while loop since that may never execute.
Again, it all depends on your needs.
It's at least logically possible that the file contains nothing but the ID. For example, if I enter "10" as an ID and the file is:
10
10
10
10
...
It might be the case that you know that that'll never actually happen, but the compiler can't really prove that it won't. From the compiler's "perspective," there's not really a difference between "might happen" and "can't prove that it won't happen."
Also, your logic is wrong. If you know that the user requested a duplicate ID, you don't need to check the rest of the file - you already know it's a duplicate.
Right now, if the first line of the file isn't the ID they requested, it'll allow the user to take it. For example, if the user requested "9" as an ID and the file is as follows:
3 -- It only actually checks this line
5
9 -- Obviously the ID is already taken here but it'll never check this line
2
1
See my comments below:
// I'd suggest making this "bool" - they already know what the ID number is,
// so there's no point in returning it back to them
static int checkIDNumber(int ID)
{
// Check the number passed in & then loop through all the lines...
// If number is taken then output error, because id exists already
// Else allow the value to be used in the stock system.
int IDNumber = ID;
using (StreamReader sr = new StreamReader("Stockfile.txt"))
{
string lineValues;
// In general, you shouldn't explicitly compare to "true" or "false."
// Just write this as "!sr.EndOfStream"
while (sr.EndOfStream == false)
{
lineValues = sr.ReadLine();
if (lineValues.Contains(IDNumber.ToString()))
{
// In this case, you don't have to bother checking the rest of the file
// since you already know that the ID is taken
Console.WriteLine("Id number is currently already taken.");
}
else
{
// You actually can't return that at this point - you need to check
// the *entire* file before you conclude that it's not a duplicate
return IDNumber;
}
}
}
}

How to store a variable by using a method in C#?

I have a few problems with the code below. I'm still learning and I don't know how to fix it.
1 .-What I'm trying to do is create a method (GetInt) to store variables like I'm trying to do in the second method (GetTrack) that will go into my main method.
2.-I can't get the GetInt method to loop when theres an invalid input, I'm guessing there's something wrong with the try/catch and boolean thingy
Thank you
//Get int Method
static public void GetInt(string sPrompt, int iMin, int iMax)
{
int iNum;
bool bError = false;
do
{
bError = true;
try
{
Console.Write(sPrompt);
iNum = int.Parse(Console.ReadLine());
if ((iNum < iMin) || (iNum > iMax))
{
Console.WriteLine("The value is out of range.");
bError = true;
}
}
catch (ArgumentException)
{
Console.WriteLine("An invalid number was entered, please try again.");
bError = true;
}
}
while (bError == false);
}
//Get Track Method
static public void GetTrack()
{
int iMin;
int iSec;
iMin = GetInt("Enter the minutes: ", 0, 10);
iSec = GetInt("Enter the seconds: ", 0, 59);
}
Immediately in the beginning of GetInt you set bError to true. This most likely should be false so you would actually loop since nowhere do you set it to false.
Also you don't return anything from the method so you don't get anything back. You have to change the method to return int and actually return the value when you get it.
The declaration of your GetInt method should be changed to the following:
//Get int Method
static public int GetInt(string sPrompt, int iMin, int iMax)
Remove the bError = true; statement from the beginning of your do...while loop.
After your do...while loop, add the following statement:
return iNum;
Also, your while condition should be changed from bError == false to bError == true or simply to bError, which means the same thing, if your intent is to keep prompting the user until the input is acceptable.
Here is how I "get" user input from the console:
string choice = string.Empty;
bool goodChoice = false;
while (!goodChoice)
{
Console.Clear();
Console.WriteLine(string.Empty);
Console.WriteLine("Do you really want to hurt me?");
Console.WriteLine(string.Empty);
Console.WriteLine(string.Empty);
Console.WriteLine("Please Y or N (or 0 to exit)");
choice = Console.ReadLine().Trim();
if (choice.Equals("Y", StringComparison.OrdinalIgnoreCase))
{
goodChoice = true;
}
if (choice.Equals("N", StringComparison.OrdinalIgnoreCase))
{
goodChoice = true;
}
if (choice.Equals("0"))
{
goodChoice = true;
return; /* exist the routine */
}
}
Modified for your case
string choice = string.Empty;
bool goodChoice = false;
while (!goodChoice)
{
Console.Clear();
Console.WriteLine(string.Empty);
Console.WriteLine("Enter an Integer between {0} and {1}", minValue, maxValue);
Console.WriteLine(string.Empty);
Console.WriteLine(string.Empty);
Console.WriteLine("Please enter an integer (or X to exit)");
choice = Console.ReadLine().Trim();
int intParseResult = 0;
bool intParseAttempt = int.TryParse(choice, out intParseResult);
if(!intParseAttempt)
{
goodChoice = false;
}
else
{
if ((intParseResult < minValue) || (intParseResult > maxValue))
{
Console.WriteLine("Out of Range");
}
else
{
goodChoice = true;
}
}
if (choice.Equals("X"))
{
goodChoice = true;
return -99999; /* you'll have to figure out how to handle exits on your own */
}
}

Categories

Resources