<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Scanner;
import static org.junit.jupiter.api.Assertions.*;

/**
 * Class to test the functionality of the Frontend class using JUnit5.
 */
public class FrontendTests {

    // Instance variables to test with
    private Frontend frontend;
    private BackendInterface backend; 
    private ByteArrayOutputStream outputStream;

    /**
     * Class to set up tests
     */
    @BeforeEach
    public void setup() {

        backend = new Backend(new IterableRedBlackTree&lt;Song&gt;());
        outputStream = new ByteArrayOutputStream();

        // Allow for printed output can be captured
        System.setOut(new PrintStream(outputStream));

        // Initialize Frontend 
        frontend = new Frontend(new Scanner(System.in), backend);
    }

     /**
     * Method to test the displayCommandInstructions() method.
     */
    @Test
    public void frontendTest1() {
      
        // Call the method that prints the instructions.
        frontend.displayCommandInstructions();
        String output = outputStream.toString();


        // Check for key commands
        assertTrue(output.contains("load FILEPATH"), "Output is wrong");
        assertTrue(output.contains("danceability"), "Output is wrong");
        assertTrue(output.contains("quit"), "Output is wrong");
        assertTrue(output.contains("speed"), "Output is wrong");

        // Reset the output stream
        outputStream.reset();
    }

    /**
     * Tests the executeSingleCommmand
     */
    @Test
    public void frontendTest2() {

        // Test danceability command.
        frontend.executeSingleCommand("danceability 100");
        String output = outputStream.toString();
        // We expect a success message.
        assertTrue(output.contains("Success"), "Danceability command failed.");
        outputStream.reset();

        // Test speed command.
        frontend.executeSingleCommand("speed 100");
        output = outputStream.toString();
        assertTrue(output.contains("Success"), "Speed failed");
        outputStream.reset();

        // Test a show command
        frontend.executeSingleCommand("show most recent");
        output = outputStream.toString();
        assertTrue(output.contains("Success"), "show command failed.");
        outputStream.reset();

    }

    /**
     * Method to test runCommandLoop()
     */
    @Test
    public void frontendTest3() {

        // Simulate a series of commands
        String input = "help\n" +
                                "danceability 0 to 100\n" +
                                "quit\n";
        InputStream inputStream = new ByteArrayInputStream(input.getBytes());
        Scanner scanner = new Scanner(inputStream);
        frontend = new Frontend(scanner, backend);

        // Run commands
        frontend.runCommandLoop();
        String output = outputStream.toString();
        
        // Check that the help instructions are printed
        assertTrue(output.contains("The following commands are valid"), "Help command failed.");

        // Check that the backend still returns an empty list
        List&lt;String&gt; range = backend.getRange(0, 100);
        assertTrue(range.isEmpty(), "Wrong songs were returned");
    }

    /**
     * Integration check to ensure that songs can be properly loaded into the backend through the frontend
     */
    @Test
    public void integrationTestOne() {

        // Use try/catch block to catch errors with file creation
        try {

            // Create a temporary CSV file with a song
            Path file = Files.createTempFile("testLoad", ".csv");
            String csvContent = "title,artist,top genre,year,bpm,nrgy,dnce,dB,live,val,dur,acous,spch,pop\n"+
                                "Take Me Out,Franz Ferdinand,rock,2004,82,89,67,-4,8,80,217,19,4,83\n";
            Files.write(file, csvContent.getBytes());

            // Execute load command
            frontend.executeSingleCommand("load " + file.toString());

            // Obtain list of all songs and check that song was properly loaded
            List&lt;String&gt; songs = backend.getRange(null, null);
            assertTrue(songs.contains("Take Me Out"), "Load command failed");

            // Delete file for testing purposes
            Files.delete(file);
        } 
        
        // Catch errors with the CSV file
        catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

     /**
     * An integration test to check that calling an invalid command in the frontend does not alter the backend
     */
    @Test
    public void integrationTestTwo() {

        // Call invalid command
        frontend.executeSingleCommand("exit");

        // Check that the list of songs was not updated
        List&lt;String&gt; songs = backend.getRange(null, null);
        assertTrue(songs.isEmpty(), "Unknown command should not alter backend song data.");
    }

    /**
     * Integration test that utilizes a series of commands in the frontend
     * and then employs the backend's five most method to check that the songs were processed properly
     */
    @Test
    public void integrationTestThree() {
        try {
            
            // Create a temporary CSV file with a song
            Path file = Files.createTempFile("testLoad", ".csv");
            String csvContent = "title,artist,top genre,year,bpm,nrgy,dnce,dB,live,val,dur,acous,spch,pop\n"+
                                "Take Me Out,Franz Ferdinand,rock,2004,82,89,67,-4,8,80,217,19,4,83\n" +
                                "Habits (Stay High),Tove Lo,R&amp;B,2013,90,59,63,-7,10,68,194,20,11,71";
            Files.write(file, csvContent.getBytes());

            // Simulate a series of commands: load, set danceability, set speed, then quit.
            String input = "load " + file.toString() + "\n" +
                                    "speed 120\n" +
                                    "help\n" +
                                    "quit\n";
            InputStream inputStream = new ByteArrayInputStream(input.getBytes());
            Scanner scanner = new Scanner(inputStream);
            frontend = new Frontend(scanner, backend);
            frontend.runCommandLoop();
            
            //  Use the backend's fiveMost method to ensure that the songs were properly processed
            List&lt;String&gt; mostRecent = backend.fiveMost();
            assertTrue(!mostRecent.isEmpty(), "Songs should exist");

            // Delete file for testing purposes
            Files.delete(file);
        } 
        
         // Catch errors with the CSV file
        catch (IOException e) {
            fail("Temporary file creation failed: " + e.getMessage());
        }
    }

    /**
     * Integration test to check that updating the danceability in the frontend accurately updates the backend
     */
    @Test
    public void integrationTestFour() {

        // Use a try/catch block in case exceptions are thrown during file creation
        try {

            // Create a temporary CSV file with a song
            Path file = Files.createTempFile("testLoad", ".csv");
            String csvContent = "title,artist,top genre,year,bpm,nrgy,dnce,dB,live,val,dur,acous,spch,pop\n"+
                                "Take Me Out,Franz Ferdinand,rock,2004,82,89,67,-4,8,80,217,19,4,83\n";
            Files.write(file, csvContent.getBytes());

            // Load the song.
            frontend.executeSingleCommand("load " + file.toString());

            // Delete file for testing purposes
            Files.delete(file);
        }

        // Catch errors with the CSV file
        catch (IOException e) {
            fail("Temporary file creation failed: " + e.getMessage());
        }

        // Set danceability to include Take Me Out
        frontend.executeSingleCommand("danceability 60 to 70");

        // Get list of songs from backend and check that it includes Take Me Out
        List&lt;String&gt; correctRange = backend.getRange(60, 70);
        assertTrue(correctRange.contains("Take Me Out"), "Danceability command");

        // Set danceability to exclude Take Me Out
        frontend.executeSingleCommand("danceability 0 to 10");

         // Get list of songs from backend and check that it excludes Take Me Out
        List&lt;String&gt; incorrectRange = backend.getRange(0, 10);
        assertTrue(!incorrectRange.contains("Take Me Out"), "Danceability command failed");
    }
}
</pre></body></html>