[JS TESTS] Rewrite web demo tests using new test infrastructure

This commit is contained in:
Ivan Kylchik
2021-10-20 22:15:16 +03:00
parent af0e40a0d2
commit 8a1362de03
45 changed files with 369 additions and 579 deletions
+77
View File
@@ -0,0 +1,77 @@
// MAIN_ARGS: [2]
/**
* This example implements the famous "99 Bottles of Beer" program
* See http://99-bottles-of-beer.net/
*
* The point is to print out a song with the following lyrics:
*
* The "99 bottles of beer" song
*
* 99 bottles of beer on the wall, 99 bottles of beer.
* Take one down, pass it around, 98 bottles of beer on the wall.
*
* 98 bottles of beer on the wall, 98 bottles of beer.
* Take one down, pass it around, 97 bottles of beer on the wall.
*
* ...
*
* 2 bottles of beer on the wall, 2 bottles of beer.
* Take one down, pass it around, 1 bottle of beer on the wall.
*
* 1 bottle of beer on the wall, 1 bottle of beer.
* Take one down, pass it around, no more bottles of beer on the wall.
*
* No more bottles of beer on the wall, no more bottles of beer.
* Go to the store and buy some more, 99 bottles of beer on the wall.
*
* Additionally, you can pass the desired initial number of bottles to use (rather than 99)
* as a command-line argument
*/
fun main(args: Array<String>) {
if (args.isEmpty()) {
printBottles(99)
}
else {
val bottles = args[0].toIntOrNull()
if (bottles != null) {
printBottles(bottles);
}
else {
println("You have passed '${args[0]}' as a number of bottles, " +
"but it is not a valid integral number")
}
}
}
fun printBottles(bottleCount: Int) {
if (bottleCount <= 0) {
println("No bottles - no song")
return
}
println("The \"${bottlesOfBeer(bottleCount)}\" song\n")
var bottles = bottleCount
while (bottles > 0) {
val bottlesOfBeer = bottlesOfBeer(bottles)
print("$bottlesOfBeer on the wall, $bottlesOfBeer.\nTake one down, pass it around, ")
bottles--
println("${bottlesOfBeer(bottles)} on the wall.\n")
}
println("No more bottles of beer on the wall, no more bottles of beer.\n" +
"Go to the store and buy some more, ${bottlesOfBeer(bottleCount)} on the wall.")
}
fun bottlesOfBeer(count: Int): String =
when (count) {
0 -> "no more bottles"
1 -> "1 bottle"
else -> "$count bottles"
} + " of beer"
// From the std package
// This is an extension property, i.e. a property that is defined for the
// type Array<T>, but does not sit inside the class Array
fun <T> Array<T>.isEmpty() = size == 0
+10
View File
@@ -0,0 +1,10 @@
The "2 bottles of beer" song
2 bottles of beer on the wall, 2 bottles of beer.
Take one down, pass it around, 1 bottle of beer on the wall.
1 bottle of beer on the wall, 1 bottle of beer.
Take one down, pass it around, no more bottles of beer on the wall.
No more bottles of beer on the wall, no more bottles of beer.
Go to the store and buy some more, 2 bottles of beer on the wall.
+142
View File
@@ -0,0 +1,142 @@
// MAIN_ARGS: [over9000]
/**
* This is an example of a Type-Safe Groovy-style Builder
*
* Builders are good for declaratively describing data in your code.
* In this example we show how to describe an HTML page in Kotlin.
*
* See this page for details:
* https://confluence.jetbrains.net/display/Kotlin/Type-safe+Groovy-style+builders
*/
fun main(args: Array<String>) {
val result =
html {
head {
title { +"XML encoding with Kotlin" }
}
body {
h1 { +"XML encoding with Kotlin" }
p { +"this format can be used as an alternative markup to XML" }
// an element with attributes and text content
a(href = "https://jetbrains.com/kotlin") { +"Kotlin" }
// mixed content
p {
+"This is some"
b { +"mixed" }
+"text. For more see the"
a(href = "https://jetbrains.com/kotlin") { +"Kotlin" }
+"project"
}
p { +"some text" }
// content generated from command-line arguments
p {
+"Command line arguments were:"
ul {
for (arg in args)
li { +arg }
}
}
}
}
println(result)
}
abstract class Element {
abstract fun render(builder: StringBuilder, indent: String)
override fun toString(): String {
val builder = StringBuilder()
render(builder, "")
return builder.toString()
}
}
class TextElement(val text: String) : Element() {
override fun render(builder: StringBuilder, indent: String) {
builder.append("$indent$text\n")
}
}
abstract class Tag(val name: String) : Element() {
val children = ArrayList<Element>()
val attributes = HashMap<String, String>()
protected fun <T : Element> initTag(tag: T, init: T.() -> Unit): T {
tag.init()
children.add(tag)
return tag
}
override fun render(builder: StringBuilder, indent: String) {
builder.append("$indent<$name${renderAttributes()}>\n")
for (c in children) {
c.render(builder, indent + " ")
}
builder.append("$indent</$name>\n")
}
private fun renderAttributes(): String? {
val builder = StringBuilder()
for (a in attributes.keys) {
builder.append(" $a=\"${attributes[a]}\"")
}
return builder.toString()
}
}
abstract class TagWithText(name: String) : Tag(name) {
operator fun String.unaryPlus() {
children.add(TextElement(this))
}
}
class HTML() : TagWithText("html") {
fun head(init: Head.() -> Unit) = initTag(Head(), init)
fun body(init: Body.() -> Unit) = initTag(Body(), init)
}
class Head() : TagWithText("head") {
fun title(init: Title.() -> Unit) = initTag(Title(), init)
}
class Title() : TagWithText("title")
abstract class BodyTag(name: String) : TagWithText(name) {
fun b(init: B.() -> Unit) = initTag(B(), init)
fun p(init: P.() -> Unit) = initTag(P(), init)
fun h1(init: H1.() -> Unit) = initTag(H1(), init)
fun ul(init: UL.() -> Unit) = initTag(UL(), init)
fun a(href: String, init: A.() -> Unit) {
val a = initTag(A(), init)
a.href = href
}
}
class Body() : BodyTag("body")
class UL() : BodyTag("ul") {
fun li(init: LI.() -> Unit) = initTag(LI(), init)
}
class B() : BodyTag("b")
class LI() : BodyTag("li")
class P() : BodyTag("p")
class H1() : BodyTag("h1")
class A() : BodyTag("a") {
public var href: String
get() = attributes["href"]!!
set(value) {
attributes["href"] = value
}
}
fun html(init: HTML.() -> Unit): HTML {
val html = HTML()
html.init()
return html
}
+41
View File
@@ -0,0 +1,41 @@
<html>
<head>
<title>
XML encoding with Kotlin
</title>
</head>
<body>
<h1>
XML encoding with Kotlin
</h1>
<p>
this format can be used as an alternative markup to XML
</p>
<a href="https://jetbrains.com/kotlin">
Kotlin
</a>
<p>
This is some
<b>
mixed
</b>
text. For more see the
<a href="https://jetbrains.com/kotlin">
Kotlin
</a>
project
</p>
<p>
some text
</p>
<p>
Command line arguments were:
<ul>
<li>
over9000
</li>
</ul>
</p>
</body>
</html>
+11
View File
@@ -0,0 +1,11 @@
// MAIN_ARGS: [a,b,c]
fun main(args: Array<String>) {
for (arg in args)
println(arg)
// or
println()
for (i in args.indices)
println(args[i])
}
@@ -0,0 +1,7 @@
a
b
c
a
b
c
+11
View File
@@ -0,0 +1,11 @@
// MAIN_ARGS: [123]
fun main(args: Array<String>) {
for (arg in args)
println(arg)
// or
println()
for (i in args.indices)
println(args[i])
}
@@ -0,0 +1,3 @@
123
123
@@ -0,0 +1,5 @@
// MAIN_ARGS: [10,20]
fun main(args: Array<String>) {
println(maxOf(args[0].toInt(), args[1].toInt()))
}
@@ -0,0 +1 @@
20
+12
View File
@@ -0,0 +1,12 @@
// MAIN_ARGS: []
fun main(args: Array<String>) {
println(getStringLength("aaa"))
println(getStringLength(1))
}
fun getStringLength(obj: Any): Int? {
if (obj is String)
return obj.length // no cast to String is needed
return null
}
+2
View File
@@ -0,0 +1,2 @@
3
null
+143
View File
@@ -0,0 +1,143 @@
// MAIN_ARGS: [2]
/**
* This is a straightforward implementation of The Game of Life
* See http://en.wikipedia.org/wiki/Conway's_Game_of_Life
*/
/*
* A field where cells live. Effectively immutable
*/
class Field(
val width: Int,
val height: Int,
// This function tells the constructor which cells are alive
// if init(i, j) is true, the cell (i, j) is alive
init: (Int, Int) -> Boolean
) {
private val live: Array<Array<Boolean>> = Array(height) { i -> Array(width) { j -> init(i, j) } }
private fun liveCount(i: Int, j: Int)
= if (i in 0..height - 1 &&
j in 0..width - 1 &&
live[i][j]) 1
else 0
// How many neighbors of (i, j) are alive?
fun liveNeighbors(i: Int, j: Int) =
liveCount(i - 1, j - 1) +
liveCount(i - 1, j) +
liveCount(i - 1, j + 1) +
liveCount(i, j - 1) +
liveCount(i, j + 1) +
liveCount(i + 1, j - 1) +
liveCount(i + 1, j) +
liveCount(i + 1, j + 1)
// You can say field[i, j], and this function gets called
operator fun get(i: Int, j: Int) = live[i][j]
}
/**
* This function takes the present state of the field
* and return a new field representing the next moment of time
*/
fun next(field: Field): Field {
return Field(field.width, field.height) { i, j ->
val n = field.liveNeighbors(i, j)
if (field[i, j])
// (i, j) is alive
n in 2..3 // It remains alive iff it has 2 or 3 neighbors
else
// (i, j) is dead
n == 3 // A new cell is born if there are 3 neighbors alive
}
}
/** A few colony examples here */
fun main(args: Array<String>) {
// Simplistic demo
printField("***", 3)
// "Star burst"
printField("""
__*__
_***_
__*__
""", 10)
// Stable colony
printField("""
__*__
_*_*_
__*__
""", 3)
// Stable from the step 2
printField("""
__**__
__**__
__**__
""", 3)
// Oscillating colony
printField("""
__**__
__**__
__**__
__**__
""", 6)
// A fancier oscillating colony
printField("""
---------------
---***---***---
---------------
-*----*-*----*-
-*----*-*----*-
-*----*-*----*-
---***---***---
---------------
---***---***---
-*----*-*----*-
-*----*-*----*-
-*----*-*----*-
---------------
---***---***---
---------------
""", 10)
}
// UTILITIES
fun printField(s: String, steps: Int) {
var field = makeField(s)
for (step in 1..steps) {
println("Step: $step")
for (i in 0..field.height - 1) {
for (j in 0..field.width - 1) {
print(if (field[i, j]) "*" else " ")
}
println("")
}
field = next(field)
}
}
fun makeField(s: String): Field {
val lines: List<String> = s.split("\n")
val w = lines.maxOf { it.length }
val data = Array(lines.size) { Array(w) { false } }
// workaround
for (i in data.indices) {
data[i] = Array(w) { false }
for (j in data[i].indices)
data[i][j] = false
}
for (line in lines.indices) {
for (x in lines[line].indices) {
val c = lines[line][x]
data[line][x] = c == '*'
}
}
return Field(w, lines.size) { i, j -> data[i][j] }
}
+324
View File
@@ -0,0 +1,324 @@
Step: 1
***
Step: 2
*
Step: 3
Step: 1
*
***
*
Step: 2
***
* *
***
Step: 3
*
* *
* *
* *
*
Step: 4
*
***
** **
***
*
Step: 5
***
* *
* *
* *
***
Step: 6
***
* * *
*** **
* * *
***
Step: 7
***
* *
* *
* *
***
Step: 8
**
* * *
*** **
* * *
**
Step: 9
***
* * *
* * *
* * *
***
Step: 10
***
* *
** * *
* *
***
Step: 1
*
* *
*
Step: 2
*
* *
*
Step: 3
*
* *
*
Step: 1
**
**
**
Step: 2
**
* *
**
Step: 3
**
* *
**
Step: 1
**
**
**
**
Step: 2
**
*
*
**
Step: 3
**
**
**
**
Step: 4
**
*
*
**
Step: 5
**
**
**
**
Step: 6
**
*
*
**
Step: 1
*** ***
* * * *
* * * *
* * * *
*** ***
*** ***
* * * *
* * * *
* * * *
*** ***
Step: 2
* *
* *
** **
*** ** ** ***
* * * * * *
** **
** **
* * * * * *
*** ** ** ***
** **
* *
* *
Step: 3
** **
** **
* * * * * *
*** ** ** ***
* * * * * *
*** ***
*** ***
* * * * * *
*** ** ** ***
* * * * * *
** **
** **
Step: 4
*** ***
* * * *
* * * *
* * * *
*** ***
*** ***
* * * *
* * * *
* * * *
*** ***
Step: 5
* *
* *
** **
*** ** ** ***
* * * * * *
** **
** **
* * * * * *
*** ** ** ***
** **
* *
* *
Step: 6
** **
** **
* * * * * *
*** ** ** ***
* * * * * *
*** ***
*** ***
* * * * * *
*** ** ** ***
* * * * * *
** **
** **
Step: 7
*** ***
* * * *
* * * *
* * * *
*** ***
*** ***
* * * *
* * * *
* * * *
*** ***
Step: 8
* *
* *
** **
*** ** ** ***
* * * * * *
** **
** **
* * * * * *
*** ** ** ***
** **
* *
* *
Step: 9
** **
** **
* * * * * *
*** ** ** ***
* * * * * *
*** ***
*** ***
* * * * * *
*** ** ** ***
* * * * * *
** **
** **
Step: 10
*** ***
* * * *
* * * *
* * * *
*** ***
*** ***
* * * *
* * * *
* * * *
*** ***
+215
View File
@@ -0,0 +1,215 @@
// MAIN_ARGS: []
/**
* Let's Walk Through a Maze.
*
* Imagine there is a maze whose walls are the big 'O' letters.
* Now, I stand where a big 'I' stands and some cool prize lies
* somewhere marked with a '$' sign. Like this:
*
* OOOOOOOOOOOOOOOOO
* O O
* O$ O O
* OOOOO O
* O O
* O OOOOOOOOOOOOOO
* O O I O
* O O
* OOOOOOOOOOOOOOOOO
*
* I want to get the prize, and this program helps me do so as soon
* as I possibly can by finding a shortest path through the maze.
*/
fun <E> MutableList<E>.offer(element: E) = this.add(element)
fun <E> MutableList<E>.poll() = this.removeAt(0)
/**
* This function looks for a path from max.start to maze.end through
* free space (a path does not go through walls). One can move only
* straightly up, down, left or right, no diagonal moves allowed.
*/
fun findPath(maze: Maze): List<Pair<Int, Int>>? {
val previous = HashMap<Pair<Int, Int>, Pair<Int, Int>>()
val queue = ArrayDeque<Pair<Int, Int>>()
val visited = HashSet<Pair<Int, Int>>()
queue.offer(maze.start)
visited.add(maze.start)
while (!queue.isEmpty()) {
val cell = queue.poll()
if (cell == maze.end) break
for (newCell in maze.neighbors(cell.first, cell.second)) {
if (newCell in visited) continue
previous[newCell] = cell
queue.offer(newCell)
visited.add(cell)
}
}
if (previous[maze.end] == null) return null
val path = ArrayList<Pair<Int, Int>>()
var current = previous[maze.end]
while (current != maze.start) {
path.add(0, current!!)
current = previous[current]
}
return path
}
/**
* Find neighbors of the (i, j) cell that are not walls
*/
fun Maze.neighbors(i: Int, j: Int): List<Pair<Int, Int>> {
val result = ArrayList<Pair<Int, Int>>()
addIfFree(i - 1, j, result)
addIfFree(i, j - 1, result)
addIfFree(i + 1, j, result)
addIfFree(i, j + 1, result)
return result
}
fun Maze.addIfFree(i: Int, j: Int, result: MutableList<Pair<Int, Int>>) {
if (i !in 0..height - 1) return
if (j !in 0..width - 1) return
if (walls[i][j]) return
result.add(Pair(i, j))
}
/**
* A data class that represents a maze
*/
class Maze(
// Number or columns
val width: Int,
// Number of rows
val height: Int,
// true for a wall, false for free space
val walls: Array<out Array<out Boolean>>,
// The starting point (must not be a wall)
val start: Pair<Int, Int>,
// The target point (must not be a wall)
val end: Pair<Int, Int>
) {
}
/** A few maze examples here */
fun main(args: Array<String>) {
printMaze("I $")
printMaze("I O $")
printMaze("""
O $
O
O
O
O I
""".trimIndent())
printMaze("""
OOOOOOOOOOO
O $ O
OOOOOOO OOO
O O
OOOOO OOOOO
O O
O OOOOOOOOO
O OO
OOOOOO IO
""".trimIndent())
printMaze("""
OOOOOOOOOOOOOOOOO
O O
O$ O O
OOOOO O
O O
O OOOOOOOOOOOOOO
O O I O
O O
OOOOOOOOOOOOOOOOO
""".trimIndent())
}
// UTILITIES
fun printMaze(str: String) {
val maze = makeMaze(str)
println("Maze:")
val path = findPath(maze)
for (i in 0..maze.height - 1) {
for (j in 0..maze.width - 1) {
val cell = Pair(i, j)
print(
if (maze.walls[i][j]) "O"
else if (cell == maze.start) "I"
else if (cell == maze.end) "$"
else if (path != null && path.contains(cell)) "~"
else " "
)
}
println("")
}
println("Result: " + if (path == null) "No path" else "Path found")
println("")
}
/**
* A maze is encoded in the string s: the big 'O' letters are walls.
* I stand where a big 'I' stands and the prize is marked with
* a '$' sign.
*
* Example:
*
* OOOOOOOOOOOOOOOOO
* O O
* O$ O O
* OOOOO O
* O O
* O OOOOOOOOOOOOOO
* O O I O
* O O
* OOOOOOOOOOOOOOOOO
*/
fun makeMaze(s: String): Maze {
val lines = s.split("\n")!!
val w = lines.maxWithOrNull(Comparator { o1, o2 ->
val l1: Int = o1?.length ?: 0
val l2 = o2?.length ?: 0
l1 - l2
})!!
val data = Array<Array<Boolean>>(lines.size) { Array<Boolean>(w.length) { false } }
var start: Pair<Int, Int>? = null
var end: Pair<Int, Int>? = null
for (line in lines.indices) {
for (x in lines[line].indices) {
val c = lines[line]!![x]
data[line][x] = c == 'O'
when (c) {
'I' -> start = Pair(line, x)
'$' -> end = Pair(line, x)
else -> {
}
}
}
}
if (start == null) {
throw IllegalArgumentException("No starting point in the maze (should be indicated with 'I')")
}
if (end == null) {
throw IllegalArgumentException("No goal point in the maze (should be indicated with a '$' sign)")
}
return Maze(w.length, lines.size, data, start!!, end!!)
}
// An excerpt from the Standard Library
val String?.indices: IntRange get() = IntRange(0, this!!.length)
+40
View File
@@ -0,0 +1,40 @@
Maze:
I~~$
Result: Path found
Maze:
I O $
Result: No path
Maze:
O $
O ~
O ~
O ~
O ~~~~~~~~~I
Result: Path found
Maze:
OOOOOOOOOOO
O $~~~~~ O
OOOOOOO~OOO
O ~~~ O
OOOOO~OOOOO
O~~~~~ O
O~OOOOOOOOO
O~~~~~~ OO
OOOOOO~~~IO
Result: Path found
Maze:
OOOOOOOOOOOOOOOOO
O ~~~ O
O$~~O~ O
OOOOO~ O
O ~~~~ O
O ~OOOOOOOOOOOOOO
O ~ O I O
O ~~~~~~~~~~~~~ O
OOOOOOOOOOOOOOOOO
Result: Path found
@@ -0,0 +1,11 @@
// MAIN_ARGS: [FR]
fun main(args: Array<String>) {
val language = if (args.size == 0) "EN" else args[0]
println(when (language) {
"EN" -> "Hello!"
"FR" -> "Salut!"
"IT" -> "Ciao!"
else -> "Sorry, I can't greet you in $language yet"
})
}
@@ -0,0 +1 @@
Salut!
@@ -0,0 +1,21 @@
// MAIN_ARGS: []
// Return null if str does not hold a number
fun myParseInt(str: String): Int? = str.toIntOrNull().also {
if (it == null) println("One of arguments isn't Int")
}
fun main(args: Array<String>) {
if (args.size < 2) {
print("No number supplied");
}
else {
val x = myParseInt(args[0])
val y = myParseInt(args[1])
// We cannot say 'x * y' now because they may hold nulls
if (x != null && y != null) {
print(x * y) // Now we can
}
}
}
@@ -0,0 +1 @@
No number supplied
@@ -0,0 +1,21 @@
// MAIN_ARGS: [2,3]
// Return null if str does not hold a number
fun myParseInt(str: String): Int? = str.toIntOrNull().also {
if (it == null) println("One of arguments isn't Int")
}
fun main(args: Array<String>) {
if (args.size < 2) {
print("No number supplied");
}
else {
val x = myParseInt(args[0])
val y = myParseInt(args[1])
// We cannot say 'x * y' now because they may hold nulls
if (x != null && y != null) {
print(x * y) // Now we can
}
}
}
@@ -0,0 +1 @@
6
@@ -0,0 +1,12 @@
// MAIN_ARGS: [Pavel]
class Greeter(name: String) {
val name = name
fun greet() {
println("Hello, ${name}!");
}
}
fun main(args: Array<String>) {
Greeter(args[0]).greet()
}
@@ -0,0 +1 @@
Hello, Pavel!
@@ -0,0 +1,20 @@
// MAIN_ARGS: []
fun main(args: Array<String>) {
cases("Hello")
cases(1)
cases(MyClass())
cases("hello")
}
fun cases(obj: Any) {
when(obj) {
1 -> println("One")
"Hello" -> println("Greeting")
!is String -> println("Not a string")
else -> println("Unknown")
}
}
class MyClass() {
}
@@ -0,0 +1,4 @@
Greeting
One
Not a string
Unknown
+5
View File
@@ -0,0 +1,5 @@
// MAIN_ARGS: [Hello_world!]
fun main(args: Array<String>) {
print(args[0]);
}
@@ -0,0 +1 @@
Hello_world!
+35
View File
@@ -0,0 +1,35 @@
// MAIN_ARGS: [4]
fun main(args: Array<String>) {
val x = args[0].toInt()
//Check if a number lies within a range:
val y = 10
if (x in 1..y - 1)
println("OK")
//Iterate over a range:
for (a in 1..5)
print(" ${a}")
//Check if a number is out of range:
println()
val array = mutableListOf<String>()
array.add("aaa")
array.add("bbb")
array.add("ccc")
if (x !in 0..array.size)
println("Out: array has only ${array.size} elements. x = ${x}")
//Check if a collection contains an object:
if ("aaa" in array) // collection.contains(obj) is called
println("Yes: array contains aaa")
if ("ddd" in array) // collection.contains(obj) is called
println("Yes: array contains ddd")
else
println("No: array doesn't contains ddd")
}
+5
View File
@@ -0,0 +1,5 @@
OK
1 2 3 4 5
Out: array has only 3 elements. x = 4
Yes: array contains aaa
No: array doesn't contains ddd
+35
View File
@@ -0,0 +1,35 @@
// MAIN_ARGS: [10]
fun main(args: Array<String>) {
val x = args[0].toInt()
//Check if a number lies within a range:
val y = 10
if (x in 1..y - 1)
println("OK")
//Iterate over a range:
for (a in 1..5)
print(" ${a}")
//Check if a number is out of range:
println()
val array = mutableListOf<String>()
array.add("aaa")
array.add("bbb")
array.add("ccc")
if (x !in 0..array.size)
println("Out: array has only ${array.size} elements. x = ${x}")
//Check if a collection contains an object:
if ("aaa" in array) // collection.contains(obj) is called
println("Yes: array contains aaa")
if ("ddd" in array) // collection.contains(obj) is called
println("Yes: array contains ddd")
else
println("No: array doesn't contains ddd")
}
+4
View File
@@ -0,0 +1,4 @@
1 2 3 4 5
Out: array has only 3 elements. x = 10
Yes: array contains aaa
No: array doesn't contains ddd
@@ -0,0 +1,7 @@
// MAIN_ARGS: [guest1,guest2,guest3,guest4]
fun main(args: Array<String>) {
var i = 0
while (i < args.size)
println(args[i++])
}
@@ -0,0 +1,4 @@
guest1
guest2
guest3
guest4