Untitled

Anonymous
plain_text
02/08/2026 10:16 PM
23.3 KB
14
Indexable
import java.io.IOException;
import student.TestCase;

/**
 * Test suite for the Songs database project.
 * 
 * Exercises the SongsDB, Hash, and MemManager classes using
 * the public Songs interface, plus direct unit tests where
 * allowed, to validate behavior and output formatting.
 * 
 * @author Leguejou Awunganyi
 * @author Ishita Punna
 * @version 2026-02-08
 */
public class SongsTest extends TestCase {

    /**
     * Shared Songs reference used by several tests.
     * It is reset or re-created inside each test as needed.
     */
    private Songs it;

    /**
     * Set up method run before each test. No shared
     * fixture is required, so this method is empty.
     */
    public void setUp() {
        // Nothing to initialize globally for these tests.
    }

    /**
     * Memory manager edge-case: start with very small pool size,
     * force an expansion on insert, and verify strings are still
     * stored and printed correctly via SongsDB.
     *
     * @throws IOException
     *         if an I/O error occurs (not expected here)
     */
    public void testMemManEdge1() throws IOException {
        SongsDB db = new SongsDB();
        db.create(1, 8); // very small memory to trigger expansion quickly

        // Insert a song that fits
        db.insert("A", "S1");

        // Insert a song that is larger than the remaining pool
        String out = db.insert("B", "LONG_SONG_NAME");

        // This should trigger memory pool expansion
        assertTrue(out.contains("Memory pool expanded"));

        // Check that both artist and song tables reflect the inserts
        String artistPrint = db.print("artist");
        String songPrint = db.print("song");
        assertTrue(artistPrint.contains("A"));
        assertTrue(artistPrint.contains("B"));
        assertTrue(songPrint.contains("S1"));
        assertTrue(songPrint.contains("LONG_SONG_NAME"));
    }

    /**
     * Hash function coverage: insert artists/songs with different
     * length names to exercise both branches of the sfold hash
     * multiplier logic, then verify all songs are present.
     *
     * @throws IOException
     *         if an I/O error occurs (not expected here)
     */
    public void testHashFunctionCollisions() throws IOException {
        SongsDB db = new SongsDB();
        db.create(8, 64);

        // Insert strings of different lengths to hit different branches in h()
        db.insert("abcd", "Song1");      // length 4
        db.insert("abcdefgh", "Song2");  // length 8
        db.insert("ijklmnop", "Song3");  // length 8

        // Print songs and check if inserted strings exist
        String allSongs = db.print("song");
        assertTrue(allSongs.contains("Song1"));
        assertTrue(allSongs.contains("Song2"));
        assertTrue(allSongs.contains("Song3"));
    }

    /**
     * Verify that create() rejects an invalid initial hash size.
     */
    public void testInvalidHash() {
        Songs invalidDB = new SongsDB();
        assertFuzzyEquals("Initial hash table size must be positive",
            invalidDB.create(-1, 4));
    }

    /**
     * Verify that create() rejects an invalid initial memory size.
     */
    public void testInvalidMemory() {
        Songs invalidMemMan = new SongsDB();
        assertFuzzyEquals("Initial memory manager size must be positive",
            invalidMemMan.create(10, -10));
    }

    /**
     * Verify that insert() reports an error when called before
     * the database has been initialized with create().
     *
     * @throws IOException
     *         if an I/O error occurs (not expected here)
     */
    public void testInvalidInsert() throws IOException {
        Songs invalidDB = new SongsDB();
        assertFuzzyEquals("Database not initialized",
            invalidDB.insert("Ish", "Punna"));
    }

    /**
     * Verify that printing artists right after a valid create()
     * reports the correct empty-artist summary line.
     *
     * @throws IOException
     *         if an I/O error occurs (not expected here)
     */
    public void testInvalidArtist() throws IOException {
        Songs invalidDB = new SongsDB();
        invalidDB.create(1, 4);
        assertFuzzyEquals("total artists: 0", invalidDB.print("artist"));
    }

    /**
     * Verify that print() reports the correct message when given
     * an empty string as the print type parameter.
     *
     * @throws IOException
     *         if an I/O error occurs (not expected here)
     */
    public void testInvalidPrint() throws IOException {
        Songs invalidDB = new SongsDB();
        invalidDB.create(1, 4);
        assertFuzzyEquals("Input strings cannot be null or empty",
            invalidDB.print(""));
    }

    /**
     * Validate create() for invalid hash size and invalid memory
     * size, using the SongsDB implementation directly.
     */
    public void testCreateInvalidInputs() {
        SongsDB db = new SongsDB();

        String msg;

        // invalid hash table size
        msg = db.create(0, 8);
        assertEquals("Initial hash table size must be positive", msg);

        // invalid memory manager size
        msg = db.create(8, 0);
        assertEquals("Initial memory manager size must be positive", msg);
    }

    /**
     * Validate that create() correctly rejects a non-power-of-two
     * memory manager size, and accepts a proper power of two.
     */
    public void testCreateNonPowerOfTwoMem() {
        SongsDB db = new SongsDB();

        // Non-power-of-2 mem size triggers error
        String msg = db.create(10, 3);
        assertEquals("Initial memory manager size must be a power of 2", msg);

        // Positive power-of-2 works
        msg = db.create(10, 8);
        assertEquals("", msg);
    }

    /**
     * Test various bad inputs for create, insert, remove, and print,
     * including uninitialized database state and invalid parameters.
     *
     * @throws Exception
     *         if an unexpected error occurs
     */
    public void testBadInput() throws Exception {
        it = new SongsDB();
        // Not been initialized yet
        assertFalse(it.clear());
        assertFuzzyEquals(
            "Initial hash table size must be positive",
            it.create(-1, 32));
        assertFuzzyEquals(
            "Initial memory manager size must be positive",
            it.create(10, 0));
        assertFuzzyEquals(
            "Initial memory manager size must be a power of 2",
            it.create(10, 3));

        assertFuzzyEquals(
            "Database not initialized",
            it.insert("a", "b"));
        assertFuzzyEquals(
            "Database not initialized",
            it.remove("song", "a"));
        assertFuzzyEquals(
            "Database not initialized",
            it.print("blocks"));

        it.create(32, 32);
        assertFuzzyEquals(
            "Bad print parameter",
            it.print("dum"));
        assertFuzzyEquals(
            "Bad type value |Dum| on remove",
            it.remove("Dum", "Dum"));

        assertFuzzyEquals(
            "Input strings cannot be null or empty",
            it.print(""));
        assertFuzzyEquals(
            "Input strings cannot be null or empty",
            it.print(null));

        assertFuzzyEquals(
            "Input strings cannot be null or empty",
            it.insert("", "b"));
        assertFuzzyEquals(
            "Input strings cannot be null or empty",
            it.insert(null, "b"));
        assertFuzzyEquals(
            "Input strings cannot be null or empty",
            it.insert("a", ""));
        assertFuzzyEquals(
            "Input strings cannot be null or empty",
            it.insert("a", null));

        assertFuzzyEquals(
            "Input strings cannot be null or empty",
            it.remove("song", ""));
        assertFuzzyEquals(
            "Input strings cannot be null or empty",
            it.remove("song", null));
        assertFuzzyEquals(
            "Input strings cannot be null or empty",
            it.remove("", "a"));
        assertFuzzyEquals(
            "Input strings cannot be null or empty",
            it.remove(null, "a"));
    }

    /**
     * Test behavior on an otherwise empty database after create():
     * printing tables, inserting one record, and then checking
     * block printing and failed removes.
     *
     * @throws Exception
     *         if an unexpected error occurs
     */
    public void testEmpty() throws Exception {
        it = new SongsDB();
        it.create(10, 32);

        assertFuzzyEquals(
            "total artists: 0",
            it.print("artist"));
        assertFuzzyEquals(
            "total songs: 0",
            it.print("song"));

        it.insert("Hello World", "Hello World2");
        assertFuzzyEquals(
            "No free blocks are available.",
            it.print("blocks"));
        assertFuzzyEquals(
            "|Dum| does not exist in the Artist database",
            it.remove("artist", "Dum"));
        assertFuzzyEquals(
            "|Dum| does not exist in the song database",
            it.remove("song", "Dum"));
    }

    /**
     * Verify that clear() succeeds after a valid create()
     * and that subsequent artist printing matches the empty
     * summary output.
     *
     * @throws IOException
     *         if an I/O error occurs (not expected here)
     */
    public void testClearWorks() throws IOException {
        SongsDB db = new SongsDB();
        db.create(4, 32);

        assertTrue(db.clear());
        assertFuzzyEquals("total artists: 0", db.print("artist"));
    }

    /**
     * Verify the error message when remove() is called with an
     * invalid table type parameter.
     *
     * @throws Exception
     *         if an unexpected error occurs
     */
    public void testRemoveBadTypeMessage() throws Exception {
        SongsDB db = new SongsDB();
        db.create(4, 32);

        String out = db.remove("bad", "x");
        assertTrue(out.contains("Bad type value"));
    }

    /**
     * Exact-output test for inserting artist and song pairs,
     * including a duplicate artist insertion, using newline
     * formatting as specified by the project sample.
     *
     * @throws IOException
     *         if an I/O error occurs (not expected here)
     */
    public void testInsertArtistAndSongExactOutput() throws IOException {
        SongsDB db = new SongsDB();
        db.create(4, 32);
        String out1 = db.insert("A", "S");
        assertFuzzyEquals("|A| is added to the Artist database\n"
            + "|S| is added to the Song database", out1);
        String out2 = db.insert("A", "S2");
        assertFuzzyEquals("|A| duplicates a record already in the Artist database\n"
            + "|S2| is added to the Song database", out2);
    }

    /**
     * Verify that tombstone slots in the artist hash table
     * can be reused by new inserts without producing a
     * duplicate-record error.
     *
     * @throws IOException
     *         if an I/O error occurs (not expected here)
     */
    public void testTombstoneReuse() throws IOException {
        SongsDB db = new SongsDB();
        db.create(4, 32);

        db.insert("A", "S1");
        db.insert("B", "S2");
        db.remove("artist", "A");

        String out = db.insert("A", "S3");
        assertFalse(out.contains("duplicates"));
    }

    /**
     * Verify that the blocks printing functionality can be reached
     * via SongsDB.print(\"blocks\") and returns a non-empty formatted
     * string once some data have been inserted.
     *
     * @throws Exception
     *         if an unexpected error occurs
     */
    public void testBlocksPrintViaSongsDB() throws Exception {
        SongsDB db = new SongsDB();
        db.create(4, 32);

        db.insert("A", "This song name is very long");
        String out = db.print("blocks");

        assertTrue(out.contains(":"));
    }

    /**
     * Full sample-input test from the project specification.
     * Checks that the sequence of operations produces the
     * exact output formatting in the sample.
     *
     * @throws Exception
     *         if an unexpected error occurs
     */
    public void testSampleInput() throws Exception {
        it = new SongsDB();
        it.create(10, 32);

        assertFuzzyEquals(
            "|When Summer's Through| does not exist in the Song database",
            it.remove("song", "When Summer's Through"));
        assertFuzzyEquals(
            "|Blind Lemon Jefferson| is added to the Artist database\r\n"
            + "Memory pool expanded to be 64 bytes\r\n"
            + "|Long Lonesome Blues| is added to the Song database",
            it.insert("Blind Lemon Jefferson", "Long Lonesome Blues"));
        assertFuzzyEquals(
            "Memory pool expanded to be 128 bytes\r\n"
            + "|Ma Rainey| is added to the Artist database\r\n"
            + "|Ma Rainey's Black Bottom| is added to the Song database",
            it.insert("Ma Rainey", "Ma Rainey's Black Bottom"));
        assertFuzzyEquals(
            "|Charley Patton| is added to the Artist database\r\n"
            + "Memory pool expanded to be 256 bytes\r\n"
            + "|Mississippi Boweavil Blues| is added to the Song database",
            it.insert("Charley Patton", "Mississippi Boweavil Blues"));
        assertFuzzyEquals(
            "|Sleepy John Estes| is added to the Artist database\r\n"
            + "|Street Car Blues| is added to the Song database",
            it.insert("Sleepy John Estes", "Street Car Blues"));
        assertFuzzyEquals(
            "|Bukka White| is added to the Artist database\r\n"
            + "|Fixin' To Die Blues| is added to the Song database",
            it.insert("Bukka White", "Fixin' To Die Blues"));
        assertFuzzyEquals(
            "0: |Blind Lemon Jefferson|\r\n"
            + "1: |Sleepy John Estes|\r\n"
            + "4: |Charley Patton|\r\n"
            + "5: |Bukka White|\r\n"
            + "7: |Ma Rainey|\r\n"
            + "total artists: 5",
            it.print("artist"));
        assertFuzzyEquals(
            "1: |Fixin' To Die Blues|\r\n"
            + "2: |Mississippi Boweavil Blues|\r\n"
            + "5: |Long Lonesome Blues|\r\n"
            + "6: |Ma Rainey's Black Bottom|\r\n"
            + "9: |Street Car Blues|\r\n"
            + "total songs: 5",
            it.print("song"));
        assertFuzzyEquals(
            "Memory pool expanded to be 512 bytes\r\n"
            + "Artist hash table size doubled\r\n"
            + "|Guitar Slim| is added to the Artist database\r\n"
            + "Song hash table size doubled\r\n"
            + "|The Things That I Used To Do| is added to the Song database",
            it.insert("Guitar Slim", "The Things That I Used To Do"));
        assertFuzzyEquals(
            "|Style Council| does not exist in the Artist database",
            it.remove("artist", "Style Council"));
        assertFuzzyEquals(
            "|Ma Rainey| is removed from the Artist database",
            it.remove("artist", "Ma Rainey"));
        assertFuzzyEquals(
            "|Mississippi Boweavil Blues| is removed from the Song database",
            it.remove("song", "Mississippi Boweavil Blues"));
        assertFuzzyEquals(
            "|(The Best Part Of) Breakin' Up| does not exist in the Song database",
            it.remove("song", "(The Best Part Of) Breakin' Up"));
        assertFuzzyEquals(
            "16: 64 272\r\n"
            + "32: 128\r\n"
            + "64: 320\r\n"
            + "128: 384",
            it.print("blocks"));
        assertFuzzyEquals(
            "|Blind Lemon Jefferson| duplicates a record already in the Artist database\r\n"
            + "|Got The Blues| is added to the Song database",
            it.insert("Blind Lemon Jefferson", "Got The Blues"));
        assertFuzzyEquals(
            "|Little Eva| is added to the Artist database\r\n"
            + "|The Loco-Motion| is added to the Song database",
            it.insert("Little Eva", "The Loco-Motion"));
        assertFuzzyEquals(
            "0: |Blind Lemon Jefferson|\r\n"
            + "4: |Bukka White|\r\n"
            + "7: TOMBSTONE\r\n"
            + "10: |Sleepy John Estes|\r\n"
            + "12: |Guitar Slim|\r\n"
            + "14: |Charley Patton|\r\n"
            + "18: |Little Eva|\r\n"
            + "total artists: 6",
            it.print("artist"));
        assertFuzzyEquals(
            "1: |Fixin' To Die Blues|\r\n"
            + "2: TOMBSTONE\r\n"
            + "5: |Street Car Blues|\r\n"
            + "8: |Got The Blues|\r\n"
            + "15: |Long Lonesome Blues|\r\n"
            + "16: |Ma Rainey's Black Bottom|\r\n"
            + "17: |The Things That I Used To Do|\r\n"
            + "18: |The Loco-Motion|\r\n"
            + "total songs: 7",
            it.print("song"));
        assertFuzzyEquals(
            "|Jim Reeves| is added to the Artist database\r\n"
            + "|Jingle Bells| is added to the Song database",
            it.insert("Jim Reeves", "Jingle Bells"));
        assertFuzzyEquals(
            "|Mongo Santamaria| is added to the Artist database\r\n"
            + "|Watermelon Man| is added to the Song database",
            it.insert("Mongo Santamaria", "Watermelon Man"));
        assertFuzzyEquals(
            "16: 368\r\n"
            + "128: 384",
            it.print("blocks"));
    }
}
Editor is loading...
Leave a Comment