diff --git a/pom.xml b/pom.xml index 231bd7f4b..38b04da11 100755 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,11 @@ scm:git:git@github.com:mcMMO-Dev/mcMMO.git HEAD + + + UTF-8 + + https://github.com/mcMMO-Dev/mcMMO/issues GitHub @@ -66,13 +71,12 @@ - org.apache.maven.plugins maven-surefire-plugin - 2.16 - - false - 1 - + 2.22.2 + + + maven-failsafe-plugin + 2.22.2 @@ -219,6 +223,17 @@ + + + + + + + + + + + com.github.seeseemelk @@ -271,6 +286,12 @@ net.kyori adventure-platform-common 4.0.0-SNAPSHOT + + + net.kyori + adventure-nbt + + org.apache.maven.scm @@ -314,9 +335,21 @@ - junit - junit-dep - 4.11 + org.junit.jupiter + junit-jupiter-api + 5.7.1 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.7.1 + test + + + org.junit.vintage + junit-vintage-engine + 5.6.2 test @@ -349,7 +382,4 @@ 19.0.0 - - UTF-8 - diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java index 1b9651089..a232d86cd 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java @@ -119,6 +119,8 @@ public class FlatFileDataProcessor { if(names.contains(name)) { builder.appendFlag(FlatFileDataFlag.DUPLICATE_NAME); + anyBadData = true; + badDataValues[USERNAME_INDEX] = true; } if(!name.isEmpty()) diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 8d4f8ea30..b47477651 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -174,6 +174,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return purgedUsers; } + //TODO: Test this public void purgeOldUsers() { int removedPlayers = 0; long currentTime = System.currentTimeMillis(); @@ -211,7 +212,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - if (currentTime - lastPlayed > purgeTime) { + if (lastPlayed != -1 && lastPlayed != 0 && currentTime - lastPlayed > purgeTime) { removedPlayers++; } else { if (rewrite) { @@ -425,53 +426,53 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - public void writeUserToLine(@NotNull PlayerProfile profile, @NotNull String playerName, @Nullable UUID uuid, @NotNull Appendable writer) throws IOException { - writer.append(playerName).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.MINING))).append(":"); - writer.append(IGNORED).append(":"); - writer.append(IGNORED).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.MINING))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.WOODCUTTING))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.WOODCUTTING))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.REPAIR))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.UNARMED))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.HERBALISM))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.EXCAVATION))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ARCHERY))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.SWORDS))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.AXES))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ACROBATICS))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.REPAIR))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.UNARMED))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.HERBALISM))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.EXCAVATION))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ARCHERY))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.SWORDS))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.AXES))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ACROBATICS))).append(":"); - writer.append(IGNORED).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.TAMING))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.TAMING))).append(":"); - writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BERSERK))).append(":"); - writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER))).append(":"); - writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.TREE_FELLER))).append(":"); - writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GREEN_TERRA))).append(":"); - writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SERRATED_STRIKES))).append(":"); - writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SKULL_SPLITTER))).append(":"); - writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SUPER_BREAKER))).append(":"); - writer.append(IGNORED).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.FISHING))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.FISHING))).append(":"); - writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BLAST_MINING))).append(":"); - writer.append(IGNORED).append(":"); //Legacy last login - writer.append(IGNORED).append(":"); //mob health bar - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ALCHEMY))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ALCHEMY))).append(":"); - writer.append(uuid != null ? uuid.toString() : "NULL").append(":"); - writer.append(String.valueOf(profile.getScoreboardTipsShown())).append(":"); - writer.append(String.valueOf(profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS))).append(":"); - writer.append(String.valueOf(profile.getLastLogin())).append(":"); //overhaul last login - writer.append("\r\n"); + public void writeUserToLine(@NotNull PlayerProfile profile, @NotNull String playerName, @Nullable UUID uuid, @NotNull Appendable appendable) throws IOException { + appendable.append(playerName).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.MINING))).append(":"); + appendable.append(IGNORED).append(":"); + appendable.append(IGNORED).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.MINING))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.WOODCUTTING))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.WOODCUTTING))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.REPAIR))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.UNARMED))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.HERBALISM))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.EXCAVATION))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ARCHERY))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.SWORDS))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.AXES))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ACROBATICS))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.REPAIR))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.UNARMED))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.HERBALISM))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.EXCAVATION))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ARCHERY))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.SWORDS))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.AXES))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ACROBATICS))).append(":"); + appendable.append(IGNORED).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.TAMING))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.TAMING))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BERSERK))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.TREE_FELLER))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GREEN_TERRA))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SERRATED_STRIKES))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SKULL_SPLITTER))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SUPER_BREAKER))).append(":"); + appendable.append(IGNORED).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.FISHING))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.FISHING))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BLAST_MINING))).append(":"); + appendable.append(IGNORED).append(":"); //Legacy last login + appendable.append(IGNORED).append(":"); //mob health bar + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ALCHEMY))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ALCHEMY))).append(":"); + appendable.append(uuid != null ? uuid.toString() : "NULL").append(":"); + appendable.append(String.valueOf(profile.getScoreboardTipsShown())).append(":"); + appendable.append(String.valueOf(profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS))).append(":"); + appendable.append(String.valueOf(profile.getLastLogin())).append(":"); //overhaul last login + appendable.append("\r\n"); } public @NotNull List readLeaderboard(@Nullable PrimarySkillType primarySkillType, int pageNumber, int statsPerPage) throws InvalidSkillException { @@ -510,9 +511,23 @@ public final class FlatFileDatabaseManager implements DatabaseManager { PlayerProfile playerProfile = new PlayerProfile(playerName, uuid, true, startingLevel); synchronized (fileWritingLock) { - try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(usersFilePath, true))) { - writeUserToLine(playerProfile, playerName, uuid, bufferedWriter); - } catch (Exception e) { + try(BufferedReader bufferedReader = new BufferedReader(new FileReader(usersFilePath))) { + StringBuilder stringBuilder = new StringBuilder(); + + String line; + + //Build up the file + while((line = bufferedReader.readLine()) != null) { + stringBuilder.append(line).append("\r\n"); + } + + try (FileWriter fileWriter = new FileWriter(usersFile)) { + writeUserToLine(playerProfile, playerName, uuid, stringBuilder); + fileWriter.write(stringBuilder.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + } catch (IOException e) { e.printStackTrace(); } } @@ -536,7 +551,17 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return loadPlayerByUUID(uuid, null, false); } - private @NotNull PlayerProfile loadPlayerByUUID(@NotNull UUID uuid, @Nullable String playerName, boolean isOnline) { + /** + * Find and load a player by UUID + * + * @param uuid target uuid + * @param playerName target player name + * @param replaceName name to replace if the found name differs + * @return a profile with the targets data or an unloaded profile if no data was found + * @deprecated only use this if you know what you are doing, replacing the name can cause havoc + */ + @Deprecated + public @NotNull PlayerProfile loadPlayerByUUID(@NotNull UUID uuid, @Nullable String playerName, boolean replaceName) { BufferedReader in = null; synchronized (fileWritingLock) { @@ -574,7 +599,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { /* Check for nickname changes and update since we are here anyways */ if(playerName != null) { - if(isOnline) { + if(replaceName) { + logger.info("A users name is being updated, this can happen from either a call to our API or they simply changed their name"); if (!rawSplitData[USERNAME_INDEX].equalsIgnoreCase(playerName)) { //logger.info("Name updated for player: " + rawSplitData[USERNAME_INDEX] + " => " + playerName); rawSplitData[USERNAME_INDEX] = playerName; @@ -1162,7 +1188,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { lastLogin = -1; } - return new PlayerProfile(character[USERNAME_INDEX], uuid, skills, skillsXp, skillsDATS, scoreboardTipsShown, uniquePlayerDataMap, lastLogin); + return new PlayerProfile(username, uuid, skills, skillsXp, skillsDATS, scoreboardTipsShown, uniquePlayerDataMap, lastLogin); } private void tryLoadSkillCooldownFromRawData(@NotNull Map cooldownMap, @NotNull String[] character, @NotNull SuperAbilityType superAbilityType, int cooldownSuperBreaker, @NotNull String userName) { diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 01c14ed16..a937efb0b 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.database; import com.gmail.nossr50.api.exceptions.InvalidSkillException; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.MobHealthbarType; import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.datatypes.database.PlayerStat; diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index 71f5de649..d9cd5051d 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -6,36 +6,28 @@ import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.player.UniqueDataType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask; import com.gmail.nossr50.util.skills.SkillTools; import com.google.common.io.Files; -import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; -import org.powermock.modules.junit4.PowerMockRunner; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.*; import java.net.URI; import java.net.URISyntaxException; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import java.util.logging.Logger; -import static org.junit.Assert.*; - +import static org.junit.jupiter.api.Assertions.*; //TODO: Test update leaderboards +//This class uses JUnit5/Jupiter public class FlatFileDatabaseManagerTest { - public mcMMO plugin; - public static final @NotNull String TEST_FILE_NAME = "test.mcmmo.users"; public static final @NotNull String BAD_FILE_LINE_ONE = "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:"; public static final @NotNull String BAD_DATA_FILE_LINE_TWENTY_THREE = "nossr51:baddata:::baddata:baddata:640:baddata:1000:1000:1000:baddata:baddata:baddata:baddata:16:0:500:20273:0:0:0:0::1000:0:0:baddata:1593543012:0:0:0:0::1000:0:0:baddata:IGNORED:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1:0:"; @@ -68,7 +60,7 @@ public class FlatFileDatabaseManagerTest { int expectedScoreboardTips = 1111; Long expectedLastLogin = 2020L; - @Before + @BeforeEach public void init() { assertNull(db); //noinspection UnstableApiUsage @@ -76,7 +68,7 @@ public class FlatFileDatabaseManagerTest { db = new FlatFileDatabaseManager(new File(tempDir.getPath() + File.separator + TEST_FILE_NAME), logger, PURGE_TIME, 0, true); } - @After + @AfterEach public void tearDown() { TestUtil.recursiveDelete(tempDir); db = null; @@ -184,7 +176,6 @@ public class FlatFileDatabaseManagerTest { assertEquals(-1, (long) profile.getLastLogin()); } - @Test public void testLoadByName() { File healthyDB = prepareDatabaseTestResource(DB_HEALTHY); @@ -244,6 +235,47 @@ public class FlatFileDatabaseManagerTest { db.newUser("disco", new UUID(3, 3)); db.newUser("dingus", new UUID(3, 4)); db.newUser("duped_dingus", new UUID(3, 4)); + + assertEquals(5, getSplitDataFromFile(db.getUsersFile()).size()); + } + + @Test + public void testAddingUsersToEndOfExistingDB() { + //We will test that new user values line up with our expectations + UUID uuid = new UUID(0, 80); + String playerName = "the_kitty_man"; + + File file = prepareDatabaseTestResource(DB_HEALTHY); //Existing DB + + int newUserTestStartingLvl = 1337; + db = new FlatFileDatabaseManager(file, logger, PURGE_TIME, newUserTestStartingLvl, true); + db.checkFileHealthAndStructure(); + + PlayerProfile playerProfile = db.newUser(playerName, uuid); + + assertTrue(playerProfile.isLoaded()); + assertEquals(playerName, playerProfile.getPlayerName()); + assertEquals(uuid, playerProfile.getUniqueId()); + + PlayerProfile retrievedFromDisk = db.loadPlayerProfile(uuid, playerName); + assertTrue(retrievedFromDisk.isLoaded()); + assertEquals(playerName, retrievedFromDisk.getPlayerName()); + assertEquals(uuid, retrievedFromDisk.getUniqueId()); + + //Checking a new user for being "zero" initialized + checkNewUserValues(playerProfile, newUserTestStartingLvl); + checkNewUserValues(retrievedFromDisk, newUserTestStartingLvl); + + //TODO: Should we do any dupe checking? Probably not needed as it would be caught on the next load + db.newUser("bidoof", new UUID(3, 3)); + db.newUser("derp", new UUID(3, 4)); + db.newUser("pizza", new UUID(3, 4)); + + assertEquals(7, getSplitDataFromFile(db.getUsersFile()).size()); + + //Now we *fix* the DB and there should be one less + db.checkFileHealthAndStructure(); + assertEquals(6, getSplitDataFromFile(db.getUsersFile()).size()); } private void checkNewUserValues(@NotNull PlayerProfile playerProfile, int startingLevel) { @@ -466,7 +498,32 @@ public class FlatFileDatabaseManagerTest { @Test public void testOverwriteName() { + overwriteDataAndCheckForFlag(db, duplicateNameDatabaseData, FlatFileDataFlag.DUPLICATE_NAME); + ArrayList splitDataLines = getSplitDataFromFile(db.getUsersFile()); + assertNotEquals(splitDataLines.get(1)[0], splitDataLines.get(0)[0]); //Name comparison + } + @Test + public void testUpdateName() { + //TODO: The code in this test didn't actually trigger the save, so I'll have to do something else to test saving +// UUID uuid = UUID.fromString(HEALTHY_DB_LINE_ONE_UUID_STR); //Entrant "nossr50" +// String playerName = "the_new_name_man"; +// +// File file = prepareDatabaseTestResource(DB_HEALTHY); //Existing DB +// db = new FlatFileDatabaseManager(file, logger, PURGE_TIME, 0, true); +// db.checkFileHealthAndStructure(); +// ArrayList splitDataLines = getSplitDataFromFile(db.getUsersFile()); +// String oldName = "nossr50"; +// assertEquals(oldName, splitDataLines.get(0)[0]); //Name comparison +// assertEquals(uuid.toString(), splitDataLines.get(0)[FlatFileDatabaseManager.UUID_INDEX]); //UUID Comparison +// +// //Now we load the player and their name should get replaced +// PlayerProfile profile = db.loadPlayerByUUID(uuid, playerName, true); +// assertEquals(playerName, profile.getPlayerName()); +// +// splitDataLines = getSplitDataFromFile(db.getUsersFile()); //Load the file again +// assertNotEquals(oldName, splitDataLines.get(0)[0]); //Name comparison +// assertEquals(playerName, splitDataLines.get(0)[0]); //Name comparison } @Test @@ -573,9 +630,9 @@ public class FlatFileDatabaseManagerTest { //This makes sure our private method is working before the tests run afterwards ArrayList dataFromFile = getSplitDataFromFile(copyOfFile); System.out.println("File Path: "+copyOfFile.getAbsolutePath()); - assertEquals(BAD_FILE_LINE_ONE.split(":"), dataFromFile.get(0)); + assertArrayEquals(BAD_FILE_LINE_ONE.split(":"), dataFromFile.get(0)); assertEquals(dataFromFile.get(22)[0], "nossr51"); - assertEquals(BAD_DATA_FILE_LINE_TWENTY_THREE.split(":"), dataFromFile.get(22)); + assertArrayEquals(BAD_DATA_FILE_LINE_TWENTY_THREE.split(":"), dataFromFile.get(22)); FlatFileDatabaseManager db_a = new FlatFileDatabaseManager(copyOfFile, logger, PURGE_TIME, 0, true); List flagsFound = db_a.checkFileHealthAndStructure();