1

I'm currently writing some JUnit tests for some assignments on Replit.com's Teams for education. I have a test that's getting stuck, I believe, because of a while loop in the main method. If the first input is valid, according to the program, the test runs. If the first input is invalid, the test gets stuck.

Here's the test:

@Test
public void validPW(){
String correctOutput = "Enter a password >>  Not enough uppercase letters!\nNot enough digits!\nReEnter a password >> Valid password\nGoodbye!";
  try{
    // IMPORTANT: Save the old System.out!
    PrintStream old = System.out;

    // Create a stream to hold the output
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    //PrintStream ps = new PrintStream(baos);
    System.setOut(new PrintStream(baos, false, "UTF-8"));

    // IMPORTANT: save old Sytem.in!
    InputStream is = System.in;

    // Set new System.in
    System.setIn(new ByteArrayInputStream("Iljvm4\nVaGN76js\n".getBytes()));

    // Calling main method should save main method's output as string literal to baos.
    String[] requiredArray = {"Hello", "There"};
    ValidatePassword.main(requiredArray);

    // Put things back
    System.out.flush();
    System.setOut(old);

    //Restore
    System.setIn(is);


    assertEquals(correctOutput, baos.toString());
  }catch(IOException ioe){
     new IOException("i/o problem - test not executed\n");
   }
}

Here's the program:

import java.util.*;

public class ValidatePassword {
    public static void main(String[] args) {

        String passWord;
        boolean Valid = false;

        final int NUM = 2; // two digits and two Upper case letters
        // counters to count the required digits and letters
        int upperCount = 0;
        int lowerCount = 0;
        int digitCount = 0;

        while (!Valid) {
            
            Scanner in = new Scanner(System.in);
            int numSpaces = 0;
            System.out.print("Enter a password >> ");
            passWord = in.next();
            in.nextLine(); // capture dangling newline char.
            // Using a for loop to iterate over each character in the String
            for (int i = 0; i < passWord.length(); i++) {
                char ch = passWord.charAt(i);
                if (Character.isUpperCase(ch)){ // Using the Character class's methods
                    upperCount++;
                }
                else if (Character.isLowerCase(ch)){
                    lowerCount++;
                }
                else if (Character.isDigit(ch)){
                    digitCount++;
                }
            }

            if (upperCount >= NUM && lowerCount >= 3 && digitCount >= NUM) {
                System.out.println("Valid password\nGoodbye!");
                Valid = true;   
            } else {                
                if (upperCount < NUM)
                    System.out.println("Not enough uppercase letters!");
                if (lowerCount < 3)
                    System.out.println("Not enough lowercase letters!");
                if (digitCount < NUM)
                    System.out.println("Not enough digits!");
                System.out.print("Re");
                // Resetting the counters if not a valid password
                upperCount = 0;
                lowerCount = 0;
                digitCount = 0;

            }            
        }
    }
}
Squanch
  • 13
  • 6
  • Try https://stackoverflow.com/questions/8743594/whats-the-best-way-to-set-up-a-per-test-or-per-class-timeout-when-using-junit – Brian Hoover Jun 09 '21 at 20:37
  • @BrianHoover , thanks! However, Replit's JUnit feature doesn't seem to allow the specification of any test other than `@Test`. It also won't allow any global variables... kinda weak, but that's what I'm dealing with. – Squanch Jun 09 '21 at 20:52

1 Answers1

0

First, the code in ValidatePassword tries to read the input stream beyond its end, so the scanner initialization needs to be moved out of the loop and a condition in.hasNextLine() needs to be checked.

Also, it's better to use a single reading of the line passWord = in.nextLine(); instead of a pair in.next(); in.nextLine();.

These two fixes should resolve the issue with incorrect loop.

        Scanner in = new Scanner(System.in);
        while (!Valid && in.hasNextLine()) {
            
            int numSpaces = 0;
            System.out.print("Enter a password >> ");
            passWord = in.nextLine();
            //in.nextLine(); // capture dangling newline char.
        // ... keep the rest as is

And the last, correctOutput needs to be fixed for assertEquals to complete successfully.

Nowhere Man
  • 19,170
  • 9
  • 17
  • 42