Add manually written tests covering both min/max/By/With and their nullable variants
diff --git a/libraries/stdlib/test/collections/ArraysTest.kt b/libraries/stdlib/test/collections/ArraysTest.kt
index 42d6e13..3bcf8f0 100644
--- a/libraries/stdlib/test/collections/ArraysTest.kt
+++ b/libraries/stdlib/test/collections/ArraysTest.kt
@@ -7,10 +7,11 @@
 
 package test.collections
 
+import test.assertIsNegativeZero
+import test.assertIsPositiveZero
 import test.assertStaticTypeIs
 import test.assertTypeEquals
 import test.collections.behaviors.*
-import test.comparisons.STRING_CASE_INSENSITIVE_ORDER
 import test.text.isAsciiLetter
 import kotlin.test.*
 import kotlin.random.Random
@@ -347,15 +348,164 @@
 
 
 
-    @Test fun minOrNull() {
-        expect(null, { arrayOf<Int>().minOrNull() })
-        expect(1, { arrayOf(1).minOrNull() })
-        expect(2, { arrayOf(2, 3).minOrNull() })
-        expect(2000000000000, { arrayOf(3000000000000, 2000000000000).minOrNull() })
-        expect('a', { arrayOf('a', 'b').minOrNull() })
-        expect("a", { arrayOf("a", "b").minOrNull() })
+
+    @Test
+    fun minMax() = with(MinMaxOperations.ArrayT) {
+        expectMinMax(1, 1, arrayOf(1))
+        expectMinMax(2, 3, arrayOf(2, 3))
+        expectMinMax(2, 3, arrayOf(3, 2))
+        expectMinMax(2000000000000, 3000000000000, arrayOf(3000000000000, 2000000000000))
+        expectMinMax('a', 'b', arrayOf('a', 'b'))
+        expectMinMax("a", "b", arrayOf("a", "b"))
+
+        MinMaxOperations.ArrayT<Int>().expectMinMaxEmpty(emptyArray())
     }
 
+    @Test
+    fun minMaxIntArray() = with(MinMaxOperations.AInt) {
+        expectMinMaxEmpty(intArrayOf())
+        expectMinMax(1, 1, intArrayOf(1))
+        expectMinMax(1, 2, intArrayOf(1, 2))
+    }
+
+    @Test
+    fun minMaxLongArray() = with(MinMaxOperations.ALong) {
+        expectMinMaxEmpty(longArrayOf())
+        expectMinMax(1, 1, longArrayOf(1))
+        expectMinMax(1, 2, longArrayOf(1, 2))
+    }
+
+    @Test
+    fun minMaxShortArray() = with(MinMaxOperations.AShort) {
+        expectMinMaxEmpty(shortArrayOf())
+        expectMinMax(1, 1, shortArrayOf(1))
+        expectMinMax(1, 2, shortArrayOf(1, 2))
+    }
+
+    @Test
+    fun minMaxByteArray() = with(MinMaxOperations.AByte) {
+        expectMinMaxEmpty(byteArrayOf())
+        expectMinMax(1, 1, byteArrayOf(1))
+        expectMinMax(1, 2, byteArrayOf(1, 2))
+    }
+
+    @Test
+    fun minMaxFloatArray() = with(MinMaxOperations.AFloat) {
+        expectMinMaxEmpty(floatArrayOf())
+        expectMinMax(1F, 1F, floatArrayOf(1F))
+        expectMinMax(1F, 2F, floatArrayOf(1F, 2F))
+    }
+    
+    @Test
+    fun minMaxDoubleArray() = with(MinMaxOperations.ADouble) {
+        expectMinMaxEmpty(doubleArrayOf())
+        expectMinMax(1.0, 1.0, doubleArrayOf(1.0))
+        expectMinMax(1.0, 2.0, doubleArrayOf(1.0, 2.0))
+    }
+
+    @Test
+    fun minMaxCharArray() = with(MinMaxOperations.AChar) {
+        expectMinMaxEmpty(charArrayOf())
+        expectMinMax('a', 'a', charArrayOf('a'))
+        expectMinMax('a', 'b', charArrayOf('a', 'b'))
+    }
+
+    @Test
+    fun minMaxFloatingPoint() {
+        val doubleZeroes = arrayOf(0.0, -0.0).also { it.shuffle() }
+        val floatZeroes = arrayOf(0.0F, -0.0F).also { it.shuffle() }
+        val doubleNaN = arrayOf(0.0, Double.NaN).also { it.shuffle() }
+        val floatNaN = arrayOf(0.0F, Float.NaN).also { it.shuffle() }
+
+        assertIsNegativeZero(doubleZeroes.min())
+        assertIsNegativeZero(doubleZeroes.minOrNull()!!)
+        assertIsNegativeZero(floatZeroes.min().toDouble())
+        assertIsNegativeZero(floatZeroes.minOrNull()!!.toDouble())
+        assertTrue(doubleNaN.min().isNaN())
+        assertTrue(doubleNaN.minOrNull()!!.isNaN())
+        assertTrue(floatNaN.min().isNaN())
+        assertTrue(floatNaN.minOrNull()!!.isNaN())
+
+        assertIsPositiveZero(doubleZeroes.max())
+        assertIsPositiveZero(doubleZeroes.maxOrNull()!!)
+        assertIsPositiveZero(floatZeroes.max().toDouble())
+        assertIsPositiveZero(floatZeroes.maxOrNull()!!.toDouble())
+        assertTrue(doubleNaN.max().isNaN())
+        assertTrue(doubleNaN.maxOrNull()!!.isNaN())
+        assertTrue(floatNaN.max().isNaN())
+        assertTrue(floatNaN.maxOrNull()!!.isNaN())
+    }
+
+    @Test
+    fun minMaxPrimitiveFloatingPoint() {
+        val doubleZeroes = doubleArrayOf(0.0, -0.0).also { it.shuffle() }
+        val floatZeroes = floatArrayOf(0.0F, -0.0F).also { it.shuffle() }
+        val doubleNaN = doubleArrayOf(0.0, Double.NaN).also { it.shuffle() }
+        val floatNaN = floatArrayOf(0.0F, Float.NaN).also { it.shuffle() }
+
+        assertIsNegativeZero(doubleZeroes.min())
+        assertIsNegativeZero(doubleZeroes.minOrNull()!!)
+        assertIsNegativeZero(floatZeroes.min().toDouble())
+        assertIsNegativeZero(floatZeroes.minOrNull()!!.toDouble())
+        assertTrue(doubleNaN.min().isNaN())
+        assertTrue(doubleNaN.minOrNull()!!.isNaN())
+        assertTrue(floatNaN.min().isNaN())
+        assertTrue(floatNaN.minOrNull()!!.isNaN())
+
+        assertIsPositiveZero(doubleZeroes.max())
+        assertIsPositiveZero(doubleZeroes.maxOrNull()!!)
+        assertIsPositiveZero(floatZeroes.max().toDouble())
+        assertIsPositiveZero(floatZeroes.maxOrNull()!!.toDouble())
+        assertTrue(doubleNaN.max().isNaN())
+        assertTrue(doubleNaN.maxOrNull()!!.isNaN())
+        assertTrue(floatNaN.max().isNaN())
+        assertTrue(floatNaN.maxOrNull()!!.isNaN())
+    }
+
+//    private fun <T> expectMinMaxWith(min: T, max: T, elements: Array<T>, comparator: Comparator<T>) {
+//        assertEquals(min, elements.minWithOrNull(comparator))
+//        assertEquals(max, elements.maxWithOrNull(comparator))
+//        assertEquals(min, elements.minWith(comparator))
+//        assertEquals(max, elements.maxWith(comparator))
+//    }
+
+    @Test
+    fun minMaxWith() = with(MinMaxOperationsWith.ArrayT) {
+        expectMinMaxWith(1, 1, arrayOf(1), naturalOrder())
+        expectMinMaxWith("a", "B", arrayOf("a", "B"), String.CASE_INSENSITIVE_ORDER)
+    }
+
+    @Test
+    fun minMaxWithEmpty() = with(MinMaxOperationsWith.ArrayT<Int>()) {
+        expectMinMaxWithEmpty(emptyArray(), naturalOrder())
+    }
+
+    private inline fun <T, K : Comparable<K>> expectMinMaxBy(min: T, max: T, elements: Array<T>, selector: (T) -> K) {
+        assertEquals(min, elements.minBy(selector))
+        assertEquals(min, elements.minByOrNull(selector))
+        assertEquals(max, elements.maxByOrNull(selector))
+        assertEquals(max, elements.maxByOrNull(selector))
+    }
+
+    @Test
+    fun minMaxBy() {
+        expectMinMaxBy(1, 1, arrayOf(1), { it })
+        expectMinMaxBy(3, 2, arrayOf(2, 3), { -it })
+        expectMinMaxBy('a', 'b', arrayOf('a', 'b'), { "x$it" })
+        expectMinMaxBy("b", "abc", arrayOf("abc", "b"), { it.length })
+    }
+
+    @Test
+    fun minMaxByEmpty() {
+        val empty = emptyArray<Int>()
+        val selector = Int::toString
+        assertNull(empty.minByOrNull(selector))
+        assertNull(empty.maxByOrNull(selector))
+        assertFailsWith<NoSuchElementException> { empty.minBy(selector) }
+        assertFailsWith<NoSuchElementException> { empty.maxBy(selector) }
+    }
+
+
     @Test fun minOrNullInPrimitiveArrays() {
         expect(null, { intArrayOf().minOrNull() })
         expect(1, { intArrayOf(1).minOrNull() })
@@ -368,14 +518,6 @@
         expect('a', { charArrayOf('a', 'b').minOrNull() })
     }
 
-    @Test fun maxOrNull() {
-        expect(null, { arrayOf<Int>().maxOrNull() })
-        expect(1, { arrayOf(1).maxOrNull() })
-        expect(3, { arrayOf(2, 3).maxOrNull() })
-        expect(3000000000000, { arrayOf(3000000000000, 2000000000000).maxOrNull() })
-        expect('b', { arrayOf('a', 'b').maxOrNull() })
-        expect("b", { arrayOf("a", "b").maxOrNull() })
-    }
 
     @Test fun maxOrNullInPrimitiveArrays() {
         expect(null, { intArrayOf().maxOrNull() })
@@ -389,10 +531,6 @@
         expect('b', { charArrayOf('a', 'b').maxOrNull() })
     }
 
-    @Test fun minWithOrNull() {
-        assertEquals(null, arrayOf<Int>().minWithOrNull(naturalOrder()))
-        assertEquals("a", arrayOf("a", "B").minWithOrNull(STRING_CASE_INSENSITIVE_ORDER))
-    }
 
     @Test fun minWithOrNullInPrimitiveArrays() {
         expect(null, { intArrayOf().minWithOrNull(naturalOrder()) })
@@ -400,25 +538,12 @@
         expect(4, { intArrayOf(2, 3, 4).minWithOrNull(compareBy { it % 4 }) })
     }
 
-    @Test fun maxWithOrNull() {
-        assertEquals(null, arrayOf<Int>().maxWithOrNull(naturalOrder()))
-        assertEquals("B", arrayOf("a", "B").maxWithOrNull(STRING_CASE_INSENSITIVE_ORDER))
-    }
-
     @Test fun maxWithOrNullInPrimitiveArrays() {
         expect(null, { intArrayOf().maxWithOrNull(naturalOrder()) })
         expect(1, { intArrayOf(1).maxWithOrNull(naturalOrder()) })
         expect(-4, { intArrayOf(2, 3, -4).maxWithOrNull(compareBy { it * it }) })
     }
 
-    @Test fun minByOrNull() {
-        expect(null, { arrayOf<Int>().minByOrNull { it } })
-        expect(1, { arrayOf(1).minByOrNull { it } })
-        expect(3, { arrayOf(2, 3).minByOrNull { -it } })
-        expect('a', { arrayOf('a', 'b').minByOrNull { "x$it" } })
-        expect("b", { arrayOf("b", "abc").minByOrNull { it.length } })
-    }
-
     @Test fun minByOrNullInPrimitiveArrays() {
         expect(null, { intArrayOf().minByOrNull { it } })
         expect(1, { intArrayOf(1).minByOrNull { it } })
@@ -430,14 +555,6 @@
         expect(2.0, { doubleArrayOf(2.0, 3.0).minByOrNull { it * it } })
     }
 
-    @Test fun maxByOrNull() {
-        expect(null, { arrayOf<Int>().maxByOrNull { it } })
-        expect(1, { arrayOf(1).maxByOrNull { it } })
-        expect(2, { arrayOf(2, 3).maxByOrNull { -it } })
-        expect('b', { arrayOf('a', 'b').maxByOrNull { "x$it" } })
-        expect("abc", { arrayOf("b", "abc").maxByOrNull { it.length } })
-    }
-
     @Test fun maxByOrNullInPrimitiveArrays() {
         expect(null, { intArrayOf().maxByOrNull { it } })
         expect(1, { intArrayOf(1).maxByOrNull { it } })
diff --git a/libraries/stdlib/test/collections/CollectionTest.kt b/libraries/stdlib/test/collections/CollectionTest.kt
index 193ed2a..fd1ed1e 100644
--- a/libraries/stdlib/test/collections/CollectionTest.kt
+++ b/libraries/stdlib/test/collections/CollectionTest.kt
@@ -10,7 +10,6 @@
 import test.assertStaticAndRuntimeTypeIs
 import kotlin.test.*
 import test.collections.behaviors.*
-import test.comparisons.STRING_CASE_INSENSITIVE_ORDER
 import kotlin.math.pow
 import kotlin.random.Random
 
@@ -833,66 +832,104 @@
         assertTrue(hashSetOf(45, 14, 13).toIterable().contains(14))
     }
 
-    @Test fun minOrNull() {
-        expect(null, { listOf<Int>().minOrNull() })
-        expect(1, { listOf(1).minOrNull() })
-        expect(2, { listOf(2, 3).minOrNull() })
-        expect(2000000000000, { listOf(3000000000000, 2000000000000).minOrNull() })
-        expect('a', { listOf('a', 'b').minOrNull() })
-        expect("a", { listOf("a", "b").minOrNull() })
-        expect(null, { listOf<Int>().asSequence().minOrNull() })
-        expect(2, { listOf(2, 3).asSequence().minOrNull() })
 
-        assertIsNegativeZero(listOf(0.0, -0.0).shuffled().minOrNull()!!)
-        assertIsNegativeZero(listOf(0.0F, -0.0F).shuffled().minOrNull()!!.toDouble())
+    private fun <T : Comparable<T>> expectMinMax(min: T, max: T, elements: Iterable<T>) {
+        assertEquals(min, elements.minOrNull())
+        assertEquals(max, elements.maxOrNull())
+        assertEquals(min, elements.min())
+        assertEquals(max, elements.max())
     }
 
-    @Test fun max() {
-        expect(null, { listOf<Int>().maxOrNull() })
-        expect(1, { listOf(1).maxOrNull() })
-        expect(3, { listOf(2, 3).maxOrNull() })
-        expect(3000000000000, { listOf(3000000000000, 2000000000000).maxOrNull() })
-        expect('b', { listOf('a', 'b').maxOrNull() })
-        expect("b", { listOf("a", "b").maxOrNull() })
-        expect(null, { listOf<Int>().asSequence().maxOrNull() })
-        expect(3, { listOf(2, 3).asSequence().maxOrNull() })
-
-        assertIsPositiveZero(listOf(0.0, -0.0).shuffled().maxOrNull()!!)
-        assertIsPositiveZero(listOf(0.0F, -0.0F).shuffled().maxOrNull()!!.toDouble())
+    @Test
+    fun minMax() {
+        expectMinMax(1, 1, listOf(1))
+        expectMinMax(2, 3, listOf(2, 3))
+        expectMinMax(2, 3, listOf(3, 2))
+        expectMinMax(2000000000000, 3000000000000, listOf(3000000000000, 2000000000000))
+        expectMinMax('a', 'b', listOf('a', 'b'))
+        expectMinMax("a", "b", listOf("a", "b"))
     }
 
-    @Test fun minWithOrNull() {
-        expect(null, { listOf<Int>().minWithOrNull(naturalOrder()) })
-        expect(1, { listOf(1).minWithOrNull(naturalOrder()) })
-        expect("a", { listOf("a", "B").minWithOrNull(STRING_CASE_INSENSITIVE_ORDER) })
-        expect("a", { listOf("a", "B").asSequence().minWithOrNull(STRING_CASE_INSENSITIVE_ORDER) })
+    @Test
+    fun minMaxEmpty() {
+        val empty = emptyList<Int>()
+        assertNull(empty.minOrNull())
+        assertNull(empty.maxOrNull())
+        assertFailsWith<NoSuchElementException> { empty.min() }
+        assertFailsWith<NoSuchElementException> { empty.max() }
     }
 
-    @Test fun maxWithOrNull() {
-        expect(null, { listOf<Int>().maxWithOrNull(naturalOrder()) })
-        expect(1, { listOf(1).maxWithOrNull(naturalOrder()) })
-        expect("B", { listOf("a", "B").maxWithOrNull(STRING_CASE_INSENSITIVE_ORDER) })
-        expect("B", { listOf("a", "B").asSequence().maxWithOrNull(STRING_CASE_INSENSITIVE_ORDER) })
+    @Test
+    fun minMaxFloatingPoint() {
+        val doubleZeroes = listOf(0.0, -0.0)
+        val floatZeroes = listOf(0.0F, -0.0F)
+        val doubleNaN = listOf(0.0, Double.NaN)
+        val floatNaN = listOf(0.0F, Float.NaN)
+
+        assertIsNegativeZero(doubleZeroes.shuffled().min())
+        assertIsNegativeZero(doubleZeroes.shuffled().minOrNull()!!)
+        assertIsNegativeZero(floatZeroes.shuffled().min().toDouble())
+        assertIsNegativeZero(floatZeroes.shuffled().minOrNull()!!.toDouble())
+        assertTrue(doubleNaN.shuffled().min().isNaN())
+        assertTrue(doubleNaN.shuffled().minOrNull()!!.isNaN())
+        assertTrue(floatNaN.shuffled().min().isNaN())
+        assertTrue(floatNaN.shuffled().minOrNull()!!.isNaN())
+
+        assertIsPositiveZero(doubleZeroes.shuffled().max())
+        assertIsPositiveZero(doubleZeroes.shuffled().maxOrNull()!!)
+        assertIsPositiveZero(floatZeroes.shuffled().max().toDouble())
+        assertIsPositiveZero(floatZeroes.shuffled().maxOrNull()!!.toDouble())
+        assertTrue(doubleNaN.shuffled().max().isNaN())
+        assertTrue(doubleNaN.shuffled().maxOrNull()!!.isNaN())
+        assertTrue(floatNaN.shuffled().max().isNaN())
+        assertTrue(floatNaN.shuffled().maxOrNull()!!.isNaN())
     }
 
-    @Test fun minByOrNull() {
-        expect(null, { listOf<Int>().minByOrNull { it } })
-        expect(1, { listOf(1).minByOrNull { it } })
-        expect(3, { listOf(2, 3).minByOrNull { -it } })
-        expect('a', { listOf('a', 'b').minByOrNull { "x$it" } })
-        expect("b", { listOf("b", "abc").minByOrNull { it.length } })
-        expect(null, { listOf<Int>().asSequence().minByOrNull { it } })
-        expect(3, { listOf(2, 3).asSequence().minByOrNull { -it } })
+    private fun <T> expectMinMaxWith(min: T, max: T, elements: Iterable<T>, comparator: Comparator<T>) {
+        assertEquals(min, elements.minWithOrNull(comparator))
+        assertEquals(max, elements.maxWithOrNull(comparator))
+        assertEquals(min, elements.minWith(comparator))
+        assertEquals(max, elements.maxWith(comparator))
     }
 
-    @Test fun maxByOrNull() {
-        expect(null, { listOf<Int>().maxByOrNull { it } })
-        expect(1, { listOf(1).maxByOrNull { it } })
-        expect(2, { listOf(2, 3).maxByOrNull { -it } })
-        expect('b', { listOf('a', 'b').maxByOrNull { "x$it" } })
-        expect("abc", { listOf("b", "abc").maxByOrNull { it.length } })
-        expect(null, { listOf<Int>().asSequence().maxByOrNull { it } })
-        expect(2, { listOf(2, 3).asSequence().maxByOrNull { -it } })
+    @Test
+    fun minMaxWith() {
+        expectMinMaxWith(1, 1, listOf(1), naturalOrder())
+        expectMinMaxWith("a", "B", listOf("a", "B"), String.CASE_INSENSITIVE_ORDER)
+    }
+
+    @Test
+    fun minMaxWithEmpty() {
+        val empty = emptyList<Int>()
+        assertNull(empty.minWithOrNull(naturalOrder()))
+        assertNull(empty.maxWithOrNull(naturalOrder()))
+        assertFailsWith<NoSuchElementException> { empty.minWith(naturalOrder()) }
+        assertFailsWith<NoSuchElementException> { empty.maxWith(naturalOrder()) }
+    }
+
+    private inline fun <T, K : Comparable<K>> expectMinMaxBy(min: T, max: T, elements: Iterable<T>, selector: (T) -> K) {
+        assertEquals(min, elements.minBy(selector))
+        assertEquals(min, elements.minByOrNull(selector))
+        assertEquals(max, elements.maxByOrNull(selector))
+        assertEquals(max, elements.maxByOrNull(selector))
+    }
+
+    @Test
+    fun minMaxBy() {
+        expectMinMaxBy(1, 1, listOf(1), { it })
+        expectMinMaxBy(3, 2, listOf(2, 3), { -it })
+        expectMinMaxBy('a', 'b', listOf('a', 'b'), { "x$it" })
+        expectMinMaxBy("b", "abc", listOf("abc", "b"), { it.length })
+    }
+
+    @Test
+    fun minMaxByEmpty() {
+        val empty = emptyList<Int>()
+        val selector = Int::toString
+        assertNull(empty.minByOrNull(selector))
+        assertNull(empty.maxByOrNull(selector))
+        assertFailsWith<NoSuchElementException> { empty.minBy(selector) }
+        assertFailsWith<NoSuchElementException> { empty.maxBy(selector) }
     }
 
     @Test fun minByOrNullEvaluateOnce() {
diff --git a/libraries/stdlib/test/collections/MinMaxOperations.kt b/libraries/stdlib/test/collections/MinMaxOperations.kt
new file mode 100644
index 0000000..875df43
--- /dev/null
+++ b/libraries/stdlib/test/collections/MinMaxOperations.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package test.collections
+
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+import kotlin.test.assertNull
+
+sealed class MinMaxOperations<C, T>(
+    val min: C.() -> T, val max: C.() -> T, val minOrNull: C.() -> T?, val maxOrNull: C.() -> T?,
+) {
+    object AInt : MinMaxOperations<IntArray, Int>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+    object ALong : MinMaxOperations<LongArray, Long>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+    object AShort : MinMaxOperations<ShortArray, Short>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+    object AByte : MinMaxOperations<ByteArray, Byte>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+    object AUInt : MinMaxOperations<UIntArray, UInt>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+    object AULong : MinMaxOperations<ULongArray, ULong>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+    object AUShort : MinMaxOperations<UShortArray, UShort>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+    object AUByte : MinMaxOperations<UByteArray, UByte>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+    object AFloat : MinMaxOperations<FloatArray, Float>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+    object ADouble : MinMaxOperations<DoubleArray, Double>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+    object AChar : MinMaxOperations<CharArray, Char>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+    class ArrayT<T : Comparable<T>> : MinMaxOperations<Array<T>, T>({ min() }, { max() }, { minOrNull() }, { maxOrNull() }) {
+        companion object {
+            fun <T : Comparable<T>> expectMinMax(min: T, max: T, elements: Array<T>) {
+                ArrayT<T>().expectMinMax(min, max, elements)
+            }
+        }
+    }
+    class IterableT<T : Comparable<T>> : MinMaxOperations<Iterable<T>, T>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+    class SequenceT<T : Comparable<T>> : MinMaxOperations<Sequence<T>, T>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+    object CharSeq : MinMaxOperations<CharSequence, Char>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+
+
+    fun expectMinMax(min: T, max: T, elements: C) {
+        assertEquals(min, elements.minOrNull())
+        assertEquals(max, elements.maxOrNull())
+        assertEquals(min, elements.min())
+        assertEquals(max, elements.max())
+    }
+
+    fun expectMinMaxEmpty(empty: C) {
+        assertNull(empty.minOrNull())
+        assertNull(empty.maxOrNull())
+        assertFailsWith<NoSuchElementException> { empty.min() }
+        assertFailsWith<NoSuchElementException> { empty.max() }
+    }
+}
+
+
+sealed class MinMaxOperationsWith<C, T>(
+    val minWith: C.(Comparator<T>) -> T, val maxWith: C.(Comparator<T>) -> T, val minWithOrNull: C.(Comparator<T>) -> T?, val maxWithOrNull: C.(Comparator<T>) -> T?,
+) {
+    object AInt : MinMaxOperationsWith<IntArray, Int>(IntArray::minWith, IntArray::maxWith, IntArray::minWithOrNull, IntArray::maxWithOrNull)
+    object ALong : MinMaxOperationsWith<LongArray, Long>(LongArray::minWith, LongArray::maxWith, LongArray::minWithOrNull, LongArray::maxWithOrNull)
+    object AShort : MinMaxOperationsWith<ShortArray, Short>(ShortArray::minWith, ShortArray::maxWith, ShortArray::minWithOrNull, ShortArray::maxWithOrNull)
+    object AByte : MinMaxOperationsWith<ByteArray, Byte>(ByteArray::minWith, ByteArray::maxWith, ByteArray::minWithOrNull, ByteArray::maxWithOrNull)
+    object AUInt : MinMaxOperationsWith<UIntArray, UInt>(UIntArray::minWith, UIntArray::maxWith, UIntArray::minWithOrNull, UIntArray::maxWithOrNull)
+    object AULong : MinMaxOperationsWith<ULongArray, ULong>(ULongArray::minWith, ULongArray::maxWith, ULongArray::minWithOrNull, ULongArray::maxWithOrNull)
+    object AUShort : MinMaxOperationsWith<UShortArray, UShort>(UShortArray::minWith, UShortArray::maxWith, UShortArray::minWithOrNull, UShortArray::maxWithOrNull)
+    object AUByte : MinMaxOperationsWith<UByteArray, UByte>(UByteArray::minWith, UByteArray::maxWith, UByteArray::minWithOrNull, UByteArray::maxWithOrNull)
+    object AFloat : MinMaxOperationsWith<FloatArray, Float>(FloatArray::minWith, FloatArray::maxWith, FloatArray::minWithOrNull, FloatArray::maxWithOrNull)
+    object ADouble : MinMaxOperationsWith<DoubleArray, Double>(DoubleArray::minWith, DoubleArray::maxWith, DoubleArray::minWithOrNull, DoubleArray::maxWithOrNull)
+    object AChar : MinMaxOperationsWith<CharArray, Char>(CharArray::minWith, CharArray::maxWith, CharArray::minWithOrNull, CharArray::maxWithOrNull)
+    class ArrayT<T> : MinMaxOperationsWith<Array<T>, T>(Array<T>::minWith, Array<T>::maxWith, Array<T>::minWithOrNull, Array<T>::maxWithOrNull) {
+        companion object {
+            fun <T> expectMinMaxWith(min: T, max: T, elements: Array<T>, comparator: Comparator<T>) {
+                ArrayT<T>().expectMinMaxWith(min, max, elements, comparator)
+            }
+        }
+    }
+//    class IterableT<T : Comparable<T>> : MinMaxOperationsWith<Iterable<T>, T>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+//    class SequenceT<T : Comparable<T>> : MinMaxOperationsWith<Sequence<T>, T>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+//    object CharSeq : MinMaxOperationsWith<CharSequence, Char>({ min() }, { max() }, { minOrNull() }, { maxOrNull() })
+
+
+    fun expectMinMaxWith(min: T, max: T, elements: C, comparator: Comparator<T>) {
+        assertEquals(min, elements.minWithOrNull(comparator))
+        assertEquals(max, elements.maxWithOrNull(comparator))
+        assertEquals(min, elements.minWith(comparator))
+        assertEquals(max, elements.maxWith(comparator))
+    }
+
+    fun expectMinMaxWithEmpty(empty: C, comparator: Comparator<T>) {
+        assertNull(empty.minWithOrNull(comparator))
+        assertNull(empty.maxWithOrNull(comparator))
+        assertFailsWith<NoSuchElementException> { empty.minWith(comparator) }
+        assertFailsWith<NoSuchElementException> { empty.maxWith(comparator) }
+    }
+}
+
+
diff --git a/libraries/stdlib/test/collections/SequenceTest.kt b/libraries/stdlib/test/collections/SequenceTest.kt
index 9ae24f5..4309204 100644
--- a/libraries/stdlib/test/collections/SequenceTest.kt
+++ b/libraries/stdlib/test/collections/SequenceTest.kt
@@ -5,6 +5,8 @@
 
 package test.collections
 
+import test.assertIsNegativeZero
+import test.assertIsPositiveZero
 import kotlin.random.Random
 import kotlin.test.*
 
@@ -633,6 +635,106 @@
         assertEquals(listOf('a', 'b', 'c'), chars)
     }
 
+    private fun <T : Comparable<T>> expectMinMax(min: T, max: T, elements: Sequence<T>) {
+        assertEquals(min, elements.minOrNull())
+        assertEquals(max, elements.maxOrNull())
+        assertEquals(min, elements.min())
+        assertEquals(max, elements.max())
+    }
+
+    @Test
+    fun minMax() {
+        expectMinMax(1, 1, sequenceOf(1))
+        expectMinMax(2, 3, sequenceOf(2, 3))
+        expectMinMax(2, 3, sequenceOf(3, 2))
+        expectMinMax(2000000000000, 3000000000000, sequenceOf(3000000000000, 2000000000000))
+        expectMinMax('a', 'b', sequenceOf('a', 'b'))
+        expectMinMax("a", "b", sequenceOf("a", "b"))
+    }
+
+    @Test
+    fun minMaxEmpty() {
+        val empty = emptySequence<Int>()
+        assertNull(empty.minOrNull())
+        assertNull(empty.maxOrNull())
+        assertFailsWith<NoSuchElementException> { empty.min() }
+        assertFailsWith<NoSuchElementException> { empty.max() }
+    }
+
+    @Test
+    fun minMaxFloatingPoint() {
+        val doubleZeroes = sequenceOf(0.0, -0.0)
+        val floatZeroes = sequenceOf(0.0F, -0.0F)
+        val doubleNaN = sequenceOf(0.0, Double.NaN)
+        val floatNaN = sequenceOf(0.0F, Float.NaN)
+
+        assertIsNegativeZero(doubleZeroes.shuffled().min())
+        assertIsNegativeZero(doubleZeroes.shuffled().minOrNull()!!)
+        assertIsNegativeZero(floatZeroes.shuffled().min().toDouble())
+        assertIsNegativeZero(floatZeroes.shuffled().minOrNull()!!.toDouble())
+        assertTrue(doubleNaN.shuffled().min().isNaN())
+        assertTrue(doubleNaN.shuffled().minOrNull()!!.isNaN())
+        assertTrue(floatNaN.shuffled().min().isNaN())
+        assertTrue(floatNaN.shuffled().minOrNull()!!.isNaN())
+
+        assertIsPositiveZero(doubleZeroes.shuffled().max())
+        assertIsPositiveZero(doubleZeroes.shuffled().maxOrNull()!!)
+        assertIsPositiveZero(floatZeroes.shuffled().max().toDouble())
+        assertIsPositiveZero(floatZeroes.shuffled().maxOrNull()!!.toDouble())
+        assertTrue(doubleNaN.shuffled().max().isNaN())
+        assertTrue(doubleNaN.shuffled().maxOrNull()!!.isNaN())
+        assertTrue(floatNaN.shuffled().max().isNaN())
+        assertTrue(floatNaN.shuffled().maxOrNull()!!.isNaN())
+    }
+
+    private fun <T> expectMinMaxWith(min: T, max: T, elements: Sequence<T>, comparator: Comparator<T>) {
+        assertEquals(min, elements.minWithOrNull(comparator))
+        assertEquals(max, elements.maxWithOrNull(comparator))
+        assertEquals(min, elements.minWith(comparator))
+        assertEquals(max, elements.maxWith(comparator))
+    }
+
+    @Test
+    fun minMaxWith() {
+        expectMinMaxWith(1, 1, sequenceOf(1), naturalOrder())
+        expectMinMaxWith("a", "B", sequenceOf("a", "B"), String.CASE_INSENSITIVE_ORDER)
+    }
+
+    @Test
+    fun minMaxWithEmpty() {
+        val empty = emptySequence<Int>()
+        assertNull(empty.minWithOrNull(naturalOrder()))
+        assertNull(empty.maxWithOrNull(naturalOrder()))
+        assertFailsWith<NoSuchElementException> { empty.minWith(naturalOrder()) }
+        assertFailsWith<NoSuchElementException> { empty.maxWith(naturalOrder()) }
+    }
+
+    private inline fun <T, K : Comparable<K>> expectMinMaxBy(min: T, max: T, elements: Sequence<T>, selector: (T) -> K) {
+        assertEquals(min, elements.minBy(selector))
+        assertEquals(min, elements.minByOrNull(selector))
+        assertEquals(max, elements.maxByOrNull(selector))
+        assertEquals(max, elements.maxByOrNull(selector))
+    }
+
+    @Test
+    fun minMaxBy() {
+        expectMinMaxBy(1, 1, sequenceOf(1), { it })
+        expectMinMaxBy(3, 2, sequenceOf(2, 3), { -it })
+        expectMinMaxBy('a', 'b', sequenceOf('a', 'b'), { "x$it" })
+        expectMinMaxBy("b", "abc", sequenceOf("abc", "b"), { it.length })
+    }
+    
+    @Test
+    fun minMaxByEmpty() {
+        val empty = emptySequence<Int>()
+        val selector = Int::toString
+        assertNull(empty.minByOrNull(selector))
+        assertNull(empty.maxByOrNull(selector))
+        assertFailsWith<NoSuchElementException> { empty.minBy(selector) }
+        assertFailsWith<NoSuchElementException> { empty.maxBy(selector) }
+    }
+
+
     @Test fun sorted() {
         sequenceOf(3, 7, 5).let {
             it.sorted().iterator().assertSorted { a, b -> a <= b }
diff --git a/libraries/stdlib/test/collections/UnsignedArraysTest.kt b/libraries/stdlib/test/collections/UnsignedArraysTest.kt
index a8f9231..fbc6b15 100644
--- a/libraries/stdlib/test/collections/UnsignedArraysTest.kt
+++ b/libraries/stdlib/test/collections/UnsignedArraysTest.kt
@@ -421,35 +421,38 @@
     }
 
     @Test
-    fun minOrNull() {
-        expect(null) { arrayOf<UByte>().minOrNull() }
-        expect(1u) { arrayOf<UShort>(1).minOrNull() }
-        expect(2u) { arrayOf<UInt>(2, 3).minOrNull() }
-        expect(2uL) { arrayOf<ULong>(3, 2).minOrNull() }
+    fun minMaxArrayOfUnsigned() = with(MinMaxOperations.ArrayT) {
+        expectMinMax(1u, 1u, arrayOf(1u))
+        expectMinMax(1u, UInt.MAX_VALUE, arrayOf(1u, UInt.MAX_VALUE))
+        expectMinMax(1uL, ULong.MAX_VALUE, arrayOf(1uL, ULong.MAX_VALUE))
     }
 
     @Test
-    fun minOrNullInUnsignedArrays() {
-        expect(null) { ubyteArrayOf().minOrNull() }
-        expect(1u) { ushortArrayOf(1).minOrNull() }
-        expect(2u) { uintArrayOf(2, 3).minOrNull() }
-        expect(2uL) { ulongArrayOf(3, 2).minOrNull() }
+    fun minMaxUIntArray() = with(MinMaxOperations.AUInt) {
+        expectMinMaxEmpty(uintArrayOf())
+        expectMinMax(1, 1, uintArrayOf(1))
+        expectMinMax(1, UInt.MAX_VALUE, uintArrayOf(1, UInt.MAX_VALUE))
     }
 
     @Test
-    fun maxOrNull() {
-        expect(null) { arrayOf<UByte>().maxOrNull() }
-        expect(1u) { arrayOf<UShort>(1).maxOrNull() }
-        expect(3u) { arrayOf<UInt>(2, 3).maxOrNull() }
-        expect(3uL) { arrayOf<ULong>(3, 2).maxOrNull() }
+    fun minMaxULongArray() = with(MinMaxOperations.AULong) {
+        expectMinMaxEmpty(ulongArrayOf())
+        expectMinMax(1, 1, ulongArrayOf(1))
+        expectMinMax(1, ULong.MAX_VALUE, ulongArrayOf(1, ULong.MAX_VALUE))
     }
 
     @Test
-    fun maxOrNullInUnsignedArrays() {
-        expect(null) { ubyteArrayOf().maxOrNull() }
-        expect(1u) { ushortArrayOf(1).maxOrNull() }
-        expect(3u) { uintArrayOf(2, 3).maxOrNull() }
-        expect(3uL) { ulongArrayOf(3, 2).maxOrNull() }
+    fun minMaxUShortArray() = with(MinMaxOperations.AUShort) {
+        expectMinMaxEmpty(ushortArrayOf())
+        expectMinMax(1, 1, ushortArrayOf(1))
+        expectMinMax(1, 2, ushortArrayOf(1, 2))
+    }
+
+    @Test
+    fun minMaxUByteArray() = with(MinMaxOperations.AUByte) {
+        expectMinMaxEmpty(ubyteArrayOf())
+        expectMinMax(1, 1, ubyteArrayOf(1))
+        expectMinMax(1, 2, ubyteArrayOf(1, 2))
     }
 
     @Test