From 47431f2534c5bd1163aff32bf6fbbabf180d1ff3 Mon Sep 17 00:00:00 2001 From: Frotty Date: Tue, 4 Aug 2026 16:54:45 +0200 Subject: [PATCH 1/3] move tests into dedicated packages --- README.md | 9 +- wurst/_handles/Destructable.wurst | 4 - wurst/_handles/DestructableTests.wurst | 7 + wurst/_handles/Dialog.wurst | 9 -- wurst/_handles/DialogTests.wurst | 11 ++ wurst/_handles/Effect.wurst | 9 -- wurst/_handles/EffectTests.wurst | 11 ++ wurst/_handles/Player.wurst | 5 - wurst/_handles/PlayerTests.wurst | 7 + wurst/_handles/Playercolor.wurst | 32 ---- wurst/_handles/PlayercolorTests.wurst | 35 +++++ wurst/_handles/Rect.wurst | 26 +--- wurst/_handles/RectTests.wurst | 28 ++++ wurst/closures/ClosureTimers.wurst | 31 ---- wurst/closures/ClosureTimersTests.wurst | 30 ++++ wurst/data/BitSet.wurst | 57 ------- wurst/data/BitSetTests.wurst | 58 ++++++++ wurst/file/ByteBuffer.wurst | 103 ------------- wurst/file/ByteBufferTests.wurst | 113 ++++++++++++++ wurst/file/ChunkedString.wurst | 38 ----- wurst/file/ChunkedStringTests.wurst | 44 ++++++ wurst/math/Angle.wurst | 15 -- wurst/math/AngleTests.wurst | 20 +++ wurst/math/Interpolation.wurst | 108 -------------- wurst/math/InterpolationTests.wurst | 123 +++++++++++++++ wurst/math/Maths.wurst | 20 --- wurst/math/MathsTests.wurst | 22 +++ wurst/math/Raycast.wurst | 190 ------------------------ wurst/math/RaycastTests.wurst | 181 ++++++++++++++++++++++ wurst/math/Vectors.wurst | 54 ------- wurst/math/VectorsTests.wurst | 64 ++++++++ wurst/objediting/ObjectIds.wurst | 26 ---- wurst/objediting/ObjectIdsTests.wurst | 27 ++++ wurst/util/Colors.wurst | 41 ----- wurst/util/ColorsTests.wurst | 39 +++++ wurst/util/GameTimer.wurst | 4 - wurst/util/GameTimerTests.wurst | 6 + wurst/util/MapBounds.wurst | 8 - wurst/util/MapBoundsTests.wurst | 10 ++ wurst/util/TerrainUtils.wurst | 25 ---- wurst/util/TerrainUtilsTests.wurst | 26 ++++ wurst/util/Time.wurst | 35 ----- wurst/util/TimeTests.wurst | 43 ++++++ 43 files changed, 912 insertions(+), 842 deletions(-) create mode 100644 wurst/_handles/DestructableTests.wurst create mode 100644 wurst/_handles/DialogTests.wurst create mode 100644 wurst/_handles/EffectTests.wurst create mode 100644 wurst/_handles/PlayerTests.wurst create mode 100644 wurst/_handles/PlayercolorTests.wurst create mode 100644 wurst/_handles/RectTests.wurst create mode 100644 wurst/closures/ClosureTimersTests.wurst create mode 100644 wurst/data/BitSetTests.wurst create mode 100644 wurst/file/ByteBufferTests.wurst create mode 100644 wurst/file/ChunkedStringTests.wurst create mode 100644 wurst/math/AngleTests.wurst create mode 100644 wurst/math/InterpolationTests.wurst create mode 100644 wurst/math/MathsTests.wurst create mode 100644 wurst/math/RaycastTests.wurst create mode 100644 wurst/math/VectorsTests.wurst create mode 100644 wurst/objediting/ObjectIdsTests.wurst create mode 100644 wurst/util/ColorsTests.wurst create mode 100644 wurst/util/GameTimerTests.wurst create mode 100644 wurst/util/MapBoundsTests.wurst create mode 100644 wurst/util/TerrainUtilsTests.wurst create mode 100644 wurst/util/TimeTests.wurst diff --git a/README.md b/README.md index ee9b9ec71..be0a73da9 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ ![](https://i.imgur.com/L3xfAs4.png) -[![CircleCI](https://circleci.com/gh/wurstscript/WurstStdlib2.svg?style=svg)](https://circleci.com/gh/wurstscript/WurstStdlib2) +[![Build](https://github.com/wurstscript/WurstStdlib2/actions/workflows/build.yml/badge.svg)](https://github.com/wurstscript/WurstStdlib2/actions/workflows/build.yml) # Wurst Standard Library -This is the repository of the WurstScript standard library which provides a vast amount of useful packages to users starting out with Wurst. -Many commonly used data structures, wc3 specific utility packages, Object Editing as well as extension wrappers for the blizzard natives have been implemented, are unit tested and therefore ready to use in production immediately. +This is the repository of the WurstScript standard library. It provides commonly used data structures, math and string utilities, Warcraft III native wrappers, and reusable WC3 systems for maps. + +The repository also contains opt-in object-editing APIs and generated Warcraft III asset catalogs. These map game data into Wurst so map authors can use typed constants instead of raw IDs and paths. + +Packages are unit tested and intended to be usable in production. Tests live in dedicated `*Tests` packages so production packages contain only their runtime and compiletime APIs. # Motivation diff --git a/wurst/_handles/Destructable.wurst b/wurst/_handles/Destructable.wurst index 8ba5f9729..9b0c72aa1 100644 --- a/wurst/_handles/Destructable.wurst +++ b/wurst/_handles/Destructable.wurst @@ -1,7 +1,6 @@ package Destructable import NoWurst import Vectors -import Wurstunit public function createDestructable(int id, vec3 pos, angle direction, real scale, int variation) returns destructable return createDestructable(id, pos.toVec2(), direction, scale, variation) @@ -150,6 +149,3 @@ public function elevator.setHeight(int height) if newHeight != oldHeight this.elevatable.queueAnimation(animationQueue) -@Test function testDestructables() - let destr = createDestructable(0, ZERO2, 0 .fromDeg(), 1, -1) - destr.getX().assertEquals(0.) diff --git a/wurst/_handles/DestructableTests.wurst b/wurst/_handles/DestructableTests.wurst new file mode 100644 index 000000000..de7494a14 --- /dev/null +++ b/wurst/_handles/DestructableTests.wurst @@ -0,0 +1,7 @@ +package DestructableTests +import Destructable +import Wurstunit + +@Test function testDestructables() + let destr = createDestructable(0, ZERO2, 0 .fromDeg(), 1, -1) + destr.getX().assertEquals(0.) diff --git a/wurst/_handles/Dialog.wurst b/wurst/_handles/Dialog.wurst index de6db8eb9..f22d892b3 100644 --- a/wurst/_handles/Dialog.wurst +++ b/wurst/_handles/Dialog.wurst @@ -1,6 +1,5 @@ package Dialog import NoWurst -import Wurstunit /** Dialogs are big dialog boxes at the center of the screen. The player can choose one button to click. @@ -42,11 +41,3 @@ public function dialog.display(player whichPlayer, boolean flag) public function dialog.setMessage(string messageText) DialogSetMessage(this, messageText) -@Test -function testDialog() - let dia = createDialog() - dia..addButton("text") - ..addQuitButton(true, "test") - ..display(Player(0), true) - ..clear() - ..destr() diff --git a/wurst/_handles/DialogTests.wurst b/wurst/_handles/DialogTests.wurst new file mode 100644 index 000000000..491aa6806 --- /dev/null +++ b/wurst/_handles/DialogTests.wurst @@ -0,0 +1,11 @@ +package DialogTests +import Dialog +import Wurstunit + +@Test function testDialog() + let dia = createDialog() + dia..addButton("text") + ..addQuitButton(true, "test") + ..display(Player(0), true) + ..clear() + ..destr() diff --git a/wurst/_handles/Effect.wurst b/wurst/_handles/Effect.wurst index a48769f60..501fe4938 100644 --- a/wurst/_handles/Effect.wurst +++ b/wurst/_handles/Effect.wurst @@ -2,7 +2,6 @@ package Effect import NoWurst import Quaternion import Colors -import Wurstunit public function effect.destr() DestroyEffect(this) @@ -214,11 +213,3 @@ public function effect.setScale(vec3 scaleVector) public function effect.resetScale() BlzResetSpecialEffectMatrix(this) -@Test -function testEffect() - let eff = addEffect("testPath", vec2(12,32)) - - eff.getLocalX().assertEquals(12.) - eff.getLocalY().assertEquals(32.) - - eff.destr() diff --git a/wurst/_handles/EffectTests.wurst b/wurst/_handles/EffectTests.wurst new file mode 100644 index 000000000..0f8e8e1ee --- /dev/null +++ b/wurst/_handles/EffectTests.wurst @@ -0,0 +1,11 @@ +package EffectTests +import Effect +import Wurstunit + +@Test function testEffect() + let eff = addEffect("testPath", vec2(12,32)) + + eff.getLocalX().assertEquals(12.) + eff.getLocalY().assertEquals(32.) + + eff.destr() diff --git a/wurst/_handles/Player.wurst b/wurst/_handles/Player.wurst index ee65d17e0..d071f053b 100755 --- a/wurst/_handles/Player.wurst +++ b/wurst/_handles/Player.wurst @@ -1,6 +1,5 @@ package Player import NoWurst -import Wurstunit import Unit import Annotations import String @@ -229,7 +228,3 @@ public function player.hasVisibility(vec2 pos) returns bool return IsVisibleToPlayer(pos.x, pos.y, this) -@Test -function testPlayer() - let p = Player(0) - assertTrue(p == Player(0)) diff --git a/wurst/_handles/PlayerTests.wurst b/wurst/_handles/PlayerTests.wurst new file mode 100644 index 000000000..3fd2e881a --- /dev/null +++ b/wurst/_handles/PlayerTests.wurst @@ -0,0 +1,7 @@ +package PlayerTests +import Player +import Wurstunit + +@Test function testPlayer() + let p = Player(0) + assertTrue(p == Player(0)) diff --git a/wurst/_handles/Playercolor.wurst b/wurst/_handles/Playercolor.wurst index 58f1c95ae..e2fc65863 100644 --- a/wurst/_handles/Playercolor.wurst +++ b/wurst/_handles/Playercolor.wurst @@ -2,7 +2,6 @@ package Playercolor import NoWurst import Force import Player -import Wurstunit public constant PLAYER_COLOR_BLACK_AGGRESSIVE = ConvertPlayerColor(24) public constant PLAYER_COLOR_UNKNOWN1 = ConvertPlayerColor(25) @@ -72,34 +71,3 @@ public function playercolor.getPlayers() returns force return matchingPlayers -@Test public function testToInt() - PLAYER_COLOR_RED.toInt().assertEquals(0) - PLAYER_COLOR_PEANUT.toInt().assertEquals(23) - -@Test public function testToPlayerColor() - assertTrue((0).toPlayerColor() == PLAYER_COLOR_RED) - assertTrue((23).toPlayerColor() == PLAYER_COLOR_PEANUT) - -@Test public function testGetPlayer() - assertTrue(PLAYER_COLOR_RED.getPlayer() == Player(0)) - assertTrue(PLAYER_COLOR_PEANUT.getPlayer() == Player(23)) - -@Test public function testGetPlayers() - // Test some Player package methods that this file depends on - (players[0] != null).assertTrue() - players[0].setColor(PLAYER_COLOR_RED) - (players[0].getColor() == PLAYER_COLOR_RED).assertTrue() - // Test getting forces of players. - let force1 = PLAYER_COLOR_RED.getPlayers() - force1.containsPlayer(Player(0)).assertTrue() - players[1].setColor(PLAYER_COLOR_BLUE) - players[2].setColor(PLAYER_COLOR_BLUE) - let force2 = PLAYER_COLOR_BLUE.getPlayers() - force2.containsPlayer(Player(1)).assertTrue() - force2.containsPlayer(Player(2)).assertTrue() - force2.containsPlayer(Player(3)).assertFalse() - - let p = players[5] - assertTrue(p.getColor() == null) - p.setColor(PLAYER_COLOR_AQUA) - assertTrue(p.getColor() == PLAYER_COLOR_AQUA) diff --git a/wurst/_handles/PlayercolorTests.wurst b/wurst/_handles/PlayercolorTests.wurst new file mode 100644 index 000000000..ed8553581 --- /dev/null +++ b/wurst/_handles/PlayercolorTests.wurst @@ -0,0 +1,35 @@ +package PlayercolorTests +import Playercolor +import Wurstunit + +@Test public function testToInt() + PLAYER_COLOR_RED.toInt().assertEquals(0) + PLAYER_COLOR_PEANUT.toInt().assertEquals(23) + +@Test public function testToPlayerColor() + assertTrue((0).toPlayerColor() == PLAYER_COLOR_RED) + assertTrue((23).toPlayerColor() == PLAYER_COLOR_PEANUT) + +@Test public function testGetPlayer() + assertTrue(PLAYER_COLOR_RED.getPlayer() == Player(0)) + assertTrue(PLAYER_COLOR_PEANUT.getPlayer() == Player(23)) + +@Test public function testGetPlayers() + // Test some Player package methods that this file depends on + (players[0] != null).assertTrue() + players[0].setColor(PLAYER_COLOR_RED) + (players[0].getColor() == PLAYER_COLOR_RED).assertTrue() + // Test getting forces of players. + let force1 = PLAYER_COLOR_RED.getPlayers() + force1.containsPlayer(Player(0)).assertTrue() + players[1].setColor(PLAYER_COLOR_BLUE) + players[2].setColor(PLAYER_COLOR_BLUE) + let force2 = PLAYER_COLOR_BLUE.getPlayers() + force2.containsPlayer(Player(1)).assertTrue() + force2.containsPlayer(Player(2)).assertTrue() + force2.containsPlayer(Player(3)).assertFalse() + + let p = players[5] + assertTrue(p.getColor() == null) + p.setColor(PLAYER_COLOR_AQUA) + assertTrue(p.getColor() == PLAYER_COLOR_AQUA) diff --git a/wurst/_handles/Rect.wurst b/wurst/_handles/Rect.wurst index 07a19a440..90bdfabf4 100644 --- a/wurst/_handles/Rect.wurst +++ b/wurst/_handles/Rect.wurst @@ -1,7 +1,6 @@ package Rect import NoWurst import Vectors -import Wurstunit public function rect.randomPoint() returns vec2 return vec2(GetRandomReal(this.getMinX(), this.getMaxX()), GetRandomReal(this.getMinY(), this.getMaxY())) @@ -84,30 +83,6 @@ public function rect.fromCenter(real sizeX, real sizeY) returns rect public function rect.fromCenterWithOffset(real sizeX, real sizeY, vec2 offset) returns rect let c = this.getCenter() + offset return Rect(c.x - sizeX / 2, c.y - sizeY / 2, c.x + sizeX / 2, c.y + sizeY / 2) - -@Test -function rectTest() - let rekt = Rect(2, 2, 4, 4) - - rekt.width().assertEquals(2) - rekt.height().assertEquals(2) - - rekt.getCenterX().assertEquals(3) - rekt.getCenterY().assertEquals(3) - - rekt.moveTo(1, 1) - - rekt.width().assertEquals(2) - rekt.height().assertEquals(2) - - rekt.getCenterX().assertEquals(1) - rekt.getCenterY().assertEquals(1) - - rekt.resize(ZERO2, vec2(4, 4)) - - rekt.getCenterX().assertEquals(2) - rekt.getCenterY().assertEquals(2) - public function rect.setRectFromLoc(location min, location max) SetRectFromLoc(this, min, max) @@ -126,3 +101,4 @@ public function rect.addWeatherEffect(integer effectID) returns weathereffect public function rect.setDoodadAnimationRect(integer doodadID, string animName, boolean animRandom) SetDoodadAnimationRect(this, doodadID, animName, animRandom) + diff --git a/wurst/_handles/RectTests.wurst b/wurst/_handles/RectTests.wurst new file mode 100644 index 000000000..42105f9f1 --- /dev/null +++ b/wurst/_handles/RectTests.wurst @@ -0,0 +1,28 @@ +package RectTests +import Rect +import Wurstunit + + +@Test +function rectTest() + let rekt = Rect(2, 2, 4, 4) + + rekt.width().assertEquals(2) + rekt.height().assertEquals(2) + + rekt.getCenterX().assertEquals(3) + rekt.getCenterY().assertEquals(3) + + rekt.moveTo(1, 1) + + rekt.width().assertEquals(2) + rekt.height().assertEquals(2) + + rekt.getCenterX().assertEquals(1) + rekt.getCenterY().assertEquals(1) + + rekt.resize(ZERO2, vec2(4, 4)) + + rekt.getCenterX().assertEquals(2) + rekt.getCenterY().assertEquals(2) + diff --git a/wurst/closures/ClosureTimers.wurst b/wurst/closures/ClosureTimers.wurst index 00ec1d41d..ae84697a7 100644 --- a/wurst/closures/ClosureTimers.wurst +++ b/wurst/closures/ClosureTimers.wurst @@ -3,7 +3,6 @@ import NoWurst import TimerDialog import TimerUtils import Real -import Wurstunit /** Execute an action after a certain time. The callback object is automatically destroyed. @@ -225,33 +224,3 @@ public abstract class CallbackCounted t.release() -var x = 200 -@Test function testDoAfter() - - doAfter(0.1) -> - x += 50 - - doAfter(0.2) -> - x *= 2 - - doAfter(0.3) -> - x = x div 2 - x.assertEquals(250) - - var _count = 3 - - let cb = doPeriodicallyCounted(3, 3) (CallbackCounted cb) -> - cb.getCount().assertEquals(_count) - if cb.isLast() - cb.progress().assertEquals(1, 0.0001) - cb.getCount().assertEquals(1) - else if _count == 3 - cb.progress().assertEquals(0.33333, 0.00001) - cb.getCount().assertEquals(3) - else if _count == 2 - cb.progress().assertEquals(0.66666, 0.00001) - cb.getCount().assertEquals(2) - _count-- - - cb.progress().assertEquals(0, 0.00001) - cb.getCount().assertEquals(_count) diff --git a/wurst/closures/ClosureTimersTests.wurst b/wurst/closures/ClosureTimersTests.wurst new file mode 100644 index 000000000..592bd8751 --- /dev/null +++ b/wurst/closures/ClosureTimersTests.wurst @@ -0,0 +1,30 @@ +package ClosureTimersTests +import ClosureTimers +import Wurstunit + +var x = 200 + +@Test function testDoAfter() + doAfter(0.1) -> + x += 50 + doAfter(0.2) -> + x *= 2 + doAfter(0.3) -> + x = x div 2 + x.assertEquals(250) + + var _count = 3 + let cb = doPeriodicallyCounted(3, 3) (CallbackCounted cb) -> + cb.getCount().assertEquals(_count) + if cb.isLast() + cb.progress().assertEquals(1, 0.0001) + cb.getCount().assertEquals(1) + else if _count == 3 + cb.progress().assertEquals(0.33333, 0.00001) + cb.getCount().assertEquals(3) + else if _count == 2 + cb.progress().assertEquals(0.66666, 0.00001) + cb.getCount().assertEquals(2) + _count-- + cb.progress().assertEquals(0, 0.00001) + cb.getCount().assertEquals(_count) diff --git a/wurst/data/BitSet.wurst b/wurst/data/BitSet.wurst index ae11c5384..cfb25c1c1 100644 --- a/wurst/data/BitSet.wurst +++ b/wurst/data/BitSet.wurst @@ -1,7 +1,6 @@ package BitSet import NoWurst import Integer -import Wurstunit import Annotations public constant BITSET_SIZE = 32 @@ -80,59 +79,3 @@ public function bitsetToIndex(bitset object) returns int public function bitsetFromIndex(int index) returns bitset return bitset(index) -// Tests - -@Test function testGet() - let set = bitset(45) - set.get(0).assertTrue() - set.get(1).assertFalse() - set.get(2).assertTrue() - set.get(3).assertTrue() - set.get(4).assertFalse() - set.get(5).assertTrue() - -@Test function testSet() - emptyBitset().set(0).set(2).set(3).set(5).val.assertEquals(45) - -@Test function testReset() - bitset(45).reset(3).val.assertEquals(37) - -@Test function testFlip() - emptyBitset().set(3).flip(3).get(3).assertFalse() - emptyBitset().flip(3).get(3).assertTrue() - -@Test function testHighestBit() - let bit = BITSET_SIZE - 1 - emptyBitset().set(bit).get(bit).assertTrue() - emptyBitset().set(bit).reset(bit).get(bit).assertFalse() - emptyBitset().flip(bit).get(bit).assertTrue() - emptyBitset().set(bit).flip(bit).get(bit).assertFalse() - -@Test function testIsEmpty() - emptyBitset().isEmpty().assertTrue() - emptyBitset().set(7).isEmpty().assertFalse() - -@Test function testIntersects() - emptyBitset().set(2).set(5).set(7).intersects(emptyBitset().set(1).set(4).set(21)).assertFalse() - emptyBitset().set(3).set(11).intersects(emptyBitset().set(5).set(11)).assertTrue() - -@Test function testOverall() - var bitset = emptyBitset().set(0).set(3).set(8) - - for i = 0 to 8 - if i == 0 or i == 3 or i == 8 - bitset.get(i).assertTrue() - else - bitset.get(i).assertFalse() - - bitset = bitset.reset(8) - .set(3) // should not change anything - .reset(2) // should not change anything - .flip(0) - .flip(2) - - for i = 0 to 8 - if i == 2 or i == 3 - bitset.get(i).assertTrue() - else - bitset.get(i).assertFalse() diff --git a/wurst/data/BitSetTests.wurst b/wurst/data/BitSetTests.wurst new file mode 100644 index 000000000..e4fc41f6e --- /dev/null +++ b/wurst/data/BitSetTests.wurst @@ -0,0 +1,58 @@ +package BitSetTests +import BitSet +import Wurstunit + +@Test function testGet() + let set = bitset(45) + set.get(0).assertTrue() + set.get(1).assertFalse() + set.get(2).assertTrue() + set.get(3).assertTrue() + set.get(4).assertFalse() + set.get(5).assertTrue() + +@Test function testSet() + emptyBitset().set(0).set(2).set(3).set(5).val.assertEquals(45) + +@Test function testReset() + bitset(45).reset(3).val.assertEquals(37) + +@Test function testFlip() + emptyBitset().set(3).flip(3).get(3).assertFalse() + emptyBitset().flip(3).get(3).assertTrue() + +@Test function testHighestBit() + let bit = BITSET_SIZE - 1 + emptyBitset().set(bit).get(bit).assertTrue() + emptyBitset().set(bit).reset(bit).get(bit).assertFalse() + emptyBitset().flip(bit).get(bit).assertTrue() + emptyBitset().set(bit).flip(bit).get(bit).assertFalse() + +@Test function testIsEmpty() + emptyBitset().isEmpty().assertTrue() + emptyBitset().set(7).isEmpty().assertFalse() + +@Test function testIntersects() + emptyBitset().set(2).set(5).set(7).intersects(emptyBitset().set(1).set(4).set(21)).assertFalse() + emptyBitset().set(3).set(11).intersects(emptyBitset().set(5).set(11)).assertTrue() + +@Test function testOverall() + var bitset = emptyBitset().set(0).set(3).set(8) + + for i = 0 to 8 + if i == 0 or i == 3 or i == 8 + bitset.get(i).assertTrue() + else + bitset.get(i).assertFalse() + + bitset = bitset.reset(8) + .set(3) + .reset(2) + .flip(0) + .flip(2) + + for i = 0 to 8 + if i == 2 or i == 3 + bitset.get(i).assertTrue() + else + bitset.get(i).assertFalse() diff --git a/wurst/file/ByteBuffer.wurst b/wurst/file/ByteBuffer.wurst index a0a8cc2e2..ef369ac24 100644 --- a/wurst/file/ByteBuffer.wurst +++ b/wurst/file/ByteBuffer.wurst @@ -134,106 +134,3 @@ public class ByteBuffer bufferLength = 4 intCount = newIntCount bufferLength = min(size - newIntCount * 4, bufferLength) - -@Test -function byteBufferTest() - let byteBuffer = new ByteBuffer() - byteBuffer.writeByte(3) - byteBuffer.writeByte(200) - byteBuffer.writeByte(15) - byteBuffer.writeByte(7) - - byteBuffer.writeByte(128) - - byteBuffer.writeShort(0x4a2f) - byteBuffer.writeShort(0xfabc) - byteBuffer.writeShort(0x002a) - - byteBuffer.writeInt(0xffaabbcc) - - byteBuffer.readByte().assertEquals(3) - byteBuffer.readByte().assertEquals(200) - byteBuffer.readByte().assertEquals(15) - byteBuffer.readByte().assertEquals(7) - - byteBuffer.readByte().assertEquals(128) - - byteBuffer.readShort().assertEquals(0x4a2f) - byteBuffer.readShort().assertEquals(0xfabc) - byteBuffer.readShort().assertEquals(0x002a) - - byteBuffer.readInt().assertEquals(0xffaabbcc) - -@Test -function byteBufferIterativeReadingTest() - let byteBuffer = new ByteBuffer() - - let expectedBytes = [0xb3, 0xfb, 0xc6, 0xec, 0x89, 0xf9, 0x25, 0x22, 0x4a, 0xe0, 0x99, 0x08, 0x5d, 0x1a] - for i = 0 to expectedBytes.length - 1 - byteBuffer.writeByte(expectedBytes[i]) - - int array bytes - var bytesLength = 0 - while byteBuffer.hasByte() - bytes[bytesLength] = byteBuffer.readByte() - bytesLength++ - - bytesLength.assertEquals(expectedBytes.length) - for i = 0 to bytesLength - 1 - bytes[i].assertEquals(expectedBytes[i]) - -/** hasByte() used to compare the int cursor against intCount, which stayed - true after the last byte of a buffer whose size is an exact multiple of 4. */ -@Test -function byteBufferSizeMultipleOfFourTest() - for length = 1 to 12 - let byteBuffer = new ByteBuffer() - for i = 1 to length - byteBuffer.writeByte(i) - - var read = 0 - while byteBuffer.hasByte() and read < length + 4 - byteBuffer.readByte() - read++ - - read.assertEquals(length) - destroy byteBuffer - -@Test -function byteBufferEmptyTest() - let byteBuffer = new ByteBuffer() - byteBuffer.size().assertEquals(0) - byteBuffer.hasByte().assertFalse() - destroy byteBuffer - -@Test -function byteBufferResetReadTest() - let byteBuffer = new ByteBuffer() - byteBuffer.writeInt(0x01020304) - - var first = 0 - while byteBuffer.hasByte() - byteBuffer.readByte() - first++ - - byteBuffer.resetRead() - - var second = 0 - while byteBuffer.hasByte() - byteBuffer.readByte() - second++ - - first.assertEquals(4) - second.assertEquals(4) - destroy byteBuffer - -/** Little endian: writeInt emits the least significant byte first. */ -@Test -function byteBufferEndiannessTest() - let byteBuffer = new ByteBuffer() - byteBuffer.writeInt(0x01020304) - byteBuffer.readByte().assertEquals(0x04) - byteBuffer.readByte().assertEquals(0x03) - byteBuffer.readByte().assertEquals(0x02) - byteBuffer.readByte().assertEquals(0x01) - destroy byteBuffer diff --git a/wurst/file/ByteBufferTests.wurst b/wurst/file/ByteBufferTests.wurst new file mode 100644 index 000000000..9552ca607 --- /dev/null +++ b/wurst/file/ByteBufferTests.wurst @@ -0,0 +1,113 @@ +package ByteBufferTests +import ByteBuffer +import Wurstunit + + +@Test +function byteBufferTest() + let byteBuffer = new ByteBuffer() + byteBuffer.writeByte(3) + byteBuffer.writeByte(200) + byteBuffer.writeByte(15) + byteBuffer.writeByte(7) + + byteBuffer.writeByte(128) + + byteBuffer.writeShort(0x4a2f) + byteBuffer.writeShort(0xfabc) + byteBuffer.writeShort(0x002a) + + byteBuffer.writeInt(0xffaabbcc) + + byteBuffer.readByte().assertEquals(3) + byteBuffer.readByte().assertEquals(200) + byteBuffer.readByte().assertEquals(15) + byteBuffer.readByte().assertEquals(7) + + byteBuffer.readByte().assertEquals(128) + + byteBuffer.readShort().assertEquals(0x4a2f) + byteBuffer.readShort().assertEquals(0xfabc) + byteBuffer.readShort().assertEquals(0x002a) + + byteBuffer.readInt().assertEquals(0xffaabbcc) + + +@Test +function byteBufferIterativeReadingTest() + let byteBuffer = new ByteBuffer() + + let expectedBytes = [0xb3, 0xfb, 0xc6, 0xec, 0x89, 0xf9, 0x25, 0x22, 0x4a, 0xe0, 0x99, 0x08, 0x5d, 0x1a] + for i = 0 to expectedBytes.length - 1 + byteBuffer.writeByte(expectedBytes[i]) + + int array bytes + var bytesLength = 0 + while byteBuffer.hasByte() + bytes[bytesLength] = byteBuffer.readByte() + bytesLength++ + + bytesLength.assertEquals(expectedBytes.length) + for i = 0 to bytesLength - 1 + bytes[i].assertEquals(expectedBytes[i]) + + +/** hasByte() used to compare the int cursor against intCount, which stayed + true after the last byte of a buffer whose size is an exact multiple of 4. */ +@Test +function byteBufferSizeMultipleOfFourTest() + for length = 1 to 12 + let byteBuffer = new ByteBuffer() + for i = 1 to length + byteBuffer.writeByte(i) + + var read = 0 + while byteBuffer.hasByte() and read < length + 4 + byteBuffer.readByte() + read++ + + read.assertEquals(length) + destroy byteBuffer + + +@Test +function byteBufferEmptyTest() + let byteBuffer = new ByteBuffer() + byteBuffer.size().assertEquals(0) + byteBuffer.hasByte().assertFalse() + destroy byteBuffer + + +@Test +function byteBufferResetReadTest() + let byteBuffer = new ByteBuffer() + byteBuffer.writeInt(0x01020304) + + var first = 0 + while byteBuffer.hasByte() + byteBuffer.readByte() + first++ + + byteBuffer.resetRead() + + var second = 0 + while byteBuffer.hasByte() + byteBuffer.readByte() + second++ + + first.assertEquals(4) + second.assertEquals(4) + destroy byteBuffer + + +/** Little endian: writeInt emits the least significant byte first. */ +@Test +function byteBufferEndiannessTest() + let byteBuffer = new ByteBuffer() + byteBuffer.writeInt(0x01020304) + byteBuffer.readByte().assertEquals(0x04) + byteBuffer.readByte().assertEquals(0x03) + byteBuffer.readByte().assertEquals(0x02) + byteBuffer.readByte().assertEquals(0x01) + destroy byteBuffer + diff --git a/wurst/file/ChunkedString.wurst b/wurst/file/ChunkedString.wurst index c852842d0..c094dd97e 100644 --- a/wurst/file/ChunkedString.wurst +++ b/wurst/file/ChunkedString.wurst @@ -155,41 +155,3 @@ public class ChunkedString ondestroy destroy table - -@Test -function chunkedStringTest() - let cstring = new ChunkedString(5) - cstring.append("abc") - cstring.append("def") - - cstring.chunkCount.assertEquals(1) - cstring.buffer.assertEquals("f") - - cstring.append("ghijklmnopq") - - cstring.chunkCount.assertEquals(3) - cstring.buffer.assertEquals("pq") - - cstring.getUnsafeString().assertEquals("abcdefghijklmnopq") - cstring.getUnsafeSubString(4, 12).assertEquals("efghijkl") - cstring.getUnsafeSubString(0, 3).assertEquals("abc") - cstring.getUnsafeSubString(15, 17).assertEquals("pq") - -@Test -function chunkedStringIteration() - let cstring = new ChunkedString(5) - cstring.append("abc") - cstring.append("def") - - var result = "" - - for i = 0 to cstring.getChunkCount() - 1 - result += cstring.getChunk(i) - - result.assertEquals("abcdef") - result = "" - - while cstring.hasChunk() - result += cstring.readChunk() - - result.assertEquals("abcdef") diff --git a/wurst/file/ChunkedStringTests.wurst b/wurst/file/ChunkedStringTests.wurst new file mode 100644 index 000000000..d817ad246 --- /dev/null +++ b/wurst/file/ChunkedStringTests.wurst @@ -0,0 +1,44 @@ +package ChunkedStringTests +import ChunkedString +import Wurstunit + + +@Test +function chunkedStringTest() + let cstring = new ChunkedString(5) + cstring.append("abc") + cstring.append("def") + + cstring.chunkCount.assertEquals(1) + cstring.buffer.assertEquals("f") + + cstring.append("ghijklmnopq") + + cstring.chunkCount.assertEquals(3) + cstring.buffer.assertEquals("pq") + + cstring.getUnsafeString().assertEquals("abcdefghijklmnopq") + cstring.getUnsafeSubString(4, 12).assertEquals("efghijkl") + cstring.getUnsafeSubString(0, 3).assertEquals("abc") + cstring.getUnsafeSubString(15, 17).assertEquals("pq") + + +@Test +function chunkedStringIteration() + let cstring = new ChunkedString(5) + cstring.append("abc") + cstring.append("def") + + var result = "" + + for i = 0 to cstring.getChunkCount() - 1 + result += cstring.getChunk(i) + + result.assertEquals("abcdef") + result = "" + + while cstring.hasChunk() + result += cstring.readChunk() + + result.assertEquals("abcdef") + diff --git a/wurst/math/Angle.wurst b/wurst/math/Angle.wurst index 5283c64f0..92bc7213e 100644 --- a/wurst/math/Angle.wurst +++ b/wurst/math/Angle.wurst @@ -1,6 +1,5 @@ package Angle import NoWurst -import Wurstunit /** Converts Degrees to Radians */ public constant DEGTORAD = 0.017453293 @@ -74,17 +73,3 @@ public function real.op_mult(angle ang) returns angle /** divides the angle by the given scalar */ public function angle.op_divReal(real scalar) returns angle return angle(this.radians / scalar) - -@Test function testAngle() - (180 .fromDeg().radians).assertEquals(180 .fromDeg().degrees().fromDeg().radians) - - (180 .fromDeg() + 90 .fromDeg()).degrees().assertEquals(270) - - (0 .fromDeg()).sin().assertEquals(0) - (90 .fromDeg()).sin().assertEquals(1) - -@Test function testFromRadIsRadians() - let halfTurn = 3.141592654 - halfTurn.fromRad().degrees().assertEquals(180., 0.001) - let three = 3 - three.fromRad().radians().assertEquals(3., 0.0001) diff --git a/wurst/math/AngleTests.wurst b/wurst/math/AngleTests.wurst new file mode 100644 index 000000000..eb36e6851 --- /dev/null +++ b/wurst/math/AngleTests.wurst @@ -0,0 +1,20 @@ +package AngleTests +import Angle +import Wurstunit + + +@Test function testAngle() + (180 .fromDeg().radians).assertEquals(180 .fromDeg().degrees().fromDeg().radians) + + (180 .fromDeg() + 90 .fromDeg()).degrees().assertEquals(270) + + (0 .fromDeg()).sin().assertEquals(0) + (90 .fromDeg()).sin().assertEquals(1) + + +@Test function testFromRadIsRadians() + let halfTurn = 3.141592654 + halfTurn.fromRad().degrees().assertEquals(180., 0.001) + let three = 3 + three.fromRad().radians().assertEquals(3., 0.0001) + diff --git a/wurst/math/Interpolation.wurst b/wurst/math/Interpolation.wurst index e3832f72b..4f034a66b 100644 --- a/wurst/math/Interpolation.wurst +++ b/wurst/math/Interpolation.wurst @@ -1,7 +1,6 @@ package Interpolation import NoWurst import Vectors -import Wurstunit // Credits to BlinkyBoy /** Look at linear */ @@ -108,110 +107,3 @@ public function inTan(real p1, real p2, real p3, real p, real c, real b) returns /** Returns the outtan of p2 */ public function outTan(real p1, real p2, real p3, real p, real c, real b) returns real return (1.0 - p) * (1.0 + c) * (1.0 + b) * (p2 - p1) / 2. + (1.0 - p) * (1.0 - c) * (1.0 - b) * (p3 - p2) / 2. - -@Test -function linearVecTest() - let v = linear(vec2(3, 4), vec2(6, 2), 0.5) - v.x.assertEquals(4.5) - v.y.assertEquals(3) - -@Test function testVec2Bezier3() - let start = vec2(-1, 0) - let mid = vec2(0, 2) - let stop = vec2(1, 0) - let p = 0.75 - let expected = vec2(0.5, 0.75) - start.bezier3(mid, stop, p).assertEquals(expected) - start.bezier3(mid, stop, 0).assertEquals(start) - start.bezier3(mid, stop, 1).assertEquals(stop) - -@Test function testVec2DerivBezier3() - let start = vec2(-1, 0) - let mid = vec2(0, 2) - let stop = vec2(1, 0) - let p = 0.75 - let expected = vec2(2, -2) - start.derivBezier3(mid, stop, p).assertEquals(expected) - -@Test function testVec2Bezier4() - let start = vec2(-3, 0) - let mid1 = vec2(-2, 2) - let mid2 = vec2(0, 0) - let stop = vec2(1, 1) - let p = 0.75 - let expected = vec2(0.09375, 0.703125) - start.bezier4(mid1, mid2, stop, p).assertEquals(expected) - start.bezier4(mid1, mid2, stop, 0).assertEquals(start) - start.bezier4(mid1, mid2, stop, 1).assertEquals(stop) - -@Test function testVec2DerivBezier4() - let start = vec2(-3, 0) - let mid1 = vec2(-2, 2) - let mid2 = vec2(0, 0) - let stop = vec2(1, 1) - let p = 0.75 - let expected = vec2(4.125, -0.1875) - start.derivBezier4(mid1, mid2, stop, p).assertEquals(expected) - -@Test function testVec3Bezier3() - let start = vec3(-1, 0, -2) - let mid = vec3(0, 2, 0.5) - let stop = vec3(1, 0, 3) - let p = 0.75 - let expected = vec3(0.5, 0.75, 1.75) - start.bezier3(mid, stop, p).assertEquals(expected) - start.bezier3(mid, stop, 0).assertEquals(start) - start.bezier3(mid, stop, 1).assertEquals(stop) - -@Test function testVec3DerivBezier3() - let start = vec3(-1, 0, -2) - let mid = vec3(0, 2, 0.5) - let stop = vec3(1, 0, 3) - let p = 0.75 - let expected = vec3(2, -2, 5) - start.derivBezier3(mid, stop, p).assertEquals(expected) - -@Test function testVec3Bezier4() - let start = vec3(-3, 0, 0) - let mid1 = vec3(-2, 2, -3) - let mid2 = vec3(0, 0, 0) - let stop = vec3(1, 1, 2) - let p = 0.75 - let expected = vec3(0.09375, 0.703125, 0.421875) - start.bezier4(mid1, mid2, stop, p).assertEquals(expected) - start.bezier4(mid1, mid2, stop, 0).assertEquals(start) - start.bezier4(mid1, mid2, stop, 1).assertEquals(stop) - -@Test function testVec3DerivBezier4() - let start = vec3(-3, 0, 0) - let mid1 = vec3(-2, 2, -3) - let mid2 = vec3(0, 0, 0) - let stop = vec3(1, 1, 2) - let p = 0.75 - let expected = vec3(4.125, -0.1875, 6.1875) - start.derivBezier4(mid1, mid2, stop, p).assertEquals(expected) - -@Test function testHermiteEndpoints() - hermite(3., 9., 2., -5., 0.).assertEquals(3., 0.0001) - hermite(3., 9., 2., -5., 1.).assertEquals(9., 0.0001) - -/** With zero tangents the Hermite basis degenerates to smoothstep. */ -@Test function testHermiteZeroTangents() - hermite(0., 1., 0., 0., 0.25).assertEquals(0.15625, 0.0001) - hermite(0., 1., 0., 0., 0.5).assertEquals(0.5, 0.0001) - hermite(0., 1., 0., 0., 0.75).assertEquals(0.84375, 0.0001) - -/** The endpoint derivatives must equal the supplied tangents even when - start != stop - the old 8s^3-9s^2 basis leaked a 6*(start-stop) term here. */ -@Test function testHermiteHonoursTangents() - let h = 0.001 - let start = 2. - let stop = 7. - let t1 = -3. - let t2 = 4. - - let atStart = (hermite(start, stop, t1, t2, h) - hermite(start, stop, t1, t2, 0.)) / h - atStart.assertEquals(t1, 0.05) - - let atStop = (hermite(start, stop, t1, t2, 1.) - hermite(start, stop, t1, t2, 1. - h)) / h - atStop.assertEquals(t2, 0.05) diff --git a/wurst/math/InterpolationTests.wurst b/wurst/math/InterpolationTests.wurst new file mode 100644 index 000000000..5d405aaf4 --- /dev/null +++ b/wurst/math/InterpolationTests.wurst @@ -0,0 +1,123 @@ +package InterpolationTests +import Interpolation +import Wurstunit + + +@Test +function linearVecTest() + let v = linear(vec2(3, 4), vec2(6, 2), 0.5) + v.x.assertEquals(4.5) + v.y.assertEquals(3) + + +@Test function testVec2Bezier3() + let start = vec2(-1, 0) + let mid = vec2(0, 2) + let stop = vec2(1, 0) + let p = 0.75 + let expected = vec2(0.5, 0.75) + start.bezier3(mid, stop, p).assertEquals(expected) + start.bezier3(mid, stop, 0).assertEquals(start) + start.bezier3(mid, stop, 1).assertEquals(stop) + + +@Test function testVec2DerivBezier3() + let start = vec2(-1, 0) + let mid = vec2(0, 2) + let stop = vec2(1, 0) + let p = 0.75 + let expected = vec2(2, -2) + start.derivBezier3(mid, stop, p).assertEquals(expected) + + +@Test function testVec2Bezier4() + let start = vec2(-3, 0) + let mid1 = vec2(-2, 2) + let mid2 = vec2(0, 0) + let stop = vec2(1, 1) + let p = 0.75 + let expected = vec2(0.09375, 0.703125) + start.bezier4(mid1, mid2, stop, p).assertEquals(expected) + start.bezier4(mid1, mid2, stop, 0).assertEquals(start) + start.bezier4(mid1, mid2, stop, 1).assertEquals(stop) + + +@Test function testVec2DerivBezier4() + let start = vec2(-3, 0) + let mid1 = vec2(-2, 2) + let mid2 = vec2(0, 0) + let stop = vec2(1, 1) + let p = 0.75 + let expected = vec2(4.125, -0.1875) + start.derivBezier4(mid1, mid2, stop, p).assertEquals(expected) + + +@Test function testVec3Bezier3() + let start = vec3(-1, 0, -2) + let mid = vec3(0, 2, 0.5) + let stop = vec3(1, 0, 3) + let p = 0.75 + let expected = vec3(0.5, 0.75, 1.75) + start.bezier3(mid, stop, p).assertEquals(expected) + start.bezier3(mid, stop, 0).assertEquals(start) + start.bezier3(mid, stop, 1).assertEquals(stop) + + +@Test function testVec3DerivBezier3() + let start = vec3(-1, 0, -2) + let mid = vec3(0, 2, 0.5) + let stop = vec3(1, 0, 3) + let p = 0.75 + let expected = vec3(2, -2, 5) + start.derivBezier3(mid, stop, p).assertEquals(expected) + + +@Test function testVec3Bezier4() + let start = vec3(-3, 0, 0) + let mid1 = vec3(-2, 2, -3) + let mid2 = vec3(0, 0, 0) + let stop = vec3(1, 1, 2) + let p = 0.75 + let expected = vec3(0.09375, 0.703125, 0.421875) + start.bezier4(mid1, mid2, stop, p).assertEquals(expected) + start.bezier4(mid1, mid2, stop, 0).assertEquals(start) + start.bezier4(mid1, mid2, stop, 1).assertEquals(stop) + + +@Test function testVec3DerivBezier4() + let start = vec3(-3, 0, 0) + let mid1 = vec3(-2, 2, -3) + let mid2 = vec3(0, 0, 0) + let stop = vec3(1, 1, 2) + let p = 0.75 + let expected = vec3(4.125, -0.1875, 6.1875) + start.derivBezier4(mid1, mid2, stop, p).assertEquals(expected) + + +@Test function testHermiteEndpoints() + hermite(3., 9., 2., -5., 0.).assertEquals(3., 0.0001) + hermite(3., 9., 2., -5., 1.).assertEquals(9., 0.0001) + + +/** With zero tangents the Hermite basis degenerates to smoothstep. */ +@Test function testHermiteZeroTangents() + hermite(0., 1., 0., 0., 0.25).assertEquals(0.15625, 0.0001) + hermite(0., 1., 0., 0., 0.5).assertEquals(0.5, 0.0001) + hermite(0., 1., 0., 0., 0.75).assertEquals(0.84375, 0.0001) + + +/** The endpoint derivatives must equal the supplied tangents even when + start != stop - the old 8s^3-9s^2 basis leaked a 6*(start-stop) term here. */ +@Test function testHermiteHonoursTangents() + let h = 0.001 + let start = 2. + let stop = 7. + let t1 = -3. + let t2 = 4. + + let atStart = (hermite(start, stop, t1, t2, h) - hermite(start, stop, t1, t2, 0.)) / h + atStart.assertEquals(t1, 0.05) + + let atStop = (hermite(start, stop, t1, t2, 1.) - hermite(start, stop, t1, t2, 1. - h)) / h + atStop.assertEquals(t2, 0.05) + diff --git a/wurst/math/Maths.wurst b/wurst/math/Maths.wurst index 2df52cf41..aa1372a36 100644 --- a/wurst/math/Maths.wurst +++ b/wurst/math/Maths.wurst @@ -3,7 +3,6 @@ import NoWurst import public Angle import Real import Integer -import Wurstunit /** Euler's constant */ public constant real EULER = 2.718281828 @@ -68,23 +67,4 @@ public function min(vararg real numbers) returns real minNumber = number < minNumber ? number : minNumber return minNumber -@Test function minmax() - let three = 3 - max(three,4,21,43,51,30).assertEquals(51) - max(3.,4.,5.).assertEquals(5) - max(-4,three).assertEquals(3) - min(three,4,0,-2,-1).assertEquals(-2) - min(3.,4.,-20.,-3.).assertEquals(-20.) - -@Test function test_hypot() - test_hypot_help(5,6) - test_hypot_help(5000000.,6) - test_hypot_help(3.,123456789.) - test_hypot_help(543532403425324.,123456789.) - test_hypot_help(0.0000001,0.0000000000023) - test_hypot_help(0,0) - - -function test_hypot_help(real x, real y) - hypot(x,y).assertEquals(SquareRoot(x * x + y * y), 0.0001) diff --git a/wurst/math/MathsTests.wurst b/wurst/math/MathsTests.wurst new file mode 100644 index 000000000..4c37a6d62 --- /dev/null +++ b/wurst/math/MathsTests.wurst @@ -0,0 +1,22 @@ +package MathsTests +import Maths +import Wurstunit + +@Test function minmax() + let three = 3 + max(three,4,21,43,51,30).assertEquals(51) + max(3.,4.,5.).assertEquals(5) + max(-4,three).assertEquals(3) + min(three,4,0,-2,-1).assertEquals(-2) + min(3.,4.,-20.,-3.).assertEquals(-20.) + +@Test function testHypot() + testHypotHelp(5, 6) + testHypotHelp(5000000., 6) + testHypotHelp(3., 123456789.) + testHypotHelp(543532403425324., 123456789.) + testHypotHelp(0.0000001, 0.0000000000023) + testHypotHelp(0, 0) + +function testHypotHelp(real x, real y) + hypot(x, y).assertEquals(SquareRoot(x * x + y * y), 0.0001) diff --git a/wurst/math/Raycast.wurst b/wurst/math/Raycast.wurst index c62e737da..eca49c057 100644 --- a/wurst/math/Raycast.wurst +++ b/wurst/math/Raycast.wurst @@ -1,7 +1,6 @@ package Raycast import NoWurst import Vectors -import Wurstunit /* The package defines such geometry as 'ray' for 2D and 3D separately. Both can find the intersection point with another geometry object. @@ -300,193 +299,4 @@ public function ray3d.castToTriangle(vec3 p1, vec3 p2, vec3 p3) returns result3d result.backface = det < 0 return result -/* ============== TEST ============== */ - -@Test function testProjection2d() - let ray = ray2d(vec2(-5, 3), vec2(1, 1)) - var test = vec2(-4, 8).project(ray) - test.intersects.assertTrue() - test.point.assertEquals(vec2(-2, 6)) - test.distance.assertEquals(4.2426, EPSILON) - test = vec2(-9, 0).project(ray) - test.intersects.assertTrue() - test.point.assertEquals(ray.origin) - test.distance.assertEquals(0, EPSILON) - test = vec2(-9, 0).project(ray2d(vec2(-5, 3), vec2(0, 0))) - test.intersects.assertFalse() - -@Test function testLine() - let ray = ray2d(vec2(4, 2), vec2(-1, 1)) - var test = ray.castToLine(vec2(-3, -2), vec2(2, 4)) - test.intersects.assertTrue() - test.distance.assertEquals(2.8284, EPSILON) - test.point.assertEquals(vec2(2, 4)) - test = ray.castToLine(vec2(-3, -2), vec2(5, 1)) - test.intersects.assertFalse() - test = ray.castToLine(vec2(-3, -2), vec2(-4, -1)) - test.intersects.assertFalse() - test = ray.castToLine(vec2(-3, -2), vec2(0.50001, 0.00001)) - test.intersects.assertTrue() - test.distance.assertEquals(0, EPSILON) - -@Test function testRay() - let ray = ray2d(vec2(4, 2), vec2(-1, 1)) - var test = ray.castToRay(vec2(-3, -2), vec2(1.5, 4)) - test.intersects.assertTrue() - test.point.assertEquals(vec2(0, 6)) - test.distance.assertEquals(5.65685, EPSILON) - test = ray.castToRay(vec2(-3, -2), vec2(-1, 1)) - test.intersects.assertFalse() - test = ray.castToRay(vec2(-3, -2), vec2(3.50001, 2.00001)) - test.intersects.assertTrue() - test.distance.assertEquals(0, EPSILON) - -@Test function testSegment() - let ray = ray2d(vec2(4, 2), vec2(-1, 1)) - var test = ray.castToSegment(vec2(8, 5), vec2(-4, 3)) - test.intersects.assertTrue() - test.point.assertEquals(vec2(2, 4)) - test.distance.assertEquals(2.8284, EPSILON) - test = ray.castToSegment(vec2(0, 6), vec2(4, 2)) - test.intersects.assertFalse() - test = ray.castToSegment(vec2(6, 25), vec2(5, -2)) - test.intersects.assertFalse() - test = ray.castToSegment(vec2(3, 1), vec2(5, 3)) - test.intersects.assertTrue() - test.point.assertEquals(vec2(4, 2)) - test.distance.assertEquals(0, EPSILON) - -@Test function testCircle() - let ray = ray2d(vec2(0, 6), vec2(1, -1)) - var test = ray.castToCircle(vec2(2, 4), 1.414213) - // Two - test.first.intersects.assertTrue() - test.first.point.assertEquals(vec2(1, 5)) - test.first.distance.assertEquals(1.414213, EPSILON) - test.second.intersects.assertTrue() - test.second.point.assertEquals(vec2(3, 3)) - test.second.distance.assertEquals(4.2426, EPSILON) - // Tangent - test = ray.castToCircle(vec2(-2, 4), 2.828427) - test.first.intersects.assertTrue() - test.first.point.assertEquals(vec2(0, 6)) - test.first.distance.assertEquals(0, EPSILON) - test.second.intersects.assertFalse() - // Inside - test = ray.castToCircle(vec2(-1, 7), 2.828427) - test.first.intersects.assertTrue() - test.first.point.assertEquals(vec2(1, 5)) - test.first.distance.assertEquals(1.414213, EPSILON) - test.second.intersects.assertFalse() - // Origin on circle - test = ray.castToCircle(vec2(-2, 8), 2.828427) - test.first.intersects.assertTrue() - test.first.point.assertEquals(vec2(0, 6)) - test.first.distance.assertEquals(0, EPSILON) - test.second.intersects.assertFalse() - // No intersections - test = ray.castToCircle(vec2(-3, -2), 3.5) - test.first.intersects.assertFalse() - test.second.intersects.assertFalse() - test = ray.castToCircle(vec2(-2, 8), 1) - test.first.intersects.assertFalse() - test.second.intersects.assertFalse() - -@Test function testProjection3d() - let ray = ray3d(vec3(-5, 3, 0), vec3(1, 1, 0)) - var test = vec3(-4, 8, 12).project(ray) - test.intersects.assertTrue() - test.point.assertEquals(vec3(-2, 6, 0)) - test.distance.assertEquals(4.2426, EPSILON) - test = vec3(-9, 0, -1).project(ray) - test.intersects.assertTrue() - test.point.assertEquals(ray.origin) - test.distance.assertEquals(0, EPSILON) - test = vec3(-9, 0, 45).project(ray3d(vec3(-5, 3, 8), vec3(0, 0, 0))) - test.intersects.assertFalse() - -@Test function testPlane() - let ray = ray3d(vec3(0, 0, 0), vec3(0, -1, 1)) - var test = ray.castToPlane(vec3(1, -5, 5), vec3(0, -1, 1)) - test.intersects.assertTrue() - test.point.assertEquals(vec3(0, -5, 5)) - test.distance.assertEquals(7.071, EPSILON) - test.backface.assertFalse() - test = ray.castToPlane(vec3(1, -5, 5), vec3(0, 1, -1)) - test.intersects.assertTrue() - test.backface.assertTrue() - test = ray.castToPlane(vec3(1, -5, 5), vec3(0, 1, 1)) - test.intersects.assertFalse() - test = ray.castToPlane(vec3(1, 5, 5), vec3(0, -1, 1)) - test.intersects.assertTrue() - test.distance.assertEquals(0, EPSILON) - test = ray.castToPlane(vec3(1, 6, 5), vec3(0, -1, 1)) - test.intersects.assertFalse() - -@Test function testDisk() - let ray = ray3d(vec3(0, 0, 0), vec3(0, -1, 1)) - var test = ray.castToDisk(vec3(1, -5, 5), vec3(0, -1, 1), 25) - test.intersects.assertTrue() - test.point.assertEquals(vec3(0, -5, 5)) - test.distance.assertEquals(7.071, EPSILON) - test.backface.assertFalse() - test = ray.castToDisk(vec3(1, -5, 5), vec3(0, -1, 1), 0.5) - test.intersects.assertFalse() - -@Test function testSphere() - let ray = ray3d(vec3(2, 1, -6), vec3(1, 0, 1)) - // Tangent - var test = ray.castToSphere(vec3(5, 4, -3), 3) - test.first.intersects.assertTrue() - test.first.point.assertEquals(vec3(5, 1, -3)) - test.first.distance.assertEquals(4.2426, EPSILON) - test.first.backface.assertFalse() - test.second.intersects.assertFalse() - // Two - test = ray.castToSphere(vec3(3, 1, -2), 3) - test.first.intersects.assertTrue() - test.first.point.assertEquals(vec3(3, 1, -5)) - test.first.distance.assertEquals(1.4142, EPSILON) - test.first.backface.assertFalse() - test.second.intersects.assertTrue() - // I have too much free time - test.second.point.assertEquals(vec3(6, 1, -2)) - test.second.distance.assertEquals(5.6568, EPSILON) - test.second.intersects.assertTrue() - // Inside - test = ray.castToSphere(vec3(3, 1, -5), 3) - test.first.intersects.assertTrue() - test.first.point.assertEquals(vec3(5.121321, 1, -2.87868)) - test.first.distance.assertEquals(4.4142, EPSILON) - test.first.backface.assertTrue() - test.second.intersects.assertFalse() - // No intersections - test = ray.castToSphere(vec3(-2, 1, -8), 3) - test.first.intersects.assertFalse() - test.second.intersects.assertFalse() - test = ray.castToSphere(vec3(1, 5, -2), 3) - test.first.intersects.assertFalse() - test.second.intersects.assertFalse() - -@Test function testTriangle() - let ray = ray3d(vec3(-2, 1, 3), vec3(-0.2, 0.7, 0.3)) - var test = ray.castToTriangle(vec3(1, 6, 8), vec3(-5, 9, 5), vec3(-7, 7, 7)) - test.intersects.assertTrue() - test.point.assertEquals(vec3(-4, 8, 6)) - test.distance.assertEquals(7.874, EPSILON) - test.backface.assertTrue() - test = ray.castToTriangle(vec3(1, 6, 8), vec3(-7, 7, 7), vec3(-5, 9, 5)) - test.intersects.assertTrue() - test.point.assertEquals(vec3(-4, 8, 6)) - test.distance.assertEquals(7.874, EPSILON) - test.backface.assertFalse() - test = ray.castToTriangle(vec3(-2, 1, 3), vec3(-4, 8, 5), vec3(-6, 15, 9)) - test.intersects.assertFalse() - test = ray.castToTriangle(vec3(8, -1, 5), vec3(-2, 1, 3), vec3(-6, 0, 9)) - test.intersects.assertTrue() - test.point.assertEquals(vec3(-2, 1, 3)) - test.distance.assertEquals(0, EPSILON) - test.backface.assertTrue() - test = ray.castToTriangle(vec3(0, 0, 0), vec3(1, 1, 1), vec3(-1, -1, -1)) - test.intersects.assertFalse() diff --git a/wurst/math/RaycastTests.wurst b/wurst/math/RaycastTests.wurst new file mode 100644 index 000000000..550df7fec --- /dev/null +++ b/wurst/math/RaycastTests.wurst @@ -0,0 +1,181 @@ +package RaycastTests +import Raycast +import Wurstunit + +@Test function testProjection2d() + let ray = ray2d(vec2(-5, 3), vec2(1, 1)) + var test = vec2(-4, 8).project(ray) + test.intersects.assertTrue() + test.point.assertEquals(vec2(-2, 6)) + test.distance.assertEquals(4.2426, EPSILON) + test = vec2(-9, 0).project(ray) + test.intersects.assertTrue() + test.point.assertEquals(ray.origin) + test.distance.assertEquals(0, EPSILON) + test = vec2(-9, 0).project(ray2d(vec2(-5, 3), vec2(0, 0))) + test.intersects.assertFalse() + +@Test function testLine() + let ray = ray2d(vec2(4, 2), vec2(-1, 1)) + var test = ray.castToLine(vec2(-3, -2), vec2(2, 4)) + test.intersects.assertTrue() + test.distance.assertEquals(2.8284, EPSILON) + test.point.assertEquals(vec2(2, 4)) + test = ray.castToLine(vec2(-3, -2), vec2(5, 1)) + test.intersects.assertFalse() + test = ray.castToLine(vec2(-3, -2), vec2(-4, -1)) + test.intersects.assertFalse() + test = ray.castToLine(vec2(-3, -2), vec2(0.50001, 0.00001)) + test.intersects.assertTrue() + test.distance.assertEquals(0, EPSILON) + +@Test function testRay() + let ray = ray2d(vec2(4, 2), vec2(-1, 1)) + var test = ray.castToRay(vec2(-3, -2), vec2(1.5, 4)) + test.intersects.assertTrue() + test.point.assertEquals(vec2(0, 6)) + test.distance.assertEquals(5.65685, EPSILON) + test = ray.castToRay(vec2(-3, -2), vec2(-1, 1)) + test.intersects.assertFalse() + test = ray.castToRay(vec2(-3, -2), vec2(3.50001, 2.00001)) + test.intersects.assertTrue() + test.distance.assertEquals(0, EPSILON) + +@Test function testSegment() + let ray = ray2d(vec2(4, 2), vec2(-1, 1)) + var test = ray.castToSegment(vec2(8, 5), vec2(-4, 3)) + test.intersects.assertTrue() + test.point.assertEquals(vec2(2, 4)) + test.distance.assertEquals(2.8284, EPSILON) + test = ray.castToSegment(vec2(0, 6), vec2(4, 2)) + test.intersects.assertFalse() + test = ray.castToSegment(vec2(6, 25), vec2(5, -2)) + test.intersects.assertFalse() + test = ray.castToSegment(vec2(3, 1), vec2(5, 3)) + test.intersects.assertTrue() + test.point.assertEquals(vec2(4, 2)) + test.distance.assertEquals(0, EPSILON) + +@Test function testCircle() + let ray = ray2d(vec2(0, 6), vec2(1, -1)) + var test = ray.castToCircle(vec2(2, 4), 1.414213) + test.first.intersects.assertTrue() + test.first.point.assertEquals(vec2(1, 5)) + test.first.distance.assertEquals(1.414213, EPSILON) + test.second.intersects.assertTrue() + test.second.point.assertEquals(vec2(3, 3)) + test.second.distance.assertEquals(4.2426, EPSILON) + test = ray.castToCircle(vec2(-2, 4), 2.828427) + test.first.intersects.assertTrue() + test.first.point.assertEquals(vec2(0, 6)) + test.first.distance.assertEquals(0, EPSILON) + test.second.intersects.assertFalse() + test = ray.castToCircle(vec2(-1, 7), 2.828427) + test.first.intersects.assertTrue() + test.first.point.assertEquals(vec2(1, 5)) + test.first.distance.assertEquals(1.414213, EPSILON) + test.second.intersects.assertFalse() + test = ray.castToCircle(vec2(-2, 8), 2.828427) + test.first.intersects.assertTrue() + test.first.point.assertEquals(vec2(0, 6)) + test.first.distance.assertEquals(0, EPSILON) + test.second.intersects.assertFalse() + test = ray.castToCircle(vec2(-3, -2), 3.5) + test.first.intersects.assertFalse() + test.second.intersects.assertFalse() + test = ray.castToCircle(vec2(-2, 8), 1) + test.first.intersects.assertFalse() + test.second.intersects.assertFalse() + +@Test function testProjection3d() + let ray = ray3d(vec3(-5, 3, 0), vec3(1, 1, 0)) + var test = vec3(-4, 8, 12).project(ray) + test.intersects.assertTrue() + test.point.assertEquals(vec3(-2, 6, 0)) + test.distance.assertEquals(4.2426, EPSILON) + test = vec3(-9, 0, -1).project(ray) + test.intersects.assertTrue() + test.point.assertEquals(ray.origin) + test.distance.assertEquals(0, EPSILON) + test = vec3(-9, 0, 45).project(ray3d(vec3(-5, 3, 8), vec3(0, 0, 0))) + test.intersects.assertFalse() + +@Test function testPlane() + let ray = ray3d(vec3(0, 0, 0), vec3(0, -1, 1)) + var test = ray.castToPlane(vec3(1, -5, 5), vec3(0, -1, 1)) + test.intersects.assertTrue() + test.point.assertEquals(vec3(0, -5, 5)) + test.distance.assertEquals(7.071, EPSILON) + test.backface.assertFalse() + test = ray.castToPlane(vec3(1, -5, 5), vec3(0, 1, -1)) + test.intersects.assertTrue() + test.backface.assertTrue() + test = ray.castToPlane(vec3(1, -5, 5), vec3(0, 1, 1)) + test.intersects.assertFalse() + test = ray.castToPlane(vec3(1, 5, 5), vec3(0, -1, 1)) + test.intersects.assertTrue() + test.distance.assertEquals(0, EPSILON) + test = ray.castToPlane(vec3(1, 6, 5), vec3(0, -1, 1)) + test.intersects.assertFalse() + +@Test function testDisk() + let ray = ray3d(vec3(0, 0, 0), vec3(0, -1, 1)) + var test = ray.castToDisk(vec3(1, -5, 5), vec3(0, -1, 1), 25) + test.intersects.assertTrue() + test.point.assertEquals(vec3(0, -5, 5)) + test.distance.assertEquals(7.071, EPSILON) + test.backface.assertFalse() + test = ray.castToDisk(vec3(1, -5, 5), vec3(0, -1, 1), 0.5) + test.intersects.assertFalse() + +@Test function testSphere() + let ray = ray3d(vec3(2, 1, -6), vec3(1, 0, 1)) + var test = ray.castToSphere(vec3(5, 4, -3), 3) + test.first.intersects.assertTrue() + test.first.point.assertEquals(vec3(5, 1, -3)) + test.first.distance.assertEquals(4.2426, EPSILON) + test.first.backface.assertFalse() + test.second.intersects.assertFalse() + test = ray.castToSphere(vec3(3, 1, -2), 3) + test.first.intersects.assertTrue() + test.first.point.assertEquals(vec3(3, 1, -5)) + test.first.distance.assertEquals(1.4142, EPSILON) + test.first.backface.assertFalse() + test.second.intersects.assertTrue() + test.second.point.assertEquals(vec3(6, 1, -2)) + test.second.distance.assertEquals(5.6568, EPSILON) + test.second.intersects.assertTrue() + test = ray.castToSphere(vec3(3, 1, -5), 3) + test.first.intersects.assertTrue() + test.first.point.assertEquals(vec3(5.121321, 1, -2.87868)) + test.first.distance.assertEquals(4.4142, EPSILON) + test.first.backface.assertTrue() + test.second.intersects.assertFalse() + test = ray.castToSphere(vec3(-2, 1, -8), 3) + test.first.intersects.assertFalse() + test.second.intersects.assertFalse() + test = ray.castToSphere(vec3(1, 5, -2), 3) + test.first.intersects.assertFalse() + test.second.intersects.assertFalse() + +@Test function testTriangle() + let ray = ray3d(vec3(-2, 1, 3), vec3(-0.2, 0.7, 0.3)) + var test = ray.castToTriangle(vec3(1, 6, 8), vec3(-5, 9, 5), vec3(-7, 7, 7)) + test.intersects.assertTrue() + test.point.assertEquals(vec3(-4, 8, 6)) + test.distance.assertEquals(7.874, EPSILON) + test.backface.assertTrue() + test = ray.castToTriangle(vec3(1, 6, 8), vec3(-7, 7, 7), vec3(-5, 9, 5)) + test.intersects.assertTrue() + test.point.assertEquals(vec3(-4, 8, 6)) + test.distance.assertEquals(7.874, EPSILON) + test.backface.assertFalse() + test = ray.castToTriangle(vec3(-2, 1, 3), vec3(-4, 8, 5), vec3(-6, 15, 9)) + test.intersects.assertFalse() + test = ray.castToTriangle(vec3(8, -1, 5), vec3(-2, 1, 3), vec3(-6, 0, 9)) + test.intersects.assertTrue() + test.point.assertEquals(vec3(-2, 1, 3)) + test.distance.assertEquals(0, EPSILON) + test.backface.assertTrue() + test = ray.castToTriangle(vec3(0, 0, 0), vec3(1, 1, 1), vec3(-1, -1, -1)) + test.intersects.assertFalse() diff --git a/wurst/math/Vectors.wurst b/wurst/math/Vectors.wurst index baf45be5b..616adb3ee 100644 --- a/wurst/math/Vectors.wurst +++ b/wurst/math/Vectors.wurst @@ -469,57 +469,3 @@ public function vec3.isInPolygon2d(vararg vec3 args) returns bool result = test != 0 return result -@Test -function vectorTests() - let v1 = vec2(1,2) - let v2 = vec2(2,1) - - ((v1 + v2) == (vec2(3,3))).assertTrue() - - ((v1 - v2) == (vec2(-1,1))).assertTrue() - - ((v1.moveTowards(vec2(1,0), 10.) == (vec2(1,-8)))).assertTrue() - -@Test function testSetLengthSq() - let v = vec3(3, 4, 0) // length 5, squared length 25 - v.setLengthSq(100.).lengthSquared().assertEquals(100., 0.01) - v.setLengthSq(25.).lengthSquared().assertEquals(25., 0.01) - v.setLengthSq(1.).lengthSquared().assertEquals(1., 0.01) - // degenerate inputs collapse to zero rather than producing NaN - vec3(0, 0, 0).setLengthSq(10.).assertEquals(ZERO3) - v.setLengthSq(-1.).assertEquals(ZERO3) - -@Test function testVec3InRange() - // inRange keeps its long standing xy-only contract - vec3(0, 0, 1000).inRange(vec3(0, 0, 0), 10.).assertTrue() - vec3(3, 4, 1000).inRange(vec3(0, 0, 0), 5.).assertTrue() - vec3(3, 4, 0).inRange(vec3(0, 0, 0), 4.).assertFalse() - - // inRange3d is the spherical variant - vec3(0, 0, 1000).inRange3d(vec3(0, 0, 0), 10.).assertFalse() - vec3(3, 4, 0).inRange3d(vec3(0, 0, 0), 5.).assertTrue() - vec3(0, 0, 5).inRange3d(vec3(0, 0, 0), 5.).assertTrue() - vec3(0, 0, 6).inRange3d(vec3(0, 0, 0), 5.).assertFalse() - vec3(3, 4, 12).inRange3d(vec3(0, 0, 0), 13.).assertTrue() - -@Test function testIsInTriangle() - let point2d = vec2(10, 15) - point2d.isInTriangle(vec2(9, 8), vec2(3, 5), vec2(4, 6)).assertFalse() - point2d.isInTriangle(vec2(10, 15), vec2(3, 5), vec2(4, 6)).assertTrue() - point2d.isInTriangle(vec2(48, 45), vec2(-35, 0), vec2(46, -6)).assertTrue() - let point3d = vec3(10, 15, -25) - point3d.isInTriangle2d(vec3(9, 8, 23), vec3(3, 5, 0), vec3(4, 6, 15)).assertFalse() - point3d.isInTriangle2d(vec3(10, 15, -124), vec3(3, 5, 0), vec3(4, 6, -16)).assertTrue() - point3d.isInTriangle2d(vec3(48, 45, 85), vec3(-35, 0, 11), vec3(46, -6, 22)).assertTrue() - -@Test function testIsInPolygon() - let test1 = vec2(1, 3) - let test2 = vec2(-4, -6) - let test3 = vec2(-2, 2) - let points = [vec2(-3, -6), vec2(4, 5), vec2(-4, 5), vec2(3, -2)] - test1.isInPolygon(points[0], points[1], points[2], points[3]).assertTrue() - test2.isInPolygon(points[0], points[1], points[2], points[3]).assertFalse() - test3.isInPolygon(points[0], points[1], points[2]).assertTrue() - test1.toVec3().isInPolygon2d(points[0].toVec3(), points[1].toVec3(), points[2].toVec3(), points[3].toVec3()).assertTrue() - test2.toVec3().isInPolygon2d(points[0].toVec3(), points[1].toVec3(), points[2].toVec3(), points[3].toVec3()).assertFalse() - test3.toVec3().isInPolygon2d(points[0].toVec3(), points[1].toVec3(), points[2].toVec3()).assertTrue() diff --git a/wurst/math/VectorsTests.wurst b/wurst/math/VectorsTests.wurst new file mode 100644 index 000000000..81e0ab940 --- /dev/null +++ b/wurst/math/VectorsTests.wurst @@ -0,0 +1,64 @@ +package VectorsTests +import Vectors +import Wurstunit + + +@Test +function vectorTests() + let v1 = vec2(1,2) + let v2 = vec2(2,1) + + ((v1 + v2) == (vec2(3,3))).assertTrue() + + ((v1 - v2) == (vec2(-1,1))).assertTrue() + + ((v1.moveTowards(vec2(1,0), 10.) == (vec2(1,-8)))).assertTrue() + + +@Test function testSetLengthSq() + let v = vec3(3, 4, 0) // length 5, squared length 25 + v.setLengthSq(100.).lengthSquared().assertEquals(100., 0.01) + v.setLengthSq(25.).lengthSquared().assertEquals(25., 0.01) + v.setLengthSq(1.).lengthSquared().assertEquals(1., 0.01) + // degenerate inputs collapse to zero rather than producing NaN + vec3(0, 0, 0).setLengthSq(10.).assertEquals(ZERO3) + v.setLengthSq(-1.).assertEquals(ZERO3) + + +@Test function testVec3InRange() + // inRange keeps its long standing xy-only contract + vec3(0, 0, 1000).inRange(vec3(0, 0, 0), 10.).assertTrue() + vec3(3, 4, 1000).inRange(vec3(0, 0, 0), 5.).assertTrue() + vec3(3, 4, 0).inRange(vec3(0, 0, 0), 4.).assertFalse() + + // inRange3d is the spherical variant + vec3(0, 0, 1000).inRange3d(vec3(0, 0, 0), 10.).assertFalse() + vec3(3, 4, 0).inRange3d(vec3(0, 0, 0), 5.).assertTrue() + vec3(0, 0, 5).inRange3d(vec3(0, 0, 0), 5.).assertTrue() + vec3(0, 0, 6).inRange3d(vec3(0, 0, 0), 5.).assertFalse() + vec3(3, 4, 12).inRange3d(vec3(0, 0, 0), 13.).assertTrue() + + +@Test function testIsInTriangle() + let point2d = vec2(10, 15) + point2d.isInTriangle(vec2(9, 8), vec2(3, 5), vec2(4, 6)).assertFalse() + point2d.isInTriangle(vec2(10, 15), vec2(3, 5), vec2(4, 6)).assertTrue() + point2d.isInTriangle(vec2(48, 45), vec2(-35, 0), vec2(46, -6)).assertTrue() + let point3d = vec3(10, 15, -25) + point3d.isInTriangle2d(vec3(9, 8, 23), vec3(3, 5, 0), vec3(4, 6, 15)).assertFalse() + point3d.isInTriangle2d(vec3(10, 15, -124), vec3(3, 5, 0), vec3(4, 6, -16)).assertTrue() + point3d.isInTriangle2d(vec3(48, 45, 85), vec3(-35, 0, 11), vec3(46, -6, 22)).assertTrue() + + +@Test function testIsInPolygon() + let test1 = vec2(1, 3) + let test2 = vec2(-4, -6) + let test3 = vec2(-2, 2) + let points = [vec2(-3, -6), vec2(4, 5), vec2(-4, 5), vec2(3, -2)] + test1.isInPolygon(points[0], points[1], points[2], points[3]).assertTrue() + test2.isInPolygon(points[0], points[1], points[2], points[3]).assertFalse() + test3.isInPolygon(points[0], points[1], points[2]).assertTrue() + test1.toVec3().isInPolygon2d(points[0].toVec3(), points[1].toVec3(), points[2].toVec3(), points[3].toVec3()).assertTrue() + test2.toVec3().isInPolygon2d(points[0].toVec3(), points[1].toVec3(), points[2].toVec3(), points[3].toVec3()).assertFalse() + test3.toVec3().isInPolygon2d(points[0].toVec3(), points[1].toVec3(), points[2].toVec3()).assertTrue() + diff --git a/wurst/objediting/ObjectIds.wurst b/wurst/objediting/ObjectIds.wurst index e11550a85..70085507c 100644 --- a/wurst/objediting/ObjectIds.wurst +++ b/wurst/objediting/ObjectIds.wurst @@ -1,7 +1,6 @@ package ObjectIds import NoWurst import ErrorHandling -import Wurstunit import AbilityIds import LinkedList import TypeCasting @@ -76,28 +75,3 @@ public function commaList(vararg UnitTargetType tags) returns string list.add(t.toObjectString()) return commaList(list) -@Test function asListIntTest() - realToIndex(0.) - commaList( - AbilityIds.invulnerable, - AbilityIds.reveal - ).assertEquals("Avul,Adta") - -@Test function asListStringTest() - commaList( - "self", - "structure" - ).assertEquals("self,structure") - -@Test function test_idString2IdInteger() - fromRawCode("hfoo") .assertEquals('hfoo') - fromRawCode("abcd") .assertEquals('abcd') - fromRawCode("ABCD") .assertEquals('ABCD') - -@Test function test_idInteger2IdString() - toRawCode('hfoo') .assertEquals("hfoo") - toRawCode('abcd') .assertEquals("abcd") - toRawCode('ABCD') .assertEquals("ABCD") - -@Test function test_TargetTypes() - commaList(UnitTargetType.Self, UnitTargetType.Ground).assertEquals("self,ground") \ No newline at end of file diff --git a/wurst/objediting/ObjectIdsTests.wurst b/wurst/objediting/ObjectIdsTests.wurst new file mode 100644 index 000000000..e93b2008e --- /dev/null +++ b/wurst/objediting/ObjectIdsTests.wurst @@ -0,0 +1,27 @@ +package ObjectIdsTests +import ObjectIds +import ObjEditingCommons +import AbilityIds +import Wurstunit + +@Test function asListIntTest() + commaList( + AbilityIds.invulnerable, + AbilityIds.reveal + ).assertEquals("Avul,Adta") + +@Test function asListStringTest() + commaList("self", "structure").assertEquals("self,structure") + +@Test function testIdString2IdInteger() + fromRawCode("hfoo").assertEquals('hfoo') + fromRawCode("abcd").assertEquals('abcd') + fromRawCode("ABCD").assertEquals('ABCD') + +@Test function testIdInteger2IdString() + toRawCode('hfoo').assertEquals("hfoo") + toRawCode('abcd').assertEquals("abcd") + toRawCode('ABCD').assertEquals("ABCD") + +@Test function testTargetTypes() + commaList(UnitTargetType.Self, UnitTargetType.Ground).assertEquals("self,ground") diff --git a/wurst/util/Colors.wurst b/wurst/util/Colors.wurst index a6ac5d35c..1e3e8f436 100644 --- a/wurst/util/Colors.wurst +++ b/wurst/util/Colors.wurst @@ -3,7 +3,6 @@ import NoWurst import Table import String import Integer -import Wurstunit import Playercolor import Annotations import Maths @@ -283,44 +282,4 @@ public function string.color(colorA which) returns string init initializeTable() -@Test public function testColors() - hexs[10].assertEquals("A") - decs.loadInt(hexs[10].getHash()).assertEquals(10) - - let mixed = colorA(0,0,0,0).mix(colorA(255,255,255,255), 0.5) - assertTrue(mixed == colorA(128,128,128,128)) - - assertTrue(fromHexString("33ccff44") == colorA(204, 255, 68, 51)) - - assertTrue(PLAYER_COLOR_RED != null) - -@Test public function testHSV() - colorHSV(0, 0, 1).assert() - colorHSV(0, 0, 0.5).assert() - colorHSV(0, 0, 0).assert() - for h = 0 to 11 - for s = 2 downto 1 - for v = 2 downto 1 - colorHSV(h / 12.0, s / 2.0, v / 2.0).assert() - -@Test public function testColorNames() - color(255, 2, 2).getName().assertEquals("red") - color(164, 111, 51).getName().assertEquals("peanut") - assertTrue("red".toColor() == color(255, 2, 2)) - assertTrue("peanut".toColor() == color(164, 111, 51)) - assertTrue("red".toPlayerColor() == PLAYER_COLOR_RED) - assertTrue("peanut".toPlayerColor() == PLAYER_COLOR_PEANUT) - -@Test public function testPlayerColorConversion() - assertTrue(PLAYER_COLOR_BLUE.toColor() == color(0,65,255)) - assertTrue(PLAYER_COLOR_RED.toColor() == color(255, 2, 2)) - assertTrue(PLAYER_COLOR_PEANUT.toColor() == color(164, 111, 51)) - PLAYER_COLOR_RED.getName().assertEquals("red") - PLAYER_COLOR_COAL.getName().assertEquals("coal") - -@Test public function testPlayerFromColorName() - assertTrue(toPlayerFromColorName("red") == Player(0)) - assertTrue(toPlayerFromColorName("PEANUT") == Player(23)) - assertTrue(toPlayerFromColorName("wurstlang") == null) - diff --git a/wurst/util/ColorsTests.wurst b/wurst/util/ColorsTests.wurst new file mode 100644 index 000000000..c24472486 --- /dev/null +++ b/wurst/util/ColorsTests.wurst @@ -0,0 +1,39 @@ +package ColorsTests +import Colors +import Wurstunit + +@Test public function testColors() + hexs[10].assertEquals("A") + let mixed = colorA(0,0,0,0).mix(colorA(255,255,255,255), 0.5) + assertTrue(mixed == colorA(128,128,128,128)) + assertTrue(fromHexString("33ccff44") == colorA(204, 255, 68, 51)) + assertTrue(PLAYER_COLOR_RED != null) + +@Test public function testHSV() + colorHSV(0, 0, 1).assert() + colorHSV(0, 0, 0.5).assert() + colorHSV(0, 0, 0).assert() + for h = 0 to 11 + for s = 2 downto 1 + for v = 2 downto 1 + colorHSV(h / 12.0, s / 2.0, v / 2.0).assert() + +@Test public function testColorNames() + color(255, 2, 2).getName().assertEquals("red") + color(164, 111, 51).getName().assertEquals("peanut") + assertTrue("red".toColor() == color(255, 2, 2)) + assertTrue("peanut".toColor() == color(164, 111, 51)) + assertTrue("red".toPlayerColor() == PLAYER_COLOR_RED) + assertTrue("peanut".toPlayerColor() == PLAYER_COLOR_PEANUT) + +@Test public function testPlayerColorConversion() + assertTrue(PLAYER_COLOR_BLUE.toColor() == color(0,65,255)) + assertTrue(PLAYER_COLOR_RED.toColor() == color(255, 2, 2)) + assertTrue(PLAYER_COLOR_PEANUT.toColor() == color(164, 111, 51)) + PLAYER_COLOR_RED.getName().assertEquals("red") + PLAYER_COLOR_COAL.getName().assertEquals("coal") + +@Test public function testPlayerFromColorName() + assertTrue(toPlayerFromColorName("red") == Player(0)) + assertTrue(toPlayerFromColorName("PEANUT") == Player(23)) + assertTrue(toPlayerFromColorName("wurstlang") == null) diff --git a/wurst/util/GameTimer.wurst b/wurst/util/GameTimer.wurst index 2fd28b0e6..b7831685a 100644 --- a/wurst/util/GameTimer.wurst +++ b/wurst/util/GameTimer.wurst @@ -2,7 +2,6 @@ package GameTimer import NoWurst import Basics import Timer -import Wurstunit timer gameTimer = CreateTimer()..start(100000, null) @@ -22,6 +21,3 @@ init CreateTimer().startPeriodic(ANIMATION_PERIOD) -> currentTime += ANIMATION_PERIOD -@Test -function testGameTimer() - assertTrue(getElapsedGameTime() > 0) diff --git a/wurst/util/GameTimerTests.wurst b/wurst/util/GameTimerTests.wurst new file mode 100644 index 000000000..1cc27055c --- /dev/null +++ b/wurst/util/GameTimerTests.wurst @@ -0,0 +1,6 @@ +package GameTimerTests +import GameTimer +import Wurstunit + +@Test function testGameTimer() + assertTrue(getElapsedGameTime() > 0) diff --git a/wurst/util/MapBounds.wurst b/wurst/util/MapBounds.wurst index a90a585d7..ab1660b09 100644 --- a/wurst/util/MapBounds.wurst +++ b/wurst/util/MapBounds.wurst @@ -1,7 +1,6 @@ package MapBounds import NoWurst import Vectors -import Wurstunit import Region import Rect import MagicFunctions @@ -60,10 +59,3 @@ init initMapBounds() -@Test function testMapBounds() - playableMapRect.getMinX().assertEquals(-1024) - playableMapRect.getMaxX().assertEquals(1024) - playableMapRect.getMinY().assertEquals(-1024) - playableMapRect.getMaxY().assertEquals(1024) - - (playableMin + playableMax).toString().assertEquals(playableCenter.toString()) diff --git a/wurst/util/MapBoundsTests.wurst b/wurst/util/MapBoundsTests.wurst new file mode 100644 index 000000000..1a63036df --- /dev/null +++ b/wurst/util/MapBoundsTests.wurst @@ -0,0 +1,10 @@ +package MapBoundsTests +import MapBounds +import Wurstunit + +@Test function testMapBounds() + playableMapRect.getMinX().assertEquals(-1024) + playableMapRect.getMaxX().assertEquals(1024) + playableMapRect.getMinY().assertEquals(-1024) + playableMapRect.getMaxY().assertEquals(1024) + (playableMin + playableMax).toString().assertEquals(playableCenter.toString()) diff --git a/wurst/util/TerrainUtils.wurst b/wurst/util/TerrainUtils.wurst index b241ad008..b1681ebcb 100644 --- a/wurst/util/TerrainUtils.wurst +++ b/wurst/util/TerrainUtils.wurst @@ -3,7 +3,6 @@ import NoWurst import Item import Rect import MapBounds -import Wurstunit import Colors // Terrain API @@ -151,30 +150,6 @@ public function tile.setPathing(pathingtype ttype, bool flag) for j = 0 to 3 (this.toVec2() + vec2(-48. + i * 32,-48. + j * 32)).setTerrainPathable(ttype, flag) -@Test function testMapCorners() - boundMin.getTile().id.assertEquals(0) - boundMax.getTile().id.assertEquals(TILES_COUNT - 1) - tile(boundMax.x, boundMin.y).id.assertEquals(TILES_X - 1) - tile(boundMin.x, boundMax.y).id.assertEquals(TILES_X * (TILES_Y - 1)) - -@Test function testUpperBound() - (boundMin + vec2(1,0)).getTile().id.assertEquals(0) - (boundMin + vec2(63.9999,0)).getTile().id.assertEquals(0) - (boundMin + vec2(64,0)).getTile().id.assertEquals(1) - (boundMin + vec2(128,0)).getTile().id.assertEquals(1) - - (boundMin + vec2(63.9999,63.9999)).getTile().id.assertEquals(0) - (boundMin + vec2(64,64)).getTile().id.assertEquals(TILES_X + 1) - -@Test function testLowerBound() - (boundMax - vec2(1,0)).getTile().id.assertEquals(TILES_COUNT - 1) - (boundMax - vec2(64,0)).getTile().id.assertEquals(TILES_COUNT - 1) - (boundMax - vec2(64.0002,0)).getTile().id.assertEquals(TILES_COUNT - 2) - (boundMax - vec2(128,0)).getTile().id.assertEquals(TILES_COUNT - 2) - - (boundMax - vec2(64,64)).getTile().id.assertEquals(TILES_COUNT - 1) - (boundMax - vec2(64.0002,64.0002)).getTile().id.assertEquals(TILES_COUNT - 1 - (TILES_X + 1)) - // Some notes: // tile(0,0) bounds: // x: [-64; 64) diff --git a/wurst/util/TerrainUtilsTests.wurst b/wurst/util/TerrainUtilsTests.wurst new file mode 100644 index 000000000..e433238b7 --- /dev/null +++ b/wurst/util/TerrainUtilsTests.wurst @@ -0,0 +1,26 @@ +package TerrainUtilsTests +import TerrainUtils +import MapBounds +import Wurstunit + +@Test function testMapCorners() + boundMin.getTile().id.assertEquals(0) + boundMax.getTile().id.assertEquals(TILES_COUNT - 1) + tile(boundMax.x, boundMin.y).id.assertEquals(TILES_X - 1) + tile(boundMin.x, boundMax.y).id.assertEquals(TILES_X * (TILES_Y - 1)) + +@Test function testUpperBound() + (boundMin + vec2(1,0)).getTile().id.assertEquals(0) + (boundMin + vec2(63.9999,0)).getTile().id.assertEquals(0) + (boundMin + vec2(64,0)).getTile().id.assertEquals(1) + (boundMin + vec2(128,0)).getTile().id.assertEquals(1) + (boundMin + vec2(63.9999,63.9999)).getTile().id.assertEquals(0) + (boundMin + vec2(64,64)).getTile().id.assertEquals(TILES_X + 1) + +@Test function testLowerBound() + (boundMax - vec2(1,0)).getTile().id.assertEquals(TILES_COUNT - 1) + (boundMax - vec2(64,0)).getTile().id.assertEquals(TILES_COUNT - 1) + (boundMax - vec2(64.0002,0)).getTile().id.assertEquals(TILES_COUNT - 2) + (boundMax - vec2(128,0)).getTile().id.assertEquals(TILES_COUNT - 2) + (boundMax - vec2(64,64)).getTile().id.assertEquals(TILES_COUNT - 1) + (boundMax - vec2(64.0002,64.0002)).getTile().id.assertEquals(TILES_COUNT - 1 - (TILES_X + 1)) diff --git a/wurst/util/Time.wurst b/wurst/util/Time.wurst index 594020f5c..b5d056692 100644 --- a/wurst/util/Time.wurst +++ b/wurst/util/Time.wurst @@ -287,38 +287,3 @@ public function durationToIndex(duration dur) returns int public function durationFromIndex(int index) returns duration return duration(realFromIndex(index)) - -@Test function testDisplay() - print(1..hours().displayVerbose()) - assertTrue(.1.seconds().displayVerbose() == "100 milliseconds") - assertTrue(1.1.seconds().displayVerbose() == "1 seconds") - assertTrue(61..seconds().display() == "PT1M1S") - assertTrue(1..hours().displayVerbose() == "1 hours, 0 minutes, and 0 seconds") - -@Test function testNewerThan() - assertTrue(5..minutesFromNow().isNewerThan(5..secondsFromNow())) - assertTrue(5..minutesFromNow().isInTheFuture()) - -/** Built from explicit timestamps rather than instantNow(), because the - compiletime interpreter's game clock is a unix epoch value whose 32 bit - real precision swallows small offsets. See GameTimer.getElapsedGameTime. */ -@Test function testInstantComparisons() - let earlier = instant(10.) - let later = instant(20.) - - earlier.isOlderThan(later).assertTrue() - later.isNewerThan(earlier).assertTrue() - later.isOlderThan(earlier).assertFalse() - earlier.isNewerThan(later).assertFalse() - earlier.isOlderThan(earlier).assertFalse() - earlier.isNewerThan(earlier).assertFalse() - - (later - earlier).seconds.assertEquals(10., 0.0001) - -/** Negative durations used to render as "0", because every component was - gated behind a "> 0" check. */ -@Test function testNegativeDurationDisplay() - (-61.).seconds().displayVerbose().assertEquals("-1 minutes, and 1 seconds") - (-1.).hours().display().assertEquals("-PT1H0M0S") - (0.).seconds().displayVerbose().assertEquals("0") - (61.).seconds().displayVerbose().assertEquals("1 minutes, and 1 seconds") diff --git a/wurst/util/TimeTests.wurst b/wurst/util/TimeTests.wurst new file mode 100644 index 000000000..1ccbf31c4 --- /dev/null +++ b/wurst/util/TimeTests.wurst @@ -0,0 +1,43 @@ +package TimeTests +import Time +import Wurstunit + + +@Test function testDisplay() + print(1..hours().displayVerbose()) + assertTrue(.1.seconds().displayVerbose() == "100 milliseconds") + assertTrue(1.1.seconds().displayVerbose() == "1 seconds") + assertTrue(61..seconds().display() == "PT1M1S") + assertTrue(1..hours().displayVerbose() == "1 hours, 0 minutes, and 0 seconds") + + +@Test function testNewerThan() + assertTrue(5..minutesFromNow().isNewerThan(5..secondsFromNow())) + assertTrue(5..minutesFromNow().isInTheFuture()) + + +/** Built from explicit timestamps rather than instantNow(), because the + compiletime interpreter's game clock is a unix epoch value whose 32 bit + real precision swallows small offsets. See GameTimer.getElapsedGameTime. */ +@Test function testInstantComparisons() + let earlier = instant(10.) + let later = instant(20.) + + earlier.isOlderThan(later).assertTrue() + later.isNewerThan(earlier).assertTrue() + later.isOlderThan(earlier).assertFalse() + earlier.isNewerThan(later).assertFalse() + earlier.isOlderThan(earlier).assertFalse() + earlier.isNewerThan(earlier).assertFalse() + + (later - earlier).seconds.assertEquals(10., 0.0001) + + +/** Negative durations used to render as "0", because every component was + gated behind a "> 0" check. */ +@Test function testNegativeDurationDisplay() + (-61.).seconds().displayVerbose().assertEquals("-1 minutes, and 1 seconds") + (-1.).hours().display().assertEquals("-PT1H0M0S") + (0.).seconds().displayVerbose().assertEquals("0") + (61.).seconds().displayVerbose().assertEquals("1 minutes, and 1 seconds") + From b74254646da9c54c55da6b0bdd3001083aa2d287 Mon Sep 17 00:00:00 2001 From: Frotty Date: Tue, 4 Aug 2026 17:21:54 +0200 Subject: [PATCH 2/3] fix extracted test visibility --- wurst/math/RaycastTests.wurst | 2 ++ wurst/util/Colors.wurst | 7 ------- wurst/util/ColorsTests.wurst | 7 +++++++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/wurst/math/RaycastTests.wurst b/wurst/math/RaycastTests.wurst index 550df7fec..4c4fbe25b 100644 --- a/wurst/math/RaycastTests.wurst +++ b/wurst/math/RaycastTests.wurst @@ -2,6 +2,8 @@ package RaycastTests import Raycast import Wurstunit +constant EPSILON = 0.0001 + @Test function testProjection2d() let ray = ray2d(vec2(-5, 3), vec2(1, 1)) var test = vec2(-4, 8).project(ray) diff --git a/wurst/util/Colors.wurst b/wurst/util/Colors.wurst index 1e3e8f436..d528f6816 100644 --- a/wurst/util/Colors.wurst +++ b/wurst/util/Colors.wurst @@ -258,13 +258,6 @@ public function string.toPlayerColor() returns playercolor break return pc -function colorHSV.assert() - let delta = 0.01 - let translated = this.toRGB().toHSV() - let compare = colorHSV((translated.h - this.h).abs(), (translated.s - this.s).abs(), (translated.v - this.v).abs()) - if compare.h > delta or compare.s > delta or compare.v > delta - testFail("Actual {0}, Expected {1}".format(translated.toString(), this.toString())) - public function string.color(string which) returns string return which + this + "|r" diff --git a/wurst/util/ColorsTests.wurst b/wurst/util/ColorsTests.wurst index c24472486..a370272e8 100644 --- a/wurst/util/ColorsTests.wurst +++ b/wurst/util/ColorsTests.wurst @@ -2,6 +2,13 @@ package ColorsTests import Colors import Wurstunit +function colorHSV.assert() + let delta = 0.01 + let translated = this.toRGB().toHSV() + let compare = colorHSV((translated.h - this.h).abs(), (translated.s - this.s).abs(), (translated.v - this.v).abs()) + if compare.h > delta or compare.s > delta or compare.v > delta + testFail("Actual {0}, Expected {1}".format(translated.toString(), this.toString())) + @Test public function testColors() hexs[10].assertEquals("A") let mixed = colorA(0,0,0,0).mix(colorA(255,255,255,255), 0.5) From deb9df22a1a296e1c4c155cc4121093ba9800488 Mon Sep 17 00:00:00 2001 From: Frotty Date: Tue, 4 Aug 2026 18:43:35 +0200 Subject: [PATCH 3/3] move LineGeometry tests --- wurst/math/LineGeometry.wurst | 23 ----------------------- wurst/math/LineGeometryTests.wurst | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 23 deletions(-) create mode 100644 wurst/math/LineGeometryTests.wurst diff --git a/wurst/math/LineGeometry.wurst b/wurst/math/LineGeometry.wurst index eaa882b9f..a566c0dd8 100644 --- a/wurst/math/LineGeometry.wurst +++ b/wurst/math/LineGeometry.wurst @@ -1,7 +1,6 @@ package LineGeometry import NoWurst import Vectors -import Wurstunit /** Line formula tuple representing y = m*x + b where m is slope and b is y-intercept */ public tuple lineFormular(real m, real b) @@ -28,25 +27,3 @@ public function vec2.getOrthogonalSidePoint(lineFormular line, real d) returns v let normalLength = SquareRoot(1 + Pow(line.m, 2)) return vec2(this.x - line.m * d / normalLength, this.y + d / normalLength) -@Test function testLineFormular() - let p1 = vec2(0, 2) - let p2 = vec2(4, 10) - let line = p1.getLineFormular(p2) - line.m.assertEquals(2.0, 0.001) - line.b.assertEquals(2.0, 0.001) - (0.0).getYOnLine(line).assertEquals(2.0, 0.001) - (4.0).getYOnLine(line).assertEquals(10.0, 0.001) - (2.0).getXOnLine(line).assertEquals(0.0, 0.001) - (10.0).getXOnLine(line).assertEquals(4.0, 0.001) - -@Test function testParallelLine() - let line = lineFormular(1, 0) - let parallel = line.getParallelLineWithOrthogonalDistance(SquareRoot(2)) - parallel.m.assertEquals(1.0, 0.001) - assertTrue(parallel.b != 0) - -@Test function testOrthogonalSidePoint() - let horizontal = lineFormular(0, 5) - let point = vec2(3, 5).getOrthogonalSidePoint(horizontal, 2) - point.x.assertEquals(3.0, 0.001) - point.y.assertEquals(7.0, 0.001) diff --git a/wurst/math/LineGeometryTests.wurst b/wurst/math/LineGeometryTests.wurst new file mode 100644 index 000000000..1a1837534 --- /dev/null +++ b/wurst/math/LineGeometryTests.wurst @@ -0,0 +1,26 @@ +package LineGeometryTests +import LineGeometry +import Wurstunit + +@Test function testLineFormular() + let p1 = vec2(0, 2) + let p2 = vec2(4, 10) + let line = p1.getLineFormular(p2) + line.m.assertEquals(2.0, 0.001) + line.b.assertEquals(2.0, 0.001) + (0.0).getYOnLine(line).assertEquals(2.0, 0.001) + (4.0).getYOnLine(line).assertEquals(10.0, 0.001) + (2.0).getXOnLine(line).assertEquals(0.0, 0.001) + (10.0).getXOnLine(line).assertEquals(4.0, 0.001) + +@Test function testParallelLine() + let line = lineFormular(1, 0) + let parallel = line.getParallelLineWithOrthogonalDistance(SquareRoot(2)) + parallel.m.assertEquals(1.0, 0.001) + assertTrue(parallel.b != 0) + +@Test function testOrthogonalSidePoint() + let horizontal = lineFormular(0, 5) + let point = vec2(3, 5).getOrthogonalSidePoint(horizontal, 2) + point.x.assertEquals(3.0, 0.001) + point.y.assertEquals(7.0, 0.001)