├── .EditorConfig
├── .gitignore
├── AccessList.yaml
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── pom.xml
├── settings.gradle
└── src
├── main
└── java
│ ├── Basics.kt
│ ├── MessageService.kt
│ ├── Test.kt
│ ├── basics
│ ├── API.kt
│ ├── Color.kt
│ ├── Factorial.kt
│ ├── Person.kt
│ ├── Pizza.kt
│ ├── Tree.kt
│ ├── TreeOperations.kt
│ └── Weather.java
│ ├── collections
│ ├── BestStudents.kt
│ ├── Collections.kt
│ ├── PassingStudents.kt
│ ├── PlusAt.kt
│ ├── PrimeAccessList.kt
│ ├── QuickSort.kt
│ ├── Student.kt
│ └── YamlReader.kt
│ ├── corotuines
│ ├── Downloader.kt
│ ├── Fibonacci.kt
│ ├── FlowKata.kt
│ ├── Main.kt
│ ├── Sieve.kt
│ ├── Structured.kt
│ ├── backend
│ │ ├── Api.kt
│ │ ├── ApiDsl.kt
│ │ ├── Database.kt
│ │ └── EmailService.kt
│ ├── continuation
│ │ └── ContinuationSteal.kt
│ ├── examples
│ │ ├── 1.kt
│ │ ├── 10.kt
│ │ ├── 11.kt
│ │ ├── 12.kt
│ │ ├── 13.kt
│ │ ├── 14.kt
│ │ ├── 15.kt
│ │ ├── 2.kt
│ │ ├── 3.kt
│ │ ├── 4.kt
│ │ ├── 5.kt
│ │ ├── 6.kt
│ │ ├── 7.kt
│ │ ├── 8.kt
│ │ ├── 9.kt
│ │ ├── Delay.kt
│ │ ├── Massive.kt
│ │ ├── Numbers.kt
│ │ ├── s1.kt
│ │ ├── s2.kt
│ │ ├── s3.kt
│ │ └── s4.kt
│ ├── request
│ │ └── Request.kt
│ └── ui
│ │ ├── BasePresenter.kt
│ │ └── MainPresenter.kt
│ ├── delegates
│ └── MutableLazy.kt
│ ├── dsl
│ ├── Announcements.kt
│ ├── TableDSL.kt
│ └── UsersTable.kt
│ ├── extra
│ ├── Permutations.kt
│ └── Powerset.kt
│ ├── functional
│ ├── Callbacks.kt
│ ├── Functional.kt
│ ├── Product.kt
│ ├── Rational.kt
│ ├── References.kt
│ ├── Repeat.kt
│ └── UserDocument.kt
│ ├── generics
│ ├── Consumer.kt
│ ├── Generics.kt
│ └── Response.kt
│ ├── javatask
│ ├── JavaClass.java
│ ├── JavaPerson.java
│ ├── KotlinClass.kt
│ ├── KotlinPerson.kt
│ └── TopLevel.kt
│ ├── nullability
│ ├── MessageUtil.java
│ └── Task.kt
│ ├── operators
│ └── Money.kt
│ └── types
│ ├── Relations.kt
│ └── Types.kt
└── test
└── java
├── BasicsTest.kt
├── SendMessageTest.kt
├── Test.kt
├── Utils.kt
├── basics
├── APITest.kt
├── FactorialTest.kt
├── PersonTest.kt
└── TreeOperationsTest.kt
├── collections
├── BestStudentsListTest.kt
├── MapTest.kt
├── PassingStudentsListTest.kt
├── PlusAtTest.kt
├── QuickSortTest.kt
└── StudentsData.kt
├── corotuines
├── CoroutineTest.kt
├── FibonacciTest.kt
├── FlowKataTests.kt
├── Main.kt
├── SieveTest.kt
├── continuation
│ └── ContinuationStealTest.kt
├── request
│ └── RequestTest.kt
└── ui
│ ├── BasePresenterTest.kt
│ └── CoroutineExceptionHandlingTest.kt
├── delegates
├── LateinitTest.kt
└── MutableLazyTest.kt
├── dsl
├── AnnouncementsListTest.kt
├── HtmlDslTest.kt
└── UsersTableTest.kt
├── extra
├── PermutationTest.kt
└── PowersetTest.kt
├── functional
├── CallbacksTest.kt
├── FunctionalTest.kt
├── ObservableValueTest.kt
├── ProductTest.kt
├── RationalTest.kt
└── RepeatTest.kt
└── nullability
├── Task.kt
└── TaskThrowing.kt
/.EditorConfig:
--------------------------------------------------------------------------------
1 | [*.{kt,kts}]
2 | indent_size=4
3 | insert_final_newline=true
4 | max_line_length=off
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | build
3 | out
4 | .gradle
5 | lib
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Kotlin workshop
3 |
4 | This project containes exercises and examples for [Kt. Academy Kotlin workshop](https://kt.academy/Kotlin_in_Backend).
5 |
6 | Workshop coveres:
7 | * Basic Kotlin structures
8 | * Functions on different levels and functional style
9 | * Kotlin OO programming
10 | * Data classes
11 | * Sealed classes
12 | * Object expression, object declaration and companion object
13 | * Kotlin type system
14 | * Extension functions
15 | * Functional programming in Kotlin
16 | * Collections and string processing
17 | * Scope functions (let, apply, run, also, with, takeIf, takeUnless)
18 | * Generic classes and functions, making own collection processing function
19 | * Kotlin generic type parameter declarations and modifiers
20 | * Kotlin property and interface delegates
21 | * Reflection in Kotlin, and how to use Java reflection in Kotlin
22 | * DSL usage and creation
23 | * Interoperability between Kotlin and Java
24 | * Basics of Kotlin coroutines
25 | * Rules of idiomatic Kotlin
26 | * Kotlin style guides
27 |
28 | If you are interested in having this workshop in your company, you can find details [here](https://kt.academy/Kotlin_in_Backend) or just fill [the form](https://marcinmoskala.typeform.com/to/StT0w1).
29 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.9.0'
3 | ext.kotlin_coroutines_version = '1.7.2'
4 | repositories {
5 | mavenCentral()
6 | }
7 | dependencies {
8 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
9 | }
10 | }
11 |
12 | apply plugin: 'kotlin'
13 |
14 | repositories {
15 | mavenCentral()
16 | }
17 |
18 | dependencies {
19 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
20 | implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
21 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
22 |
23 | // Callback exercise
24 | implementation "com.squareup.retrofit2:retrofit:2.4.0"
25 | implementation "com.squareup.retrofit2:converter-jackson:2.4.0"
26 | implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.9.7"
27 |
28 | // collections access list
29 | implementation('com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.13.0')
30 | implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.+")
31 |
32 | testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlin_coroutines_version"
33 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.0.0'
34 | testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
35 | }
36 |
37 | compileKotlin {
38 | kotlinOptions {
39 | jvmTarget = '1.8' //Good to target Java 8 unless you need 7
40 | javaParameters = true //Will retain parameter names for Java reflection
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.code.style=official
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarcinMoskala/advanced-kotlin-workshop-tasks/3e630849978ca82176097d21347a54c35ae38097/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 | com.marcinmoskala
7 | Workshop
8 | 1.0
9 |
10 |
11 | 1.9.0
12 | 1.8
13 | 1.8
14 |
15 |
16 |
17 |
18 |
19 | org.jetbrains.kotlin
20 | kotlin-maven-plugin
21 | ${kotlin.version}
22 |
23 |
24 | compile
25 |
26 | compile
27 |
28 |
29 |
30 | ${project.basedir}/src/main/kotlin
31 | ${project.basedir}/src/main/java
32 |
33 |
34 |
35 |
36 | test-compile
37 |
38 | test-compile
39 |
40 |
41 |
42 | ${project.basedir}/src/test/kotlin
43 | ${project.basedir}/src/test/java
44 |
45 |
46 |
47 |
48 |
49 |
50 | -java-parameters
51 |
52 |
53 |
54 |
55 | org.apache.maven.plugins
56 | maven-compiler-plugin
57 | 3.5.1
58 |
59 | 1.8
60 | 1.8
61 |
62 |
63 |
64 |
65 | default-compile
66 | none
67 |
68 |
69 |
70 | default-testCompile
71 | none
72 |
73 |
74 | java-compile
75 | compile
76 |
77 | compile
78 |
79 |
80 |
81 | java-test-compile
82 | test-compile
83 |
84 | testCompile
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | central
95 | https://jcenter.bintray.com
96 |
97 |
98 |
99 |
100 |
101 | org.jetbrains.kotlin
102 | kotlin-stdlib
103 | ${kotlin.version}
104 |
105 |
106 | org.jetbrains.kotlin
107 | kotlin-reflect
108 | ${kotlin.version}
109 |
110 |
111 | org.jetbrains.kotlinx
112 | kotlinx-coroutines-core
113 | 1.7.2
114 |
115 |
116 | org.jetbrains.kotlinx
117 | kotlinx-coroutines-test
118 | 1.7.2
119 | test
120 |
121 |
122 | com.squareup.retrofit2
123 | retrofit
124 | 2.4.0
125 |
126 |
127 | com.squareup.retrofit2
128 | converter-jackson
129 | 2.4.0
130 |
131 |
132 | com.fasterxml.jackson.dataformat
133 | jackson-dataformat-yaml
134 | 2.7.4
135 |
136 |
137 | com.fasterxml.jackson.module
138 | jackson-module-kotlin
139 | 2.9.7
140 |
141 |
142 | org.jetbrains.kotlin
143 | kotlin-test-junit
144 | ${kotlin.version}
145 | test
146 |
147 |
148 |
149 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'Workshop'
2 |
3 |
--------------------------------------------------------------------------------
/src/main/java/Basics.kt:
--------------------------------------------------------------------------------
1 | // https://en.wikipedia.org/wiki/Greatest_common_divisor
2 | fun gcd(a: Int, b: Int): Int = TODO()
3 |
4 | // fizzBuzz function that returns String that represents what should be said in the FizzBuzz game for each number between 1 and 100.
5 | // We list all this numbers in new lines, but we replace some of them with:
6 | // “Fizz” if number is divisible by 3
7 | // “Buzz” if number is divisible by 5
8 | // “FizzBuzz” if number is divisible both by 3 and 5 (by 15)
9 | // Print elements using `console.println`
10 | fun fizzBuzz(console: Console = PrintingConsole) {
11 | TODO()
12 | }
13 |
14 | interface Console {
15 | fun println(text: String)
16 | }
17 |
18 | object PrintingConsole : Console {
19 | override fun println(text: String) {
20 | kotlin.io.println(text)
21 | }
22 | }
23 |
24 | // Fibonacci number that starts from 1 and 1 (fib(0) == 1, fib(1) == 1, fib(2) == 2, fib(3) == 3, fib(4) == 5, fib(5) == 8)
25 | // https://en.wikipedia.org/wiki/Fibonacci_number
26 | fun fib(n: Int): Int = TODO()
--------------------------------------------------------------------------------
/src/main/java/MessageService.kt:
--------------------------------------------------------------------------------
1 | package sendmessage
2 |
3 | class MessageService(
4 | val messageSender: MessageSender
5 | ) {
6 | // TODO: Implement `sendMessage` function here
7 | // With parameters:
8 | // * `to` of type `String` and default value "all"
9 | // * `title` of type `String` and default value ""
10 | // * `content` of type `String` and default value ""
11 | // Without result type (or returning `Unit`)
12 | // Function should get emails using `findEmailAddresses`
13 | // Then for each email, it should send emails using `messageSender` function `sendEmail`
14 | // For iterate over emails, use
15 | // for(email in emails) {
16 | // ...
17 | // }
18 |
19 | private fun findEmailAddresses(to: String): List =
20 | if(to == "all") allEmailAddresses
21 | else allEmailAddresses.filter { it.address == to }
22 |
23 | private val allEmailAddresses = listOf(
24 | EmailAddress("alex@gmail.com"),
25 | EmailAddress("jake@gmail.com"),
26 | EmailAddress("leon@gmail.com"),
27 | EmailAddress("ally@gmail.com"),
28 | )
29 | }
30 |
31 | data class EmailAddress(val address: String)
32 |
33 | interface MessageSender {
34 | fun sendEmail(email: EmailAddress, title: String, content: String)
35 | }
36 |
37 | data class Email(
38 | val email: EmailAddress,
39 | val title: String,
40 | val content: String
41 | )
42 |
--------------------------------------------------------------------------------
/src/main/java/Test.kt:
--------------------------------------------------------------------------------
1 | fun main() {
2 | print("Hello, World")
3 | }
--------------------------------------------------------------------------------
/src/main/java/basics/API.kt:
--------------------------------------------------------------------------------
1 | package basics
2 |
3 | import generics.Response
4 |
5 | class StudentController(
6 | private val studentRepository: StudentRepository,
7 | private val analyticsRepository: AnalyticsRepository
8 | ) {
9 |
10 | @GetMapping("/student/{id}")
11 | fun getStudent(@PathVariable id: Long): StudentAPI {
12 | TODO()
13 | }
14 |
15 | @GetMapping("/student")
16 | fun getStudents(): List {
17 | TODO()
18 | }
19 | }
20 |
21 | data class StudentAPI(
22 | val name: String,
23 | val surname: String
24 | )
25 |
26 | @Entity
27 | data class StudentEntity(
28 | @Id @GeneratedValue
29 | val id: Long = -1,
30 | val firstName: String,
31 | val lastName: String
32 | )
33 |
34 | interface StudentRepository {
35 |
36 | fun findStudent(id: Long): StudentEntity?
37 | fun findStudentResult(id: Long): Response
38 | fun getAllStudents(): List
39 | }
40 |
41 | object NotFoundException : Throwable()
42 |
43 | interface AnalyticsRepository {
44 |
45 | fun getStudentByIdCount(id: Long): Int
46 | fun setStudentByIdCount(id: Long, count: Int)
47 | }
48 |
49 | data class ApiError(val code: Int, override val message: String) : Throwable(message)
50 |
51 | annotation class Entity
52 | annotation class Id
53 | annotation class GeneratedValue
54 | annotation class GetMapping(val path: String)
55 | annotation class PathVariable
56 |
--------------------------------------------------------------------------------
/src/main/java/basics/Color.kt:
--------------------------------------------------------------------------------
1 | package basics
2 |
3 | enum class Color {
4 | BLUE, RED, YELLOW
5 | }
--------------------------------------------------------------------------------
/src/main/java/basics/Factorial.kt:
--------------------------------------------------------------------------------
1 | package basics
2 |
3 | // factorial(5) = 5! = 5 * 4 * 3 * 2 * 1 = 120
4 | // https://en.wikipedia.org/wiki/Factorial
5 | fun factorial(n: Int): Long = TODO()
--------------------------------------------------------------------------------
/src/main/java/basics/Person.kt:
--------------------------------------------------------------------------------
1 | package basics
2 |
3 | interface Person {
4 | val name: String
5 | val age: Int
6 | val canBuyAlcohol: Boolean
7 |
8 | fun helloText(): String
9 |
10 | fun cheerText(person: Person): String
11 | }
12 |
13 | fun main(args: Array) {
14 | val businessman: Person = TODO("Use Businessman constructor here once it is implemented")
15 | val student: Person = TODO("Use Student constructor here once it is implemented")
16 |
17 | println(businessman.helloText())
18 | println(student.helloText())
19 |
20 | println(businessman.cheerText(student))
21 | println(student.cheerText(businessman))
22 |
23 | fun sayIfCanBuyAlcohol(person: Person) {
24 | val modal = if (person.canBuyAlcohol) "can" else "can't"
25 | println("${person.name} $modal buy alcohol")
26 | }
27 |
28 | sayIfCanBuyAlcohol(businessman)
29 | sayIfCanBuyAlcohol(student)
30 | }
--------------------------------------------------------------------------------
/src/main/java/basics/Pizza.kt:
--------------------------------------------------------------------------------
1 | package basics
2 |
3 | data class Pizza(
4 | val cheese: Int = 0,
5 | val pineapple: Int = 0,
6 | val ham: Int = 0,
7 | val egg: Int = 0,
8 | val spinach: Int = 0
9 | )
10 |
11 | fun main() {
12 | // val pizza1 = Pizza.hawaiian()
13 | // val pizza2 = PizzaFactory.hawaiian()
14 | // assert(pizza1 == Pizza(cheese = 1, pineapple = 1, ham = 1))
15 | // assert(pizza2 == Pizza(cheese = 1, pineapple = 1, ham = 1))
16 | }
--------------------------------------------------------------------------------
/src/main/java/basics/Tree.kt:
--------------------------------------------------------------------------------
1 | package basics.tree
2 |
3 | // TODO: Clean it up
4 | abstract class Tree {
5 | override fun toString(): String {
6 | return treeToString(this, StringBuilder()).toString()
7 | }
8 | }
9 |
10 | class Leaf(val value: String) : Tree()
11 | class Node(val left: Tree, val right: Tree) : Tree()
12 |
13 | private fun treeToString(tree: Tree, sb: StringBuilder): StringBuilder {
14 | if (tree is Leaf) {
15 | val leaf = tree as Leaf
16 | sb.append(leaf.value)
17 | } else if (tree is Node) {
18 | val node = tree as Node
19 | treeToString(node.left, sb)
20 | sb.append(", ")
21 | treeToString(node.right, sb)
22 | }
23 | return sb
24 | }
--------------------------------------------------------------------------------
/src/main/java/basics/TreeOperations.kt:
--------------------------------------------------------------------------------
1 | package basics.treeoperations
2 |
3 | sealed class Tree {
4 | override fun toString(): String = when (this) {
5 | is Leaf -> value.toString()
6 | is Node -> "($left, $right)"
7 | }
8 | }
9 |
10 | data class Leaf(val value: T) : Tree()
11 | data class Node(val left: Tree, val right: Tree) : Tree()
--------------------------------------------------------------------------------
/src/main/java/basics/Weather.java:
--------------------------------------------------------------------------------
1 | package basics;
2 |
3 | public class Weather {
4 |
5 | public void updateWeather(int degrees) {
6 | String description;
7 | Color color;
8 | if (degrees < 5) {
9 | description = "cold";
10 | color = Color.BLUE;
11 | } else if (degrees < 23) {
12 | description = "mild";
13 | color = Color.YELLOW;
14 | } else {
15 | description = "hot";
16 | color = Color.RED;
17 | }
18 | // ...
19 | }
20 | }
--------------------------------------------------------------------------------
/src/main/java/collections/BestStudents.kt:
--------------------------------------------------------------------------------
1 | package collections
2 |
3 | // Implement makeBestStudentsList method to display the best 10 students,
4 | // so they can get an internship. You should compare them by their result
5 | // (higher is better). To get an internship, students need to have got
6 | // at least 30 points in the semester and a result of at least 80.
7 | // The best student gets $5000, the next 3 get $3000 and the next 6 get $1000.
8 | // Display students in alphabetical order (compare first surname then name)
9 | // in the format “{name} {surname}, ${internship size}”
10 | fun List.makeBestStudentsList(): String = TODO()
--------------------------------------------------------------------------------
/src/main/java/collections/Collections.kt:
--------------------------------------------------------------------------------
1 | package collections
2 |
3 | // To prevent unintentional stdlib functions usage
4 | import kotlin.collections.flatMap as stdlibFlatMap
5 | import kotlin.collections.map as stdlibMap
6 | import kotlin.collections.filter as stdlibFilter
7 | import kotlin.collections.onEach as stdlibOnEach
8 |
9 | inline fun > C.onEach(operation: (T) -> Unit): C {
10 | for (elem in this) {
11 | operation(elem)
12 | }
13 | return this
14 | }
15 |
16 | inline fun Iterable.flatMap(transformation: (T) -> Iterable): List {
17 | val list = ArrayList()
18 | for (elem in this) {
19 | list.addAll(transformation(elem))
20 | }
21 | return list
22 | }
23 |
24 | inline fun Iterable.filter(predicate: (T) -> Boolean): List {
25 | val list = ArrayList()
26 | for (elem in this) {
27 | if (predicate(elem)) {
28 | list.add(elem)
29 | }
30 | }
31 | return list
32 | }
33 |
34 | fun main(args: Array) {
35 | val numbers = 1..10
36 | val names = listOf("Mike", "Jane", "Marcin", "John", "James")
37 |
38 | numbers.onEach { print(it) } // 12345678910
39 | println()
40 | names.onEach { print(it) } // MikeJaneMarcinJohnJames
41 | println()
42 |
43 | println(names.filter { it.startsWith("J") }) // [Jane, John, James]
44 | println(names.filter { it.startsWith("M") }) // [Mike, Marcin]
45 |
46 | println(names.flatMap { it.toList() }) // [M, i, k, e, J, a, n, e, M, a, r, c, i, n, J, o, h, n, J, a, m, e, s]
47 | println(numbers.flatMap { listOf(it, it + 10) }) // [1, 11, 2, 12, 3, 13, 4, 14, 5, 15, 6, 16, 7, 17, 8, 18, 9, 19, 10, 20]
48 |
49 | // println(names.map { it.toUpperCase() }) // [MIKE, JANE, MARCIN, JOHN, JAMES]
50 | // println(numbers.map { it * 10 }) // [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/collections/PassingStudents.kt:
--------------------------------------------------------------------------------
1 | package collections
2 |
3 | // Implement makePassingStudentsListText method to display a list of students
4 | // who have got more than 15 points in the semester and a result of at least 50.
5 | // Display in alphabetical order (surname then name), in the format:
6 | // “{name} {surname}, {result}”
7 | fun List.makePassingStudentsListText(): String = TODO()
--------------------------------------------------------------------------------
/src/main/java/collections/PlusAt.kt:
--------------------------------------------------------------------------------
1 | package collections
2 |
3 | fun List.plusAt(index: Int, element: T): List {
4 | TODO()
5 | }
--------------------------------------------------------------------------------
/src/main/java/collections/PrimeAccessList.kt:
--------------------------------------------------------------------------------
1 | package collections
2 |
3 | import java.io.File
4 | import kotlin.system.measureTimeMillis
5 |
6 | val file = File("AccessList.yaml")
7 | val yamlReader = YamlReader()
8 |
9 | class PrimeAccessListRepository {
10 | private val accessList: PrimeAccessList = yamlReader.readYaml(file)
11 |
12 | fun isOnAllowList(userId: Long): Boolean = TODO()
13 |
14 | fun isOnDenyList(userId: Long): Boolean = TODO()
15 | }
16 |
17 | class PrimeAccessList(
18 | val entries: List
19 | )
20 |
21 | class PrimeAccessEntry(
22 | val userId: Long,
23 | val allowList: Boolean,
24 | val allowListReason: String?,
25 | val denyList: Boolean,
26 | val denyListReason: String?
27 | )
28 |
29 | fun main() {
30 | val repo = PrimeAccessListRepository()
31 |
32 | measureTimeMillis {
33 | for (userId in 1L..10_000L) {
34 | repo.isOnAllowList(userId)
35 | }
36 | }.let { println("Checking 10_000 ids by isOnAllowList took $it") }
37 |
38 | measureTimeMillis {
39 | for (userId in 1L..10_000L) {
40 | repo.isOnDenyList(userId)
41 | }
42 | }.let { println("Checking 10_000 ids by isOnDenyList took $it") }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/collections/QuickSort.kt:
--------------------------------------------------------------------------------
1 | package collections
2 |
3 | // TODO: Quick sort should take first element (pivot), then split rest to bigger then pivot and smaller and finally return
4 | // first smaller sorted, then pivot and finally bigger sorted
5 | fun > List.quickSort(): List {
6 | TODO()
7 | }
--------------------------------------------------------------------------------
/src/main/java/collections/Student.kt:
--------------------------------------------------------------------------------
1 | package collections
2 |
3 | data class Student(
4 | val name: String,
5 | val surname: String,
6 | val result: Double,
7 | val pointsInSemester: Int
8 | )
--------------------------------------------------------------------------------
/src/main/java/collections/YamlReader.kt:
--------------------------------------------------------------------------------
1 | package collections
2 |
3 | import com.fasterxml.jackson.core.JsonParser
4 | import com.fasterxml.jackson.databind.ObjectMapper
5 | import com.fasterxml.jackson.databind.SerializationFeature
6 | import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
7 | import com.fasterxml.jackson.module.kotlin.KotlinModule
8 | import java.io.File
9 |
10 | class YamlReader {
11 | private val mapper = ObjectMapper(YAMLFactory()).apply {
12 | registerModule(KotlinModule())
13 | configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true)
14 | disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
15 | }
16 |
17 | fun readYaml(file: File, clazz: Class): T =
18 | mapper.readValue(file, clazz)
19 |
20 | inline fun readYaml(file: File): T =
21 | readYaml(file, T::class.java)
22 |
23 | fun writeYaml(file: File, value: T) =
24 | mapper.writeValue(file, value)
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/corotuines/Downloader.kt:
--------------------------------------------------------------------------------
1 | package corotuines
2 |
3 | import kotlinx.coroutines.*
4 | import kotlin.random.Random
5 |
6 | class User(val name: String)
7 |
8 | class NetworkService {
9 | suspend fun getUser(): User {
10 | delay(2)
11 | return User(Random.nextLong().toString())
12 | }
13 | }
14 |
15 | class UserDownloader(val api: NetworkService) {
16 | private val users = mutableListOf()
17 |
18 | fun all(): List = users
19 |
20 | suspend fun downloadNext(num: Int) = coroutineScope {
21 | repeat(num) {
22 | val newUser = api.getUser()
23 | users.add(newUser)
24 | }
25 | }
26 | }
27 |
28 | fun main() = runBlocking(Dispatchers.Default) {
29 | val downloader = UserDownloader(NetworkService())
30 | coroutineScope {
31 | repeat(1000) {
32 | launch {
33 | downloader.downloadNext(1000)
34 | }
35 | }
36 | }
37 | print(downloader.all().size)
38 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/Fibonacci.kt:
--------------------------------------------------------------------------------
1 | package coroutines
2 |
3 | val fibonacci: Sequence = sequence {
4 | TODO()
5 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/FlowKata.kt:
--------------------------------------------------------------------------------
1 | package corotuines
2 |
3 | import kotlinx.coroutines.flow.Flow
4 |
5 | // Produces a flow of Unit
6 | // For instance producingUnits(5) -> [Unit, Unit, Unit, Unit, Unit]
7 | fun producingUnits(num: Int): Flow = TODO()
8 |
9 | // Adds a delay of time `timeMillis` between elements
10 | fun Flow.delayEach(timeMillis: Long): Flow = TODO()
11 |
12 | // Should transform Unit's to toggled boolean value starting from true
13 | // For instance flowOf(Unit, Unit, Unit, Unit).toNextNumbers() -> [true, false, true, false]
14 | fun Flow<*>.toToggle(): Flow = TODO()
15 |
16 | // Should transform Unit's to next numbers startling from 1
17 | // For instance flowOf(Unit, Unit, Unit, Unit).toNextNumbers() -> [1, 2, 3, 4]
18 | fun Flow<*>.toNextNumbers(): Flow = TODO()
19 |
20 | // Produces not only elements, but the whole history till now
21 | // For instance flowOf(1, "A", 'C').withHistory() -> [[], [1], [1, A], [1, A, C]]
22 | fun Flow.withHistory(): Flow> = TODO()
23 |
24 | // Should create a flow that every `tickEveryMillis` should emit next numbers from `startNum` to `endNum`
25 | fun makeTimer(tickEveryMillis: Long, startNum: Int, endNum: Int): Flow = TODO()
26 |
27 | // Based on two light switches, should decide if the general light should be switched on.
28 | // Should be if one is true and another is false
29 | fun makeLightSwitch(switch1: Flow, switch2: Flow): Flow = TODO()
30 |
31 | // Based on two light switches, should decide if the general light should be switched on.
32 | // Should be if one is turned on and another is off
33 | // At the beginning, both switches are off, and each action toggles
34 | fun makeLightSwitchToggle(switch1: Flow, switch2: Flow): Flow = TODO()
35 |
36 | fun polonaisePairing(track1: Flow, track2: Flow): Flow> = TODO()
37 |
38 | data class Person(val name: String)
39 |
40 |
--------------------------------------------------------------------------------
/src/main/java/corotuines/Main.kt:
--------------------------------------------------------------------------------
1 | package coroutines
2 |
3 | import kotlinx.coroutines.delay
4 | import kotlinx.coroutines.runBlocking
5 |
6 | fun main(): Unit = runBlocking {
7 | println("Started!")
8 | test()
9 | println("Done.")
10 | }
11 |
12 | suspend fun test() {
13 | delay(1000)
14 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/Sieve.kt:
--------------------------------------------------------------------------------
1 | package coroutines
2 |
3 | val primes: Sequence = sequence {
4 | TODO()
5 | }
6 |
7 | // TODO: Delete it and replace it with sequence builder (above)
8 | fun getPrimeNumbers(num: Int): List {
9 | var numbers = generateSequence(2) { it + 1 }
10 | val primes = mutableListOf()
11 | repeat(num) {
12 | val prime = numbers.first()
13 | primes += prime
14 | numbers = numbers.drop(1).filter { it % prime != 0 }
15 | }
16 | return primes
17 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/Structured.kt:
--------------------------------------------------------------------------------
1 | package coroutines
2 |
3 | import kotlinx.coroutines.runBlocking
4 | import java.util.*
5 |
6 | // We have a worker who makes machines every 800ms as long as there is less than 5 of them
7 | // Every machine produces a code using `produce` function every second. It saves this code to shared space. In case of an error, it ends working.
8 | // We have a single manager that once a 2 seconds takes all produced codes and prints them all. After 5 times it ends all jobs (including machines and worker).
9 |
10 | fun main() = runBlocking {
11 | TODO()
12 | }
13 |
14 | class RandomError : Throwable()
15 |
16 | private val letters = ('a'..'z') + ('0'..'9')
17 | private val random = Random()
18 |
19 | private fun produce(): String = when (random.nextInt(8)) {
20 | 0 -> throw RandomError()
21 | else -> (1..5).map { letters[random.nextInt(letters.size)] }.joinToString(separator = "")
22 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/backend/Api.kt:
--------------------------------------------------------------------------------
1 | package coroutines.backend
2 |
3 | import kotlinx.coroutines.runBlocking
4 |
5 | data class User(val name: String)
6 |
7 | fun main() {
8 | val database = Database()
9 | val emailService = EmailService()
10 | api {
11 | get("users") {
12 | "[]"
13 | }
14 | post("user") { body ->
15 | val user = body as? User ?: throw Error("Passed user is not correct")
16 | print("I just get $user")
17 | "OK"
18 | }
19 | get("user/count") {
20 | 0
21 | }
22 | }.start()
23 |
24 | runBlocking {
25 | println("User count is ${get("user/count")}")
26 | println("Users are ${get("users")}")
27 | post("user", User("Marcin"))
28 | }
29 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/backend/ApiDsl.kt:
--------------------------------------------------------------------------------
1 | package coroutines.backend
2 |
3 | fun api(config: ApiConfig.() -> Unit) = ApiConfig().also(config)
4 |
5 | var publicHandles = mapOf Any>()
6 |
7 | data class Endpoint(val method: String, val path: String)
8 |
9 | class ApiConfig {
10 | var handles = mapOf Any>()
11 |
12 | fun get(path: String, handle: suspend (body: Any?) -> Any) {
13 | addHandle("get", path, handle)
14 | }
15 |
16 | fun post(path: String, handle: suspend (body: Any?) -> Any) {
17 | addHandle("post", path, handle)
18 | }
19 |
20 | fun start() {
21 | publicHandles += handles
22 | }
23 |
24 | private fun addHandle(method: String, path: String, handle: suspend (body: Any?) -> Any) {
25 | handles += Endpoint(method, path) to handle
26 | }
27 | }
28 |
29 | suspend fun get(path: String, body: Any? = null) = respond("get", path, body)
30 |
31 | suspend fun post(path: String, body: Any? = null) = respond("post", path, body)
32 |
33 | suspend fun respond(method: String, path: String, body: Any?): Any? {
34 | val handle = publicHandles[Endpoint(method, path)] ?: throw NoSuchMethodError()
35 | return try {
36 | handle(body)
37 | } catch (e: Throwable) {
38 | e.printStackTrace()
39 | null
40 | }
41 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/backend/Database.kt:
--------------------------------------------------------------------------------
1 | package coroutines.backend
2 |
3 | class Database {
4 |
5 | suspend fun getUser() {}
6 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/backend/EmailService.kt:
--------------------------------------------------------------------------------
1 | package coroutines.backend
2 |
3 | import kotlinx.coroutines.delay
4 |
5 | class EmailService {
6 |
7 | suspend fun sendEmail(to: String, body: String) {
8 | delay(2000)
9 | print("Sent email to $to with body $body")
10 | }
11 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/continuation/ContinuationSteal.kt:
--------------------------------------------------------------------------------
1 | package continuation
2 |
3 | import kotlinx.coroutines.*
4 | import kotlin.coroutines.Continuation
5 | import kotlin.coroutines.resume
6 |
7 | fun main(): Unit = runBlocking {
8 | val cont = continuationSteal()
9 | delay(1000)
10 | cont?.resume("This is some text")
11 | }
12 |
13 | fun continuationSteal(console: Console = Console()): Continuation? = runBlocking {
14 | var continuation: Continuation? = null
15 | GlobalScope.launch(Dispatchers.Unconfined) {
16 | console.println("Before")
17 | TODO()
18 | console.println("After")
19 | }
20 | continuation
21 | }
22 |
23 | open class Console {
24 |
25 | open fun println(text: Any?) {
26 | kotlin.io.println(text)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/1.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.GlobalScope
4 | import kotlinx.coroutines.delay
5 | import kotlinx.coroutines.launch
6 |
7 | fun main() {
8 | GlobalScope.launch {
9 | delay(1000L)
10 | println("World!")
11 | }
12 | println("Hello,")
13 | Thread.sleep(2000L)
14 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/10.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.coroutineScope
4 | import kotlinx.coroutines.delay
5 | import kotlinx.coroutines.launch
6 | import kotlinx.coroutines.runBlocking
7 |
8 | fun main() = runBlocking {
9 | launch {
10 | delay(200L)
11 | println("Task from runBlocking")
12 | }
13 |
14 | coroutineScope {
15 | launch {
16 | delay(500L)
17 | println("Task from nested launch")
18 | }
19 |
20 | delay(100L)
21 | println("Task from coroutine scope")
22 | }
23 |
24 | println("Coroutine scope is over")
25 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/11.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.async
4 | import kotlinx.coroutines.coroutineScope
5 | import kotlinx.coroutines.runBlocking
6 |
7 | suspend fun makeAsyncCalculationsInCoroutineScope(): String = coroutineScope {
8 | val one = async { doSomethingUsefulOne() }
9 | val two = async { doSomethingUsefulTwo() }
10 | "The answer is ${one.await() + two.await()}"
11 | }
12 |
13 | fun main() = runBlocking {
14 | val value = makeAsyncCalculationsInCoroutineScope()
15 | println(value)
16 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/12.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.async
4 | import kotlinx.coroutines.coroutineScope
5 | import kotlinx.coroutines.delay
6 | import kotlinx.coroutines.runBlocking
7 |
8 | suspend fun failedConcurrentSum(): Int = coroutineScope {
9 | val one = async {
10 | try {
11 | delay(Long.MAX_VALUE)
12 | 42
13 | } finally {
14 | println("First child was cancelled")
15 | }
16 | }
17 | val two = async {
18 | println("2nd child throws an exception")
19 | throw ArithmeticException()
20 | }
21 | one.await() + two.await()
22 | }
23 |
24 | fun main() = runBlocking {
25 | try {
26 | failedConcurrentSum()
27 | } catch (e: ArithmeticException) {
28 | println("Computation failed with ArithmeticException")
29 | }
30 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/13.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.GlobalScope
4 | import kotlinx.coroutines.async
5 | import kotlinx.coroutines.runBlocking
6 |
7 | fun main() = runBlocking {
8 | val deferred = GlobalScope.async {
9 | println("Throwing exception from async")
10 | throw ArithmeticException()
11 | }
12 | try {
13 | deferred.await()
14 | println("Unreached")
15 | } catch (e: ArithmeticException) {
16 | println("Caught ArithmeticException")
17 | }
18 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/14.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val supervisor = SupervisorJob()
7 | with(CoroutineScope(coroutineContext + supervisor)) {
8 | launch(CoroutineExceptionHandler { _, _ -> }) {
9 | delay(1000)
10 | throw AssertionError("Cancelled")
11 | }
12 | launch {
13 | delay(2000)
14 | println("AAA")
15 | }
16 | }
17 | supervisor.join()
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/15.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | supervisorScope {
7 | launch(CoroutineExceptionHandler { _, _ -> }) {
8 | delay(1000)
9 | throw AssertionError("Cancelled")
10 | }
11 | launch {
12 | delay(2000)
13 | println("AAA")
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/2.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.GlobalScope
4 | import kotlinx.coroutines.delay
5 | import kotlinx.coroutines.launch
6 | import kotlinx.coroutines.runBlocking
7 |
8 | fun main() {
9 | GlobalScope.launch {
10 | delay(1000L)
11 | println("World!")
12 | }
13 | println("Hello,")
14 | runBlocking {
15 | delay(2000L)
16 | }
17 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/3.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.GlobalScope
4 | import kotlinx.coroutines.delay
5 | import kotlinx.coroutines.launch
6 | import kotlinx.coroutines.runBlocking
7 |
8 | fun main() = runBlocking {
9 | GlobalScope.launch {
10 | delay(1000L)
11 | println("World!")
12 | }
13 | println("Hello,")
14 | delay(2000L)
15 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/4.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun CoroutineScope.log(msg: String) = println("[${coroutineContext[CoroutineName]?.name}] $msg")
6 |
7 | fun main() = runBlocking(CoroutineName("main")) {
8 | log("Started main coroutine")
9 | val v1 = async(CoroutineName("v1coroutine")) {
10 | delay(500)
11 | log("Computing v1")
12 | "KOKO"
13 | }
14 | val v2 = async(CoroutineName("v2coroutine")) {
15 | delay(1000)
16 | log("Computing v2")
17 | 6
18 | }
19 | log("The answer for v1 = ${v1.await()}")
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/5.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.Job
4 | import kotlinx.coroutines.delay
5 | import kotlinx.coroutines.launch
6 | import kotlinx.coroutines.runBlocking
7 |
8 | fun main() = runBlocking {
9 | val job = Job()
10 | launch(job) {
11 | repeat(1000) { i ->
12 | println("I'm sleeping $i ...")
13 | delay(500L)
14 | }
15 | }
16 | delay(1300L) // delay a bit
17 | println("main: I'm tired of waiting!")
18 | job.cancel()
19 | job.join()
20 | println("main: Now I can quit.")
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/6.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.delay
4 | import kotlinx.coroutines.launch
5 | import kotlinx.coroutines.runBlocking
6 |
7 | fun main() = runBlocking {
8 | val job = launch {
9 | repeat(1000) { i ->
10 | println("I'm sleeping $i ...")
11 | delay(500L)
12 | }
13 | }
14 | delay(1300L) // delay a bit
15 | println("main: I'm tired of waiting!")
16 | job.cancel()
17 | job.join()
18 | println("main: Now I can quit.")
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/7.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.CoroutineExceptionHandler
4 | import kotlinx.coroutines.GlobalScope
5 | import kotlinx.coroutines.launch
6 | import kotlinx.coroutines.runBlocking
7 |
8 | fun main() = runBlocking {
9 | val handler = CoroutineExceptionHandler { _, exception ->
10 | println("Caught $exception")
11 | }
12 | val job = GlobalScope.launch(handler) {
13 | throw AssertionError()
14 | }
15 | job.join() // Caught java.lang.AssertionError
16 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/8.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.Dispatchers
4 | import kotlinx.coroutines.launch
5 | import kotlinx.coroutines.newSingleThreadContext
6 | import kotlinx.coroutines.runBlocking
7 |
8 | fun main() = runBlocking {
9 | fun getThreadName() = Thread.currentThread().name
10 | launch {
11 | println("main runBlocking : I'm working in thread ${getThreadName()}")
12 | }
13 | launch(Dispatchers.Default) {
14 | println("Default : I'm working in thread ${getThreadName()}")
15 | launch(Dispatchers.Unconfined) {
16 | println("Unconfined : I'm working in thread ${getThreadName()}")
17 | }
18 | }
19 |
20 | launch(newSingleThreadContext("MyOwnThread")) {
21 | println("newSingleThreadContext: I'm working in thread ${getThreadName()}")
22 | }
23 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/9.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.GlobalScope
4 | import kotlinx.coroutines.async
5 | import kotlinx.coroutines.delay
6 | import kotlinx.coroutines.runBlocking
7 | import java.util.*
8 |
9 | suspend fun makeAsyncCalculations(): String {
10 | val one = GlobalScope.async { doSomethingUsefulOne() }
11 | val two = GlobalScope.async { doSomethingUsefulTwo() }
12 | return "The answer is ${one.await() + two.await()}"
13 | }
14 |
15 | suspend fun doSomethingUsefulOne(): Int {
16 | delay(1000)
17 | println("I am done")
18 | return 1
19 | }
20 |
21 | val random = Random()
22 |
23 | suspend fun doSomethingUsefulTwo(): Int {
24 | delay(100)
25 | if (random.nextBoolean()) throw Error() else return 2
26 | }
27 |
28 | fun main() = runBlocking {
29 | val value = makeAsyncCalculations()
30 | println(value)
31 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/Delay.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import java.util.concurrent.Executors
4 | import java.util.concurrent.TimeUnit
5 | import kotlin.coroutines.resume
6 | import kotlin.coroutines.suspendCoroutine
7 |
8 | private val excecutor = Executors.newSingleThreadScheduledExecutor {
9 | Thread(it, "scheduler").apply { isDaemon = true }
10 | }
11 |
12 | suspend fun customDelay(time: Long): Unit = suspendCoroutine { cont ->
13 | excecutor.schedule({ cont.resume(Unit) }, time, TimeUnit.MILLISECONDS)
14 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/Massive.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.delay
4 | import kotlinx.coroutines.launch
5 | import kotlinx.coroutines.runBlocking
6 |
7 | fun main() = runBlocking {
8 | repeat(100_000) {
9 | launch {
10 | delay(1000L)
11 | print(".")
12 | }
13 | }
14 | }
15 |
16 | //// No! Don't do it! Very bed idea on threads
17 | //fun main() {
18 | // repeat(100_000) {
19 | // thread {
20 | // Thread.sleep(1000L)
21 | // print(".")
22 | // }
23 | // }
24 | //}
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/Numbers.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | val childNumbers = sequence {
4 | println("Um, first number is... one!")
5 | yield(1)
6 |
7 | println("Next is... eeeee two!")
8 | yield(2)
9 |
10 | println("twotwotwo... ummmm three!")
11 | yield(3)
12 |
13 | println("That's all I've learned")
14 | }
15 |
16 | fun main() {
17 | val iterator = childNumbers.iterator()
18 | println("What is first?")
19 | println("Yes, it is ${iterator.next()}")
20 | println("What is next?")
21 | println("Good, it is ${iterator.next()}")
22 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/s1.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples
2 |
3 | import kotlinx.coroutines.CoroutineScope
4 | import kotlinx.coroutines.GlobalScope
5 | import kotlinx.coroutines.launch
6 | import kotlinx.coroutines.runBlocking
7 |
8 | var counter = 0
9 |
10 | fun main() = runBlocking {
11 | GlobalScope.massiveRun {
12 | counter++
13 | }
14 | println("Counter = ${counter}")
15 | }
16 |
17 | suspend fun CoroutineScope.massiveRun(action: suspend () -> Unit) {
18 | val jobs = List(1000) {
19 | launch {
20 | repeat(1000) { action() }
21 | }
22 | }
23 | jobs.forEach { it.join() }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/s2.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples.n1
2 |
3 | import coroutines.examples.massiveRun
4 | import kotlinx.coroutines.GlobalScope
5 | import kotlinx.coroutines.runBlocking
6 | import java.util.concurrent.atomic.AtomicInteger
7 |
8 | private var counter = AtomicInteger()
9 |
10 | fun main() = runBlocking {
11 | GlobalScope.massiveRun {
12 | counter.incrementAndGet()
13 | }
14 | println("Counter = ${counter.get()}")
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/s3.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples.n2
2 |
3 | import coroutines.examples.massiveRun
4 | import kotlinx.coroutines.GlobalScope
5 | import kotlinx.coroutines.newSingleThreadContext
6 | import kotlinx.coroutines.runBlocking
7 | import kotlinx.coroutines.withContext
8 |
9 | private var counter = 0
10 |
11 | fun main() = runBlocking {
12 | val counterContext = newSingleThreadContext("CounterContext")
13 |
14 | GlobalScope.massiveRun {
15 | withContext(counterContext) {
16 | counter++
17 | }
18 | }
19 | println("Counter = $counter")
20 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/examples/s4.kt:
--------------------------------------------------------------------------------
1 | package coroutines.examples.n3
2 |
3 | import coroutines.examples.massiveRun
4 | import kotlinx.coroutines.GlobalScope
5 | import kotlinx.coroutines.runBlocking
6 | import kotlinx.coroutines.sync.Mutex
7 | import kotlinx.coroutines.sync.withLock
8 |
9 | private val mutex = Mutex()
10 | private var counter = 0
11 |
12 | fun main() = runBlocking {
13 | GlobalScope.massiveRun {
14 | mutex.withLock {
15 | counter++
16 | }
17 | }
18 | println("Counter = $counter")
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/corotuines/request/Request.kt:
--------------------------------------------------------------------------------
1 | package corotuines.request
2 |
3 | import kotlinx.coroutines.GlobalScope
4 | import kotlinx.coroutines.async
5 | import kotlinx.coroutines.coroutineScope
6 |
7 | /*
8 | TODO: This function should return the best student on the [semester].
9 | */
10 | suspend fun getBestStudent(semester: String, repo: StudentsRepository): Student = TODO()
11 |
12 | data class Student(val id: Int, val result: Double, val semester: String)
13 |
14 | interface StudentsRepository {
15 | suspend fun getStudentIds(semester: String): List
16 | suspend fun getStudent(id: Int): Student
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/corotuines/ui/BasePresenter.kt:
--------------------------------------------------------------------------------
1 | package coroutines.ui
2 |
3 | import kotlinx.coroutines.*
4 |
5 | val UI = newSingleThreadContext("UIThread") // Normally it will be Dispatchers.Main
6 |
7 | // TODO: Edit only this class
8 | abstract class BasePresenter(
9 | private val onError: (Throwable) -> Unit = {}
10 | ) {
11 |
12 | fun onDestroy() {}
13 | }
--------------------------------------------------------------------------------
/src/main/java/corotuines/ui/MainPresenter.kt:
--------------------------------------------------------------------------------
1 | package coroutines.ui
2 |
3 | import kotlinx.coroutines.launch
4 | import java.util.*
5 |
6 | class MainPresenter(
7 | val view: MainView,
8 | val repo: NetworkRepository
9 | ) : BasePresenter(view::onError) {
10 |
11 | fun onCreate() {
12 | // TODO: Uncomment
13 | // launch {
14 | // val user = repo.getUser()
15 | // view.showUserData(user)
16 | // }
17 | // launch {
18 | // val news = repo.getNews()
19 | // .sortedByDescending { it.date }
20 | // view.showNews(news)
21 | // }
22 | }
23 | }
24 |
25 | interface MainView {
26 | fun onError(throwable: Throwable): Unit
27 | fun showUserData(user: UserData)
28 | fun showNews(news: List)
29 | }
30 |
31 | interface NetworkRepository {
32 | suspend fun getUser(): UserData
33 | suspend fun getNews(): List
34 | }
35 |
36 | class UserData
37 | class News(val date: Date)
--------------------------------------------------------------------------------
/src/main/java/delegates/MutableLazy.kt:
--------------------------------------------------------------------------------
1 | @file:JvmName("Mutable")
2 | package delegates
3 |
4 | import kotlin.properties.ReadWriteProperty
5 |
6 | fun mutableLazy(initializer: () -> T): ReadWriteProperty = TODO()
--------------------------------------------------------------------------------
/src/main/java/dsl/Announcements.kt:
--------------------------------------------------------------------------------
1 | package dsl
2 |
3 | fun getAnnouncements(passingStudentsListText: String, bestStudentsListText: String): List = TODO()
4 | // announcements {
5 | // reminder("If you want to receive internship, you need to provide documents till end of September")
6 | // info {
7 | // title = "Students who are passing:"
8 | // content = passingStudentsListText
9 | // }
10 | // info {
11 | // title = "Internships:"
12 | // content = bestStudentsListText
13 | // }
14 | // reminder("Work hard whole year and prepare to all classes")
15 | // info {
16 | // content = "Checking this app periodically will help you be up to date with your university"
17 | // }
18 | // }
19 |
20 | data class Announcement(
21 | val title: String?,
22 | val text: String
23 | )
--------------------------------------------------------------------------------
/src/main/java/dsl/TableDSL.kt:
--------------------------------------------------------------------------------
1 | package dsl
2 |
3 | fun createTable(): TableBuilder {
4 | // TODO: This is how I would prefer to print it
5 | //return table {
6 | // tr {
7 | // td { +"A" }
8 | // td { +"B" }
9 | // }
10 | // tr {
11 | // td { +"C" }
12 | // td { +"D" }
13 | // }
14 | //}
15 | val td1 = TdBuilder()
16 | td1.text = "A"
17 | val td2 = TdBuilder()
18 | td2.text = "B"
19 |
20 | val tr1 = TrBuilder()
21 | tr1.tds += td1
22 | tr1.tds += td2
23 |
24 | val td3 = TdBuilder()
25 | td3.text = "C"
26 | val td4 = TdBuilder()
27 | td4.text = "D"
28 |
29 | val tr2 = TrBuilder()
30 | tr2.tds += td3
31 | tr2.tds += td4
32 |
33 | val html = TableBuilder()
34 | html.trs += tr1
35 | html.trs += tr2
36 | return html
37 | }
38 |
39 | fun main() {
40 | println(createTable()) //This is row 1 | This is row 2 |
41 | }
42 |
43 | data class TableBuilder(var trs: List = emptyList()) {
44 | override fun toString(): String = "${trs.joinToString(separator = "")}
"
45 | }
46 | data class TrBuilder(var tds: List = emptyList()) {
47 | override fun toString(): String = "${tds.joinToString(separator = "")}
"
48 | }
49 | data class TdBuilder(var text: String = "") {
50 | override fun toString(): String = "$text | "
51 | }
--------------------------------------------------------------------------------
/src/main/java/dsl/UsersTable.kt:
--------------------------------------------------------------------------------
1 | package dsl
2 |
3 | data class User(val id: String, val name: String, val points: Int, val category: String)
4 |
5 | fun usersTable(users: List): TableBuilder = TODO()
6 |
--------------------------------------------------------------------------------
/src/main/java/extra/Permutations.kt:
--------------------------------------------------------------------------------
1 | package extra
2 |
3 | /**
4 | * Permutations are all different ways to arrange elements from some collection (https://en.wikipedia.org/wiki/Permutation).
5 | * For sets it's number is n!, for lists it is n! / (n1! * n2! * ...) where n1, n2... are numbers elements that are the same.
6 | */
7 |
8 | /* This function returns number of all permutations of elements from set. It is equal to n! where n is size of set. */
9 | fun Set.permutationsNumber(): Long = TODO()
10 |
11 | /* This function returns number of all permutations of elements from list. It is equal to n! / (n1! * n2! * ...) where n1, n2... are numbers elements that are the same. */
12 | fun List.permutationsNumber(): Long = TODO()
13 |
14 | /* This function returns all permutations of elements from set. These are different ways to arrange elements from this list. */
15 | fun Set.permutations(): Set> = TODO()
16 |
17 | /* This function returns all permutations of elements from list. These are different ways to arrange elements from this list. */
18 | fun List.permutations(): Set> = TODO()
--------------------------------------------------------------------------------
/src/main/java/extra/Powerset.kt:
--------------------------------------------------------------------------------
1 | package extra
2 |
3 | // Powerset returns set of all subsets including full set and empty set
4 | // https://en.wikipedia.org/wiki/Power_set
5 | fun Collection.powerset(): Set> = TODO()
--------------------------------------------------------------------------------
/src/main/java/functional/Callbacks.kt:
--------------------------------------------------------------------------------
1 | package functional
2 |
3 | import basics.ApiError
4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties
5 | import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
6 | import okhttp3.OkHttpClient
7 | import retrofit2.Call
8 | import retrofit2.Callback
9 | import retrofit2.Response
10 | import retrofit2.Retrofit
11 | import retrofit2.converter.jackson.JacksonConverterFactory
12 | import retrofit2.http.GET
13 | import retrofit2.http.Path
14 | import java.util.*
15 |
16 | fun main() {
17 | val username = ""
18 | val token = ""
19 | val service: GitHubService = createGitHubService(username, token)
20 |
21 | getAggregatedContributions(service) { users ->
22 | val sortedUsers = users.sortedByDescending { it.contributions }
23 | println("Aggregated contributions:")
24 | for ((index, user) in sortedUsers.withIndex()) {
25 | println("$index: ${user.login} with ${user.contributions} contributions")
26 | }
27 | }
28 | }
29 |
30 | fun getAggregatedContributions(service: GitHubService, callback: (List) -> Unit) {
31 | TODO()
32 | }
33 |
34 | interface GitHubService {
35 | fun getOrgRepos(callback: (List) -> Unit)
36 | fun getRepoContributors(repo: String, callback: (List) -> Unit)
37 | }
38 |
39 | fun createGitHubService(username: String, password: String): GitHubService {
40 | val authToken = "Basic " + Base64.getEncoder().encode("$username:$password".toByteArray()).toString(Charsets.UTF_8)
41 | val httpClient = OkHttpClient.Builder()
42 | .addInterceptor { chain ->
43 | val original = chain.request()
44 | val builder = original.newBuilder()
45 | .header("Accept", "application/vnd.github.v3+json")
46 | .header("Authorization", authToken)
47 | val request = builder.build()
48 | chain.proceed(request)
49 | }
50 | .build()
51 |
52 | return Retrofit.Builder()
53 | .baseUrl("https://api.github.com")
54 | .addConverterFactory(JacksonConverterFactory.create(jacksonObjectMapper()))
55 | .client(httpClient)
56 | .build()
57 | .create(GitHubServiceApiDef::class.java)
58 | .let(::GitHubServiceImpl)
59 | }
60 |
61 | class GitHubServiceImpl(val apiService: GitHubServiceApiDef) : GitHubService {
62 | override fun getOrgRepos(callback: (List) -> Unit) =
63 | apiService.getOrgReposCall().onResponse {
64 | callback(it.body() ?: throw ApiError(it.code(), it.message()))
65 | }
66 |
67 | override fun getRepoContributors(repo: String, callback: (List) -> Unit) =
68 | apiService.getRepoContributorsCall(repo).onResponse {
69 | callback(it.body() ?: throw ApiError(it.code(), it.message()))
70 | }
71 | }
72 |
73 | interface GitHubServiceApiDef {
74 | @GET("orgs/jetbrains/repos?per_page=100")
75 | fun getOrgReposCall(): Call>
76 |
77 | @GET("repos/jetbrains/{repo}/contributors?per_page=100")
78 | fun getRepoContributorsCall(
79 | @Path("repo") repo: String
80 | ): Call>
81 | }
82 |
83 | @JsonIgnoreProperties(ignoreUnknown = true)
84 | data class Repo(
85 | val id: Long,
86 | val name: String
87 | )
88 |
89 | @JsonIgnoreProperties(ignoreUnknown = true)
90 | data class User(
91 | val login: String,
92 | val contributions: Int
93 | )
94 |
95 | inline fun Call.onResponse(crossinline callback: (Response) -> Unit) {
96 | enqueue(object : Callback {
97 | override fun onResponse(call: Call, response: Response) {
98 | callback(response)
99 | }
100 |
101 | override fun onFailure(call: Call, t: Throwable) {
102 | throw t
103 | }
104 | })
105 | }
--------------------------------------------------------------------------------
/src/main/java/functional/Functional.kt:
--------------------------------------------------------------------------------
1 | package functional
2 |
3 | class FunctionsClassic {
4 |
5 | fun add(num1: Int, num2: Int): Int = num1 + num2
6 |
7 | fun printNum(num: Int) {
8 | print(num)
9 | }
10 |
11 | fun triple(num: Int): Int = num * 3
12 |
13 | fun longestOf(str1: String, str2: String, str3: String): String = listOf(str1, str2, str3)
14 | .maxByOrNull { it.length }!!
15 | }
16 |
17 | interface FunctionsFunctional {
18 | val add: Any
19 | val printNum: Any
20 | val triple: Any
21 | val longestOf: Any
22 | }
23 |
24 | class AnonymousFunctionalTypeSpecified : FunctionsFunctional {
25 | override val add: (Int, Int) -> Int = fun(num1, num2) = num1 + num2
26 | override val printNum = TODO()
27 | override val triple = TODO()
28 | override val longestOf = TODO()
29 | }
30 |
31 | class AnonymousFunctionalTypeInferred : FunctionsFunctional {
32 | override val add = fun(num1: Int, num2: Int) = num1 + num2
33 | override val printNum = TODO()
34 | override val triple = TODO()
35 | override val longestOf = TODO()
36 | }
37 |
38 | class LambdaFunctionalTypeSpecified : FunctionsFunctional {
39 | override val add: (Int, Int) -> Int = { num1, num2 -> num1 + num2 }
40 | override val printNum = TODO()
41 | override val triple = TODO()
42 | override val longestOf = TODO()
43 | }
44 |
45 | class LambdaFunctionalTypeInferred : FunctionsFunctional {
46 | override val add = { num1: Int, num2: Int -> num1 + num2 }
47 | override val printNum = TODO()
48 | override val triple = TODO()
49 | override val longestOf = TODO()
50 | }
51 |
52 | class FunctionReference : FunctionsFunctional {
53 | override val add: (Int, Int) -> Int = Int::plus
54 | override val printNum: (Int) -> Unit = TODO()
55 | override val triple: (Int) -> Int = TODO()
56 | override val longestOf: (String, String, String) -> String = TODO()
57 | }
58 |
59 | class FunctionMemberReference : FunctionsFunctional {
60 | override val add: (Int, Int) -> Int = this::add
61 | override val printNum: (Int) -> Unit = TODO()
62 | override val triple: (Int) -> Int = TODO()
63 | override val longestOf: (String, String, String) -> String = TODO()
64 |
65 | private fun add(num1: Int, num2: Int): Int = num1 + num2
66 |
67 | private fun printNum(num: Int) {
68 | print(num)
69 | }
70 |
71 | private fun triple(num: Int): Int = num * 3
72 |
73 | private fun longestOf(str1: String, str2: String, str3: String): String = listOf(str1, str2, str3)
74 | .maxByOrNull { it.length }!!
75 | }
76 |
77 | class BoundedFunctionReference : FunctionsFunctional {
78 | private val classic = FunctionsClassic()
79 |
80 | override val add: (Int, Int) -> Int = classic::add
81 | override val printNum: (Int) -> Unit = TODO()
82 | override val triple: (Int) -> Int = TODO()
83 | override val longestOf: (String, String, String) -> String = TODO()
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/functional/Product.kt:
--------------------------------------------------------------------------------
1 | package functional
2 |
3 | fun Iterable.product(): Long = TODO()
--------------------------------------------------------------------------------
/src/main/java/functional/Rational.kt:
--------------------------------------------------------------------------------
1 | package functional
2 |
3 | data class Rational(val numerator: Int, val denominator: Int)
4 |
5 | fun Int.r(): Rational = TODO()
6 | fun Pair.r(): Rational = TODO()
7 |
8 | fun main(args: Array) {
9 | print(1.r())
10 | print((1 to 2).r())
11 | }
--------------------------------------------------------------------------------
/src/main/java/functional/References.kt:
--------------------------------------------------------------------------------
1 | package functional
2 |
3 | fun zeroComplex(): Complex = Complex(0.0, 0.0)
4 | fun makeComplex(real: Double = 0.0, imaginary: Double = 0.0): Complex = Complex(real, imaginary)
5 |
6 | data class Complex(var real: Double, val imaginary: Double) {
7 | fun doubled(): Complex = Complex(this.real * 2, this.imaginary * 2)
8 | fun times(num: Int) = Complex(real * num, imaginary * num)
9 | }
10 |
11 | fun Complex.plus(other: Complex): Complex = Complex(real + other.real, imaginary + other.imaginary)
12 | fun Int.toComplex(): Complex = Complex(this.toDouble(), 0.0)
13 |
14 | fun produceAndPrint(producer: () -> Complex) {
15 | println(producer())
16 | }
17 |
18 | fun main() {
19 | val c0: Complex = zeroComplex()
20 | val c1: Complex = makeComplex(1.0, 2.0)
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/functional/Repeat.kt:
--------------------------------------------------------------------------------
1 | package functional
2 |
3 | fun repeat(times: Int, action: () -> Unit) {
4 |
5 | }
6 |
7 | fun main(args: Array) {
8 | repeat(5) { print("A") } // AAAAA
9 |
10 | // var i = 1
11 | // loop {
12 | // print("A")
13 | // i *= 2
14 | // if(i > 1000) {
15 | // // break
16 | // }
17 | // }
18 | }
--------------------------------------------------------------------------------
/src/main/java/functional/UserDocument.kt:
--------------------------------------------------------------------------------
1 | package functional.document
2 |
3 | class User(
4 | val id: String,
5 | val name: String,
6 | val surname: String,
7 | val age: Int,
8 | val tokens: List
9 | )
10 |
11 | class UserDocument(
12 | val userId: String,
13 | val firstName: String,
14 | val lastName: String,
15 | val age: Int,
16 | val tokens: List
17 | )
18 |
19 | fun User.toUserDocument(): UserDocument = TODO()
20 |
21 | fun UserDocument.toUser(): User = TODO()
--------------------------------------------------------------------------------
/src/main/java/generics/Consumer.kt:
--------------------------------------------------------------------------------
1 | abstract class Consumer {
2 | abstract fun consume(elem: T)
3 | }
4 |
5 | class Printer : Consumer() {
6 | private var toPrint: T? = null
7 |
8 | fun print() {
9 | println("Printing $toPrint")
10 | }
11 |
12 | override fun consume(elem: T) {
13 | toPrint = elem
14 | }
15 | }
16 |
17 | class Sender : Consumer() {
18 | override fun consume(elem: T) {
19 | // ...
20 | }
21 | }
22 |
23 | fun getConsumer(): Consumer = Printer()
24 |
25 | fun sendInt(sender: Sender) {}
26 | fun sendFloat(sender: Sender) {}
27 |
28 | fun main(args: Array) {
29 | val consumer = getConsumer()
30 | consumer.consume(10)
31 |
32 | val sender = Sender()
33 | // sendInt(sender)
34 | // sendFloat(sender)
35 | // val c1: Consumer = Printer()
36 | // val c2: Consumer = Sender()
37 | // val c3: Printer = Printer()
38 | // val c4: Sender = Sender()
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/generics/Generics.kt:
--------------------------------------------------------------------------------
1 | package generics
2 |
3 | class Box(e: T) {
4 | var e: T = e
5 | fun get(): T = e
6 | fun put(e: T) {
7 | this.e = e
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/generics/Response.kt:
--------------------------------------------------------------------------------
1 | package generics
2 |
3 | sealed class Response
4 | class Success(val value: R) : Response()
5 | class Failure(val error: E) : Response()
6 |
7 | fun processResponseInt(response: Response) { /*...*/
8 | }
9 |
10 | fun processResponseString(response: Response) { /*...*/
11 | }
12 |
13 | //fun usage() {
14 | // processResponseInt(Success(1))
15 | // processResponseInt(Failure("ERROR"))
16 | // processResponseString(Success("ERROR"))
17 | // processResponseString(Failure(Error("ERROR")))
18 | //
19 | // val rs1 = Success(1)
20 | // val re1 = Failure(Error())
21 | // val re2 = Failure("Error")
22 | //
23 | // val rs1asNumber: Success = rs1
24 | // val rs1asAny: Success = rs1
25 | //
26 | // val re1asThrowable: Failure = re1
27 | // val re1asAny: Failure = re1
28 | //
29 | // val r1: Response = rs1
30 | // val r2: Response = re1
31 | //
32 | // val r3: Response = rs1
33 | // val r4: Response = re2
34 | //
35 | // val r5: Response = rs1
36 | // val r6: Response = re1
37 | //
38 | // val s = Success(String())
39 | // val s1: Success = s
40 | // val s2: Success = s
41 | //
42 | // val e = Failure(Error())
43 | // val e1: Failure = e
44 | // val e2: Failure = e
45 | //}
46 |
47 |
--------------------------------------------------------------------------------
/src/main/java/javatask/JavaClass.java:
--------------------------------------------------------------------------------
1 | package javatask;
2 |
3 | public class JavaClass {
4 |
5 | public static void main(String[] args) {
6 | // KotlinClass.staticFunction();
7 | // KotlinPerson person = new KotlinPerson("Marcin");
8 | // KotlinPerson person2 = new KotlinPerson();
9 | // KotlinTopLevel.topLevelFunction();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/javatask/JavaPerson.java:
--------------------------------------------------------------------------------
1 | package javatask;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 |
5 | public class JavaPerson {
6 |
7 | @NotNull
8 | private String name;
9 | private int age;
10 |
11 | public JavaPerson(@NotNull String name, int age) {
12 | super();
13 | this.name = name;
14 | this.age = age;
15 | }
16 |
17 | public final boolean isMature() {
18 | return this.age > 18;
19 | }
20 |
21 | @NotNull
22 | public final String getName() {
23 | return this.name;
24 | }
25 |
26 | public final void setName(@NotNull String name) {
27 | this.name = name;
28 | }
29 |
30 | public final int getAge() {
31 | return this.age;
32 | }
33 |
34 | public final void setAge(int var1) {
35 | this.age = var1;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/javatask/KotlinClass.kt:
--------------------------------------------------------------------------------
1 | package javatask
2 |
3 | class KotlinClass {
4 | companion object {
5 | fun staticFunction() {
6 | print("This is staticFunction")
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/src/main/java/javatask/KotlinPerson.kt:
--------------------------------------------------------------------------------
1 | package javatask
2 |
3 | class KotlinPerson(
4 | var name: String = "",
5 | var age: Int = -1
6 | ) {
7 | val isMature: Boolean
8 | get() = age > 18
9 | }
--------------------------------------------------------------------------------
/src/main/java/javatask/TopLevel.kt:
--------------------------------------------------------------------------------
1 | package javatask
2 |
3 | fun topLevelFunction() {
4 | print("This is topLevelFunction")
5 | }
--------------------------------------------------------------------------------
/src/main/java/nullability/MessageUtil.java:
--------------------------------------------------------------------------------
1 | package nullability;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 | import org.jetbrains.annotations.Nullable;
5 |
6 | public class MessageUtil {
7 | public static void sendMessageToClient(@Nullable Client client, @Nullable String message, @NotNull Mailer mailer) {
8 | if (client == null || message == null) return;
9 |
10 | PersonalInfo personalInfo = client.getPersonalInfo();
11 | if (personalInfo == null) return;
12 |
13 | String email = personalInfo.getEmail();
14 | if (email == null) return;
15 |
16 | mailer.sendMessage(email, message);
17 | }
18 | }
--------------------------------------------------------------------------------
/src/main/java/nullability/Task.kt:
--------------------------------------------------------------------------------
1 | package nullability
2 |
3 | class Client(val personalInfo: PersonalInfo?)
4 | class PersonalInfo(val email: String?)
5 |
6 | interface Mailer {
7 | fun sendMessage(email: String, message: String)
8 | }
9 |
10 | // 1. Use Elvis operator for unpacking both values
11 | // 2. Use Elvis operator for unpacking email and smart-casting message
12 | // 3. Use Elvis operator smart-casting email and message
13 | // 4. Use if for smart-casting email and message
14 | // 5. Use if with return for smart-casting email and message
15 | // Optional: 6. Use let for email and message
16 |
17 | /*
18 | Send message if the message, client, personal info and email are not null.
19 | */
20 | fun sendMessageToClient(client: Client?, message: String?, mailer: Mailer) {
21 |
22 | }
--------------------------------------------------------------------------------
/src/main/java/operators/Money.kt:
--------------------------------------------------------------------------------
1 | package operators
2 |
3 | import java.math.BigDecimal
4 |
5 | enum class Currency { EUR, PLN, GBP }
6 |
7 | data class Money(val amount: BigDecimal, val currency: Currency) {
8 | }
9 |
10 | fun main() {
11 | val money1 = Money(10.toBigDecimal(), Currency.EUR)
12 | val money2 = Money(20.toBigDecimal(), Currency.EUR)
13 |
14 | // println(money1 + money2)
15 | }
--------------------------------------------------------------------------------
/src/main/java/types/Relations.kt:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import kotlin.random.Random
4 |
5 | open class Animal
6 | class Dog : Animal()
7 |
8 | fun main() {
9 | val dog: Dog = Dog()
10 | val nullableDog: Dog? = if (Random.nextBoolean()) Dog() else null
11 | val animal: Animal = Animal()
12 | val nullableAnimal: Animal? = if (Random.nextBoolean()) Animal() else null
13 | }
14 |
15 | fun consumeDog(dog: Dog) {}
16 | fun consumeNullableDog(dog: Dog?) {}
17 | fun consumeAnimal(animal: Animal) {}
18 | fun consumeNullableAnimal(animal: Animal?) {}
19 | fun consumeAny(any: Any) {}
20 | fun consumeNullableAny(any: Any?) {}
21 | fun consumeNothing(nothing: Any) {}
22 | fun consumeNullableNothing(nothing: Any?) {}
23 |
--------------------------------------------------------------------------------
/src/main/java/types/Types.kt:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import kotlin.random.Random
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | fun main() {
41 | val a: Int = if (Random.nextBoolean()) 42 else 10
42 |
43 | val message: String = produceMessage() ?: "ABC"
44 |
45 | val grade: Char = when (result) {
46 | in 0 until 50 -> 'F'
47 | in 50 until 65 -> 'D'
48 | in 65 until 80 -> 'C'
49 | in 80 until 90 -> 'B'
50 | in 90..100 -> 'A'
51 | else -> 'X'
52 | }
53 | }
54 |
55 | val result = Random.nextInt(1, 100)
56 | fun produceMessage(): String? = null
57 |
--------------------------------------------------------------------------------
/src/test/java/BasicsTest.kt:
--------------------------------------------------------------------------------
1 | import org.junit.Test
2 | import kotlin.test.assertEquals
3 | import kotlin.test.assertTrue
4 |
5 | @Suppress("FunctionName")
6 | internal class BasicsTest {
7 |
8 | @Test
9 | fun `gcd returnes x for x and x`() {
10 | assertEquals(5, gcd(5, 5))
11 | assertEquals(7, gcd(7, 7))
12 | for (x in 1..100) {
13 | assertEquals(x, gcd(x, x))
14 | }
15 | }
16 |
17 | @Test
18 | fun `gcd returnes 1 when x and y are primes`() {
19 | assertEquals(1, gcd(3, 7))
20 | assertEquals(1, gcd(5, 7))
21 |
22 | for ((x, y) in twoDifferentPrimesPermutations) {
23 | assertEquals(1, gcd(x, y), "Should be 1 for $x and $y, but is ${gcd(x, y)}")
24 | }
25 | }
26 |
27 | @Test
28 | fun `gcd for simple examples`() {
29 | assertEquals(4, gcd(12, 8))
30 | assertEquals(6, gcd(12, 6))
31 | assertEquals(14, gcd(42, 56))
32 | assertEquals(18, gcd(461952, 116298))
33 | assertEquals(32, gcd(7966496, 314080416))
34 | assertEquals(526, gcd(24826148, 45296490))
35 | }
36 |
37 | @Test
38 | fun `gcd x and 0 gives x`() {
39 | assertEquals(12, gcd(12, 0))
40 | assertEquals(0, gcd(0, 0))
41 | assertEquals(9, gcd(0, 9))
42 | }
43 |
44 | @Test
45 | fun `FizzBuzz prints 100 elements`() {
46 | val list = fuzzBuzzPrinted()
47 | assertEquals(100, list.size)
48 | }
49 |
50 | @Test
51 | fun `FizzBuzz starts from 1 and 2`() {
52 | val (first, second) = fuzzBuzzPrinted()
53 | assertEquals("1", first)
54 | assertEquals("2", second)
55 | }
56 |
57 | @Test
58 | fun `Third FizzBuzz element is Fizz`() {
59 | val (_, _, third) = fuzzBuzzPrinted()
60 | assertEquals("Fizz", third)
61 | }
62 |
63 | @Test
64 | fun `Fifth FizzBuzz element is Buzz`() {
65 | val (_, _, _, _, fifth) = fuzzBuzzPrinted()
66 | assertEquals("Buzz", fifth)
67 | }
68 |
69 | @Test
70 | fun `Fifteenth FizzBuzz element is FizzBuzz`() {
71 | val text = fuzzBuzzPrinted()
72 | assertEquals("FizzBuzz", text[14])
73 | }
74 |
75 | @Test
76 | fun `Every third element returns Fizz`() {
77 | val text = fuzzBuzzPrinted()
78 | for (position in positionsForNumbersDividableBy(3)) {
79 | assertTrue("Fizz" in text[position])
80 | }
81 | }
82 |
83 | @Test
84 | fun `Every fifth element returns Fizz`() {
85 | val text = fuzzBuzzPrinted()
86 | for (position in positionsForNumbersDividableBy(5)) {
87 | assertTrue("Buzz" in text[position])
88 | }
89 | }
90 |
91 | @Test
92 | fun `Every fifteenth element returns FizzBuzz`() {
93 | val text = fuzzBuzzPrinted()
94 | for (position in positionsForNumbersDividableBy(15)) {
95 | assertEquals("FizzBuzz", text[position])
96 | }
97 | }
98 |
99 | private fun positionsForNumbersDividableBy(num: Int) =
100 | (1..100).filter { it % num == 0 }.map { it - 1 }
101 |
102 | @Test
103 | fun fizzBuzzTest() {
104 | val text = fuzzBuzzPrinted()
105 | val solution =
106 | "1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n11\nFizz\n13\n14\nFizzBuzz\n16\n17\nFizz\n19\nBuzz\nFizz\n22\n23\nFizz\nBuzz\n26\nFizz\n28\n29\nFizzBuzz\n31\n32\nFizz\n34\nBuzz\nFizz\n37\n38\nFizz\nBuzz\n41\nFizz\n43\n44\nFizzBuzz\n46\n47\nFizz\n49\nBuzz\nFizz\n52\n53\nFizz\nBuzz\n56\nFizz\n58\n59\nFizzBuzz\n61\n62\nFizz\n64\nBuzz\nFizz\n67\n68\nFizz\nBuzz\n71\nFizz\n73\n74\nFizzBuzz\n76\n77\nFizz\n79\nBuzz\nFizz\n82\n83\nFizz\nBuzz\n86\nFizz\n88\n89\nFizzBuzz\n91\n92\nFizz\n94\nBuzz\nFizz\n97\n98\nFizz\nBuzz"
107 | assertEquals(solution, text.joinToString(separator = "\n") { it.trim() })
108 | }
109 |
110 | private fun fuzzBuzzPrinted(): List {
111 | val printedLines = mutableListOf()
112 | val printer = object : Console {
113 | override fun println(text: String) {
114 | printedLines += text
115 | }
116 | }
117 | fizzBuzz(printer)
118 | return printedLines
119 | }
120 |
121 | @Test
122 | fun `fib first numbers`() {
123 | assertEquals(1, fib(0))
124 | assertEquals(1, fib(1))
125 | assertEquals(2, fib(2))
126 | assertEquals(3, fib(3))
127 | assertEquals(5, fib(4))
128 | assertEquals(8, fib(5))
129 | assertEquals(13, fib(6))
130 | assertEquals(21, fib(7))
131 | assertEquals(34, fib(8))
132 | assertEquals(55, fib(9))
133 | assertEquals(89, fib(10))
134 | }
135 |
136 | companion object {
137 | private val somePrimes = listOf(2, 3, 5, 7, 11, 13, 17, 19)
138 |
139 | private val twoDifferentPrimesPermutations = somePrimes
140 | .flatMap { p1 -> somePrimes.map { p2 -> p1 to p2 } }
141 | .filter { (p1, p2) -> p1 != p2 }
142 | }
143 | }
--------------------------------------------------------------------------------
/src/test/java/SendMessageTest.kt:
--------------------------------------------------------------------------------
1 | import org.junit.After
2 | import org.junit.Test
3 | import sendmessage.Email
4 | import sendmessage.EmailAddress
5 | import sendmessage.MessageSender
6 | import sendmessage.MessageService
7 | import kotlin.reflect.full.functions
8 | import kotlin.reflect.typeOf
9 | import kotlin.test.assertEquals
10 | import kotlin.test.assertNotNull
11 |
12 | class SendMessageTest {
13 | private val sender = FakeMessageSender()
14 | private val messageService: MessageService = MessageService(sender)
15 |
16 | @After
17 | fun cleanup() {
18 | sender.clear()
19 | }
20 |
21 | @Test
22 | fun `function with correct name exist`() {
23 | val function = MessageService::class.functions.find { it.name == "sendMessage" }
24 | assertNotNull(function) { "You must define a function with name sendMessage" }
25 | }
26 |
27 | @Test
28 | fun `the function has 3 parameters (+ receiver)`() {
29 | val function = MessageService::class.functions.find { it.name == "sendMessage" }
30 | assertNotNull(function) { "You must define a function with name sendMessage" }
31 | assertEquals(4, function.parameters.size, "Function should have three parameters" )
32 | }
33 |
34 | @Test
35 | fun `the function parameters has correct types`() {
36 | val function = MessageService::class.functions.find { it.name == "sendMessage" }
37 | assertNotNull(function) { "You must define a function with name sendMessage" }
38 | assertEquals(typeOf(), function.parameters[1].type)
39 | assertEquals(typeOf(), function.parameters[2].type)
40 | assertEquals(typeOf(), function.parameters[3].type)
41 | }
42 |
43 | @Test
44 | fun `the function has correct result type`() {
45 | val function = MessageService::class.functions.find { it.name == "sendMessage" }
46 | assertNotNull(function) { "You must define a function with name sendMessage" }
47 | assertEquals(typeOf(), function.returnType)
48 | }
49 |
50 | @Test
51 | fun `the function parameters have correct names`() {
52 | val function = MessageService::class.functions.find { it.name == "sendMessage" }
53 | assertNotNull(function) { "You must define a function with name sendMessage" }
54 | assertEquals("to", function.parameters[1].name)
55 | assertEquals("title", function.parameters[2].name)
56 | assertEquals("content", function.parameters[3].name)
57 | }
58 |
59 | @Test
60 | fun `all parameters of the function have default arguments`() {
61 | val function = MessageService::class.functions.find { it.name == "sendMessage" }
62 | assertNotNull(function) { "You must define a function with name sendMessage" }
63 | assert(function.parameters[1].isOptional)
64 | assert(function.parameters[2].isOptional)
65 | assert(function.parameters[3].isOptional)
66 | }
67 |
68 | @Test
69 | fun `calling the function with no arguments sends empty message to everyone`() {
70 | val function = messageService::class.functions.find { it.name == "sendMessage" }
71 | assertNotNull(function) { "You must define a function with name sendMessage" }
72 | function.callBy(mapOf(function.parameters[0] to messageService))
73 | assertEquals(listOf(
74 | Email(email=EmailAddress(address="alex@gmail.com"), title="", content=""),
75 | Email(email=EmailAddress(address="jake@gmail.com"), title="", content=""),
76 | Email(email=EmailAddress(address="leon@gmail.com"), title="", content=""),
77 | Email(email=EmailAddress(address="ally@gmail.com"), title="", content="")
78 | ), sender.messagesSent)
79 | }
80 |
81 | @Test
82 | fun `calling the function with arguments sends message to concrete email`() {
83 | val function = messageService::class.functions.find { it.name == "sendMessage" }
84 | assertNotNull(function) { "You must define a function with name sendMessage" }
85 | function.callBy(mapOf(
86 | function.parameters[0] to messageService,
87 | function.parameters[1] to "jake@gmail.com",
88 | function.parameters[2] to "Some title",
89 | function.parameters[3] to "Some content",
90 | ))
91 | assertEquals(listOf(
92 | Email(email=EmailAddress(address="jake@gmail.com"), title="Some title", content="Some content"),
93 | ), sender.messagesSent)
94 | }
95 |
96 | class FakeMessageSender: MessageSender {
97 | var messagesSent = listOf()
98 | private set
99 |
100 | override fun sendEmail(email: EmailAddress, title: String, content: String) {
101 | messagesSent += Email(email, title, content)
102 | }
103 |
104 | fun clear() {
105 | messagesSent = emptyList()
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/test/java/Test.kt:
--------------------------------------------------------------------------------
1 | import javax.swing.text.View
2 |
3 | var listeners: List = listOf()
4 | fun addListener(listener: Listener) {
5 | listeners += listener
6 | }
7 | private typealias Listener = (id: Int, current: View, parent: View)->Unit
8 |
9 | fun main() {
10 |
11 | }
--------------------------------------------------------------------------------
/src/test/java/Utils.kt:
--------------------------------------------------------------------------------
1 | import kotlin.test.assertEquals
2 |
3 | inline fun assertThrows(message: String? = null, body: ()->Unit): T {
4 | try {
5 | body()
6 | } catch (throwable: Throwable) {
7 | assert(throwable is T) { "The type of caught exception is not correct. It is $throwable" }
8 | if(message != null) assertEquals(message, throwable.message)
9 | return throwable as T
10 | }
11 | throw AssertionError("Body does not throw exception as expected")
12 | }
--------------------------------------------------------------------------------
/src/test/java/basics/APITest.kt:
--------------------------------------------------------------------------------
1 | package basics
2 |
3 | import assertThrows
4 | import generics.Failure
5 | import generics.Response
6 | import generics.Success
7 | import org.junit.Assert.assertEquals
8 | import org.junit.Test
9 |
10 | class APITest {
11 |
12 | @Test
13 | fun `When asked for a user, correct user is returned`() {
14 | val studentsRepo = FakeStudentRepository()
15 | val analyticsRepository = FakeAnalyticsRepository()
16 | val controller = StudentController(studentsRepo, analyticsRepository)
17 |
18 | assertEquals(StudentAPI("Alec", "Strong"), controller.getStudent(1))
19 | assertEquals(StudentAPI("Jordan", "Peterson"), controller.getStudent(2))
20 | assertEquals(StudentAPI("Joe", "Regan"), controller.getStudent(3))
21 | assertEquals(StudentAPI("Adam", "Savage"), controller.getStudent(4))
22 | }
23 |
24 | @Test
25 | fun `When asked for a user that does not exist, correct error is thrown`() {
26 | val studentsRepo = FakeStudentRepository()
27 | val analyticsRepository = FakeAnalyticsRepository()
28 | val controller = StudentController(studentsRepo, analyticsRepository)
29 |
30 | val err = assertThrows("No user with id 10") { controller.getStudent(10) }
31 | assertEquals("Error code should be 400", 400, err.code)
32 | assertThrows("No user with id 0") { controller.getStudent(0) }
33 | }
34 |
35 | @Test
36 | fun `When asked for a user, ananlytics counter is bumped`() {
37 | val studentsRepo = FakeStudentRepository()
38 | val analyticsRepository = FakeAnalyticsRepository()
39 | val controller = StudentController(studentsRepo, analyticsRepository)
40 |
41 | assertEquals(0, analyticsRepository.getStudentByIdCount(1))
42 | controller.getStudent(1)
43 | assertEquals(1, analyticsRepository.getStudentByIdCount(1))
44 | controller.getStudent(1)
45 | controller.getStudent(1)
46 | assertEquals(3, analyticsRepository.getStudentByIdCount(1))
47 |
48 | assertEquals(0, analyticsRepository.getStudentByIdCount(4))
49 | controller.getStudent(4)
50 | assertEquals(1, analyticsRepository.getStudentByIdCount(4))
51 | assertEquals(3, analyticsRepository.getStudentByIdCount(1))
52 | }
53 |
54 | @Test
55 | fun `When asked for users, all users are returned and they are sorted by surname`() {
56 | val studentsRepo = FakeStudentRepository()
57 | val analyticsRepository = FakeAnalyticsRepository()
58 | val controller = StudentController(studentsRepo, analyticsRepository)
59 |
60 | val ret = controller.getStudents()
61 | val expected = listOf(
62 | StudentAPI("Jordan", "Peterson"),
63 | StudentAPI("Joe", "Regan"),
64 | StudentAPI("Adam", "Savage"),
65 | StudentAPI("Alec", "Strong")
66 | )
67 | assertEquals(expected, ret)
68 | }
69 |
70 | class FakeStudentRepository: StudentRepository {
71 | private val students = listOf(
72 | StudentEntity(1, "Alec", "Strong"),
73 | StudentEntity(2, "Jordan", "Peterson"),
74 | StudentEntity(3, "Joe", "Regan"),
75 | StudentEntity(4, "Adam", "Savage")
76 | )
77 |
78 | override fun findStudent(id: Long): StudentEntity? =
79 | students.firstOrNull { it.id == id }
80 |
81 | override fun findStudentResult(id: Long): Response {
82 | return students.firstOrNull { it.id == id }
83 | ?.let { Success(it) }
84 | ?: Failure(NotFoundException)
85 | }
86 |
87 |
88 | override fun getAllStudents(): List =
89 | students
90 | }
91 |
92 | class FakeAnalyticsRepository: AnalyticsRepository {
93 | // Maps id to count
94 | private val counter: MutableMap = mutableMapOf(1L to 0, 2L to 3, 3L to 5, 4L to 0)
95 |
96 | override fun getStudentByIdCount(id: Long): Int = counter[id] ?: throw Error("No user with such ID")
97 |
98 | override fun setStudentByIdCount(id: Long, count: Int) {
99 | counter[id] = count
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/test/java/basics/FactorialTest.kt:
--------------------------------------------------------------------------------
1 | package basics
2 |
3 | import org.junit.Test
4 | import kotlin.test.assertEquals
5 |
6 | class FactorialTest {
7 |
8 | @Test
9 | fun `Test factorial results`() {
10 | val numberWithFactorial = mapOf(
11 | 0 to 1L,
12 | 1 to 1L,
13 | 2 to 2L,
14 | 3 to 6L,
15 | 4 to 24L,
16 | 10 to 3628800L,
17 | 15 to 1307674368000L,
18 | 20 to 2432902008176640000L
19 | )
20 | for ((i, factorialResult) in numberWithFactorial) {
21 | assertEquals(factorialResult, factorial(i))
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/src/test/java/basics/PersonTest.kt:
--------------------------------------------------------------------------------
1 | package basics
2 |
3 | import org.junit.Assert
4 | import org.junit.Assert.assertTrue
5 | import org.junit.Test
6 |
7 | class PersonTest {
8 |
9 | // @Test
10 | // fun businessmanImplementsPerson() {
11 | // assertTrue("Businessman needs to be a person", Businessman("AAA", 30) is Person)
12 | // }
13 | //
14 | // @Test
15 | // fun studentImplementsPerson() {
16 | // assertTrue("Student needs to be a person", Student("AAA", 30) is Person)
17 | // }
18 | //
19 | // @Test
20 | // fun personCanBuyAlcoholIfOver21() {
21 | // assertTrue("Adult businessman can buy alcohol", Businessman("AAA", 30).canBuyAlcohol)
22 | // assertTrue("Adult businessman can buy alcohol", Businessman("AAA", 21).canBuyAlcohol)
23 | // assertTrue("Young businessman can' buy alcohol", !Businessman("AAA", 19).canBuyAlcohol)
24 | // assertTrue("Young businessman can' buy alcohol", !Businessman("AAA", 17).canBuyAlcohol)
25 | // assertTrue("Adult student can buy alcohol", Student("AAA", 30).canBuyAlcohol)
26 | // assertTrue("Adult student can buy alcohol", Student("AAA", 21).canBuyAlcohol)
27 | // assertTrue("Young student can' buy alcohol", !Student("AAA", 19).canBuyAlcohol)
28 | // assertTrue("Young student can' buy alcohol", !Student("AAA", 17).canBuyAlcohol)
29 | // }
30 | //
31 | // @Test
32 | // fun testBusinessmanHelloText() {
33 | // Assert.assertEquals("Good morning", Businessman("AAA", 30).helloText())
34 | // }
35 | //
36 | // @Test
37 | // fun testStudentHelloText() {
38 | // Assert.assertEquals("Hi", Student("AAA", 30).helloText())
39 | // }
40 | //
41 | // @Test
42 | // fun testStudentGreetText() {
43 | // val name1 = "Some name"
44 | // val name2 = "Another name"
45 | // val student = Student(name1, 12)
46 | // val businessman = Businessman(name2, 12)
47 | // Assert.assertEquals("Hey $name2, I am $name1", Student(name1, 30).cheerText(businessman))
48 | // Assert.assertEquals("Hey $name1, I am $name2", Student(name2, 30).cheerText(student))
49 | // }
50 | //
51 | // @Test
52 | // fun testBusinessmanGreetText() {
53 | // val name1 = "Some name"
54 | // val name2 = "Another name"
55 | // val student = Student(name1, 12)
56 | // val businessman = Businessman(name2, 12)
57 | // Assert.assertEquals("Hello, my name is $name1, nice to see you $name2", Businessman(name1, 30).cheerText(businessman))
58 | // Assert.assertEquals("Hello, my name is $name2, nice to see you $name1", Businessman(name2, 30).cheerText(student))
59 | // }
60 | }
--------------------------------------------------------------------------------
/src/test/java/basics/TreeOperationsTest.kt:
--------------------------------------------------------------------------------
1 | package basics.treeoperations
2 |
3 | import junit.framework.TestCase.assertEquals
4 | import junit.framework.TestCase.assertTrue
5 | import org.junit.Test
6 |
7 | class TreeOperationsTest {
8 | /*
9 | root Node
10 | / \
11 | Node CCC
12 | / \
13 | AAA BBB
14 | */
15 | private val tree1 = Node(Node(Leaf("AAA"), Leaf("BBB")), Leaf("CCC"))
16 |
17 | /*
18 | root Node
19 | / \
20 | Node Node
21 | / \ / \
22 | Node CCC Node CCC
23 | / \ / \
24 | AAA BBB AAA BBB
25 | */
26 | private val tree2 =
27 | Node(Node(Node(Leaf("AAA"), Leaf("BBB")), Leaf("CCC")), Node(Node(Leaf("AAA"), Leaf("BBB")), Leaf("CCC")))
28 |
29 | /*
30 | root Node
31 | / \
32 | Node DDD
33 | / \
34 | Node CCC
35 | / \
36 | AAA BBB
37 | */
38 | private val tree3 = Node(Node(Node(Leaf("AAA"), Leaf("BBB")), Leaf("CCC")), Leaf("DDD"))
39 |
40 | /*
41 | root Node
42 | / \
43 | Node 3
44 | / \
45 | Node 4
46 | / \
47 | 5 3
48 | */
49 | val treeInt = Node(Node(Node(Leaf(5), Leaf(3)), Leaf(4)), Leaf(3))
50 |
51 | // @Test
52 | // fun `Count of a leaf is 1`() {
53 | // assertEquals(1, Leaf("AAA").count())
54 | // }
55 | //
56 | // @Test
57 | // fun `Count of a single node with two leafs is 2`() {
58 | // assertEquals(2, Node(Leaf("AAA"), Leaf("BBB")).count())
59 | // }
60 | //
61 | // @Test
62 | // fun `Count returns number of leafs in the tree`() {
63 | // assertEquals(3, tree1.count())
64 | // assertEquals(6, tree2.count())
65 | // assertEquals(4, tree3.count())
66 | // }
67 | //
68 | // @Test
69 | // fun `countAll of a leaf is 1`() {
70 | // assertEquals(1, Leaf("AAA").countAll())
71 | // }
72 | //
73 | // @Test
74 | // fun `countAll of a single node with two leafs is 3`() {
75 | // assertEquals(3, Node(Leaf("AAA"), Leaf("BBB")).countAll())
76 | // }
77 | //
78 | // @Test
79 | // fun `countAll returns number of leafs in the tree`() {
80 | // assertEquals(5, tree1.countAll())
81 | // }
82 | //
83 | // @Test
84 | // fun `Height of a leaf is 1`() {
85 | // assertEquals(1, Leaf("AAA").height())
86 | // }
87 | //
88 | // @Test
89 | // fun `Height of a single node with two leafs is 2`() {
90 | // assertEquals(2, Node(Leaf("AAA"), Leaf("BBB")).height())
91 | // }
92 | //
93 | // @Test
94 | // // Every level in height is one more to the result
95 | // fun `Height returns the highest distance from the root to a leaf`() {
96 | // assertEquals(3, tree1.height())
97 | // assertEquals(4, tree2.height())
98 | // assertEquals(4, tree3.height())
99 | // }
100 | //
101 | // @Test
102 | // fun `Biggest on leaf returns its element`() {
103 | // assertEquals(1, Leaf(1).biggest())
104 | // assertEquals("Z", Leaf("Z").biggest())
105 | // assertEquals(Float.POSITIVE_INFINITY, Leaf(Float.POSITIVE_INFINITY).biggest())
106 | // }
107 | //
108 | // @Test
109 | // fun biggestTest() {
110 | // assertEquals("CCC", tree1.biggest())
111 | // assertEquals("CCC", tree2.biggest())
112 | // assertEquals("DDD", tree3.biggest())
113 | // assertEquals(5, treeInt.biggest())
114 | // }
115 | //
116 | // @Test
117 | // fun sumTest() {
118 | // assertEquals(15, treeInt.sum())
119 | // }
120 | //
121 | // @Test
122 | // fun `Value of a leaf is in this leaf`() {
123 | // assertTrue(Leaf("AAA").contains("AAA"))
124 | // }
125 | //
126 | // @Test
127 | // fun `Node with leafs contains values of its leafs`() {
128 | // val tree = Node(Leaf("AAA"), Leaf("BBB"))
129 | // assertTrue(tree.contains("AAA"))
130 | // assertTrue(tree.contains("BBB"))
131 | // assertTrue(!tree.contains("CCC"))
132 | // assertTrue(!tree.contains("DDD"))
133 | // }
134 | //
135 | // @Test
136 | // fun `Complex cases`() {
137 | // assertTrue("AAA" in tree1)
138 | // assertTrue("BBB" in tree1)
139 | // assertTrue("CCC" in tree1)
140 | // assertTrue("CCCC" !in tree1)
141 | // assertTrue("D" !in tree1)
142 | //
143 | // assertTrue("AAA" in tree2)
144 | // assertTrue("BBB" in tree2)
145 | // assertTrue("CCC" in tree2)
146 | // assertTrue("CCCC" !in tree2)
147 | // assertTrue("D" !in tree2)
148 | //
149 | //
150 | // assertTrue("AAA" in tree3)
151 | // assertTrue("BBB" in tree3)
152 | // assertTrue("CCC" in tree3)
153 | // assertTrue("DDD" in tree3)
154 | // assertTrue("CCCC" !in tree3)
155 | // assertTrue("D" !in tree3)
156 | // }
157 | //
158 | // @Test
159 | // fun `Plus of two leafs test`() {
160 | // val tree = Leaf("AAA") + Leaf("BBB")
161 | // assertTrue(tree is Node)
162 | // val n = tree as Node
163 | // assertTrue(n.left == Leaf("AAA"))
164 | // assertTrue(n.right == Leaf("BBB"))
165 | // }
166 | //
167 | // @Test
168 | // fun `Plus just places subtrees on the left and right side without copying them`() {
169 | // val tree = tree1 + tree2
170 | // assertTrue(tree is Node)
171 | // val n = tree as Node
172 | // assertTrue(n.left === tree1)
173 | // assertTrue(n.right === tree2)
174 | // }
175 | }
176 |
--------------------------------------------------------------------------------
/src/test/java/collections/BestStudentsListTest.kt:
--------------------------------------------------------------------------------
1 | package collections
2 |
3 | import kotlin.test.assertEquals
4 | import org.junit.Test
5 |
6 | @Suppress("FunctionName")
7 | class BestStudentsListTest {
8 |
9 | @Test
10 | fun `Single student that matches criteria gets biggest internship`() {
11 | val text = listOf(internshipStudent).makeBestStudentsList()
12 | val expected = "Marc Smith, \$5000"
13 | assertEquals(expected, text)
14 | }
15 |
16 | @Test
17 | fun `Single student with too low result doesn't get internship`() {
18 | val text = listOf(studentWithTooLowResultToInternship).makeBestStudentsList()
19 | assertEquals("", text)
20 | }
21 |
22 | @Test
23 | fun `Result 80 is acceptable`() {
24 | val student = Student("Noely", "Peterson", 80.0, 32)
25 | val text = listOf(student).makeBestStudentsList()
26 | assertEquals("Noely Peterson, \$5000", text)
27 | }
28 |
29 | @Test
30 | fun `30 points is acceptable`() {
31 | val student = Student("Noely", "Peterson", 81.0, 30)
32 | val text = listOf(student).makeBestStudentsList()
33 | assertEquals("Noely Peterson, \$5000", text)
34 | }
35 |
36 | @Test
37 | fun `Single student with not enough doesn't get internship`() {
38 | val text = listOf(studentWithNotEnoughPointsForInternship).makeBestStudentsList()
39 | assertEquals("", text)
40 | }
41 |
42 | @Test
43 | fun `Complex test`() {
44 | val text = allStudents.makeBestStudentsList()
45 | val expected = """
46 | Ester Adams, ${'$'}1000
47 | Dior Angel, ${'$'}3000
48 | Oregon Dart, ${'$'}1000
49 | Jack Johnson, ${'$'}1000
50 | James Johnson, ${'$'}1000
51 | Jon Johnson, ${'$'}1000
52 | Naja Marcson, ${'$'}5000
53 | Alex Nolan, ${'$'}1000
54 | Ron Peters, ${'$'}3000
55 | Marc Smith, ${'$'}3000
56 | """.trimIndent()
57 | assertEquals(expected, text)
58 | }
59 | }
--------------------------------------------------------------------------------
/src/test/java/collections/MapTest.kt:
--------------------------------------------------------------------------------
1 | package collections
2 |
3 | import org.junit.*
4 | import org.junit.Assert.*
5 |
6 | // TODO: Uncomment it
7 | //import kotlin.collections.map as stdlibMap
8 |
9 | class MapTest {
10 |
11 | @Test
12 | fun mapTests() {
13 | val numbers = 1..5
14 | val names = listOf("Mike", "Jane", "Marcin", "John", "James")
15 |
16 | val upper = names.map { it.uppercase() }
17 | val doubled = numbers.map { it * 2 }
18 |
19 | assertEquals(listOf("MIKE", "JANE", "MARCIN", "JOHN", "JAMES"), upper)
20 | assertEquals(listOf(2, 4, 6, 8, 10), doubled)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/test/java/collections/PassingStudentsListTest.kt:
--------------------------------------------------------------------------------
1 | package collections
2 |
3 | import org.junit.Test
4 | import kotlin.test.assertEquals
5 |
6 | @Suppress("FunctionName")
7 | class PassingStudentsListTest {
8 |
9 | @Test
10 | fun `Single student that matches criteria is displayed`() {
11 | val text = listOf(internshipStudent).makePassingStudentsListText()
12 | val expected = "Marc Smith, 87.0"
13 | assertEquals(expected, text)
14 | }
15 |
16 | @Test
17 | fun `Single student with too low result doesn't get internship`() {
18 | val text = listOf(studentNotPassingBecauseOfResult).makePassingStudentsListText()
19 | assertEquals("", text)
20 | }
21 |
22 | @Test
23 | fun `15 points is not acceptable`() {
24 | val student = Student("Noely", "Peterson", 81.0, 15)
25 | val text = listOf(student).makePassingStudentsListText()
26 | assertEquals("", text)
27 | }
28 |
29 | @Test
30 | fun `result 50 points is acceptable`() {
31 | val student = Student("Noely", "Peterson", 50.0, 25)
32 | val text = listOf(student).makePassingStudentsListText()
33 | assertEquals("Noely Peterson, 50.0", text)
34 | }
35 |
36 | @Test
37 | fun `Students are displayed in an alphanumerical order sorted by surname and then by name`() {
38 | val students = listOf(
39 | Student(name = "B", surname = "A", result = 81.0, pointsInSemester = 16),
40 | Student(name = "B", surname = "B", result = 82.0, pointsInSemester = 16),
41 | Student(name = "A", surname = "A", result = 83.0, pointsInSemester = 16),
42 | Student(name = "A", surname = "B", result = 84.0, pointsInSemester = 16)
43 | )
44 |
45 | // When
46 | val text = students.makePassingStudentsListText()
47 |
48 | // Then
49 | val expected = """
50 | A A, 83.0
51 | B A, 81.0
52 | A B, 84.0
53 | B B, 82.0
54 | """.trimIndent()
55 | assertEquals(expected, text)
56 | }
57 |
58 | @Test
59 | fun `Single student with not enough doesn't get internship`() {
60 | val text = listOf(studentNotPassingBecauseOfPoints).makePassingStudentsListText()
61 | assertEquals("", text)
62 | }
63 |
64 | @Test
65 | fun `Complex test`() {
66 | val text = allStudents.makePassingStudentsListText()
67 | val expected = """
68 | Ester Adams, 81.0
69 | Dior Angel, 88.5
70 | Oregon Dart, 85.5
71 | Jack Johnson, 85.3
72 | James Johnson, 85.2
73 | Jon Johnson, 85.1
74 | Jamme Lannister, 80.0
75 | Naja Marcson, 100.0
76 | Alex Nolan, 86.0
77 | Ron Peters, 89.0
78 | Noe Peterson, 91.0
79 | Noely Peterson, 91.0
80 | Harry Potter, 80.0
81 | Marc Smith, 87.0
82 | """.trimIndent()
83 | assertEquals(expected, text)
84 | }
85 |
86 | }
--------------------------------------------------------------------------------
/src/test/java/collections/PlusAtTest.kt:
--------------------------------------------------------------------------------
1 | package collections
2 |
3 | import org.junit.Assert.assertTrue
4 | import org.junit.Test
5 | import kotlin.test.assertEquals
6 |
7 | @Suppress("FunctionName")
8 | class PlusAtTest {
9 |
10 | @Test
11 | fun `Simple addition to the middle adds correctly at the position`() {
12 | assertEquals(listOf(1, 2, 7, 3), listOf(1, 2, 3).plusAt(2, 7))
13 | assertEquals(listOf("1", "2", "7", "3"), listOf("1", "2", "3").plusAt(2, "7"))
14 | }
15 |
16 | @Test
17 | fun `When we add at size position, element is added at the end`() {
18 | assertEquals(listOf(1, 2, 3, 7), listOf(1, 2, 3).plusAt(3, 7))
19 | assertEquals(listOf("1", "2", "3", "7"), listOf("1", "2", "3").plusAt(3, "7"))
20 | }
21 |
22 | @Test
23 | fun `When we add at 0, element is added at the beginning`() {
24 | assertEquals(listOf(7, 1, 2, 3), listOf(1, 2, 3).plusAt(0, 7))
25 | assertEquals(listOf("7", "1", "2", "3"), listOf("1", "2", "3").plusAt(0, "7"))
26 | }
27 |
28 | @Test
29 | fun `When we try to insert at illegal position, IllegalArgumentException error is thrown`() {
30 | assertTrue(catchError { listOf(1, 2, 3).plusAt(-1, 7) } is IllegalArgumentException)
31 | assertTrue(catchError { listOf(1, 2, 3).plusAt(8, 7) } is IllegalArgumentException)
32 | assertTrue(catchError { listOf(1, 2, 3).plusAt(10, 7) } is IllegalArgumentException)
33 | assertTrue(catchError { listOf(1, 2, 3).plusAt(100, 7) } is IllegalArgumentException)
34 |
35 | }
36 |
37 | private fun catchError(f: () -> Unit): Throwable? = try {
38 | f()
39 | null
40 | } catch (e: Throwable) {
41 | e
42 | }
43 | }
--------------------------------------------------------------------------------
/src/test/java/collections/QuickSortTest.kt:
--------------------------------------------------------------------------------
1 | package collections
2 |
3 | import org.junit.Test
4 | import java.util.*
5 | import kotlin.test.assertEquals
6 |
7 | @Suppress("FunctionName")
8 | class QuickSortTest {
9 |
10 | @Test
11 | fun `Empty list is sorted`() {
12 | assertEquals(emptyList(), emptyList().quickSort())
13 | }
14 |
15 | @Test
16 | fun `Single element is sorted`() {
17 | assertEquals(listOf(1), listOf(1).quickSort())
18 | }
19 |
20 | @Test
21 | fun `Simple numbers sorting`() {
22 | assertEquals(listOf(1, 2, 3, 5, 6), listOf(3, 2, 5, 1, 6).quickSort())
23 | }
24 |
25 | @Test
26 | fun `Simple String sorting`() {
27 | assertEquals(listOf("A", "B", "C", "D"), listOf("C", "D", "A", "B").quickSort())
28 | }
29 |
30 | @Test
31 | fun `Random list sorting should give the same result as when we use stdlib sorted function`() {
32 | val rand = Random(244252)
33 | val listOfRandomLists = (1..100).map { _ -> (1..100).map { rand.nextInt() } }
34 | for (list: List in listOfRandomLists) {
35 | assertEquals(list.sorted(), list.quickSort())
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/src/test/java/collections/StudentsData.kt:
--------------------------------------------------------------------------------
1 | package collections
2 |
3 | val internshipStudent = Student("Marc", "Smith", 87.0, 32)
4 | val studentWithTooLowResultToInternship = Student("Marcus", "Smith", 37.0, 32)
5 | val studentWithNotEnoughPointsForInternship = Student("Marcello", "Smith", 87.0, 12)
6 | val studentNotPassingBecauseOfResult = Student("Peter", "Jackson", 21.0, 24)
7 | val studentNotPassingBecauseOfPoints = Student("Michael", "Angelo", 71.0, 12)
8 |
9 | val allStudents = listOf(
10 | internshipStudent,
11 | studentWithTooLowResultToInternship,
12 | studentWithNotEnoughPointsForInternship,
13 | studentNotPassingBecauseOfResult,
14 | Student("Noely", "Peterson", 91.0, 22),
15 | studentNotPassingBecauseOfPoints,
16 | Student("Noe", "Samson", 41.0, 18),
17 | Student("Timothy", "Johnson", 51.0, 15),
18 | Student("Noe", "Peterson", 91.0, 22),
19 | Student("Ester", "Adams", 81.0, 30),
20 | Student("Dior", "Angel", 88.5, 38),
21 | Student("Naja", "Marcson", 100.0, 31),
22 | Student("Oregon", "Dart", 85.5, 30),
23 | Student("Ron", "Peters", 89.0, 31),
24 | Student("Harry", "Potter", 80.0, 30),
25 | Student("Sansa", "Stark", 49.5, 14),
26 | Student("Jamme", "Lannister", 80.0, 30),
27 | Student("Alex", "Nolan", 86.0, 33),
28 | Student("Jon", "Johnson", 85.1, 31),
29 | Student("James", "Johnson", 85.2, 31),
30 | Student("Jack", "Johnson", 85.3, 31)
31 | )
--------------------------------------------------------------------------------
/src/test/java/corotuines/CoroutineTest.kt:
--------------------------------------------------------------------------------
1 | package corotuines
2 |
3 | import kotlinx.coroutines.runBlocking
4 | import org.junit.Test
5 |
6 | class CoroutineTest {
7 | @Test
8 | fun testMySuspendingFunction() = runBlocking {
9 | //...
10 | }
11 | }
--------------------------------------------------------------------------------
/src/test/java/corotuines/FibonacciTest.kt:
--------------------------------------------------------------------------------
1 | package coroutines
2 |
3 | import org.junit.Test
4 | import kotlin.test.assertEquals
5 |
6 | @Suppress("FunctionName")
7 | internal class FibonacciTest {
8 |
9 | @Test
10 | fun `First two numbers should be 1 and 1`() {
11 | assertEquals(listOf(1, 1), fibonacci.take(2).toList())
12 | }
13 |
14 | @Test
15 | fun `Check first 11 numbers`() {
16 | assertEquals(listOf(1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89), fibonacci.take(11).toList())
17 | }
18 | }
--------------------------------------------------------------------------------
/src/test/java/corotuines/FlowKataTests.kt:
--------------------------------------------------------------------------------
1 | package corotuines
2 |
3 | import kotlinx.coroutines.delay
4 | import kotlinx.coroutines.flow.flow
5 | import kotlinx.coroutines.flow.*
6 | import kotlinx.coroutines.flow.toList
7 | import kotlinx.coroutines.launch
8 | import kotlinx.coroutines.sync.Mutex
9 | import kotlinx.coroutines.sync.withLock
10 | import kotlinx.coroutines.test.runTest
11 | import org.junit.Test
12 | import java.util.concurrent.atomic.AtomicInteger
13 | import kotlin.test.assertEquals
14 |
15 | @Suppress("FunctionName")
16 | class FlowKataTests {
17 |
18 | @Test()
19 | fun producingUnitsTests() = runTest {
20 | assertEquals(listOf(), producingUnits(0).toList())
21 | assertEquals(listOf(Unit), producingUnits(1).toList())
22 | assertEquals(listOf(Unit, Unit), producingUnits(2).toList())
23 | assertEquals(listOf(Unit, Unit, Unit), producingUnits(3).toList())
24 | for (i in 1..100 step 7) {
25 | assertEquals(List(i) { Unit }, producingUnits(i).toList())
26 | }
27 | }
28 |
29 | @Test()
30 | fun toToggleTests() = runTest {
31 | assertEquals(listOf(), producingUnits(0).toToggle().toList())
32 | assertEquals(listOf(true), producingUnits(1).toToggle().toList())
33 | assertEquals(listOf(true, false), producingUnits(2).toToggle().toList())
34 | assertEquals(listOf(true, false, true), producingUnits(3).toToggle().toList())
35 | assertEquals(listOf(true, false, true, false), producingUnits(4).toToggle().toList())
36 | }
37 |
38 | @Test()
39 | fun toNextNumbersTests() = runTest {
40 | assertEquals(listOf(), producingUnits(0).toNextNumbers().toList())
41 | assertEquals(listOf(1), producingUnits(1).toNextNumbers().toList())
42 | assertEquals(listOf(1, 2), producingUnits(2).toNextNumbers().toList())
43 | assertEquals(listOf(1, 2, 3), producingUnits(3).toNextNumbers().toList())
44 | for (i in 1..100 step 7) {
45 | val list = List(i) { it + 1 }
46 | assertEquals(list, list.map { Unit }.asFlow().toNextNumbers().toList())
47 | }
48 | }
49 |
50 | @Test()
51 | fun withHistoryTests() = runTest {
52 | assertEquals(listOf(listOf()), producingUnits(0).withHistory().toList())
53 | assertEquals(listOf(listOf(), listOf(Unit)), producingUnits(1).withHistory().toList())
54 | assertEquals(listOf(listOf(), listOf(Unit), listOf(Unit, Unit)), producingUnits(2).withHistory().toList())
55 |
56 | assertEquals(
57 | listOf(listOf(), listOf(1), listOf(1, 2)),
58 | producingUnits(2).toNextNumbers().withHistory().toList()
59 | )
60 | assertEquals(
61 | listOf(listOf(), listOf(true), listOf(true, false)),
62 | producingUnits(2).toToggle().withHistory().toList()
63 | )
64 |
65 | val flow = flow {
66 | emit("A")
67 | delay(100)
68 | emit(10)
69 | emit("C")
70 | }
71 | assertEquals(listOf(listOf(), listOf("A"), listOf("A", 10), listOf("A", 10, "C")), flow.withHistory().toList())
72 | }
73 |
74 | @Test()
75 | fun flowDelayEachTests() = runTest {
76 | val emittedNum = AtomicInteger()
77 |
78 | producingUnits(100)
79 | .delayEach(1000)
80 | .onEach { emittedNum.incrementAndGet() }
81 | .launchIn(this)
82 |
83 | assertEquals(0, emittedNum.get())
84 |
85 | // After 1 500ms there should be one element
86 | delay(1_500)
87 | assertEquals(1, emittedNum.get())
88 |
89 | // After another 2 000ms there should be two more elements
90 | delay(2_000)
91 | assertEquals(3, emittedNum.get())
92 |
93 | // After another 12 000ms there should be twelve more elements
94 | delay(12_000)
95 | assertEquals(15, emittedNum.get())
96 | }
97 |
98 | @Test()
99 | fun makeTimerTests() = runTest {
100 | val mutex = Mutex()
101 | var ticked = listOf()
102 | makeTimer(1000, 10, 20)
103 | .onEach {
104 | mutex.withLock { ticked += it }
105 | }
106 | .launchIn(this)
107 |
108 | assertEquals(listOf(10), mutex.withLock { ticked })
109 |
110 | // After 1 500ms there should be one element
111 | delay(1_500)
112 | assertEquals(listOf(10, 11), mutex.withLock { ticked })
113 |
114 | // After another 2 000ms there should be two more elements
115 | delay(2_000)
116 | assertEquals(listOf(10, 11, 12, 13), mutex.withLock { ticked })
117 |
118 | // After another 12 000ms there should be twelve more elements
119 | delay(12_000)
120 | assertEquals((10..20).toList(), mutex.withLock { ticked })
121 | }
122 |
123 | @Test()
124 | fun `makeTimer if delayed in between, do not provide old values but only shows the last one`() = runTest {
125 | val maxValue = 20
126 | val res = makeTimer(100, 1, maxValue)
127 | .onEach {
128 | if (it == 1) delay(50) // To make it clearly after timer delay
129 | // We don't need to check more often than every 0.5s
130 | delay(500)
131 | }
132 | .toList()
133 |
134 | assertEquals(listOf(1, 6, 11, 16, 20), res)
135 | }
136 |
137 | @Test()
138 | fun makeLightSwitchTests() = runTest {
139 | val switchOne = flow {
140 | emit(true)
141 | delay(1000)
142 | emit(false)
143 | delay(10)
144 | emit(true)
145 | delay(500) // 1500
146 | emit(false)
147 | }
148 | val switchTwo = flow {
149 | emit(false)
150 | delay(200)
151 | emit(true)
152 | delay(1000) // 1200
153 | emit(false)
154 | }
155 |
156 | var lightOn = false
157 | launch {
158 | makeLightSwitch(switchOne, switchTwo).collect {
159 | lightOn = it
160 | }
161 | }
162 |
163 | delay(50)
164 | assertEquals(true, lightOn)
165 | delay(200) // 250
166 | assertEquals(false, lightOn)
167 | delay(800) // 1050
168 | assertEquals(false, lightOn)
169 | delay(200) // 1250
170 | assertEquals(true, lightOn)
171 | delay(300) // 1550
172 | assertEquals(false, lightOn)
173 | }
174 |
175 | @Test()
176 | fun makeLightSwitchToggleTests() = runTest {
177 | val switchOne = flow {
178 | emit(Unit)
179 | delay(1000)
180 | emit(Unit)
181 | delay(10)
182 | emit(Unit)
183 | delay(500) // 1500
184 | emit(Unit)
185 | }
186 | val switchTwo = flow {
187 | emit(Unit)
188 | delay(200)
189 | emit(Unit)
190 | delay(1000) // 1200
191 | emit(Unit)
192 | }
193 |
194 | var lightOn = false
195 | launch {
196 | makeLightSwitchToggle(switchOne, switchTwo).collect {
197 | lightOn = it
198 | }
199 | }
200 |
201 | delay(50)
202 | assertEquals(true, lightOn)
203 | delay(200) // 250
204 | assertEquals(false, lightOn)
205 | delay(800) // 1050
206 | assertEquals(false, lightOn)
207 | delay(200) // 1250
208 | assertEquals(true, lightOn)
209 | delay(300) // 1550
210 | assertEquals(false, lightOn)
211 | }
212 |
213 | @Test()
214 | fun polonaisePairingTests() = runTest {
215 | val track1 = flow {
216 | emit(Person("A"))
217 | emit(Person("B"))
218 | delay(1000)
219 | emit(Person("C"))
220 | emit(Person("D"))
221 | }
222 | val track2 = flow {
223 | emit(Person("1"))
224 | delay(600)
225 | emit(Person("2"))
226 | delay(1000)
227 | emit(Person("3"))
228 | }
229 |
230 | val res = polonaisePairing(track1, track2).toList()
231 | val expected = listOf("A" to "1", "B" to "2", "C" to "3").map { Person(it.first) to Person(it.second) }
232 | assertEquals(expected, res)
233 |
234 | var lastPair: Pair? = null
235 | launch {
236 | polonaisePairing(track1, track2).collect { lastPair = it }
237 | }
238 |
239 | assertEquals(Person("A") to Person("1"), lastPair)
240 | delay(200) // 200
241 | assertEquals(Person("A") to Person("1"), lastPair)
242 |
243 | delay(500) // 700
244 | assertEquals(Person("B") to Person("2"), lastPair)
245 | delay(500) // 1200
246 | assertEquals(Person("B") to Person("2"), lastPair)
247 |
248 | delay(500) // 1700
249 | assertEquals(Person("C") to Person("3"), lastPair)
250 | }
251 | }
252 |
--------------------------------------------------------------------------------
/src/test/java/corotuines/Main.kt:
--------------------------------------------------------------------------------
1 | package coroutines
2 |
3 | import kotlinx.coroutines.delay
4 | import kotlinx.coroutines.runBlocking
5 |
6 | fun main(): Unit = runBlocking {
7 | println("Started!")
8 | test()
9 | println("Done.")
10 | }
11 |
12 | suspend fun test() {
13 | delay(1000)
14 | }
--------------------------------------------------------------------------------
/src/test/java/corotuines/SieveTest.kt:
--------------------------------------------------------------------------------
1 | package coroutines
2 |
3 | import org.junit.Test
4 | import kotlin.test.assertEquals
5 |
6 | @Suppress("FunctionName")
7 | class SieveTest {
8 |
9 | @Test
10 | fun `First prime number is 2`() {
11 | assert(2 in primes)
12 | assertEquals(0, primes.indexOf(2))
13 | assertEquals(2, primes.first())
14 | }
15 |
16 | @Test
17 | fun `Second prime number is 3`() {
18 | assert(3 in primes)
19 | assertEquals(1, primes.indexOf(3))
20 | assertEquals(3, primes.take(2).last())
21 | }
22 |
23 | @Test
24 | fun `Third prime number is 5`() {
25 | assert(5 in primes)
26 | assertEquals(2, primes.indexOf(5))
27 | assertEquals(5, primes.take(3).last())
28 | }
29 |
30 | @Test
31 | fun `Check first 10 prime numbers`() {
32 | assertEquals(listOf(2, 3, 5, 7, 11, 13, 17, 19, 23, 29), primes.take(10).toList())
33 | }
34 |
35 | @Test
36 | fun `Check first 100 prime numbers`() {
37 | val first100primes = listOf(
38 | 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
39 | 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
40 | 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
41 | 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443,
42 | 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541
43 | )
44 | assertEquals(first100primes, primes.take(100).toList())
45 | }
46 |
47 | @Test
48 | fun `Prime at 200th position is 1223`() {
49 | assertEquals(1223, primes.take(200).last())
50 | }
51 | }
--------------------------------------------------------------------------------
/src/test/java/corotuines/continuation/ContinuationStealTest.kt:
--------------------------------------------------------------------------------
1 | package continuation
2 |
3 | import org.junit.Test
4 | import kotlin.coroutines.resume
5 | import kotlin.test.assertEquals
6 | import kotlin.test.assertNotNull
7 |
8 | @Suppress("FunctionName")
9 | class ContinuationStealTest {
10 |
11 | private val fakeText = "This is some text"
12 |
13 | class FakeConsole: Console() {
14 | val printed = mutableListOf()
15 |
16 | override fun println(text: Any?) {
17 | printed += text
18 | }
19 | }
20 |
21 | @Test(timeout = 500)
22 | fun `At the beginning function says "Before"`() {
23 | val fakeConsole = FakeConsole()
24 | continuationSteal(fakeConsole)
25 | assertEquals("Before", fakeConsole.printed.first())
26 | }
27 |
28 | @Test(timeout = 500)
29 | fun `At the end function says "After"`() {
30 | val fakeConsole = FakeConsole()
31 | val cont = continuationSteal(fakeConsole)
32 | cont?.resume(fakeText)
33 | assertEquals("After", fakeConsole.printed.last())
34 | }
35 |
36 | @Test(timeout = 500)
37 | fun `In the middle, we suspend function`() {
38 | val fakeConsole = FakeConsole()
39 | val cont = continuationSteal(fakeConsole)
40 | assertEquals(mutableListOf("Before"), fakeConsole.printed)
41 | }
42 |
43 | @Test(timeout = 500)
44 | fun `Function should return continuation`() {
45 | val fakeConsole = FakeConsole()
46 | val cont = continuationSteal(fakeConsole)
47 | assertNotNull(cont)
48 | cont.resume(fakeText)
49 | assertEquals("After", fakeConsole.printed.last())
50 | }
51 |
52 | @Test(timeout = 500)
53 | fun `Only "Before" is printed before resume`() {
54 | val fakeConsole = FakeConsole()
55 | val cont = continuationSteal(fakeConsole)
56 | assertNotNull(cont)
57 | assertEquals("Before", fakeConsole.printed.first())
58 | }
59 |
60 | @Test(timeout = 500)
61 | fun `After resume function should print text to resume`() {
62 | val fakeConsole = FakeConsole()
63 | val cont = continuationSteal(fakeConsole)
64 | cont?.resume(fakeText)
65 | assertEquals(3, fakeConsole.printed.size)
66 | assertEquals(fakeText, fakeConsole.printed[1])
67 | }
68 | }
--------------------------------------------------------------------------------
/src/test/java/corotuines/request/RequestTest.kt:
--------------------------------------------------------------------------------
1 | package corotuines.request
2 |
3 | import kotlinx.coroutines.delay
4 | import kotlinx.coroutines.launch
5 | import kotlinx.coroutines.runBlocking
6 | import kotlinx.coroutines.sync.Mutex
7 | import kotlinx.coroutines.sync.withLock
8 | import org.junit.Test
9 | import kotlin.system.measureTimeMillis
10 |
11 | class RequestTest {
12 |
13 | @Test
14 | fun `Function does return the best student in the semester`() = runBlocking {
15 | val semester = "19L"
16 | val best = Student(2, 95.0, semester)
17 | val repo = ImmediateFakeStudentRepo(listOf(
18 | Student(1, 90.0, semester),
19 | best,
20 | Student(3, 50.0, semester)
21 | ))
22 | val chosen = getBestStudent(semester, repo)
23 | kotlin.test.assertEquals(best, chosen)
24 | }
25 |
26 | @Test
27 | fun `When no students, correct error is thrown`() = runBlocking {
28 | val semester = "19L"
29 | val best = Student(2, 95.0, semester)
30 | val repo = ImmediateFakeStudentRepo(listOf())
31 | assertThrowsError {
32 | val chosen = getBestStudent(semester, repo)
33 | }
34 | }
35 |
36 | @Test
37 | fun `Requests do not wait for each other`() = runBlocking {
38 | val repo = WaitingFakeStudentRepo()
39 | assertTimeAround(1200) {
40 | val chosen = getBestStudent("AAA", repo)
41 | }
42 | }
43 |
44 | @Test
45 | fun `Cancellation works fine`() = runBlocking {
46 | val repo = WaitingFakeStudentRepo()
47 | val job = launch {
48 | val chosen = getBestStudent("AAA", repo)
49 | }
50 | delay(300)
51 | job.cancel()
52 | delay(1000)
53 | kotlin.test.assertEquals(0, repo.returnedStudents)
54 | }
55 |
56 | @Test
57 | fun `When one request has error, all are stopped and error is thrown`() = runBlocking {
58 | val repo = FirstFailingFakeStudentRepo()
59 | assertThrowsError {
60 | getBestStudent("AAA", repo)
61 | }
62 | delay(1000)
63 | kotlin.test.assertEquals(0, repo.studentsReturned, "Looks like some requests were still running after the first one had an error")
64 | }
65 | }
66 |
67 | class ImmediateFakeStudentRepo(
68 | private val students: List
69 | ) : StudentsRepository {
70 |
71 | override suspend fun getStudentIds(semester: String): List =
72 | students.filter { it.semester == semester }
73 | .map { it.id }
74 |
75 | override suspend fun getStudent(id: Int): Student =
76 | students.first { it.id == id }
77 | }
78 |
79 | inline fun assertTimeAround(expectedTime: Int, upperMargin: Int = 100, body: () -> Unit) {
80 | val actualTime = measureTimeMillis(body)
81 | assert(actualTime in expectedTime..(expectedTime + upperMargin)) {
82 | "Operation should take around $expectedTime, but it took $actualTime"
83 | }
84 | }
85 |
86 | inline fun assertThrowsError(body: ()->Unit) {
87 | try {
88 | body()
89 | assert(false) { "There should be an error of type ${T::class.simpleName}" }
90 | } catch (throwable: Throwable) {
91 | if(throwable !is T) {
92 | throw throwable
93 | }
94 | }
95 | }
96 |
97 | class WaitingFakeStudentRepo : StudentsRepository {
98 | var returnedStudents = 0
99 |
100 | override suspend fun getStudentIds(semester: String): List {
101 | delay(200)
102 | return (1..5).toList()
103 | }
104 |
105 | override suspend fun getStudent(id: Int): Student {
106 | delay(1000)
107 | returnedStudents++
108 | return Student(12, 12.0, "AAA")
109 | }
110 | }
111 |
112 | class FirstFailingFakeStudentRepo : StudentsRepository {
113 | var first = true
114 | var studentsReturned = 0
115 | val mutex = Mutex()
116 |
117 | override suspend fun getStudentIds(semester: String): List {
118 | delay(200)
119 | return (1..5).toList()
120 | }
121 |
122 | override suspend fun getStudent(id: Int): Student {
123 | delay(100)
124 | mutex.withLock { // To prevent more than one throwing
125 | if (first) {
126 | first = false
127 | throw FirstFailingError()
128 | }
129 | }
130 | delay(100)
131 | studentsReturned++
132 | return Student(12, 12.0, "AAA")
133 | }
134 |
135 | class FirstFailingError(): Error()
136 | }
--------------------------------------------------------------------------------
/src/test/java/corotuines/ui/BasePresenterTest.kt:
--------------------------------------------------------------------------------
1 | package coroutines.ui
2 |
3 | import kotlinx.coroutines.*
4 | import org.junit.Test
5 | import kotlin.coroutines.CoroutineContext
6 | import kotlin.coroutines.EmptyCoroutineContext
7 | import kotlin.test.assertEquals
8 |
9 | @Suppress("FunctionName")
10 | class BasePresenterTest {
11 |
12 | class FakePresenter(
13 | private val jobInterceptor: (() -> Unit)? = null,
14 | onError: (Throwable) -> Unit = {}
15 | ) : BasePresenter(onError) {
16 |
17 | var cancelledJobs = 0
18 |
19 | fun onCreate() {
20 | // launch {
21 | // try {
22 | // delay(100)
23 | // jobInterceptor?.invoke()
24 | // delay(2000)
25 | // } finally {
26 | // cancelledJobs += 1
27 | // }
28 | // }
29 | // launch {
30 | // try {
31 | // delay(100)
32 | // jobInterceptor?.invoke()
33 | // delay(2000)
34 | // } finally {
35 | // cancelledJobs += 1
36 | // }
37 | // }
38 | }
39 | }
40 |
41 | @Test
42 | fun `onDestroy cancels all jobs`() = runBlocking {
43 | val presenter = FakePresenter()
44 | presenter.onCreate()
45 | delay(200)
46 | presenter.onDestroy()
47 | delay(200)
48 | assertEquals(2, presenter.cancelledJobs)
49 | }
50 |
51 | @Test
52 | fun `Coroutines run on main thread`() = runBlocking {
53 | var threads = listOf()
54 | val presenter = FakePresenter(
55 | jobInterceptor = {
56 | threads += Thread.currentThread()
57 | }
58 | )
59 | presenter.onCreate()
60 | delay(100)
61 | presenter.onDestroy()
62 | delay(100)
63 | threads.forEach {
64 | assert(it.name.startsWith("UIThread")) { "We should switch to UI thread, and now we are on ${it.name}" }
65 | }
66 | }
67 |
68 | @Test
69 | fun `When a job throws an error, it is handled`(): Unit = runBlocking {
70 | val error = Error()
71 | var errors = listOf()
72 | val presenter = FakePresenter(
73 | jobInterceptor = { throw error },
74 | onError = { errors += it }
75 | )
76 | presenter.onCreate()
77 | delay(200)
78 | assertEquals(listOf(error, error), errors)
79 | }
80 | }
--------------------------------------------------------------------------------
/src/test/java/corotuines/ui/CoroutineExceptionHandlingTest.kt:
--------------------------------------------------------------------------------
1 | package coroutines.ui
2 |
3 | import kotlinx.coroutines.delay
4 | import kotlinx.coroutines.launch
5 | import kotlinx.coroutines.runBlocking
6 | import kotlinx.coroutines.supervisorScope
7 | import org.junit.Test
8 | import kotlin.test.assertEquals
9 | import kotlin.test.assertTrue
10 |
11 | @Suppress("FunctionName")
12 | class CoroutineExceptionHandlingTest {
13 |
14 | class FakePresenterForSingleExceptionHandling(val onSecondAction: ()->Unit) : BasePresenter() {
15 |
16 | var cancelledJobs = 0
17 |
18 | fun onCreate() {
19 | // launch {
20 | // delay(100)
21 | // throw Error()
22 | // }
23 | // launch {
24 | // delay(200)
25 | // onSecondAction()
26 | // }
27 | }
28 | }
29 |
30 | @Test
31 | fun `Error on a single coroutine, does not cancel others`() = runBlocking {
32 | var called = false
33 | val presenter = FakePresenterForSingleExceptionHandling(
34 | onSecondAction = { called = true }
35 | )
36 | presenter.onCreate()
37 | delay(300)
38 | assertTrue(called)
39 | }
40 | }
--------------------------------------------------------------------------------
/src/test/java/delegates/LateinitTest.kt:
--------------------------------------------------------------------------------
1 | @file:JvmName("Mutable")
2 |
3 | package delegates
4 |
5 | import org.junit.Test
6 | import java.lang.IllegalArgumentException
7 | import kotlin.properties.ReadWriteProperty
8 | import kotlin.reflect.KProperty
9 | import kotlin.test.assertEquals
10 | import kotlin.test.assertNotNull
11 |
12 |
13 | @Suppress("FunctionName")
14 | class LateinitTest {
15 |
16 | // @Test
17 | // fun `Throws exception if accessed before initialization`() {
18 | // var value: Int by Lateinit()
19 | // val res = runCatching {
20 | // println(value)
21 | // }
22 | // val exception = res.exceptionOrNull()
23 | // assertNotNull(exception)
24 | // assert(exception is IllegalStateException)
25 | // assertEquals("Variable value must be set before it is initialized", exception.message)
26 | //
27 | // var value2: Int by Lateinit()
28 | // val res2 = runCatching {
29 | // println(value2)
30 | // }
31 | // val exception2 = res2.exceptionOrNull()
32 | // assertNotNull(exception2)
33 | // assert(exception2 is IllegalStateException)
34 | // assertEquals("Variable value2 must be set before it is initialized", exception2.message)
35 | // }
36 | //
37 | // @Test
38 | // fun `Behaves like a normal variable for Int`() {
39 | // var value: Int by Lateinit()
40 | // value = 10
41 | // assertEquals(10, value)
42 | // value = 20
43 | // assertEquals(20, value)
44 | // }
45 | //
46 | // @Test
47 | // fun `Behaves like a normal variable for String`() {
48 | // var value: String by Lateinit()
49 | // value = "AAA"
50 | // assertEquals("AAA", value)
51 | // value = "BBB"
52 | // assertEquals("BBB", value)
53 | // }
54 | //
55 | // @Test
56 | // fun `Behaves like a normal variable for nullable String`() {
57 | // var value: String? by Lateinit()
58 | // value = "AAA"
59 | // assertEquals("AAA", value)
60 | // value = null
61 | // assertEquals(null, value)
62 | // value = "BBB"
63 | // assertEquals("BBB", value)
64 | // }
65 | }
--------------------------------------------------------------------------------
/src/test/java/delegates/MutableLazyTest.kt:
--------------------------------------------------------------------------------
1 | @file:JvmName("Mutable")
2 |
3 | package delegates
4 |
5 | import collections.Student
6 | import org.junit.Assert
7 | import org.junit.Test
8 | import kotlin.properties.ReadWriteProperty
9 | import kotlin.reflect.KProperty
10 | import kotlin.system.measureTimeMillis
11 |
12 | @Suppress("FunctionName")
13 | class MutableLazyTest {
14 |
15 | @Test
16 | fun `Do not initialize if initialized`() {
17 | val time = measureTimeMillis {
18 | var game: Game? by mutableLazy { readGameFromSave() }
19 | game = Game()
20 | print(game)
21 | }
22 | assert(time in 0..100)
23 | }
24 |
25 | @Test
26 | fun `Initializes if not initialized`() {
27 | val time = measureTimeMillis {
28 | val game: Game? by mutableLazy { readGameFromSave() }
29 | print(game)
30 | }
31 | assert(time in 450..550)
32 | }
33 |
34 | @Test
35 | fun `Do not initialize again if already initialized`() {
36 | val time = measureTimeMillis {
37 | val game: Game? by mutableLazy { readGameFromSave() }
38 | print(game)
39 | print(game)
40 | print(game)
41 | }
42 | assert(time in 450..550)
43 | }
44 |
45 | @Test
46 | fun `MutableLazy should accept nullable values`() {
47 | val lazy by mutableLazy { null }
48 | Assert.assertNull(lazy)
49 |
50 | var lazy2 by mutableLazy { "A" }
51 | lazy2 = null
52 | Assert.assertNull(lazy2)
53 | }
54 |
55 | private class Game()
56 |
57 | private fun readGameFromSave(): Game? {
58 | Thread.sleep(500)
59 | return Game()
60 | }
61 | }
--------------------------------------------------------------------------------
/src/test/java/dsl/AnnouncementsListTest.kt:
--------------------------------------------------------------------------------
1 | package dsl
2 |
3 | import org.junit.Test
4 | import kotlin.test.assertEquals
5 | import kotlin.test.assertNull
6 |
7 | @Suppress("FunctionName")
8 | class AnnouncementsListTest {
9 |
10 | @Test
11 | fun `Reminders have title "Remember!"`() {
12 | val (r1, _, _, r2, _) = getAnnouncements("", "")
13 | assertEquals(r1.title, "Remember!")
14 | assertEquals(r2.title, "Remember!")
15 | }
16 |
17 | @Test
18 | fun `Info without title fills it with null`() {
19 | val (_, _, _, _, info) = getAnnouncements("", "")
20 | assertNull(info.title)
21 | }
22 |
23 | @Test
24 | fun `Whole announcements list is interpreted correctly`() {
25 | val actual = getAnnouncements("passing", "internships")
26 | val expected = listOf(
27 | Announcement("Remember!", "If you want to receive internship, you need to provide documents till end of September"),
28 | Announcement("Students who are passing:", "passing"),
29 | Announcement("Internships:", "internships"),
30 | Announcement("Remember!", "Work hard whole year and prepare to all classes"),
31 | Announcement(null, "Checking this app periodically will help you be up to date with your university")
32 | )
33 | assertEquals(expected, actual)
34 | }
35 | }
--------------------------------------------------------------------------------
/src/test/java/dsl/HtmlDslTest.kt:
--------------------------------------------------------------------------------
1 | package dsl
2 |
3 | import org.junit.Test
4 | import kotlin.test.assertEquals
5 |
6 | class HtmlDslTest {
7 |
8 | @Test
9 | fun createTableTest() {
10 | @Suppress("SuspiciousCollectionReassignment")
11 | val html = TableBuilder().apply {
12 | trs += TrBuilder().apply {
13 | tds += TdBuilder().apply { text = "A" }
14 | tds += TdBuilder().apply { text = "B" }
15 | }
16 | trs += TrBuilder().apply {
17 | tds += TdBuilder().apply { text = "C" }
18 | tds += TdBuilder().apply { text = "D" }
19 | }
20 | }
21 | assertEquals(html, createTable())
22 | }
23 |
24 | // @Test
25 | // fun `Table can be created and it is empty by default`() {
26 | // @Suppress("SuspiciousCollectionReassignment")
27 | // val expected = TableBuilder()
28 | // val actual = table {}
29 | // assertEquals(expected, actual)
30 | // }
31 | //
32 | // @Test
33 | // fun `Tr can be created and it is empty`() {
34 | // @Suppress("SuspiciousCollectionReassignment")
35 | // val expected = TableBuilder().apply {
36 | // trs += TrBuilder()
37 | // }
38 | // val actual = table {
39 | // tr {}
40 | // }
41 | // assertEquals(expected, actual)
42 | // }
43 | //
44 | // @Test
45 | // fun `Multiple tr can be created`() {
46 | // @Suppress("SuspiciousCollectionReassignment")
47 | // val expected = TableBuilder().apply {
48 | // trs += TrBuilder()
49 | // trs += TrBuilder()
50 | // }
51 | // val actual = table {
52 | // tr {}
53 | // tr {}
54 | // }
55 | // assertEquals(expected, actual)
56 | // }
57 | //
58 | // @Test
59 | // fun `Td can be created and it is empty`() {
60 | // @Suppress("SuspiciousCollectionReassignment")
61 | // val expected = TableBuilder().apply {
62 | // trs += TrBuilder().apply {
63 | // tds += TdBuilder()
64 | // }
65 | // }
66 | // val actual = table {
67 | // tr {
68 | // td {}
69 | // }
70 | // }
71 | // assertEquals(expected, actual)
72 | // }
73 | //
74 | // @Test
75 | // fun dslTestStandard() {
76 | // @Suppress("SuspiciousCollectionReassignment")
77 | // val expected = TableBuilder().apply {
78 | // trs += TrBuilder().apply {
79 | // tds += TdBuilder().apply { text = "A" }
80 | // tds += TdBuilder().apply { text = "B" }
81 | // }
82 | // trs += TrBuilder().apply {
83 | // tds += TdBuilder().apply { text = "C" }
84 | // tds += TdBuilder().apply { text = "D" }
85 | // }
86 | // }
87 | // val actual = table {
88 | // tr {
89 | // td { +"A" }
90 | // td { +"B" }
91 | // }
92 | // tr {
93 | // td { +"C" }
94 | // td { +"D" }
95 | // }
96 | // }
97 | // assertEquals(expected, actual)
98 | // }
99 | //
100 | // @Test
101 | // fun dslTestMoreColons() {
102 | // @Suppress("SuspiciousCollectionReassignment")
103 | // val expected = TableBuilder().apply {
104 | // trs += TrBuilder().apply {
105 | // tds += TdBuilder().apply { text = "A" }
106 | // tds += TdBuilder().apply { text = "B" }
107 | // tds += TdBuilder().apply { text = "C" }
108 | // }
109 | // trs += TrBuilder().apply {
110 | // tds += TdBuilder().apply { text = "C" }
111 | // tds += TdBuilder().apply { text = "D" }
112 | // }
113 | // }
114 | // val actual = table {
115 | // tr {
116 | // td { +"A" }
117 | // td { +"B" }
118 | // td { +"C" }
119 | // }
120 | // tr {
121 | // td { +"C" }
122 | // td { +"D" }
123 | // }
124 | // }
125 | // assertEquals(expected, actual)
126 | // }
127 | }
--------------------------------------------------------------------------------
/src/test/java/dsl/UsersTableTest.kt:
--------------------------------------------------------------------------------
1 | package dsl
2 |
3 | import org.junit.Test
4 | import org.junit.jupiter.api.Assertions.*
5 |
6 | class UsersTableTest {
7 | @Test
8 | fun `should work for empty list`() {
9 | // when
10 | val result = usersTable(listOf())
11 |
12 | // then
13 | val expected = TableBuilder().apply {
14 | trs += TrBuilder().apply {
15 | tds += TdBuilder().apply { text = "Id" }
16 | tds += TdBuilder().apply { text = "Name" }
17 | tds += TdBuilder().apply { text = "Points" }
18 | tds += TdBuilder().apply { text = "Category" }
19 | }
20 | }
21 | assertEquals(expected, result)
22 | }
23 |
24 | @Test
25 | fun `should work for a list with a single element`() {
26 | // given
27 | val users = listOf(
28 | User("1", "Randy", 2, "A"),
29 | )
30 |
31 | // when
32 | val result = usersTable(users)
33 |
34 | // then
35 | val expected = TableBuilder().apply {
36 | trs += TrBuilder().apply {
37 | tds += TdBuilder().apply { text = "Id" }
38 | tds += TdBuilder().apply { text = "Name" }
39 | tds += TdBuilder().apply { text = "Points" }
40 | tds += TdBuilder().apply { text = "Category" }
41 | }
42 | trs += TrBuilder().apply {
43 | tds += TdBuilder().apply { text = "1" }
44 | tds += TdBuilder().apply { text = "Randy" }
45 | tds += TdBuilder().apply { text = "2" }
46 | tds += TdBuilder().apply { text = "A" }
47 | }
48 | }
49 | assertEquals(expected, result)
50 | }
51 |
52 | @Test
53 | fun `should work for a list with multiple users`() {
54 | // given
55 | val users = listOf(
56 | User("1", "Randy", 2, "A"),
57 | User("4", "Andy", 4, "B"),
58 | User("3", "Mandy", 1, "C"),
59 | User("5", "Cindy", 5, "A"),
60 | User("2", "Lindy", 3, "B"),
61 | )
62 |
63 | // when
64 | val result = usersTable(users)
65 |
66 | // then
67 | val expected = TableBuilder().apply {
68 | trs += TrBuilder().apply {
69 | tds += TdBuilder().apply { text = "Id" }
70 | tds += TdBuilder().apply { text = "Name" }
71 | tds += TdBuilder().apply { text = "Points" }
72 | tds += TdBuilder().apply { text = "Category" }
73 | }
74 | for (user in users) {
75 | trs += TrBuilder().apply {
76 | tds += TdBuilder().apply { text = user.id }
77 | tds += TdBuilder().apply { text = user.name }
78 | tds += TdBuilder().apply { text = user.points.toString() }
79 | tds += TdBuilder().apply { text = user.category }
80 | }
81 | }
82 | }
83 | assertEquals(expected, result)
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/test/java/extra/PermutationTest.kt:
--------------------------------------------------------------------------------
1 | package extra
2 |
3 | import basics.factorial
4 | import functional.product
5 | import org.junit.Test
6 | import kotlin.test.assertEquals
7 |
8 | @Suppress("FunctionName")
9 | internal class PermutationTest {
10 |
11 | @Test
12 | fun `Test permutation numbers for Sets with different sizes`() {
13 | val setSizeToPermutations = mapOf(
14 | 0 to 1L,
15 | 1 to 1L,
16 | 2 to 2L,
17 | 3 to 6L,
18 | 4 to 24L
19 | )
20 | for ((setSize, expectedNumber) in setSizeToPermutations) {
21 | val set = (1..setSize).toSet()
22 | assertEquals(expectedNumber, set.permutationsNumber())
23 | }
24 | }
25 |
26 | @Test
27 | fun `Test permutation numbers for Lists with different sizes and different elements`() {
28 | val listSizeToPermutations = mapOf(
29 | 0 to 1L,
30 | 1 to 1L,
31 | 2 to 2L,
32 | 3 to 6L,
33 | 4 to 24L
34 | )
35 | for ((listSize, expectedNumber) in listSizeToPermutations) {
36 | val set = (1..listSize).toList()
37 | assertEquals(expectedNumber, set.permutationsNumber())
38 | }
39 | }
40 |
41 | @Test
42 | fun `Test permutation numbers for Lists with different sizes and same elements`() {
43 | val listToPermutations = mapOf(
44 | listOf(1, 1, 1, 1) to 1L,
45 | listOf(1, 1, 2, 2) to 6L,
46 | listOf(1, 1, 1, 2) to 4L
47 | )
48 | for ((list, expectedNumber) in listToPermutations) {
49 | assertEquals(expectedNumber, list.permutationsNumber())
50 | }
51 | }
52 |
53 | @Test
54 | fun `Get all permutations for different elements`() {
55 | val setToPermutations = mapOf(
56 | setOf() to setOf>(),
57 | setOf(1, 2) to setOf(listOf(1, 2), listOf(2, 1)),
58 | setOf(1, 2, 3) to setOf(listOf(1, 2, 3), listOf(2, 1, 3), listOf(1, 3, 2), listOf(2, 3, 1), listOf(3, 1, 2), listOf(3, 2, 1))
59 | )
60 | for ((set, allExpectedPermutations) in setToPermutations) {
61 | assertEquals(allExpectedPermutations, set.permutations())
62 | }
63 | }
64 |
65 | @Test
66 | fun `Check permutations number in allPermutations for bigger numbers`() {
67 | val set = (1..5).toSet()
68 | assertEquals(set.permutationsNumber(), set.permutations().size.toLong())
69 | }
70 | }
--------------------------------------------------------------------------------
/src/test/java/extra/PowersetTest.kt:
--------------------------------------------------------------------------------
1 | package extra
2 |
3 | import kotlin.test.assertEquals
4 | import org.junit.Test
5 |
6 | @Suppress("FunctionName")
7 | class PowersetTest {
8 |
9 | @Test
10 | fun `Powerset of empty list is only empty list`() {
11 | val emptyList = setOf()
12 | assertEquals(setOf(emptyList), emptyList.powerset())
13 | }
14 |
15 | @Test
16 | fun `Powerset of list with single element is empty list and single element`() {
17 | assertEquals(setOf(setOf(1), setOf()), setOf(1).powerset())
18 | }
19 |
20 | @Test
21 | fun `Powerset simple example test`() {
22 | val set = setOf(
23 | setOf(1, 2, 3),
24 | setOf(1, 2),
25 | setOf(1, 3),
26 | setOf(2, 3),
27 | setOf(1),
28 | setOf(2),
29 | setOf(3),
30 | setOf())
31 | assertEquals(set, setOf(1, 2, 3).powerset())
32 | }
33 |
34 | @Test
35 | fun `Size of n element set powerset is 2^n`() {
36 | for(n in 1..6) {
37 | val set = (1..n).toSet()
38 | val size = 2.pow(n)
39 | assertEquals(size, set.powerset().size)
40 | }
41 | }
42 |
43 | private fun Int.pow(power: Int): Int = Math.pow(this.toDouble(), power.toDouble()).toInt()
44 | }
--------------------------------------------------------------------------------
/src/test/java/functional/CallbacksTest.kt:
--------------------------------------------------------------------------------
1 | package functional
2 |
3 | import org.junit.Test
4 | import kotlin.concurrent.thread
5 | import kotlin.test.assertEquals
6 | import kotlin.test.assertTrue
7 |
8 | @Suppress("FunctionName")
9 | internal class CallbacksTest {
10 | private val user1 = User("AAA", 123)
11 | private val user2 = User("BBB", 1)
12 | private val repo1 = Repo(10, "R1")
13 | private val repo2 = Repo(11, "R2")
14 |
15 | @Test
16 | fun `Function works without errors`() {
17 | getAggregatedContributions(EmptyService) {}
18 | }
19 |
20 | @Test
21 | fun `When no repositories or no users, returns empty lists`() {
22 | var times = 0
23 | getAggregatedContributions(EmptyService) {
24 | times++
25 | }
26 | assertEquals(times, 1)
27 | getAggregatedContributions(FakeStaticSyncService(listOf(), listOf(user1))) {
28 | assertEquals(listOf(), it)
29 | times++
30 | }
31 | assertEquals(times, 2)
32 | getAggregatedContributions(FakeStaticSyncService(listOf(repo1), listOf())) {
33 | assertEquals(listOf(), it)
34 | times++
35 | }
36 | assertEquals(times, 3)
37 | }
38 |
39 | @Test
40 | fun `Lists all unique users`() {
41 | var called = false
42 | getAggregatedContributions(FakeStaticSyncService(listOf(repo1), listOf(user1, user2))) {
43 | assertEquals(listOf(user1, user2), it)
44 | called = true
45 | }
46 | assertTrue(called)
47 | }
48 |
49 | @Test
50 | fun `Accumulates contributions of a single user`() {
51 | var called = false
52 | getAggregatedContributions(FakeStaticSyncService(listOf(repo1), listOf(user1, user1))) {
53 | assertEquals(listOf(User(user1.login, user1.contributions * 2)), it)
54 | called = true
55 | }
56 | assertTrue(called)
57 | }
58 |
59 | @Test
60 | fun `Accumulates contributions of multiple users user`() {
61 | var called = false
62 | getAggregatedContributions(FakeStaticSyncService(listOf(repo1, repo2), listOf(user1, user1, user2))) {
63 | val expected = listOf(
64 | User(user1.login, user1.contributions * 4),
65 | User(user2.login, user2.contributions * 2)
66 | ).sortedBy { it.contributions }
67 | assertEquals(expected, it.sortedBy { it.contributions })
68 | called = true
69 | }
70 | assertTrue(called)
71 | }
72 |
73 | @Test
74 | fun `Prepared for multithreading`() {
75 | val service = FakeDelayedAsyncService(List(100) { repo1 }, List(100) { user1 })
76 | var res = listOf()
77 | getAggregatedContributions(service) { res = it }
78 | Thread.sleep(500)
79 | assertEquals(listOf(User(user1.login, user1.contributions * 100 * 100)), res)
80 | }
81 |
82 | class FakeStaticSyncService(private val repos: List, private val users: List) : GitHubService {
83 | override fun getOrgRepos(callback: (List) -> Unit) {
84 | callback(repos)
85 | }
86 |
87 | override fun getRepoContributors(repo: String, callback: (List) -> Unit) {
88 | callback(users)
89 | }
90 | }
91 |
92 | class FakeDelayedAsyncService(private val repos: List, private val users: List) : GitHubService {
93 |
94 | override fun getOrgRepos(callback: (List) -> Unit) {
95 | thread {
96 | Thread.sleep(DELAY_TIME_MS)
97 | callback(repos)
98 | }
99 | }
100 |
101 | override fun getRepoContributors(repo: String, callback: (List) -> Unit) {
102 | thread {
103 | Thread.sleep(DELAY_TIME_MS)
104 | callback(users)
105 | }
106 | }
107 |
108 | companion object {
109 | val DELAY_TIME_MS = 30L
110 | }
111 | }
112 |
113 | object EmptyService : GitHubService {
114 | override fun getOrgRepos(callback: (List) -> Unit) {
115 | callback(emptyList())
116 | }
117 |
118 | override fun getRepoContributors(repo: String, callback: (List) -> Unit) {
119 | callback(emptyList())
120 | }
121 | }
122 | }
--------------------------------------------------------------------------------
/src/test/java/functional/FunctionalTest.kt:
--------------------------------------------------------------------------------
1 | package functional
2 |
3 | import org.junit.Test
4 | import kotlin.test.assertEquals
5 |
6 | class FunctionalTest {
7 |
8 | @Test
9 | fun testLambdaFunctionalTypeSpecified() {
10 | testFunctions(LambdaFunctionalTypeSpecified())
11 | }
12 |
13 | @Test
14 | fun testLambdaFunctionalTypeInferred() {
15 | testFunctions(LambdaFunctionalTypeInferred())
16 | }
17 |
18 | @Test
19 | fun testAnonymousFunctionalTypeSpecified() {
20 | testFunctions(AnonymousFunctionalTypeSpecified())
21 | }
22 |
23 | @Test
24 | fun testAnonymousFunctionalTypeInferred() {
25 | testFunctions(AnonymousFunctionalTypeInferred())
26 | }
27 |
28 | @Test
29 | fun testFunctionReference() {
30 | testFunctions(FunctionReference())
31 | }
32 |
33 | @Test
34 | fun testFunctionMemberReference() {
35 | testFunctions(FunctionMemberReference())
36 | }
37 |
38 | @Test
39 | fun testBoundedFunctionReference() {
40 | testFunctions(BoundedFunctionReference())
41 | }
42 |
43 | fun testFunctions(obj: FunctionsFunctional) {
44 | assertEquals(3, (obj.add as (Int, Int)->Int)(1, 2))
45 | assertEquals(6, (obj.triple as (Int)->Int)(2))
46 | assertEquals("BBB", (obj.longestOf as (String, String, String)->String)("AA", "BBB", "CC"))
47 | assertEquals("AA", (obj.longestOf as (String, String, String)->String)("AA", "B", "C"))
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/test/java/functional/ObservableValueTest.kt:
--------------------------------------------------------------------------------
1 | package functional
2 |
3 | import org.junit.Test
4 | import kotlin.test.assertEquals
5 |
6 | class ObservableValue(initial: T) {
7 | var value: T = initial
8 |
9 | fun observe(observer: (T) -> Unit) {
10 | TODO()
11 | }
12 | }
13 |
14 | class ObservableValueTest {
15 |
16 | @Test
17 | fun `should behave like regular value`() {
18 | val i = ObservableValue(null)
19 | assertEquals(null, i.value)
20 | i.value = 1
21 | assertEquals(1, i.value)
22 | i.value = 2
23 | assertEquals(2, i.value)
24 | }
25 |
26 | @Test
27 | fun `should call observer when value changes`() {
28 | val o = ObservableValue("A")
29 | val called = mutableListOf()
30 | o.observe { called += it }
31 | o.value = "B"
32 | o.value = "C"
33 | o.value = "D"
34 | assertEquals(listOf("B", "C", "D"), called)
35 | }
36 |
37 | @Test
38 | fun `should call observers when value changes`() {
39 | val o1 = ObservableValue("A")
40 | val o2 = ObservableValue("A")
41 | val history1 = mutableListOf()
42 | o1.observe { history1 += it }
43 | o1.value = "B"
44 | val history2 = mutableListOf()
45 | o1.observe { history2 += it }
46 | val history3 = mutableListOf()
47 | o2.observe { history3 += it }
48 | o1.value = "C"
49 | o1.value = "D"
50 | assertEquals(listOf("B", "C", "D"), history1)
51 | assertEquals(listOf("C", "D"), history2)
52 | assertEquals(listOf(), history3)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/test/java/functional/ProductTest.kt:
--------------------------------------------------------------------------------
1 | package functional
2 |
3 | import org.junit.Test
4 | import kotlin.test.assertEquals
5 |
6 | @Suppress("FunctionName")
7 | internal class ProductTest {
8 |
9 | @Test
10 | fun `Product of empty IntRange is 1`() {
11 | @Suppress("EmptyRange")
12 | assertEquals(1, (0..-1).product())
13 | }
14 |
15 | @Test
16 | fun `Test products of different IntRanges`() {
17 | val rangeToProduct = mapOf(
18 | 2..4 to 24L,
19 | 1..4 to 24L,
20 | 3..4 to 12L,
21 | 100..100 to 100L
22 | )
23 | for ((range, product) in rangeToProduct)
24 | assertEquals(product, range.product())
25 | }
26 |
27 | @Test
28 | fun `Test products of different Int Collections`() {
29 | val collectionToProduct = mapOf(
30 | listOf(1,2,3) to 6L,
31 | listOf(2,3) to 6L,
32 | listOf(3) to 3L,
33 | listOf(10, 10, 10) to 1000L
34 | )
35 | for ((collection, product) in collectionToProduct)
36 | assertEquals(product, collection.product())
37 | }
38 | }
--------------------------------------------------------------------------------
/src/test/java/functional/RationalTest.kt:
--------------------------------------------------------------------------------
1 | package functional
2 |
3 | import org.junit.Test
4 | import kotlin.test.assertEquals
5 |
6 | class RationalTest {
7 | @Test
8 | fun testIntExtension() {
9 | assertEquals(Rational(4, 1), 4.r())
10 | for (i in 1..100) {
11 | assertEquals(Rational(i, 1), i.r())
12 | }
13 | }
14 |
15 | @Test
16 | fun testPairExtension() {
17 | assertEquals(Rational(2, 3), Pair(2, 3).r())
18 |
19 | for (l in 1..10) {
20 | for (r in 1..10) {
21 | val p = Pair(l, r)
22 | assertEquals(Rational(l, r), p.r())
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/test/java/functional/RepeatTest.kt:
--------------------------------------------------------------------------------
1 | package functional
2 |
3 | import org.junit.Assert
4 | import org.junit.Test
5 | import kotlin.repeat as `Do not use it`
6 |
7 | class RepeatTest {
8 |
9 | @Test
10 | fun add3Str() {
11 | var str = ""
12 | repeat(3) {
13 | str += "A"
14 | }
15 | Assert.assertEquals("AAA", str)
16 | }
17 |
18 | @Test
19 | fun add3Int() {
20 | var i = 0
21 | repeat(3) {
22 | i++
23 | }
24 | Assert.assertEquals(3, i)
25 | }
26 |
27 | @Test
28 | fun add0Int() {
29 | var i = 0
30 | repeat(0) {
31 | i++
32 | }
33 | Assert.assertEquals(0, i)
34 | }
35 | }
--------------------------------------------------------------------------------
/src/test/java/nullability/Task.kt:
--------------------------------------------------------------------------------
1 | package nullability
2 |
3 | import org.junit.Test
4 | import kotlin.test.assertEquals
5 |
6 | @Suppress("FunctionName")
7 | internal class NullabilityTaskTests {
8 |
9 | class MailCollector(): Mailer {
10 | data class Mail(val email: String, val message: String)
11 |
12 | var emails = listOf()
13 |
14 | override fun sendMessage(email: String, message: String) {
15 | emails += Mail(email, message)
16 | }
17 | }
18 |
19 | @Test
20 | fun `When client is null, email we do not send email`() {
21 | val mailer = MailCollector()
22 | sendMessageToClient(null, "AAA", mailer)
23 | assertEquals(emptyList(), mailer.emails)
24 | }
25 |
26 | @Test
27 | fun `When message is null, we do not send email`() {
28 | val mailer = MailCollector()
29 | sendMessageToClient(Client(PersonalInfo("AAA")), null, mailer)
30 | assertEquals(emptyList(), mailer.emails)
31 | }
32 |
33 | @Test
34 | fun `When personal info is null, we do not send email`() {
35 | val mailer = MailCollector()
36 | sendMessageToClient(Client(null), "AAA", mailer)
37 | assertEquals(emptyList(), mailer.emails)
38 | }
39 |
40 | @Test
41 | fun `When email address is null, we do not send email`() {
42 | val mailer = MailCollector()
43 | sendMessageToClient(Client(PersonalInfo(null)), null, mailer)
44 | assertEquals(emptyList(), mailer.emails)
45 | }
46 |
47 | @Test
48 | fun `Sends messages correctly for correct values`() {
49 | val mailer = MailCollector()
50 | sendMessageToClient(Client(PersonalInfo("AAA")), "BBB", mailer)
51 | assertEquals(listOf(MailCollector.Mail("AAA", "BBB")), mailer.emails)
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/test/java/nullability/TaskThrowing.kt:
--------------------------------------------------------------------------------
1 | package nullability
2 |
3 | import junit.framework.Assert.*
4 | import org.junit.*
5 |
6 | class NullabilityTaskThrowingTests {
7 |
8 | class MailCollector() : Mailer {
9 | data class Mail(val email: String, val message: String)
10 |
11 | var emails = listOf()
12 |
13 | override fun sendMessage(email: String, message: String) {
14 | emails += Mail(email, message)
15 | }
16 | }
17 |
18 | @Test
19 | fun `When client is null, email is not sent`() {
20 | val mailer = MailCollector()
21 | val res = runCatching { sendMessageToClient(null, "AAA", mailer) }
22 | val exception = res.exceptionOrNull()
23 | assert(exception != null) { "Exception not thrown" }
24 | assert(exception is IllegalArgumentException) { "Exception is $exception, and it should be of type IllegalArgumentException" }
25 | assertEquals(emptyList(), mailer.emails)
26 | }
27 |
28 | @Test
29 | fun `When message is null, email is not sent`() {
30 | val mailer = MailCollector()
31 | val res = runCatching { sendMessageToClient(Client(PersonalInfo("AAA")), null, mailer) }
32 | val exception = res.exceptionOrNull()
33 | assert(exception != null) { "Exception not thrown" }
34 | assert(exception is IllegalArgumentException) { "Exception is $exception, and it should be of type IllegalArgumentException" }
35 | assertEquals(emptyList(), mailer.emails)
36 | }
37 |
38 | @Test
39 | fun `When personal info is null, email is not sent`() {
40 | val mailer = MailCollector()
41 | val res = runCatching { sendMessageToClient(Client(null), "AAA", mailer) }
42 | val exception = res.exceptionOrNull()
43 | assert(exception != null) { "Exception not thrown" }
44 | assert(exception is IllegalArgumentException) { "Exception is $exception, and it should be of type IllegalArgumentException" }
45 | assertEquals(emptyList(), mailer.emails)
46 | }
47 |
48 | @Test
49 | fun `When email is null, email is not sent`() {
50 | val mailer = MailCollector()
51 | val res = runCatching { sendMessageToClient(Client(PersonalInfo(null)), null, mailer) }
52 | val exception = res.exceptionOrNull()
53 | assert(exception != null) { "Exception not thrown" }
54 | assert(exception is IllegalArgumentException) { "Exception is $exception, and it should be of type IllegalArgumentException" }
55 | assertEquals(emptyList(), mailer.emails)
56 | }
57 |
58 | @Test
59 | fun `Sends messages correctly`() {
60 | val mailer = MailCollector()
61 | sendMessageToClient(Client(PersonalInfo("AAA")), "BBB", mailer)
62 | assertEquals(listOf(MailCollector.Mail("AAA", "BBB")), mailer.emails)
63 | }
64 | }
65 |
--------------------------------------------------------------------------------