diff --git a/.gitignore b/.gitignore index 12ca21bf90..fdf2b4f464 100644 --- a/.gitignore +++ b/.gitignore @@ -14,8 +14,10 @@ /core/assets-raw/sprites/generated/ /annotations/build/ /kryonet/build/ -/packer/build/ +/tools/build/ +/tests/build/ /server/build/ +/test_files/ /annotations/build/ /android/assets/mindustry-maps/ /android/assets/mindustry-saves/ diff --git a/build.gradle b/build.gradle index df4df532dc..9954ae113d 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ allprojects { appName = 'Mindustry' gdxVersion = '1.9.8' roboVMVersion = '2.3.0' - uCoreVersion = '00d05bd7d3e943c8a454ccf2cb69cdffb23afbb7' + uCoreVersion = '220916714cbe63664c34f95a9dc50a362feca732' getVersionString = { String buildVersion = getBuildVersion() @@ -119,20 +119,6 @@ project(":html") { } } -project(":tests"){ - apply plugin: "java" - - dependencies { - compile project(":core") - testImplementation('org.junit.jupiter:junit-jupiter-api:5.1.0') - testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.1.0') - } - - test { - useJUnitPlatform() - } -} - project(":ios") { apply plugin: "java" apply plugin: "robovm" @@ -218,6 +204,23 @@ project(":server") { } } +project(":tests"){ + apply plugin: "java" + + dependencies { + testImplementation project(":core") + testImplementation('org.junit.jupiter:junit-jupiter-api:5.1.0') + testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.1.0') + testImplementation "com.badlogicgames.gdx:gdx-backend-headless:$gdxVersion" + testImplementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" + } + + test { + useJUnitPlatform() + workingDir = new File("../core/assets") + } +} + project(":tools") { apply plugin: "java" diff --git a/core/assets-raw/sprites/blocks/units/revenant-factory.png b/core/assets-raw/sprites/blocks/units/revenant-factory.png index 6182b7ea09..a236936f62 100644 Binary files a/core/assets-raw/sprites/blocks/units/revenant-factory.png and b/core/assets-raw/sprites/blocks/units/revenant-factory.png differ diff --git a/core/assets/sprites/sprites.png b/core/assets/sprites/sprites.png index c81d3af0bd..e84fb5e1c2 100644 Binary files a/core/assets/sprites/sprites.png and b/core/assets/sprites/sprites.png differ diff --git a/core/src/io/anuke/mindustry/maps/Sector.java b/core/src/io/anuke/mindustry/maps/Sector.java index 7c363f7164..89f4a487fa 100644 --- a/core/src/io/anuke/mindustry/maps/Sector.java +++ b/core/src/io/anuke/mindustry/maps/Sector.java @@ -11,6 +11,7 @@ import io.anuke.mindustry.type.ItemStack; import io.anuke.ucore.util.Bits; import static io.anuke.mindustry.Vars.control; +import static io.anuke.mindustry.Vars.headless; @Serialize public class Sector{ @@ -46,11 +47,11 @@ public class Sector{ } public SaveSlot getSave(){ - return control.getSaves().getByID(saveID); + return !hasSave() ? null : control.getSaves().getByID(saveID); } public boolean hasSave(){ - return control.getSaves().getByID(saveID) != null; + return !headless && control.getSaves().getByID(saveID) != null; } public int packedPosition(){ diff --git a/core/src/io/anuke/mindustry/maps/Sectors.java b/core/src/io/anuke/mindustry/maps/Sectors.java index 11a48a92c9..3b629b379e 100644 --- a/core/src/io/anuke/mindustry/maps/Sectors.java +++ b/core/src/io/anuke/mindustry/maps/Sectors.java @@ -47,7 +47,9 @@ public class Sectors{ } world.loadSector(sector); logic.play(); - sector.saveID = control.getSaves().addSave("sector-" + sector.packedPosition()).index; + if(!headless){ + sector.saveID = control.getSaves().addSave("sector-" + sector.packedPosition()).index; + } world.sectors().save(); world.setSector(sector); sector.currentMission().onBegin(); diff --git a/core/src/io/anuke/mindustry/net/Administration.java b/core/src/io/anuke/mindustry/net/Administration.java index b303bf4d2a..e8ca496d2f 100644 --- a/core/src/io/anuke/mindustry/net/Administration.java +++ b/core/src/io/anuke/mindustry/net/Administration.java @@ -1,7 +1,6 @@ package io.anuke.mindustry.net; import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.IntMap; import com.badlogic.gdx.utils.ObjectMap; import io.anuke.annotations.Annotations.Serialize; import io.anuke.ucore.core.Settings; @@ -16,8 +15,6 @@ public class Administration{ private ObjectMap playerInfo = new ObjectMap<>(); /**Maps UUIDs to trace infos. This is wiped when a player logs off.*/ private ObjectMap traceInfo = new ObjectMap<>(); - /** Maps packed coordinates to logs for that coordinate*/ - private IntMap> editLogs = new IntMap<>(); private Array bannedIPs = new Array<>(); public Administration(){ @@ -46,16 +43,6 @@ public class Administration{ Settings.save(); } - public void setAntiGriefParams(int maxBreak, int cooldown){ - Settings.putInt("antigrief-max", maxBreak); - Settings.putInt("antigrief-cooldown", cooldown); - Settings.save(); - } - - public IntMap> getEditLogs(){ - return editLogs; - } - /** * Call when a player joins to update their information here. */ diff --git a/core/src/io/anuke/mindustry/net/EditLog.java b/core/src/io/anuke/mindustry/net/EditLog.java deleted file mode 100644 index ab922ae8e0..0000000000 --- a/core/src/io/anuke/mindustry/net/EditLog.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.anuke.mindustry.net; - -import io.anuke.mindustry.world.Block; - -public class EditLog{ - public String playername; - public Block block; - public int rotation; - public EditAction action; - - EditLog(String playername, Block block, int rotation, EditAction action){ - this.playername = playername; - this.block = block; - this.rotation = rotation; - this.action = action; - } - - public enum EditAction{ - PLACE, BREAK - } -} diff --git a/server/src/io/anuke/mindustry/server/ServerLauncher.java b/server/src/io/anuke/mindustry/server/ServerLauncher.java index 3ed3280250..17ce9d6a8d 100644 --- a/server/src/io/anuke/mindustry/server/ServerLauncher.java +++ b/server/src/io/anuke/mindustry/server/ServerLauncher.java @@ -1,7 +1,6 @@ package io.anuke.mindustry.server; import com.badlogic.gdx.ApplicationListener; -import com.badlogic.gdx.ApplicationLogger; import com.badlogic.gdx.Files.FileType; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Preferences; @@ -13,6 +12,7 @@ import io.anuke.kryonet.KryoClient; import io.anuke.kryonet.KryoServer; import io.anuke.mindustry.net.Net; import io.anuke.ucore.io.BinaryPreferences; +import io.anuke.ucore.util.EmptyLogger; import io.anuke.ucore.util.OS; import java.io.File; @@ -24,31 +24,7 @@ public class ServerLauncher extends HeadlessApplication{ super(listener, config); //don't do anything at all for GDX logging: don't want controller info and such - Gdx.app.setApplicationLogger(new ApplicationLogger(){ - @Override - public void log(String tag, String message){ - } - - @Override - public void log(String tag, String message, Throwable exception){ - } - - @Override - public void error(String tag, String message){ - } - - @Override - public void error(String tag, String message, Throwable exception){ - } - - @Override - public void debug(String tag, String message){ - } - - @Override - public void debug(String tag, String message, Throwable exception){ - } - }); + Gdx.app.setApplicationLogger(new EmptyLogger()); } public static void main(String[] args){ diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java new file mode 100644 index 0000000000..5cee8a0c0a --- /dev/null +++ b/tests/src/test/java/ApplicationTests.java @@ -0,0 +1,204 @@ +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.backends.headless.HeadlessApplication; +import com.badlogic.gdx.backends.headless.HeadlessApplicationConfiguration; +import io.anuke.mindustry.Vars; +import io.anuke.mindustry.content.Items; +import io.anuke.mindustry.content.blocks.Blocks; +import io.anuke.mindustry.content.blocks.StorageBlocks; +import io.anuke.mindustry.core.GameState.State; +import io.anuke.mindustry.core.Logic; +import io.anuke.mindustry.core.NetServer; +import io.anuke.mindustry.core.World; +import io.anuke.mindustry.game.Content; +import io.anuke.mindustry.game.Team; +import io.anuke.mindustry.io.BundleLoader; +import io.anuke.mindustry.io.SaveIO; +import io.anuke.mindustry.maps.Map; +import io.anuke.mindustry.world.Tile; +import io.anuke.ucore.core.Timers; +import io.anuke.ucore.modules.ModuleCore; +import io.anuke.ucore.util.EmptyLogger; +import io.anuke.ucore.util.Log; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.File; + +import static io.anuke.mindustry.Vars.*; +import static org.junit.jupiter.api.Assertions.*; + +public class ApplicationTests{ + + @BeforeAll + static void launchApplication(){ + try{ + boolean[] begins = {false}; + Throwable[] exceptionThrown = {null}; + Log.setUseColors(false); + + ModuleCore core = new ModuleCore(){ + @Override + public void init(){ + Vars.init(); + + headless = true; + + BundleLoader.load(); + content.load(); + content.initialize(Content::init); + + module(logic = new Logic()); + module(world = new World()); + module(netServer = new NetServer()); + } + + @Override + public void postInit(){ + super.postInit(); + begins[0] = true; + } + }; + + HeadlessApplicationConfiguration config = new HeadlessApplicationConfiguration(); + config.preferencesDirectory = "test_files/"; + + new File("tests_files/").delete(); + + new HeadlessApplication(core, config){{ + Gdx.app.setApplicationLogger(new EmptyLogger()); + }}; + + for(Thread thread : Thread.getAllStackTraces().keySet()){ + if(thread.getName().equals("HeadlessApplication")){ + thread.setUncaughtExceptionHandler((t, throwable) -> exceptionThrown[0] = throwable); + break; + } + } + + while(!begins[0]){ + if(exceptionThrown[0] != null){ + fail(exceptionThrown[0]); + } + Thread.sleep(10); + } + }catch(Throwable r){ + fail(r); + } + } + + @BeforeEach + void resetWorld(){ + Timers.setDeltaProvider(() -> 1f); + logic.reset(); + state.set(State.menu); + } + + @Test + void initialization(){ + assertTrue(logic != null); + assertTrue(world != null); + assertTrue(content.getContentMap().length > 0); + } + + @Test + void loadSector(){ + world.sectors().createSector(0, 0); + world.sectors().playSector(world.sectors().get(0, 0)); + } + + @Test + void playMap(){ + assertTrue(world.maps().all().size > 0); + + world.loadMap(world.maps().all().first()); + } + + @Test + void spawnWaves(){ + world.loadMap(world.maps().all().first()); + logic.runWave(); + unitGroups[waveTeam.ordinal()].updateEvents(); + assertFalse(unitGroups[waveTeam.ordinal()].isEmpty()); + } + + @Test + void createMap(){ + assertTrue(world.maps().all().size > 0); + + Tile[][] tiles = world.createTiles(8, 8); + + world.beginMapLoad(); + for(int x = 0; x < tiles.length; x++){ + for(int y = 0; y < tiles[0].length; y++){ + tiles[x][y] = new Tile(x, y, (byte)0, (byte)0); + } + } + world.endMapLoad(); + } + + @Test + void multiblock(){ + createMap(); + int bx = 4; + int by = 4; + world.setBlock(world.tile(bx, by), StorageBlocks.core, Team.blue); + assertTrue(world.tile(bx, by).getTeam() == Team.blue); + for(int x = bx-1; x <= bx + 1; x++){ + for(int y = by-1; y <= by + 1; y++){ + if(x == bx && by == y){ + assertTrue(world.tile(x, y).block() == StorageBlocks.core); + }else{ + assertTrue(world.tile(x, y).block() == Blocks.blockpart && world.tile(x, y).getLinked() == world.tile(bx, by)); + } + } + } + } + + @Test + void blockInventories(){ + multiblock(); + Tile tile = world.tile(4, 4); + tile.entity.items.add(Items.coal, 5); + tile.entity.items.add(Items.titanium, 50); + assertTrue(tile.entity.items.total() == 55); + tile.entity.items.remove(Items.phasematter, 10); + tile.entity.items.remove(Items.titanium, 10); + assertTrue(tile.entity.items.total() == 45); + } + + @Test + void timers(){ + boolean[] ran = {false}; + Timers.run(1.9999f, () -> ran[0] = true); + + Timers.update(); + assertFalse(ran[0]); + Timers.update(); + assertTrue(ran[0]); + } + + @Test + void save(){ + assertTrue(world.maps().all().size > 0); + + world.loadMap(world.maps().all().first()); + SaveIO.saveToSlot(0); + } + + @Test + void load(){ + assertTrue(world.maps().all().size > 0); + + world.loadMap(world.maps().all().first()); + Map map = world.getMap(); + + SaveIO.saveToSlot(0); + resetWorld(); + SaveIO.loadFromSlot(0); + + assertTrue(world.getMap() == map); + assertTrue(world.width() == map.meta.width); + assertTrue(world.height() == map.meta.height); + } +} \ No newline at end of file diff --git a/tests/src/test/java/Tests.java b/tests/src/test/java/Tests.java deleted file mode 100644 index 261bc16c5f..0000000000 --- a/tests/src/test/java/Tests.java +++ /dev/null @@ -1,9 +0,0 @@ -import org.junit.jupiter.api.BeforeEach; - -public class Tests{ - - @BeforeEach - void launchApplication(){ - - } -} \ No newline at end of file