Skip to content

Commit

Permalink
feat: adds a test that does load after save and save after load
Browse files Browse the repository at this point in the history
  • Loading branch information
Scoppio committed Nov 6, 2024
1 parent fd8ab00 commit 57553c1
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 1 deletion.
59 changes: 58 additions & 1 deletion megameklab/src/megameklab/util/UnitUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
package megameklab.util;

import java.awt.Font;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
Expand All @@ -32,12 +35,16 @@
import javax.swing.JFrame;
import javax.swing.JOptionPane;

import megamek.client.ui.enums.ValidationState;
import megamek.common.*;
import megamek.common.annotations.Nullable;
import megamek.common.equipment.AmmoMounted;
import megamek.common.equipment.ArmorType;
import megamek.common.equipment.MiscMounted;
import megamek.common.equipment.WeaponMounted;
import megamek.common.loaders.BLKFile;
import megamek.common.loaders.EntityLoadingException;
import megamek.common.loaders.EntitySavingException;
import megamek.common.verifier.*;
import megamek.common.verifier.TestEntity.Ceil;
import megamek.common.weapons.AmmoWeapon;
Expand Down Expand Up @@ -71,6 +78,17 @@ public class UnitUtil {
private static Font rsFont = null;
private static Font rsBoldFont = null;

public enum UnitValidation {
VALID,
INVALID;

public static UnitValidation of(boolean valid) {
return valid ? VALID : INVALID;
}
}

public record Validation(UnitValidation state, String report) { }

/**
* tells is EquipementType is an equipment that uses crits/mounted and is
* spread across multiple locations
Expand Down Expand Up @@ -1689,9 +1707,11 @@ public static TestEntity getEntityVerifier(Entity unit) {
/**
* check that the unit is vaild
*
* @deprecated prefer to use the new <strong>verify</strong> method which uses the validation record
* @param unit The entity
* @return
* @return report on the errors
*/
@Deprecated
public static String validateUnit(Entity unit) {
StringBuffer sb = new StringBuffer();
TestEntity testEntity = getEntityVerifier(unit);
Expand All @@ -1703,6 +1723,28 @@ public static String validateUnit(Entity unit) {
return sb.toString();
}


/**
* verify
* <p>
* Checks if the unit is valid, returns a record with a state enum saying if it is valid or not, and a report if it failed.
* </p>
*
* @param unit Entity
* @return returns a Validation record with the results of the verification, being an enum saying if it succeeded or failed and the
* report if needed
*/
public static Validation verify(Entity unit) {
StringBuffer sb = new StringBuffer();
TestEntity testEntity = getEntityVerifier(unit);

var succeeded = testEntity.correctEntity(sb, unit.getTechLevel());

var validation = new Validation(UnitValidation.of(succeeded), sb.toString());

return validation;
}

public static void removeAllMiscMounteds(Entity unit, BigInteger flag) {
for (int pos = unit.getEquipment().size() - 1; pos >= 0; pos--) {
Mounted<?> mount = unit.getEquipment().get(pos);
Expand Down Expand Up @@ -2140,4 +2182,19 @@ static boolean isNonMekOrTankWeapon(Entity unit, WeaponType weapon) {
}
return false;
}

public static boolean persistUnit(File outFile, Entity entity) throws EntitySavingException {
if (entity instanceof Mek) {
try (BufferedWriter out = new BufferedWriter(new FileWriter(outFile))) {
out.write(((Mek) entity).getMtf());
} catch (Exception e) {
System.out.println(e.getMessage());
return false;
}
return true;
}

BLKFile.encode(outFile, entity);
return true;
}
}
109 changes: 109 additions & 0 deletions megameklab/unittests/megameklab/loaders/BLKFileTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright (c) 2024 - The MegaMek Team. All Rights Reserved.
*
* This file is part of MegaMek.
*
* MegaMek is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MegaMek is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MegaMek. If not, see <http://www.gnu.org/licenses/>.
*/
package megameklab.loaders;

import megamek.common.*;
import megamek.common.equipment.ArmorType;
import megamek.common.loaders.EntitySavingException;
import megameklab.util.UnitUtil;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.*;

class BLKFileTest {

@ParameterizedTest(name = "{0}")
@MethodSource("allMekfiles")
void loadVerifyUnit(File unitFIle) {
Entity entity = loadUnit(unitFIle);
var validation = UnitUtil.verify(entity);
assertEquals(validation.state(), UnitUtil.UnitValidation.VALID,
"The unit is invalid:\n\t" + entity.getDisplayName() + "\n" + validation.report());
}

// Total of 169 failed entities
// from 4990 entities
@ParameterizedTest(name = "{0}")
@MethodSource("allMekfiles")
void loadVerifySaveVerify(File file) throws EntitySavingException, IOException {
Entity entity = loadUnit(file);
var validation = UnitUtil.verify(entity);

assertEquals(UnitUtil.UnitValidation.VALID, validation.state(),
"The unit is invalid:\n\t" + entity.getDisplayName() + "\n" + validation.report());
File tmpFile;
if (entity instanceof Mek) {
tmpFile = File.createTempFile("tmp_mekfiles/" + UUID.randomUUID() + "/" + file.getName(), ".mtf");

Check warning

Code scanning / CodeQL

Local information disclosure in a temporary directory Medium

Local information disclosure vulnerability due to use of file readable by other local users.
} else {
tmpFile = File.createTempFile("tmp_mekfiles/" + UUID.randomUUID() + "/" + file.getName(), ".blk");

Check warning

Code scanning / CodeQL

Local information disclosure in a temporary directory Medium

Local information disclosure vulnerability due to use of file readable by other local users.
}

if (UnitUtil.persistUnit(tmpFile, entity)) {
Entity repersistedEntity = loadUnit(tmpFile);
var reValidation = UnitUtil.verify(repersistedEntity);
assertEquals(UnitUtil.UnitValidation.VALID, reValidation.state(),
"The unit is invalid after repersisting:\n\t" + tmpFile + "\n\t" + entity.getDisplayName() + "\n" + reValidation.report());
assertEquals(reValidation.state(), validation.state());
}
}

public static List<File> allMekfiles() {
initializeStuff();
try (Stream<Path> paths = Files.walk(Paths.get("data/mekfiles"))) {
return paths
.filter(Files::isRegularFile)
.filter(path -> path.toString().endsWith(".blk"))
.map(Path::toFile)
.toList();
} catch (IOException e) {
// do nothing
}
return List.of();
}

private static void initializeStuff() {
EquipmentType.initializeTypes();
AmmoType.initializeTypes();
ArmorType.initializeTypes();
WeaponType.initializeTypes();
MiscType.initializeTypes();
BombType.initializeTypes();
}

private Entity loadUnit(File file) {
try {
MekFileParser mfp = new MekFileParser(file);
return mfp.getEntity();
} catch (Exception ex) {
fail(ex.getMessage());
}
throw new IllegalStateException("Should not reach here");
}

}

0 comments on commit 57553c1

Please sign in to comment.