cleaned up a whole bunch of stuff and started unit tests on helper functions
This commit is contained in:
parent
244ca8d134
commit
f72a44dfee
@ -19,7 +19,7 @@ package controllers
|
|||||||
*
|
*
|
||||||
* 1. Obtaining an Automaton instance bound to the current OS/desktop
|
* 1. Obtaining an Automaton instance bound to the current OS/desktop
|
||||||
* 2. Calling methods like [moveMouse] and [mouseClick] to perform actions
|
* 2. Calling methods like [moveMouse] and [mouseClick] to perform actions
|
||||||
* 3. Using [sleep] and [sleepWithVariance] to add delays
|
* 3. Using [sleep] and [sleep] to add delays
|
||||||
*
|
*
|
||||||
* This interface allows the underlying OS/desktop implementation details to be abstracted and swapped as needed.
|
* This interface allows the underlying OS/desktop implementation details to be abstracted and swapped as needed.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -41,19 +41,18 @@ interface InputController {
|
|||||||
/**
|
/**
|
||||||
* Performs a mousewheel scroll in motion.
|
* Performs a mousewheel scroll in motion.
|
||||||
*
|
*
|
||||||
* This will move the scroll wheel forward by the number of ticks
|
* This will move the scroll wheel forward by the number of ticks over the duration. It will sleep for short
|
||||||
* over the duration. It will sleep for short intervals between
|
* intervals between ticks using the provided sleep duration and variance.
|
||||||
* ticks using the provided sleep duration and variance.
|
|
||||||
*
|
*
|
||||||
* @param sleepDur The base sleep duration between scroll ticks.
|
* @param sleepDurationMillis The base sleep duration between scroll ticks.
|
||||||
* @param sleepDurVariance The variance in sleep duration.
|
* @param sleepDurationVarianceMillis The variance in sleep duration.
|
||||||
*/
|
*/
|
||||||
fun scrollIn(sleepDur: Long, sleepDurVariance: Long)
|
fun scrollIn(sleepDurationMillis: Long, sleepDurationVarianceMillis: Long)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a mousewheel scroll out motion.
|
* Performs a mousewheel scroll out motion.
|
||||||
*
|
*
|
||||||
* Same as [scrollIn] but moves the scroll wheel backward.
|
* Same as [scrollIn] but moves the scroll wheel backward.
|
||||||
*/
|
*/
|
||||||
fun scrollOut(sleepDur: Long, sleepDurVariance: Long)
|
fun scrollOut(sleepDurationMillis: Long, sleepDurationVarianceMillis: Long)
|
||||||
}
|
}
|
||||||
@ -101,10 +101,10 @@ interface Orchestrator {
|
|||||||
*/
|
*/
|
||||||
fun moveMouseLeftClickAndSleep(p: Point, sleepDuration: Long, sleepDurationVariance: Long = 1) {
|
fun moveMouseLeftClickAndSleep(p: Point, sleepDuration: Long, sleepDurationVariance: Long = 1) {
|
||||||
automaton.moveMouse(p)
|
automaton.moveMouse(p)
|
||||||
automaton.sleepWithVariance(100, 50)
|
automaton.sleep(100, 50)
|
||||||
//left click
|
//left click
|
||||||
automaton.mouseClick(InputEvent.BUTTON1_DOWN_MASK)
|
automaton.mouseClick(InputEvent.BUTTON1_DOWN_MASK)
|
||||||
automaton.sleepWithVariance(sleepDuration, sleepDurationVariance)
|
automaton.sleep(sleepDuration, sleepDurationVariance)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package controllers
|
|||||||
|
|
||||||
import java.awt.Point
|
import java.awt.Point
|
||||||
import java.awt.Robot
|
import java.awt.Robot
|
||||||
import java.awt.event.InputEvent
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -20,10 +19,9 @@ open class RobotAutomaton(internal val robot: Robot = Robot()) : Automaton {
|
|||||||
*
|
*
|
||||||
* Uses the Robot's mouseMove() method to move to the x, y coordinates.
|
* Uses the Robot's mouseMove() method to move to the x, y coordinates.
|
||||||
*
|
*
|
||||||
* Due to a bug in OpenJDK, the mouse may not move all the way to the given
|
* Due to a bug in OpenJDK, the mouse may not move all the way to the given point if using a non-default Windows
|
||||||
* point if using a non-default Windows display scale. So this method checks
|
* display scale. So this method checks the current mouse position after moving and retries up to 10 times until the
|
||||||
* the current mouse position after moving and retries up to 10 times until
|
* mouse reaches the exact intended point. Multiple retries will reach the desired destination typically within 3 tries.
|
||||||
* the mouse reaches the exact intended point.
|
|
||||||
*
|
*
|
||||||
* @param point The Point representing the x, y coordinates to move the mouse to.
|
* @param point The Point representing the x, y coordinates to move the mouse to.
|
||||||
*/
|
*/
|
||||||
@ -53,15 +51,7 @@ open class RobotAutomaton(internal val robot: Robot = Robot()) : Automaton {
|
|||||||
/**
|
/**
|
||||||
* Performs a mouse click with the given button.
|
* Performs a mouse click with the given button.
|
||||||
*
|
*
|
||||||
* Uses the Robot to simulate pressing and releasing the mouse button.
|
* A random sleep is added after pressing the button before releasing.
|
||||||
*
|
|
||||||
* A random sleep is added after pressing the button before releasing,
|
|
||||||
* to add variance in timing and avoid robotic behavior.
|
|
||||||
*
|
|
||||||
* Valid button values are:
|
|
||||||
* - InputEvent.BUTTON1 (left click)
|
|
||||||
* - InputEvent.BUTTON2 (right click)
|
|
||||||
* - InputEvent.BUTTON3 (middle click)
|
|
||||||
*
|
*
|
||||||
* @param button the mouse button to click
|
* @param button the mouse button to click
|
||||||
*/
|
*/
|
||||||
@ -73,7 +63,7 @@ open class RobotAutomaton(internal val robot: Robot = Robot()) : Automaton {
|
|||||||
robot.mousePress(button)
|
robot.mousePress(button)
|
||||||
|
|
||||||
// Add random sleep to vary timing
|
// Add random sleep to vary timing
|
||||||
sleepWithVariance(8, 8)
|
sleep(8, 8)
|
||||||
|
|
||||||
robot.mouseRelease(button)
|
robot.mouseRelease(button)
|
||||||
}
|
}
|
||||||
@ -81,8 +71,6 @@ open class RobotAutomaton(internal val robot: Robot = Robot()) : Automaton {
|
|||||||
/**
|
/**
|
||||||
* Presses and releases the given key.
|
* Presses and releases the given key.
|
||||||
*
|
*
|
||||||
* Uses the Robot's keyPress() and keyRelease() methods to simulate pressing and releasing the key.
|
|
||||||
*
|
|
||||||
* A random sleep is added after pressing the key before releasing, to add variance in timing and avoid robotic
|
* A random sleep is added after pressing the key before releasing, to add variance in timing and avoid robotic
|
||||||
* behavior. The worst-case delay is ~1 frame at 60fps.
|
* behavior. The worst-case delay is ~1 frame at 60fps.
|
||||||
*
|
*
|
||||||
@ -97,7 +85,7 @@ open class RobotAutomaton(internal val robot: Robot = Robot()) : Automaton {
|
|||||||
robot.keyPress(keyCode)
|
robot.keyPress(keyCode)
|
||||||
|
|
||||||
// Add random sleep to vary timing
|
// Add random sleep to vary timing
|
||||||
sleepWithVariance(8, 8)
|
sleep(8, 8)
|
||||||
|
|
||||||
robot.keyRelease(keyCode)
|
robot.keyRelease(keyCode)
|
||||||
}
|
}
|
||||||
@ -106,28 +94,28 @@ open class RobotAutomaton(internal val robot: Robot = Robot()) : Automaton {
|
|||||||
* Scrolls the mouse wheel down by one unit.
|
* Scrolls the mouse wheel down by one unit.
|
||||||
*
|
*
|
||||||
* Uses the [Robot.mouseWheel] method to scroll down and then sleeps for a random duration between the given
|
* Uses the [Robot.mouseWheel] method to scroll down and then sleeps for a random duration between the given
|
||||||
* sleepDur + rand(0, sleepDurVariance) ms. This is to add variance in scrolling speed and avoid robotic behavior.
|
* sleepDurationMillis + rand(0, sleepDurationVarianceMillis) ms. This adds variance in scrolling speed.
|
||||||
*
|
*
|
||||||
* @param sleepDur The average duration to sleep after scrolling.
|
* @param sleepDurationMillis The minimum duration to sleep after scrolling
|
||||||
* @param sleepDurVariance The variance in sleep duration.
|
* @param sleepDurationVarianceMillis The maximum allowed additional sleep duration
|
||||||
*/
|
*/
|
||||||
override fun scrollOut(sleepDur: Long, sleepDurVariance: Long) {
|
override fun scrollOut(sleepDurationMillis: Long, sleepDurationVarianceMillis: Long) {
|
||||||
robot.mouseWheel(1)
|
robot.mouseWheel(1)
|
||||||
sleepWithVariance(sleepDur, sleepDurVariance)
|
sleep(sleepDurationMillis, sleepDurationVarianceMillis)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scrolls the mouse wheel up by one unit.
|
* Scrolls the mouse wheel down by one unit.
|
||||||
*
|
*
|
||||||
* Uses the [Robot.mouseWheel] method to scroll up and then sleeps for a random duration between the given
|
* Uses the [Robot.mouseWheel] method to scroll down and then sleeps for a random duration between the given
|
||||||
* sleepDur + rand(0, sleepDurVariance) ms. This adds variance in scrolling speed to avoid robotic behavior.
|
* sleepDurationMillis + rand(0, sleepDurationVarianceMillis) ms. This adds variance in scrolling speed.
|
||||||
*
|
*
|
||||||
* @param sleepDur The average duration to sleep after scrolling
|
* @param sleepDurationMillis The minimum duration to sleep after scrolling
|
||||||
* @param sleepDurVariance The variance in sleep duration
|
* @param sleepDurationVarianceMillis The maximum allowed additional sleep duration
|
||||||
*/
|
*/
|
||||||
override fun scrollIn(sleepDur: Long, sleepDurVariance: Long) {
|
override fun scrollIn(sleepDurationMillis: Long, sleepDurationVarianceMillis: Long) {
|
||||||
robot.mouseWheel(-1)
|
robot.mouseWheel(-1)
|
||||||
sleepWithVariance(sleepDur, sleepDurVariance)
|
sleep(sleepDurationMillis, sleepDurationVarianceMillis)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -3,38 +3,36 @@ package controllers
|
|||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for components that control time-related behavior.
|
||||||
|
*
|
||||||
|
* Implementations of this interface allow pausing execution for certain durations,
|
||||||
|
* optionally with random variance.
|
||||||
|
*/
|
||||||
interface TemporalController {
|
interface TemporalController {
|
||||||
/**
|
|
||||||
* Sleeps for the specified duration.
|
|
||||||
*
|
|
||||||
* This uses [TimeUnit.MILLISECONDS] to sleep for the given duration in milliseconds.
|
|
||||||
*
|
|
||||||
* @param dur The sleep duration in milliseconds.
|
|
||||||
*/
|
|
||||||
fun sleep(dur: Long) {
|
|
||||||
TimeUnit.MILLISECONDS.sleep(dur)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sleeps for the specified duration with some variance.
|
* Sleep for a specified base duration, with optional random variance added.
|
||||||
*
|
*
|
||||||
* This will sleep for the given duration plus a random variance between 0 inclusive and [variance] exclusive.
|
* Random variance is approximated to a normal distribution and guarantees not to pause for longer than
|
||||||
* The variance is divided in half to generate a random positive value that is added to the duration.
|
* [maxAdditionalDuration].
|
||||||
*
|
*
|
||||||
* If the duration is negative or the variance is less than 1, this method
|
* @param baseDuration the minimum time to sleep
|
||||||
* will return immediately without sleeping.
|
* @param maxAdditionalDuration maximum extra random duration to add
|
||||||
*
|
* @return Unit
|
||||||
* @param duration The base sleep duration in ms
|
|
||||||
* @param variance The amount of variance to add in ms. Gets divided in half
|
|
||||||
* and rolled as two separate random numbers to create a normal distribution
|
|
||||||
*/
|
*/
|
||||||
fun sleepWithVariance(duration: Long, variance: Long) {
|
fun sleep(baseDuration: Long, maxAdditionalDuration: Long = 0L) {
|
||||||
if (duration < 0 || variance <= 1) {
|
// Check for invalid input
|
||||||
|
if (baseDuration < 0 || maxAdditionalDuration < 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val dSize = (variance) / 2
|
// If no variance, sleep the base duration
|
||||||
val r1 = Random.nextLong(dSize)
|
val duration = if(maxAdditionalDuration == 0L){
|
||||||
val r2 = Random.nextLong(dSize)
|
baseDuration
|
||||||
sleep(duration + r1 + r2)
|
}else{
|
||||||
|
baseDuration + util.HelperFunctions.getRandomLongFromNormalDistribution((maxAdditionalDuration) / 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeUnit.MILLISECONDS.sleep(duration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
package game_logic.runescape
|
package game_logic.runescape
|
||||||
|
|
||||||
import controllers.Automaton
|
import controllers.Automaton
|
||||||
|
import controllers.MouseWiggleParams
|
||||||
import controllers.RobotAutomaton
|
import controllers.RobotAutomaton
|
||||||
import params.MouseWiggleParams
|
|
||||||
import params.StandingTaskParams
|
import params.StandingTaskParams
|
||||||
import params.TravelTaskParams
|
import params.TravelTaskParams
|
||||||
import java.awt.Point
|
import java.awt.Point
|
||||||
@ -98,7 +98,7 @@ class RSAgent(override val automaton: Automaton = RobotAutomaton()) : RSOrchestr
|
|||||||
//press the "accept" default hotkey
|
//press the "accept" default hotkey
|
||||||
automaton.keyPress(KeyEvent.VK_SPACE)
|
automaton.keyPress(KeyEvent.VK_SPACE)
|
||||||
//wait for the desired time to finish
|
//wait for the desired time to finish
|
||||||
automaton.sleepWithVariance(taskParams.craftingWaitDurationMillis, taskParams.craftingWaitDurationVarianceMillis)
|
automaton.sleep(taskParams.craftingWaitDurationMillis, taskParams.craftingWaitDurationVarianceMillis)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -147,7 +147,7 @@ class RSAgent(override val automaton: Automaton = RobotAutomaton()) : RSOrchestr
|
|||||||
automaton.keyPress(KeyEvent.VK_SPACE)
|
automaton.keyPress(KeyEvent.VK_SPACE)
|
||||||
|
|
||||||
//wait for it to complete
|
//wait for it to complete
|
||||||
automaton.sleepWithVariance(taskParams.craftingWaitDurationMillis, taskParams.craftingWaitDurationVarianceMillis)
|
automaton.sleep(taskParams.craftingWaitDurationMillis, taskParams.craftingWaitDurationVarianceMillis)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -201,7 +201,7 @@ class RSAgent(override val automaton: Automaton = RobotAutomaton()) : RSOrchestr
|
|||||||
override fun sleepForNTicks(n: Long) {
|
override fun sleepForNTicks(n: Long) {
|
||||||
val latencyPadding = LATENCY_PADDING_MS
|
val latencyPadding = LATENCY_PADDING_MS
|
||||||
val baseWaitTime = n * TICK_DURATION_MS
|
val baseWaitTime = n * TICK_DURATION_MS
|
||||||
automaton.sleepWithVariance(latencyPadding + baseWaitTime, 150)
|
automaton.sleep(latencyPadding + baseWaitTime, 150)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import controllers.Orchestrator
|
import controllers.Orchestrator
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A collection of helper functions for common utility tasks.
|
* A collection of helper functions for common utility tasks.
|
||||||
@ -32,6 +33,30 @@ object HelperFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a random long value approximating a normal distribution.
|
||||||
|
*
|
||||||
|
* Takes two random samples from 0 to upperBound/2 and adds them together. This approximates a normal distribution
|
||||||
|
* better than a single random sample.
|
||||||
|
*
|
||||||
|
* @param upperBound The upper bound to sample from
|
||||||
|
* @return A random long value following an approximate normal distribution
|
||||||
|
*/
|
||||||
|
fun getRandomLongFromNormalDistribution(upperBound: Long): Long{
|
||||||
|
//anything lower to 2 will round down to zero, so return zero
|
||||||
|
if(upperBound <= 2L){
|
||||||
|
return 0L
|
||||||
|
}
|
||||||
|
|
||||||
|
// To create more natural distribution Take two random samples from 0 to upperBound/2 and add them. This
|
||||||
|
// approximates a normal distribution better than single random sample.
|
||||||
|
val subBound = upperBound/2L
|
||||||
|
val result1 = Random.nextLong(subBound)
|
||||||
|
val result2 = Random.nextLong(subBound)
|
||||||
|
return result1 + result2
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints a progress report to console showing current step, total steps, elapsed time, and estimated remaining time.
|
* Prints a progress report to console showing current step, total steps, elapsed time, and estimated remaining time.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package controllers
|
|||||||
|
|
||||||
import org.mockito.Mockito.mock
|
import org.mockito.Mockito.mock
|
||||||
import org.mockito.Mockito.`when`
|
import org.mockito.Mockito.`when`
|
||||||
import params.MouseWiggleParams
|
|
||||||
import java.awt.Point
|
import java.awt.Point
|
||||||
import java.awt.event.InputEvent
|
import java.awt.event.InputEvent
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
@ -75,7 +74,7 @@ class AutomatonTest {
|
|||||||
val automaton = mock(Automaton::class.java)
|
val automaton = mock(Automaton::class.java)
|
||||||
|
|
||||||
automaton.sleep(1000)
|
automaton.sleep(1000)
|
||||||
automaton.sleepWithVariance(1000, 200)
|
automaton.sleep(1000, 200)
|
||||||
// Asserts Automaton extends TemporalController
|
// Asserts Automaton extends TemporalController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import params.MouseWiggleParams
|
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
import org.mockito.Mockito.*
|
import org.mockito.Mockito.*
|
||||||
import java.awt.Point
|
import java.awt.Point
|
||||||
|
|||||||
@ -12,30 +12,22 @@ internal class TemporalControllerTest {
|
|||||||
* Creates an instance of TemporalController for testing.
|
* Creates an instance of TemporalController for testing.
|
||||||
*/
|
*/
|
||||||
private val controller = object : TemporalController {
|
private val controller = object : TemporalController {
|
||||||
|
|
||||||
/**
|
|
||||||
* Sleeps for the given duration in milliseconds.
|
|
||||||
*/
|
|
||||||
override fun sleep(dur: Long) {
|
|
||||||
TimeUnit.MILLISECONDS.sleep(dur)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sleeps for around the given duration, with variance.
|
* Sleeps for around the given duration, with variance.
|
||||||
*
|
*
|
||||||
* @param duration the desired duration to sleep
|
* @param baseDuration the desired duration to sleep
|
||||||
* @param variance the amount of variance in the actual duration
|
* @param maxAdditionalDuration the amount of variance in the actual duration
|
||||||
*/
|
*/
|
||||||
override fun sleepWithVariance(duration: Long, variance: Long) {
|
override fun sleep(baseDuration: Long, maxAdditionalDuration: Long) {
|
||||||
if (duration < 0 || variance <= 1) {
|
if (baseDuration < 0 || maxAdditionalDuration <= 1) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val dSize = (variance) / 2
|
val dSize = (maxAdditionalDuration) / 2
|
||||||
val r1 = Random.nextLong(dSize)
|
val r1 = Random.nextLong(dSize)
|
||||||
val r2 = Random.nextLong(dSize)
|
val r2 = Random.nextLong(dSize)
|
||||||
|
|
||||||
sleep(duration + r1 + r2)
|
sleep(baseDuration + r1 + r2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +45,7 @@ internal class TemporalControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that [TemporalController.sleepWithVariance] sleeps for approximately
|
* Tests that [TemporalController.sleep] sleeps for approximately
|
||||||
* the given duration, within the specified variance.
|
* the given duration, within the specified variance.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@ -62,7 +54,7 @@ internal class TemporalControllerTest {
|
|||||||
val variance = 500L
|
val variance = 500L
|
||||||
|
|
||||||
val start = System.currentTimeMillis()
|
val start = System.currentTimeMillis()
|
||||||
controller.sleepWithVariance(duration, variance)
|
controller.sleep(duration, variance)
|
||||||
val end = System.currentTimeMillis()
|
val end = System.currentTimeMillis()
|
||||||
val elapsed = end - start
|
val elapsed = end - start
|
||||||
|
|
||||||
@ -74,13 +66,13 @@ internal class TemporalControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that [TemporalController.sleepWithVariance] returns immediately
|
* Tests that [TemporalController.sleep] returns immediately
|
||||||
* if passed a negative duration.
|
* if passed a negative duration.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun `sleepWithVariance returns immediately if duration is negative`() {
|
fun `sleepWithVariance returns immediately if duration is negative`() {
|
||||||
val start = System.currentTimeMillis()
|
val start = System.currentTimeMillis()
|
||||||
controller.sleepWithVariance(-100, 500)
|
controller.sleep(-100, 500)
|
||||||
val end = System.currentTimeMillis()
|
val end = System.currentTimeMillis()
|
||||||
val elapsed = end - start
|
val elapsed = end - start
|
||||||
|
|
||||||
@ -88,13 +80,13 @@ internal class TemporalControllerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that [TemporalController.sleepWithVariance] returns immediately
|
* Tests that [TemporalController.sleep] returns immediately
|
||||||
* if the variance parameter is 0.
|
* if the variance parameter is 0.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun `sleepWithVariance returns immediately if variance is 0`() {
|
fun `sleepWithVariance returns immediately if variance is 0`() {
|
||||||
val start = System.currentTimeMillis()
|
val start = System.currentTimeMillis()
|
||||||
controller.sleepWithVariance(100, 0)
|
controller.sleep(100, 0)
|
||||||
val end = System.currentTimeMillis()
|
val end = System.currentTimeMillis()
|
||||||
val elapsed = end - start
|
val elapsed = end - start
|
||||||
|
|
||||||
|
|||||||
29
src/test/kotlin/util/HelperFunctionsTest.kt
Normal file
29
src/test/kotlin/util/HelperFunctionsTest.kt
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import kotlin.math.pow
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
|
||||||
|
class HelperFunctionsTest {
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test getRandomLongFromNormalDistribution generates normal distribution`() {
|
||||||
|
|
||||||
|
// Generate a large number of samples
|
||||||
|
val numSamples = 10000
|
||||||
|
val upperBound = 1000L
|
||||||
|
val samples = (1..numSamples).map {
|
||||||
|
HelperFunctions.getRandomLongFromNormalDistribution(upperBound)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate mean and standard deviation
|
||||||
|
val mean = samples.average()
|
||||||
|
val stdDev = samples.map { (it - mean).pow(2) }.average().pow(0.5)
|
||||||
|
|
||||||
|
// Assert mean and std dev are within expected range
|
||||||
|
assert(mean > upperBound * 0.4 && mean < upperBound * 0.6)
|
||||||
|
assert(stdDev > upperBound * 0.2 && stdDev < upperBound * 0.3)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user