All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonTest.TopologicalSortTest.kt Maven / Gradle / Ivy

package com.amplitude.experiment.evaluation

import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import kotlin.test.fail

fun evaluationFlag(key: Int, dependencies: Set): EvaluationFlag {
    return EvaluationFlag(
        key = key.toString(),
        variants = mapOf(),
        segments = listOf(),
        dependencies = dependencies.map { it.toString() }.toSet()
    )
}

class TopologicalSortTest {

    @Test
    fun testEmpty() {
        run { // no flag keys
            val flagConfigs = listOf()
            val result = topologicalSort(flagConfigs)
            assertTrue(result.isEmpty())
        }
        run { // with flag keys
            val flagConfigs = listOf()
            val result = topologicalSort(flagConfigs, setOf("1"))
            assertTrue(result.isEmpty())
        }
    }

    @Test
    fun testSingleFlagNoDependencies() {
        val dependencies = setOf()
        run { // no flag keys
            val flagConfigs = listOf(evaluationFlag(1, dependencies))
            val result = topologicalSort(flagConfigs)
            assertEquals(listOf(evaluationFlag(1, dependencies)), result)
        }
        run { // with flag keys
            val flagConfigs = listOf(evaluationFlag(1, dependencies))
            val result = topologicalSort(flagConfigs, setOf("1"))
            assertEquals(listOf(evaluationFlag(1, dependencies)), result)
        }
        run { // with flag keys, no match
            val flagConfigs = listOf(evaluationFlag(1, dependencies))
            val result = topologicalSort(flagConfigs, setOf("999"))
            assertTrue(result.isEmpty())
        }
    }

    @Test
    fun testSingleFlagWithDependencies() {
        val dependencies = setOf(2)
        run { // no flag keys
            val flagConfigs = listOf(evaluationFlag(1, dependencies))
            val result = topologicalSort(flagConfigs)
            assertEquals(listOf(evaluationFlag(1, dependencies)), result)
        }
        run { // with flag keys
            val flagConfigs = listOf(evaluationFlag(1, dependencies))
            val result = topologicalSort(flagConfigs, setOf("1"))
            assertEquals(listOf(evaluationFlag(1, dependencies)), result)
        }
        run { // with flag keys, no match
            val flagConfigs = listOf(evaluationFlag(1, dependencies))
            val result = topologicalSort(flagConfigs, setOf("999"))
            assertTrue(result.isEmpty())
        }
    }

    @Test
    fun testMultipleFlagsNoDependencies() {
        val dependencies = setOf()
        run { // no flag keys
            val flagConfigs = listOf(
                evaluationFlag(1, dependencies),
                evaluationFlag(2, dependencies),
            )
            val result = topologicalSort(flagConfigs)
            assertEquals(
                listOf(
                    evaluationFlag(1, dependencies),
                    evaluationFlag(2, dependencies),
                ),
                result
            )
        }
        run { // with flag keys
            val flagConfigs = listOf(
                evaluationFlag(1, dependencies),
                evaluationFlag(2, dependencies),
            )
            val result = topologicalSort(flagConfigs, setOf("1", "2"))
            assertEquals(
                listOf(
                    evaluationFlag(1, dependencies),
                    evaluationFlag(2, dependencies),
                ),
                result
            )
        }
        run { // with flag keys, no match
            val flagConfigs = listOf(
                evaluationFlag(1, dependencies),
                evaluationFlag(2, dependencies),
            )
            val result = topologicalSort(flagConfigs, setOf("99", "999"))
            assertTrue(result.isEmpty())
        }
    }

    @Test
    fun testMultipleFlagsWithDependencies() {
        run { // no flag keys
            val flagConfigs = listOf(
                evaluationFlag(1, setOf(2)),
                evaluationFlag(2, setOf(3)),
                evaluationFlag(3, setOf()),
            )
            val result = topologicalSort(flagConfigs)
            assertEquals(
                listOf(
                    evaluationFlag(3, setOf()),
                    evaluationFlag(2, setOf(3)),
                    evaluationFlag(1, setOf(2)),
                ),
                result
            )
        }
        run { // with flag keys
            val flagConfigs = listOf(
                evaluationFlag(1, setOf(2)),
                evaluationFlag(2, setOf(3)),
                evaluationFlag(3, setOf()),
            )
            val result = topologicalSort(flagConfigs, setOf("1", "2"))
            assertEquals(
                listOf(
                    evaluationFlag(3, setOf()),
                    evaluationFlag(2, setOf(3)),
                    evaluationFlag(1, setOf(2)),
                ),
                result
            )
        }
        run { // with flag keys, no match
            val flagConfigs = listOf(
                evaluationFlag(1, setOf(2)),
                evaluationFlag(2, setOf(3)),
                evaluationFlag(3, setOf()),
            )
            val result = topologicalSort(flagConfigs, setOf("99", "999"))
            assertTrue(result.isEmpty())
        }
    }

    @Test
    fun testSingleFlagCycle() {
        run { // no flag keys
            try {
                val flagConfigs = listOf(
                    evaluationFlag(1, setOf(1)),
                )
                val result = topologicalSort(flagConfigs)
                fail("expected cycle, instead: $result")
            } catch (e: CycleException) {
                e.printStackTrace()
            }
        }
        run { // with flag keys
            try {
                val flagConfigs = listOf(
                    evaluationFlag(1, setOf(1)),
                )
                val result = topologicalSort(flagConfigs, setOf("1"))
                fail("expected cycle, instead: $result")
            } catch (e: CycleException) {
                e.printStackTrace()
            }
        }
        run { // with flag keys, no match
            try {
                val flagConfigs = listOf(
                    evaluationFlag(1, setOf(1)),
                )
                val result = topologicalSort(flagConfigs, setOf("999"))
                assertTrue(result.isEmpty())
            } catch (e: CycleException) {
                fail(e.message)
            }
        }
    }

    @Test
    fun testTwoFlagCycle() {
        run { // no flag keys
            try {
                val flagConfigs = listOf(
                    evaluationFlag(1, setOf(2)),
                    evaluationFlag(2, setOf(1)),
                )
                val result = topologicalSort(flagConfigs)
                fail("expected cycle, instead: $result")
            } catch (e: CycleException) {
                e.printStackTrace()
            }
        }
        run { // with flag keys
            try {
                val flagConfigs = listOf(
                    evaluationFlag(1, setOf(2)),
                    evaluationFlag(2, setOf(1)),
                )
                val result = topologicalSort(flagConfigs, setOf("2"))
                fail("expected cycle, instead: $result")
            } catch (e: CycleException) {
                e.printStackTrace()
            }
        }
        run { // with flag keys, no match
            try {
                val flagConfigs = listOf(
                    evaluationFlag(1, setOf(2)),
                    evaluationFlag(2, setOf(1)),
                )
                val result = topologicalSort(flagConfigs, setOf("999"))
                assertTrue(result.isEmpty())
            } catch (e: CycleException) {
                fail(e.message)
            }
        }
    }

    @Test
    fun testMultipleFlagsComplexCycle() {
        val flagConfigs = listOf(
            evaluationFlag(3, setOf(1, 2)),
            evaluationFlag(1, setOf()),
            evaluationFlag(4, setOf(21, 3)),
            evaluationFlag(2, setOf()),
            evaluationFlag(5, setOf(3)),
            evaluationFlag(6, setOf()),
            evaluationFlag(7, setOf()),
            evaluationFlag(8, setOf(9)),
            evaluationFlag(9, setOf()),
            evaluationFlag(20, setOf(4)),
            evaluationFlag(21, setOf(20))
        )
        try {
            val result = topologicalSort(flagConfigs)
            fail("expected cycle, instead:$result")
        } catch (e: CycleException) {
            // Expected
            assertEquals(setOf("4", "21", "20"), e.cycle)
        }
    }

    @Test
    fun testTopologicalSortComplexNoCycle_startWithLeaf() {
        val flags = listOf(
            evaluationFlag(1, setOf(6, 3)),
            evaluationFlag(2, setOf(8, 5, 3, 1)),
            evaluationFlag(3, setOf(6, 5)),
            evaluationFlag(4, setOf(8, 7)),
            evaluationFlag(5, setOf(10, 7)),
            evaluationFlag(7, setOf(8)),
            evaluationFlag(6, setOf(7, 4)),
            evaluationFlag(8, setOf()),
            evaluationFlag(9, setOf(10, 7, 5)),
            evaluationFlag(10, setOf(7)),
            evaluationFlag(20, setOf()),
            evaluationFlag(21, setOf(20)),
            evaluationFlag(30, setOf()),
        )
        val result = topologicalSort(flags)
        val expected = listOf(
            evaluationFlag(8, setOf()),
            evaluationFlag(7, setOf(8)),
            evaluationFlag(4, setOf(8, 7)),
            evaluationFlag(6, setOf(7, 4)),
            evaluationFlag(10, setOf(7)),
            evaluationFlag(5, setOf(10, 7)),
            evaluationFlag(3, setOf(6, 5)),
            evaluationFlag(1, setOf(6, 3)),
            evaluationFlag(2, setOf(8, 5, 3, 1)),
            evaluationFlag(9, setOf(10, 7, 5)),
            evaluationFlag(20, setOf()),
            evaluationFlag(21, setOf(20)),
            evaluationFlag(30, setOf()),
        )
        assertEquals(expected, result)
    }

    @Test
    fun testTopologicalSortComplexNoCycle_startWithMiddle() {
        val flags = listOf(
            evaluationFlag(6, setOf(7, 4)),
            evaluationFlag(1, setOf(6, 3)),
            evaluationFlag(2, setOf(8, 5, 3, 1)),
            evaluationFlag(3, setOf(6, 5)),
            evaluationFlag(4, setOf(8, 7)),
            evaluationFlag(5, setOf(10, 7)),
            evaluationFlag(7, setOf(8)),
            evaluationFlag(8, setOf()),
            evaluationFlag(9, setOf(10, 7, 5)),
            evaluationFlag(10, setOf(7)),
            evaluationFlag(20, setOf()),
            evaluationFlag(21, setOf(20)),
            evaluationFlag(30, setOf()),
        )
        val result = topologicalSort(flags)
        val expected = listOf(
            evaluationFlag(8, setOf()),
            evaluationFlag(7, setOf(8)),
            evaluationFlag(4, setOf(8, 7)),
            evaluationFlag(6, setOf(7, 4)),
            evaluationFlag(10, setOf(7)),
            evaluationFlag(5, setOf(10, 7)),
            evaluationFlag(3, setOf(6, 5)),
            evaluationFlag(1, setOf(6, 3)),
            evaluationFlag(2, setOf(8, 5, 3, 1)),
            evaluationFlag(9, setOf(10, 7, 5)),
            evaluationFlag(20, setOf()),
            evaluationFlag(21, setOf(20)),
            evaluationFlag(30, setOf()),
        )
        assertEquals(expected, result)
    }

    @Test
    fun testTopologicalSortComplexNoCycle_startWithRoot() {
        val flags = listOf(
            evaluationFlag(8, setOf()),
            evaluationFlag(1, setOf(6, 3)),
            evaluationFlag(2, setOf(8, 5, 3, 1)),
            evaluationFlag(3, setOf(6, 5)),
            evaluationFlag(4, setOf(8, 7)),
            evaluationFlag(5, setOf(10, 7)),
            evaluationFlag(6, setOf(7, 4)),
            evaluationFlag(7, setOf(8)),
            evaluationFlag(9, setOf(10, 7, 5)),
            evaluationFlag(10, setOf(7)),
            evaluationFlag(20, setOf()),
            evaluationFlag(21, setOf(20)),
            evaluationFlag(30, setOf()),
        )
        val result = topologicalSort(flags)
        val expected = listOf(
            evaluationFlag(8, setOf()),
            evaluationFlag(7, setOf(8)),
            evaluationFlag(4, setOf(8, 7)),
            evaluationFlag(6, setOf(7, 4)),
            evaluationFlag(10, setOf(7)),
            evaluationFlag(5, setOf(10, 7)),
            evaluationFlag(3, setOf(6, 5)),
            evaluationFlag(1, setOf(6, 3)),
            evaluationFlag(2, setOf(8, 5, 3, 1)),
            evaluationFlag(9, setOf(10, 7, 5)),
            evaluationFlag(20, setOf()),
            evaluationFlag(21, setOf(20)),
            evaluationFlag(30, setOf()),
        )
        assertEquals(expected, result)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy