Search code examples
unit-testingkotlintestingtail-recursion

How can i test a tailrec function in Kotlin?


Im trying to test the following tailrec function:

    private tailrec fun findFixPoint(eps: Double = 5.0, x: Double = 1.0): Double = if (abs(x - cos(x)) < eps) x else findFixPoint(cos(x))

This is my test function:

@Test
fun testNewFeatures(){
    TestCase.assertEquals(0.7390851332151611, findFixPoint())
}

The fix point is 0.7390851332151611 but the assertEquals returns me 1.0 as Actualvalue i can deduct the function is only being launch one time without recursion.

Any suggestion of how can be test a tailrec function properly?

Hope anyone can help me with this. Thank you all in advance.


EDIT

The real point of this post was a test of tailrec function for avoid a StackOverflowError so, i will post here two simple test, but sa1nt´s answer was correct for my question issue, and the tip of Benoit was great for simplifying the tailrec test

So, the following functions to test the StackOverflowError are this:

Not avoided

private fun testStackOverFlow(num : Double): Double = if (num == 10000000000.0) num else testStackOverFlow(num+1)

Avoided

private tailrec fun testNOTStackOverFlow(num : Double): Double = if (num == 10000000000.0) num else testNOTStackOverFlow(num+1)

Test function:

@Test
fun testNewFeatures(){

    TestCase.assertEquals(10000000000.0, testStackOverFlow(1.0))
    TestCase.assertEquals(10000000000.0, testNOTStackOverFlow(1.0))
}

Thank you all for the answers. Have a great day.


Solution

  • TLDR

    1. Change your function to:
        tailrec fun findFixPoint(eps: Double = 5.0, x: Double = 1.0): Double =
            if (abs(x - cos(x)) < eps) x
            else findFixPoint(eps, cos(x)) // eps argument added
    
    1. And the test to:
    @Test
    fun testNewFeatures(){
        TestCase.assertEquals(0.7390851332151611, findFixPoint(eps = 0.05)) // overriding default eps value
    }
    

    Details

    1. Provide both arguments explicitly in the recursive call. Otherwise cos(x) will be used for the eps because it's the first argument:
      private tailrec fun findFixPoint(eps: Double = 5.0, x: Double = 1.0): Double = if (abs(x - cos(x)) < eps) x else findFixPoint(eps, cos(x))

    2. In the test you call the function like this findFixPoint() so default argument values are used. So, the condition if (abs(x - cos(x)) < eps) x else ... for eps = 5.0 and x = 1.0 will return x immediately after entering the function.