diff --git a/stdlib/ktSrc/JavaUtil.kt b/stdlib/ktSrc/JavaUtil.kt index a75df8656d9..64e5bf117e8 100644 --- a/stdlib/ktSrc/JavaUtil.kt +++ b/stdlib/ktSrc/JavaUtil.kt @@ -2,8 +2,102 @@ namespace std.util import java.util.* +/** Returns the size of the collection */ val Collection<*>.size : Int get() = size() +/** Returns true if this collection is empty */ val Collection<*>.empty : Boolean get() = isEmpty() + +/** Returns a new ArrayList with a variable number of initial elements */ +fun arrayList(vararg values: T) : ArrayList { + val answer = ArrayList() + for (v in values) + answer.add(v) + return answer; +} + +/** Returns a new HashSet with a variable number of initial elements */ +fun hashSet(vararg values: T) : HashSet { + val answer = HashSet() + for (v in values) + answer.add(v) + return answer; +} + +/** Returns a new collection for the results of a helper method */ +protected fun java.lang.Iterable.create(defaultSize: Int? = null) : Collection { + if (defaultSize != null) { + return ArrayList(defaultSize) + } else { + return ArrayList() + } +} + +protected fun Set.create(defaultSize: Int? = null) : Set { + if (defaultSize != null) { + return HashSet(defaultSize) + } else { + return HashSet() + } +} + + + +/** Returns true if any elements in the collection match the given predicate */ +fun java.lang.Iterable.any(predicate: fun(T): Boolean) : Boolean { + for (elem in this) { + if (predicate(elem)) { + return true + } + } + return false +} + +/** Returns true if all elements in the collection match the given predicate */ +fun java.lang.Iterable.all(predicate: fun(T): Boolean) : Boolean { + for (elem in this) { + if (!predicate(elem)) { + return false + } + } + return true +} + +/** Returns the first item in the collection which matches the given predicate or null if none matched */ +fun java.lang.Iterable.find(predicate: fun(T): Boolean) : T? { + for (elem in this) { + if (predicate(elem)) + return elem + } + return null +} + +/** Returns a new collection containing all elements in this collection which match the given predicate */ +// TODO using: Collection for the return type - I wonder if this exact type could be +// deduced somewhat from the This.Type; e.g. returning Set on a Set, Array on Array etc +fun java.lang.Iterable.filter(predicate: fun(T): Boolean) : Collection { + val result = this.create() + for (elem in this) { + if (predicate(elem)) + result.add(elem) + } + return result +} + +/** Returns a new collection containing the results of applying the given function to each element in this collection */ +fun java.lang.Iterable.map(transform : fun(T) : R) : Collection { + val result = this.create() + for (item in this) + result.add(transform(item)) + return result +} + +/** Returns a new collection containing the results of applying the given function to each element in this collection */ +fun java.util.Collection.map(transform : fun(T) : R) : Collection { + val result = this.create(this.size) + for (item in this) + result.add(transform(item)) + return result +} \ No newline at end of file diff --git a/stdlib/ktSrc/Test.kt b/stdlib/ktSrc/Test.kt new file mode 100644 index 00000000000..e30921ff75a --- /dev/null +++ b/stdlib/ktSrc/Test.kt @@ -0,0 +1,69 @@ +namespace std.test + +import std.io.* +import std.util.* +import java.util.* + +import org.junit.* +import org.junit.runner.* +import org.junit.runner.notification.* +import junit.framework.* + +fun assert(message: String, block: fun() : Boolean) { + val actual = block() + Assert.assertTrue(message, actual) +} + +fun assert(block: fun() : Boolean) = assert(block.toString(), block) + +fun assertNot(message: String, block: fun() : Boolean) { + assert(message){ !block() } +} + +fun assertNot(block: fun() : Boolean) = assertNot(block.toString(), block) + +fun assert(actual: Boolean, message: String) { + println("Answer: ${actual} for ${message}") +} + +fun assertEquals(expected: Any, actual: Any?, message: String = "") { + Assert.assertEquals(message, expected, actual) +} + +fun assertNull(actual: Any?, message: String = "") { + Assert.assertNull(message, actual) +} + +fun fails(block: fun() : Any) { + try { + block() + Assert.fail("Expected an exception to be thrown") + } catch (e: Exception) { + // OK + } +} + +fun todo(block: fun(): Any) { + // Ignore the code :) +} + +/* +TODO we could maybe create our own test runner for JUnit +to avoid a runtime dependency on JUnit for running tests? + +class KotlinTestRunner() : Runner() { + + override fun getDescription(): Description? { + return null + } + + override fun run(notifier: RunNotifier?) { + println("About to run a test case on ${this}") + } +} +*/ + +// TODO no annotations yet? +//@RunWith(KotlinTestRunner) +abstract class TestSupport() : TestCase() { +} \ No newline at end of file diff --git a/stdlib/lib/junit-4.9.jar b/stdlib/lib/junit-4.9.jar new file mode 100644 index 00000000000..14208156115 Binary files /dev/null and b/stdlib/lib/junit-4.9.jar differ diff --git a/stdlib/test/CollectionTest.kt b/stdlib/test/CollectionTest.kt new file mode 100644 index 00000000000..9b42f50bf76 --- /dev/null +++ b/stdlib/test/CollectionTest.kt @@ -0,0 +1,68 @@ +namespace test.collections + +import std.test.* + +// TODO can we avoid importing all this stuff by default I wonder? +// e.g. making println and the collection builder methods public by default? +import std.io.* +import std.util.* +import java.util.* + +class CollectionTest() : TestSupport() { + val data = arrayList("foo", "bar") + + fun testAny() { + assert { + data.any{it.startsWith("f")} + } + assertNot { + data.any{it.startsWith("x")} + } + } + + fun testAll() { + assert { + data.all{it.length == 3} + } + assertNot { + data.all{s => s.startsWith("b")} + } + } + + fun testFilter() { + val foo = data.filter{it.startsWith("f")} + + assert { + foo.all{it.startsWith("f")} + } + assertEquals(1, foo.size) + assertEquals(arrayList("foo"), foo) + } + + fun testFind() { + val x = data.find{it.startsWith("x")} + assertNull(x) + fails { + x.sure() + } + + val f = data.find{it.startsWith("f")} + f.sure() + assertEquals("foo", f) + } + + fun testMap() { + /** + TODO compiler bug + we should be able to remove the explicit type on the function + http://youtrack.jetbrains.net/issue/KT-849 + */ + val lengths = data.map{s => s.length} + assert { + lengths.all{it == 3} + } + assertEquals(2, lengths.size) + assertEquals(arrayList(3, 3), lengths) + } + +} \ No newline at end of file diff --git a/stdlib/test/SetTest.kt b/stdlib/test/SetTest.kt new file mode 100644 index 00000000000..cdc8f12d586 --- /dev/null +++ b/stdlib/test/SetTest.kt @@ -0,0 +1,72 @@ +namespace test.collections + +import std.io.* +import std.util.* +import std.test.* +import java.util.* + +class SetTest() : TestSupport() { + val data = hashSet("foo", "bar") + + fun testAny() { + assert { + data.any{it.startsWith("f")} + } + assertNot { + data.any{it.startsWith("x")} + } + } + + fun testAll() { + assert { + data.all{it.length == 3} + } + assertNot { + data.all{s => s.startsWith("b")} + } + } + + fun testFilter() { + val foo = data.filter{it.startsWith("f")} + + assert { + foo.all{it.startsWith("f")} + } + assertEquals(1, foo.size) + assertEquals(arrayList("foo"), foo) + + // TODO ideally foo would now be a set + todo { + assert("Filter on a Set should return a Set") { + foo is Set + } + } + } + + fun testFind() { + val x = data.find{it.startsWith("x")} + assertNull(x) + fails { + x.sure() + } + + val f = data.find{it.startsWith("f")} + f.sure() + assertEquals("foo", f) + } + + fun testMap() { + /** + TODO compiler bug + we should be able to remove the explicit type on the function + http://youtrack.jetbrains.net/issue/KT-849 + */ + val lengths = data.map{s => s.length} + assert { + lengths.all{it == 3} + } + assertEquals(2, lengths.size) + assertEquals(arrayList(3, 3), lengths) + } + +} \ No newline at end of file