Started the kotlin track
This commit is contained in:
parent
ce5ea92f79
commit
c0f0c379fa
148
go/robot-simulator/robot.go
Normal file
148
go/robot-simulator/robot.go
Normal file
@ -0,0 +1,148 @@
|
||||
package robot
|
||||
|
||||
import "fmt"
|
||||
|
||||
const testVersion = 3
|
||||
|
||||
// Stuff added for step 1
|
||||
const (
|
||||
N = iota
|
||||
E
|
||||
S
|
||||
W
|
||||
ErrDir
|
||||
)
|
||||
|
||||
func Advance() {
|
||||
switch Step1Robot.Dir {
|
||||
case N:
|
||||
Step1Robot.Y++
|
||||
case E:
|
||||
Step1Robot.X++
|
||||
case S:
|
||||
Step1Robot.Y--
|
||||
case W:
|
||||
Step1Robot.X--
|
||||
}
|
||||
}
|
||||
|
||||
func Left() {
|
||||
switch Step1Robot.Dir {
|
||||
case N:
|
||||
Step1Robot.Dir = W
|
||||
case E:
|
||||
Step1Robot.Dir = N
|
||||
case S:
|
||||
Step1Robot.Dir = E
|
||||
case W:
|
||||
Step1Robot.Dir = S
|
||||
}
|
||||
}
|
||||
|
||||
func Right() {
|
||||
switch Step1Robot.Dir {
|
||||
case N:
|
||||
Step1Robot.Dir = E
|
||||
case E:
|
||||
Step1Robot.Dir = S
|
||||
case S:
|
||||
Step1Robot.Dir = W
|
||||
case W:
|
||||
Step1Robot.Dir = N
|
||||
}
|
||||
}
|
||||
|
||||
func (d Dir) String() string {
|
||||
switch d {
|
||||
case N:
|
||||
return "N"
|
||||
case E:
|
||||
return "E"
|
||||
case S:
|
||||
return "S"
|
||||
default:
|
||||
return "W"
|
||||
}
|
||||
}
|
||||
|
||||
// Stuff added for step 2
|
||||
type Action byte
|
||||
|
||||
func StartRobot(cmd chan Command, act chan Action) {
|
||||
fmt.Println("Starting Robot")
|
||||
for {
|
||||
fmt.Println("Waiting for command")
|
||||
j, more := <-cmd
|
||||
fmt.Println("Received a Command:", j)
|
||||
if more {
|
||||
// Received a command, try to act in the room
|
||||
act <- Action(j)
|
||||
}
|
||||
}
|
||||
fmt.Println("Robot Done")
|
||||
}
|
||||
|
||||
func Room(extent Rect, robot Step2Robot, act chan Action, rep chan Step2Robot) {
|
||||
fmt.Println("Starting Room")
|
||||
for {
|
||||
j, more := <-act
|
||||
if more {
|
||||
// Received an action, try to perform it
|
||||
if j == 'R' { // Turn Right
|
||||
switch robot.Dir {
|
||||
case N:
|
||||
robot.Dir = E
|
||||
case E:
|
||||
robot.Dir = S
|
||||
case S:
|
||||
robot.Dir = W
|
||||
case W:
|
||||
robot.Dir = N
|
||||
}
|
||||
} else if j == 'L' { // Turn Left
|
||||
switch robot.Dir {
|
||||
case N:
|
||||
robot.Dir = W
|
||||
case E:
|
||||
robot.Dir = N
|
||||
case S:
|
||||
robot.Dir = E
|
||||
case W:
|
||||
robot.Dir = S
|
||||
}
|
||||
} else if j == 'A' { // Advance
|
||||
switch robot.Dir {
|
||||
case N:
|
||||
if robot.Pos.Northing < extent.Max.Northing {
|
||||
robot.Pos.Northing++
|
||||
} else {
|
||||
fmt.Println("Hit North Wall")
|
||||
}
|
||||
case E:
|
||||
if robot.Pos.Easting < extent.Max.Easting {
|
||||
robot.Pos.Easting++
|
||||
} else {
|
||||
fmt.Println("Hit East Wall")
|
||||
}
|
||||
case S:
|
||||
if robot.Pos.Northing > extent.Min.Northing {
|
||||
robot.Pos.Northing--
|
||||
} else {
|
||||
fmt.Println("Hit South Wall")
|
||||
}
|
||||
case W:
|
||||
if robot.Pos.Easting > extent.Min.Easting {
|
||||
robot.Pos.Easting--
|
||||
} else {
|
||||
fmt.Println("Hit West Wall")
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Done, report back
|
||||
rep <- robot
|
||||
}
|
||||
}
|
||||
close(rep)
|
||||
fmt.Println("Room Done")
|
||||
}
|
@ -2,7 +2,10 @@
|
||||
|
||||
package robot
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// For step 1 you implement robot movements, but it's not much of a simulation.
|
||||
// For example where in the source code is "the robot"? Where is "the grid"?
|
||||
@ -72,7 +75,9 @@ func TestStep2(t *testing.T) {
|
||||
rep := make(chan Step2Robot)
|
||||
go StartRobot(cmd, act)
|
||||
go Room(Rect{Pos{1, 1}, Pos{2, 2}}, test2[0].Step2Robot, act, rep)
|
||||
fmt.Println("Starting Tests")
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Println("Channeling: ", test2[j])
|
||||
cmd <- test2[j].Command
|
||||
}
|
||||
close(cmd)
|
||||
|
54
go/space-age/README.md
Normal file
54
go/space-age/README.md
Normal file
@ -0,0 +1,54 @@
|
||||
# Space Age
|
||||
|
||||
Given an age in seconds, calculate how old someone would be on:
|
||||
|
||||
- Earth: orbital period 365.25 Earth days, or 31557600 seconds
|
||||
- Mercury: orbital period 0.2408467 Earth years
|
||||
- Venus: orbital period 0.61519726 Earth years
|
||||
- Mars: orbital period 1.8808158 Earth years
|
||||
- Jupiter: orbital period 11.862615 Earth years
|
||||
- Saturn: orbital period 29.447498 Earth years
|
||||
- Uranus: orbital period 84.016846 Earth years
|
||||
- Neptune: orbital period 164.79132 Earth years
|
||||
|
||||
So if you were told someone were 1,000,000,000 seconds old, you should
|
||||
be able to say that they're 31.69 Earth-years old.
|
||||
|
||||
If you're wondering why Pluto didn't make the cut, go watch [this
|
||||
youtube video](http://www.youtube.com/watch?v=Z_2gbGXzFbs).
|
||||
|
||||
## No Stub
|
||||
|
||||
This may be the first Go track exercise you encounter without a stub: a
|
||||
pre-existing `space_age.go` file for your solution. You may not see stubs in
|
||||
the future and should begin to get comfortable with creating your own Go files
|
||||
for your solutions.
|
||||
|
||||
One way to figure out what the function signature(s) you would need is to look
|
||||
at the corresponding \*\_test.go file. It will show you what the package level
|
||||
functions(s) should be that the test will use to verify the solution.
|
||||
|
||||
|
||||
## Running the tests
|
||||
|
||||
To run the tests run the command `go test` from within the exercise directory.
|
||||
|
||||
If the test suite contains benchmarks, you can run these with the `-bench`
|
||||
flag:
|
||||
|
||||
go test -bench .
|
||||
|
||||
Keep in mind that each reviewer will run benchmarks on a different machine, with
|
||||
different specs, so the results from these benchmark tests may vary.
|
||||
|
||||
## Further information
|
||||
|
||||
For more detailed information about the Go track, including how to get help if
|
||||
you're having trouble, please visit the exercism.io [Go language page](http://exercism.io/languages/go/about).
|
||||
|
||||
## Source
|
||||
|
||||
Partially inspired by Chapter 1 in Chris Pine's online Learn to Program tutorial. [http://pine.fm/LearnToProgram/?Chapter=01](http://pine.fm/LearnToProgram/?Chapter=01)
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
61
go/space-age/cases_test.go
Normal file
61
go/space-age/cases_test.go
Normal file
@ -0,0 +1,61 @@
|
||||
package space
|
||||
|
||||
// Source: exercism/problem-specifications
|
||||
// Commit: 8d4df79 space-age: Apply new "input" policy
|
||||
// Problem Specifications Version: 1.1.0
|
||||
|
||||
var testCases = []struct {
|
||||
description string
|
||||
planet Planet
|
||||
seconds float64
|
||||
expected float64
|
||||
}{
|
||||
{
|
||||
description: "age on Earth",
|
||||
planet: "Earth",
|
||||
seconds: 1000000000,
|
||||
expected: 31.69,
|
||||
},
|
||||
{
|
||||
description: "age on Mercury",
|
||||
planet: "Mercury",
|
||||
seconds: 2134835688,
|
||||
expected: 280.88,
|
||||
},
|
||||
{
|
||||
description: "age on Venus",
|
||||
planet: "Venus",
|
||||
seconds: 189839836,
|
||||
expected: 9.78,
|
||||
},
|
||||
{
|
||||
description: "age on Mars",
|
||||
planet: "Mars",
|
||||
seconds: 2329871239,
|
||||
expected: 39.25,
|
||||
},
|
||||
{
|
||||
description: "age on Jupiter",
|
||||
planet: "Jupiter",
|
||||
seconds: 901876382,
|
||||
expected: 2.41,
|
||||
},
|
||||
{
|
||||
description: "age on Saturn",
|
||||
planet: "Saturn",
|
||||
seconds: 3000000000,
|
||||
expected: 3.23,
|
||||
},
|
||||
{
|
||||
description: "age on Uranus",
|
||||
planet: "Uranus",
|
||||
seconds: 3210123456,
|
||||
expected: 1.21,
|
||||
},
|
||||
{
|
||||
description: "age on Neptune",
|
||||
planet: "Neptune",
|
||||
seconds: 8210123456,
|
||||
expected: 1.58,
|
||||
},
|
||||
}
|
25
go/space-age/space_age_test.go
Normal file
25
go/space-age/space_age_test.go
Normal file
@ -0,0 +1,25 @@
|
||||
package space
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAge(t *testing.T) {
|
||||
const precision = 0.01
|
||||
for _, tc := range testCases {
|
||||
actual := Age(tc.seconds, tc.planet)
|
||||
if math.IsNaN(actual) || math.Abs(actual-tc.expected) > precision {
|
||||
t.Fatalf("FAIL: %s\nExpected: %#v\nActual: %#v", tc.description, tc.expected, actual)
|
||||
}
|
||||
t.Logf("PASS: %s", tc.description)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAge(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, tc := range testCases {
|
||||
Age(tc.seconds, tc.planet)
|
||||
}
|
||||
}
|
||||
}
|
BIN
kotlin/hello-world/.gradle/4.8/fileChanges/last-build.bin
Normal file
BIN
kotlin/hello-world/.gradle/4.8/fileChanges/last-build.bin
Normal file
Binary file not shown.
BIN
kotlin/hello-world/.gradle/4.8/fileContent/fileContent.lock
Normal file
BIN
kotlin/hello-world/.gradle/4.8/fileContent/fileContent.lock
Normal file
Binary file not shown.
BIN
kotlin/hello-world/.gradle/4.8/fileHashes/fileHashes.bin
Normal file
BIN
kotlin/hello-world/.gradle/4.8/fileHashes/fileHashes.bin
Normal file
Binary file not shown.
BIN
kotlin/hello-world/.gradle/4.8/fileHashes/fileHashes.lock
Normal file
BIN
kotlin/hello-world/.gradle/4.8/fileHashes/fileHashes.lock
Normal file
Binary file not shown.
Binary file not shown.
BIN
kotlin/hello-world/.gradle/4.8/taskHistory/taskHistory.bin
Normal file
BIN
kotlin/hello-world/.gradle/4.8/taskHistory/taskHistory.bin
Normal file
Binary file not shown.
BIN
kotlin/hello-world/.gradle/4.8/taskHistory/taskHistory.lock
Normal file
BIN
kotlin/hello-world/.gradle/4.8/taskHistory/taskHistory.lock
Normal file
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
#Thu Jun 21 08:10:45 CDT 2018
|
||||
gradle.version=4.8
|
BIN
kotlin/hello-world/.gradle/buildOutputCleanup/outputFiles.bin
Normal file
BIN
kotlin/hello-world/.gradle/buildOutputCleanup/outputFiles.bin
Normal file
Binary file not shown.
@ -1,50 +0,0 @@
|
||||
----
|
||||
# Quick Start Guide
|
||||
|
||||
This guide picks-up where [Running the Tests (in Kotlin)](http://exercism.io/languages/kotlin/tests)
|
||||
left off. If you haven't reviewed those instructions, do so now.
|
||||
|
||||
Need more information? A **step-by-step tutorial** is available in this directory at TUTORIAL.md or you can read
|
||||
the [HTML version](https://github.com/exercism/kotlin/blob/master/exercises/hello-world/TUTORIAL.md).
|
||||
|
||||
The following instructions work equally well on Windows, Mac OS X and Linux.
|
||||
|
||||
## Solve "Hello World"
|
||||
|
||||
Try writing a solution that passes one test at a time, running Gradle each time:
|
||||
|
||||
|
||||
```
|
||||
$ gradle test
|
||||
```
|
||||
|
||||
## Iterate through the tests
|
||||
|
||||
After your first test passes, remove the `@Ignore` from the next test, and iterate on your solution,
|
||||
testing after each change.
|
||||
|
||||
## All the tests pass? Submit your solution!
|
||||
|
||||
With a working solution that we've reviewed, we're ready to submit it to
|
||||
exercism.io.
|
||||
|
||||
```
|
||||
$ exercism submit src/main/kotlin/HelloWorld.kt
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
From here, there are a number of paths you can take.
|
||||
|
||||
1. Move on to the next exercise
|
||||
2. Review (and comment on) others' submissions to this exercise
|
||||
3. Submit another iteration
|
||||
4. Contribute to Exercism
|
||||
|
||||
|
||||
We sincerely hope you learn and enjoy being part of this community. If at any time you need assistance
|
||||
do not hesitate to ask for help:
|
||||
|
||||
http://exercism.io/languages/kotlin/help
|
||||
|
||||
Cheers!
|
@ -1,48 +1,30 @@
|
||||
# Hello World
|
||||
|
||||
Write a function that greets the user by name, or by saying "Hello, World!" if no name is given.
|
||||
The classical introductory exercise. Just say "Hello, World!".
|
||||
|
||||
["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language.
|
||||
["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is
|
||||
the traditional first program for beginning programming in a new language
|
||||
or environment.
|
||||
|
||||
**Note:** You can skip this exercise by running:
|
||||
The objectives are simple:
|
||||
|
||||
exercism skip $LANGUAGE hello-world
|
||||
- Write a function that returns the string "Hello, World!".
|
||||
- Run the test suite and make sure that it succeeds.
|
||||
- Submit your solution and check it at the website.
|
||||
|
||||
## Specification
|
||||
If everything goes well, you will be ready to fetch your first real exercise.
|
||||
|
||||
Write a `Hello World!` function that can greet someone given their name.
|
||||
The function should return the appropriate greeting.
|
||||
Since this is your first Kotlin exercise, we've included a detailed TUTORIAL.md
|
||||
file that guides you through your solution. Check it out for tips and
|
||||
assistance!
|
||||
|
||||
For an input of "Alice", the response should be "Hello, Alice!".
|
||||
|
||||
If a name is not given, the response should be "Hello, World!"
|
||||
|
||||
## Test-Driven Development
|
||||
|
||||
As programmers mature, they eventually want to test their code.
|
||||
|
||||
Here at Exercism we simulate [Test-Driven Development](http://en.wikipedia.org/wiki/Test-driven_development) (TDD), where you write your tests before writing any functionality. The simulation comes in the form of a pre-written test suite, which will signal that you have solved the problem.
|
||||
|
||||
It will also provide you with a safety net to explore other solutions without breaking the functionality.
|
||||
|
||||
### A typical TDD workflow on Exercism:
|
||||
|
||||
1. Run the test file and pick one test that's failing.
|
||||
2. Write some code to fix the test you picked.
|
||||
3. Re-run the tests to confirm the test is now passing.
|
||||
4. Repeat from step 1.
|
||||
5. Submit your solution (`exercism submit /path/to/file`)
|
||||
|
||||
## Instructions
|
||||
|
||||
Submissions are encouraged to be general, within reason. Having said that, it's also important not to over-engineer a solution.
|
||||
|
||||
It's important to remember that the goal is to make code as expressive and readable as we can. However, solutions to the hello-world exercise will not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word.
|
||||
|
||||
|
||||
## Source
|
||||
|
||||
This is an exercise to introduce users to using Exercism [http://en.wikipedia.org/wiki/%22Hello,_world!%22_program](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program)
|
||||
|
||||
## Submitting Incomplete Problems
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
|
@ -1,22 +1,15 @@
|
||||
NOTE: You can also view the HTML version of this file here:
|
||||
https://github.com/exercism/kotlin/blob/master/exercises/hello-world/TUTORIAL.md
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Exercise Structure](#exercise-structure)
|
||||
* [Solving "Hello, World!"](#solving-hello-world)
|
||||
* [Reading Gradle output](#reading-gradle-output)
|
||||
* [Fixing the first failing test](#fixing-the-first-failing-test)
|
||||
* [Enabling and fixing the second test](#enabling-and-fixing-the-second-test)
|
||||
* [Enabling and fixing the third test](#enabling-and-fixing-the-third-test)
|
||||
* [Enabling the last test](#enabling-the-last-test)
|
||||
* [Refactoring](#refactoring)
|
||||
* [Submitting your first iteration](#submitting-your-first-iteration)
|
||||
* [Next Steps](#next-steps)
|
||||
* [Review (and comment on) others' submissions to this exercise](#review-and-comment-on-others-submissions-to-this-exercise)
|
||||
* [Extend an exercise](#extend-an-exercise)
|
||||
* [Contribute to Exercism](#contribute-to-exercism)
|
||||
|
||||
----
|
||||
|
||||
# Solving "Hello, World!"
|
||||
# Introduction
|
||||
|
||||
Welcome to the first exercise on the Kotlin track!
|
||||
|
||||
@ -26,7 +19,7 @@ Each exercise comes with a set of tests. The first pass through the
|
||||
exercise is about getting all of the tests to pass, one at a time.
|
||||
|
||||
If you have not installed the Java Development Kit and Gradle, you must do
|
||||
so now. For help with this, see: http://exercism.io/languages/kotlin/installing
|
||||
so now. For help with this, see: http://exercism.io/languages/kotlin/installation
|
||||
|
||||
----
|
||||
|
||||
@ -35,7 +28,22 @@ left off. If you haven't reviewed those instructions, do so now.
|
||||
|
||||
The following instructions work equally well on Windows, Mac OS X and Linux.
|
||||
|
||||
## Reading Gradle output
|
||||
# Exercise Structure
|
||||
|
||||
When you fetch a new Kotlin exercise, you will receive:
|
||||
|
||||
* __one or more test files__ (always). These live in the `src/test/kotlin`
|
||||
directory and define a set of tests that our solution must satisfy before we
|
||||
can safely declare that it is working.
|
||||
* __one or more starter files__ (initially). If provided, these live in the
|
||||
`src/main/kotlin` directory and define shells of the classes you will need
|
||||
in order to solve the current problem.
|
||||
|
||||
|
||||
|
||||
# Solving "Hello World!"
|
||||
|
||||
## Step 1: Run the tests against the starter solution
|
||||
|
||||
Use Gradle to run the tests:
|
||||
|
||||
@ -84,19 +92,14 @@ running the task you asked it to: executing the tests against the solution.
|
||||
```
|
||||
:test
|
||||
|
||||
HelloWorldTest > helloSampleName SKIPPED
|
||||
|
||||
HelloWorldTest > helloBlankName SKIPPED
|
||||
|
||||
HelloWorldTest > helloNoName FAILED
|
||||
HelloWorldTest > helloWorldTest FAILED
|
||||
org.junit.ComparisonFailure: expected:<[Hello, World!]> but was:<[]>
|
||||
at org.junit.Assert.assertEquals(Assert.java:115)
|
||||
at org.junit.Assert.assertEquals(Assert.java:144)
|
||||
at HelloWorldTest.helloNoName(HelloWorldTest.kt:10)
|
||||
|
||||
HelloWorldTest > helloAnotherSampleName SKIPPED
|
||||
|
||||
4 tests completed, 1 failed, 3 skipped
|
||||
1 test completed, 1 failed
|
||||
:test FAILED
|
||||
|
||||
FAILURE: Build failed with an exception.
|
||||
@ -113,19 +116,19 @@ BUILD FAILED
|
||||
Total time: 7.473 secs
|
||||
```
|
||||
|
||||
Seeing the word "fail" NINE TIMES might give you the impression you've done
|
||||
Seeing the word "fail" might give you the impression you've done
|
||||
something horribly wrong! You haven't. It's a whole lot of noise over
|
||||
a single test not passing.
|
||||
|
||||
Let's focus in on the important bits:
|
||||
|
||||
```
|
||||
HelloWorldTest > helloNoName FAILED
|
||||
HelloWorldTest > helloWorldTest FAILED
|
||||
org.junit.ComparisonFailure: expected:<[Hello, World!]> but was:<[]>
|
||||
```
|
||||
|
||||
...is read: "Within the test class named `HelloWorldTest`, the test method
|
||||
`helloNoName` did not pass because the solution did not satisfy an
|
||||
`helloWorldTest` did not pass because the solution did not satisfy an
|
||||
assertion. Apparently, we expected to see the string 'Hello, World!' but
|
||||
a blank string was returned instead.
|
||||
|
||||
@ -133,7 +136,7 @@ The last line of the stack trace tells us exactly where this unsatisfied
|
||||
assertion lives:
|
||||
|
||||
```
|
||||
at HelloWorldTest.helloNoName(HelloWorldTest.kt:10)
|
||||
at HelloWorldTest.helloWorldTest(HelloWorldTest.kt:10)
|
||||
```
|
||||
|
||||
Looks like the scene of the crime is on line 10 in the test file.
|
||||
@ -145,25 +148,22 @@ Knowing these two facts,
|
||||
|
||||
we can turn this failure into success.
|
||||
|
||||
|
||||
|
||||
## Fixing the first failing test
|
||||
## Step 2: Fix the Test!
|
||||
|
||||
In your favorite text editor, open `src/test/kotlin/HelloWorldTest.kt`
|
||||
and go to line 10.
|
||||
|
||||
```kotlin
|
||||
assertEquals("Hello, World!", hello(""))
|
||||
assertEquals("Hello, World!", hello())
|
||||
```
|
||||
|
||||
The test is expecting that `hello()`, when given an empty string (`""`),
|
||||
returns "Hello, World!". Instead, `hello()` is returning `""`.
|
||||
The test is expecting that `hello()`, returns "Hello, World!". Instead, `hello()` is returning `""`.
|
||||
Let's fix that.
|
||||
|
||||
Open `src/main/kotlin/HelloWorld.kt`.
|
||||
|
||||
```kotlin
|
||||
fun hello(name: String = ""): String {
|
||||
fun hello(): String {
|
||||
return ""
|
||||
}
|
||||
```
|
||||
@ -171,7 +171,7 @@ fun hello(name: String = ""): String {
|
||||
Let's change that to return the expected string:
|
||||
|
||||
```kotlin
|
||||
fun hello(name: String = ""): String {
|
||||
fun hello(): String {
|
||||
return "Hello, World!"
|
||||
}
|
||||
```
|
||||
@ -181,7 +181,6 @@ Save the file and run the tests again:
|
||||
```
|
||||
$ gradle test
|
||||
:compileKotlin
|
||||
w: /Users/jtigger/exercism/exercises/kotlin/hello-world/src/main/kotlin/HelloWorld.kt: (1, 11): Parameter 'name' is never used
|
||||
:compileJava UP-TO-DATE
|
||||
:copyMainKotlinClasses
|
||||
:processResources UP-TO-DATE
|
||||
@ -193,419 +192,18 @@ w: /Users/jtigger/exercism/exercises/kotlin/hello-world/src/main/kotlin/HelloWor
|
||||
:testClasses UP-TO-DATE
|
||||
:test
|
||||
|
||||
HelloWorldTest > helloSampleName SKIPPED
|
||||
|
||||
HelloWorldTest > helloBlankName SKIPPED
|
||||
|
||||
HelloWorldTest > helloNoName PASSED
|
||||
|
||||
HelloWorldTest > helloAnotherSampleName SKIPPED
|
||||
HelloWorldTest > helloWorldTest PASSED
|
||||
|
||||
BUILD SUCCESSFUL
|
||||
|
||||
Total time: 7.318 secs
|
||||
```
|
||||
|
||||
"BUILD SUCCESSFUL"! Woohoo! :) You can see that `helloNoName()` test is
|
||||
"BUILD SUCCESSFUL"! Woohoo! :) You can see that `helloWorldTest()` test is
|
||||
now passing.
|
||||
|
||||
We still see the warning about `name` not being used; we'll get to that
|
||||
next.
|
||||
|
||||
With one win under our belt, we can turn our focus to some other messages
|
||||
that we've been ignoring: the lines ending in "`SKIPPED`".
|
||||
|
||||
Each test suite contains a series of tests, all of which have been marked
|
||||
to be skipped/ignored except the first one. We did this to help you focus
|
||||
on getting one test running at a time.
|
||||
|
||||
Let's tackle the next test...
|
||||
|
||||
|
||||
|
||||
## Enabling and fixing the second test
|
||||
|
||||
Right now, that second test is being skipped/ignored. Let's enable it.
|
||||
|
||||
(Re)open `src/test/kotlin/HelloWorldTest.kt` and find the second test:
|
||||
|
||||
```kotlin
|
||||
@Test
|
||||
@Ignore
|
||||
fun helloSampleName() {
|
||||
assertEquals("Hello, Alice!", hello("Alice"))
|
||||
}
|
||||
```
|
||||
|
||||
When the JUnit test runner sees that `@Ignore` annotation on the test
|
||||
method, it knows to skip over that test. Remove that line:
|
||||
|
||||
```kotlin
|
||||
@Test
|
||||
fun helloSampleName() {
|
||||
assertEquals("Hello, Alice!", hello("Alice"))
|
||||
}
|
||||
```
|
||||
|
||||
Now, when you run the tests, both tests run:
|
||||
|
||||
```
|
||||
$ gradle test
|
||||
:test
|
||||
|
||||
HelloWorldTest > helloSampleName FAILED
|
||||
org.junit.ComparisonFailure: expected:<Hello, [Alice]!> but was:<Hello, [World]!>
|
||||
at org.junit.Assert.assertEquals(Assert.java:115)
|
||||
at org.junit.Assert.assertEquals(Assert.java:144)
|
||||
at HelloWorldTest.helloSampleName(HelloWorldTest.kt:15)
|
||||
|
||||
HelloWorldTest > helloBlankName SKIPPED
|
||||
|
||||
HelloWorldTest > helloNoName PASSED
|
||||
|
||||
HelloWorldTest > helloAnotherSampleName SKIPPED
|
||||
|
||||
4 tests completed, 1 failed, 2 skipped
|
||||
```
|
||||
|
||||
The first test, `helloNoName()` continues to pass. We see that
|
||||
`helloSampleName` -- the test we just un-`@Ignore`'d -- is now running and
|
||||
failing. Yay, failing test! In fact, the "failure" message is just
|
||||
describing the difference between what the program does now and what it
|
||||
should do for us to call it "done."
|
||||
|
||||
Right now, we've hardcoded the greeting. Enabling this second test has
|
||||
unleashed a new expectation: that our program incorporate a name given
|
||||
into that greeting. When given the name "`Alice`", that's who should be
|
||||
greeted instead of "`World`".
|
||||
|
||||
(Re)open `src/main/kotlin/HelloWorld.kt`.
|
||||
|
||||
```kotlin
|
||||
fun hello(name: String = ""): String {
|
||||
return "Hello, World!"
|
||||
}
|
||||
```
|
||||
|
||||
While `hello()` does accept a reference to a string named `name`, it is not
|
||||
using it in the output. Let's change that:
|
||||
|
||||
|
||||
```kotlin
|
||||
fun hello(name: String = ""): String {
|
||||
return "Hello, $name!"
|
||||
}
|
||||
```
|
||||
|
||||
_(Kotlin allows you to embed expressions within strings, a feature known as
|
||||
string interpolation. For more about this feature, see
|
||||
https://kotlinlang.org/docs/reference/basic-types.html#string-templates )_
|
||||
|
||||
... and rerun the tests ...
|
||||
|
||||
```
|
||||
$ gradle test
|
||||
:test
|
||||
|
||||
HelloWorldTest > helloSampleName PASSED
|
||||
|
||||
HelloWorldTest > helloBlankName SKIPPED
|
||||
|
||||
HelloWorldTest > helloNoName FAILED
|
||||
org.junit.ComparisonFailure: expected:<Hello, [World]!> but was:<Hello, []!>
|
||||
at org.junit.Assert.assertEquals(Assert.java:115)
|
||||
at org.junit.Assert.assertEquals(Assert.java:144)
|
||||
at HelloWorldTest.helloNoName(HelloWorldTest.kt:10)
|
||||
|
||||
HelloWorldTest > helloAnotherSampleName SKIPPED
|
||||
|
||||
4 tests completed, 1 failed, 2 skipped
|
||||
```
|
||||
|
||||
Wait... didn't we just fix the test? Why is it failing? Take a closer look...
|
||||
|
||||
In fact, `helloSampleName()` *is* passing. It's just that at the same time,
|
||||
we just inadvertently broke that first test: `helloNoName()`.
|
||||
|
||||
This is one tiny example of the benefit of maintaining a test suite: if we
|
||||
use them to drive out our code, the second we break the program the tests
|
||||
say so. Since we saw them passing just *before* our latest change,
|
||||
whatever we *just* did most likely cause that regression.
|
||||
|
||||
Our latest change was making the greeting dependent on the name given. If
|
||||
no name is given, our function defaults to an empty string. The intent is
|
||||
that when `hello()` is called on no one in particular, our function greets
|
||||
the whole world. Sound like a job for a default value!
|
||||
|
||||
`src/main/kotlin/HelloWorld.kt`:
|
||||
```kotlin
|
||||
fun hello(name: String = "World"): String {
|
||||
return "Hello, $name!"
|
||||
}
|
||||
```
|
||||
|
||||
... and re-run the tests ...
|
||||
|
||||
```
|
||||
$ gradle test
|
||||
:compileKotlin
|
||||
:compileJava UP-TO-DATE
|
||||
:copyMainKotlinClasses
|
||||
:processResources UP-TO-DATE
|
||||
:classes UP-TO-DATE
|
||||
:compileTestKotlin
|
||||
:compileTestJava UP-TO-DATE
|
||||
:copyTestKotlinClasses
|
||||
:processTestResources UP-TO-DATE
|
||||
:testClasses UP-TO-DATE
|
||||
:test
|
||||
|
||||
HelloWorldTest > helloSampleName PASSED
|
||||
|
||||
HelloWorldTest > helloBlankName SKIPPED
|
||||
|
||||
HelloWorldTest > helloNoName PASSED
|
||||
|
||||
HelloWorldTest > helloAnotherSampleName SKIPPED
|
||||
|
||||
BUILD SUCCESSFUL
|
||||
```
|
||||
|
||||
Excellent! Not only are both our tests passing, but that pesky warning
|
||||
about not using `name` has faded into the distant past. We're now
|
||||
(at least) three-fourth the way done. Just two more tests to go...
|
||||
|
||||
|
||||
|
||||
## Enabling and fixing the third test
|
||||
|
||||
(Re)open `src/test/kotlin/HelloWorldTest.kt` and find the penultimate test:
|
||||
|
||||
```kotlin
|
||||
@Test
|
||||
@Ignore
|
||||
fun helloBlankName() {
|
||||
assertEquals("Hello, World!", hello(" "))
|
||||
}
|
||||
```
|
||||
|
||||
In this test, we're trying to be tricky. It's one thing to omit a
|
||||
parameter completely; it's a whole other situation when we provide a blank
|
||||
string for a name. This test is telling us that we'd like to treat these
|
||||
cases the same way.
|
||||
|
||||
... and remove it's `@Ignore` to enable it ...
|
||||
|
||||
```kotlin
|
||||
@Test
|
||||
fun helloBlankName() {
|
||||
assertEquals("Hello, World!", hello(" "))
|
||||
}
|
||||
```
|
||||
|
||||
... and re-run the tests ...
|
||||
|
||||
```
|
||||
$ gradle test
|
||||
:test
|
||||
|
||||
HelloWorldTest > helloSampleName PASSED
|
||||
|
||||
HelloWorldTest > helloBlankName FAILED
|
||||
org.junit.ComparisonFailure: expected:<Hello, [World]!> but was:<Hello, [ ]!>
|
||||
at org.junit.Assert.assertEquals(Assert.java:115)
|
||||
at org.junit.Assert.assertEquals(Assert.java:144)
|
||||
at HelloWorldTest.helloBlankName(HelloWorldTest.kt:20)
|
||||
|
||||
HelloWorldTest > helloNoName PASSED
|
||||
|
||||
HelloWorldTest > helloAnotherSampleName SKIPPED
|
||||
|
||||
4 tests completed, 1 failed, 1 skipped
|
||||
```
|
||||
|
||||
Since `" "` is an actual value, Kotlin does _not_ substitute in the
|
||||
default value.
|
||||
|
||||
(Re)open `src/main/kotlin/HelloWorld.kt`.
|
||||
|
||||
```kotlin
|
||||
fun hello(name: String = "World"): String {
|
||||
return "Hello, $name!"
|
||||
}
|
||||
```
|
||||
|
||||
One way to handle this case is to check to see if `name` is blank. Let's
|
||||
do that:
|
||||
|
||||
|
||||
```kotlin
|
||||
fun hello(name: String = "World"): String {
|
||||
return "Hello, ${if (name.isBlank()) "World" else name}!"
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, string templates can contain not just references to
|
||||
variables, but entire expressions! This is appropriate in a case like this
|
||||
where we want to apply a simple condition to a value.
|
||||
|
||||
... and rerun the tests ...
|
||||
|
||||
```
|
||||
$ gradle test
|
||||
:test
|
||||
|
||||
HelloWorldTest > helloSampleName PASSED
|
||||
|
||||
HelloWorldTest > helloBlankName PASSED
|
||||
|
||||
HelloWorldTest > helloNoName PASSED
|
||||
|
||||
HelloWorldTest > helloAnotherSampleName SKIPPED
|
||||
|
||||
BUILD SUCCESSFUL
|
||||
```
|
||||
|
||||
We're almost there (perhaps closer than you think)! Just _one_ more test
|
||||
to pass before we have a solution we can have real confidence in.
|
||||
|
||||
|
||||
|
||||
## Enabling the last test
|
||||
|
||||
(Re)open `src/test/kotlin/HelloWorldTest.kt` and find the last test:
|
||||
|
||||
```kotlin
|
||||
@Test
|
||||
@Ignore
|
||||
fun helloAnotherSampleName() {
|
||||
assertEquals("Hello, Bob!", hello("Bob"))
|
||||
}
|
||||
```
|
||||
|
||||
... and pop-off that `@Ignore` ...
|
||||
|
||||
```kotlin
|
||||
@Test
|
||||
fun helloAnotherSampleName() {
|
||||
assertEquals("Hello, Bob!", hello("Bob"))
|
||||
}
|
||||
```
|
||||
|
||||
... then rerun the tests ...
|
||||
|
||||
```
|
||||
:test
|
||||
|
||||
HelloWorldTest > helloSampleName PASSED
|
||||
|
||||
HelloWorldTest > helloBlankName PASSED
|
||||
|
||||
HelloWorldTest > helloNoName PASSED
|
||||
|
||||
HelloWorldTest > helloAnotherSampleName PASSED
|
||||
|
||||
BUILD SUCCESSFUL
|
||||
```
|
||||
|
||||
Oh, hello! Turns out, the solution we put into place didn't just apply for
|
||||
"`Alice`" but for "`Bob`" equally well. In this case, the test succeeded
|
||||
with no additional code on our part.
|
||||
|
||||
Congratulations!
|
||||
|
||||
|
||||
|
||||
## Refactoring
|
||||
|
||||
Now that you've got all the tests passing, you might consider whether
|
||||
the code is in the most readable/maintainable/efficient shape. What makes
|
||||
for "good" design of software is a big topic. The pursuit of it underlies
|
||||
much of what makes up the more valuable conversations on Exercism.
|
||||
|
||||
Kotlin is such a concise language and this exercise is so small, there is
|
||||
not much room for us to make adjustments. Most would leave this code, as
|
||||
is.
|
||||
|
||||
That said, we've taken such pains to illustrate two core parts of the
|
||||
Test-Driven Development approach (i.e. "red", "green"), we'd be remiss if
|
||||
we skipped the all important final part: "refactor".
|
||||
|
||||
More on TDD at http://www.jamesshore.com/Blog/Red-Green-Refactor.html.
|
||||
|
||||
The core responsibility of `hello()` is to produce a personalized greeting.
|
||||
_How_ we determine whether or not a name is given (i.e. `name` is
|
||||
effectively an empty string) is a lower-level detail.
|
||||
|
||||
```kotlin
|
||||
fun hello(name: String = "World"): String {
|
||||
return "Hello, ${if (name.isBlank()) "World" else name}!"
|
||||
}
|
||||
```
|
||||
|
||||
How would things read if we extracted that detail into a separate method?
|
||||
|
||||
```kotlin
|
||||
fun hello(name: String = ""): String {
|
||||
return "Hello, ${whom(name)}!"
|
||||
}
|
||||
|
||||
private fun whom(name: String):String {
|
||||
return if(name.isBlank()) "World" else name
|
||||
}
|
||||
```
|
||||
|
||||
By extracting that logic into the `whom()` method, we've added a little
|
||||
abstraction to our program — it's not as literal as it was before. Yet,
|
||||
it allows us to defer _needing_ to understand _how_ the recipient of the
|
||||
greeting is determined.
|
||||
|
||||
If we can assume that `whom()` just works, we don't have to
|
||||
downshift in our head to those details. Instead, we can remain at the same
|
||||
level of thinking: what's the greeting?
|
||||
|
||||
_(Yes, this is considerable more lines of code; again, not a move we'd likely
|
||||
make typically. The takeaway is this: when you are "done" with an exercise
|
||||
ask yourself, "can I adjust the shape of this code to better tell the
|
||||
story of what's going on through its shape?")_
|
||||
|
||||
We made a bunch of changes, let's make sure we didn't break the program!
|
||||
|
||||
```
|
||||
$ gradle test
|
||||
:compileKotlin
|
||||
:compileJava UP-TO-DATE
|
||||
:copyMainKotlinClasses
|
||||
:processResources UP-TO-DATE
|
||||
:classes UP-TO-DATE
|
||||
:compileTestKotlin
|
||||
:compileTestJava UP-TO-DATE
|
||||
:copyTestKotlinClasses UP-TO-DATE
|
||||
:processTestResources UP-TO-DATE
|
||||
:testClasses UP-TO-DATE
|
||||
:test
|
||||
|
||||
HelloWorldTest > helloSampleName PASSED
|
||||
|
||||
HelloWorldTest > helloBlankName PASSED
|
||||
|
||||
HelloWorldTest > helloNoName PASSED
|
||||
|
||||
HelloWorldTest > helloAnotherSampleName PASSED
|
||||
|
||||
BUILD SUCCESSFUL
|
||||
```
|
||||
|
||||
This illustrates another benefit of writing tests: you can make significant
|
||||
changes to the structure of the program and very quickly restore your
|
||||
confidence that the program still works. These tests are a far cry from a
|
||||
"proof" of correctness, but well-written tests do a much better job of
|
||||
(very quickly) giving us evidence that it is. Without them, we manually
|
||||
run the program with different inputs and/or inspecting the code
|
||||
line-by-line — time-consuming and error prone.
|
||||
|
||||
|
||||
|
||||
# Submitting your first iteration
|
||||
|
||||
With a working solution that we've reviewed, we're ready to submit it to
|
||||
@ -662,7 +260,7 @@ use the capitalized form on the person's name, regardless of the case they
|
||||
used.
|
||||
|
||||
In that situation, you'd:
|
||||
|
||||
|
||||
1. add a new test setting up that new expectation,
|
||||
2. implement that in the code (the same process we just went through
|
||||
together, above).
|
||||
|
@ -1,5 +1,5 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.0.2'
|
||||
ext.kotlin_version = '1.2.40'
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
@ -20,3 +20,9 @@ dependencies {
|
||||
testCompile 'junit:junit:4.12'
|
||||
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
|
||||
}
|
||||
test {
|
||||
testLogging {
|
||||
exceptionFormat = 'full'
|
||||
events = ["passed", "failed", "skipped"]
|
||||
}
|
||||
}
|
||||
|
BIN
kotlin/hello-world/build/classes/kotlin/main/HelloWorldKt.class
Normal file
BIN
kotlin/hello-world/build/classes/kotlin/main/HelloWorldKt.class
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
kotlin/hello-world/build/kotlin-build/artifact-difference.tab
Normal file
BIN
kotlin/hello-world/build/kotlin-build/artifact-difference.tab
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
kotlin/hello-world/build/kotlin-build/artifact-difference.tab_i
Normal file
BIN
kotlin/hello-world/build/kotlin-build/artifact-difference.tab_i
Normal file
Binary file not shown.
Binary file not shown.
1
kotlin/hello-world/build/kotlin-build/version.txt
Normal file
1
kotlin/hello-world/build/kotlin-build/version.txt
Normal file
@ -0,0 +1 @@
|
||||
11001
|
BIN
kotlin/hello-world/build/kotlin/compileKotlin/build-history.bin
Normal file
BIN
kotlin/hello-world/build/kotlin/compileKotlin/build-history.bin
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1 @@
|
||||
2011001
|
@ -0,0 +1 @@
|
||||
8011001
|
@ -0,0 +1 @@
|
||||
4011001
|
BIN
kotlin/hello-world/build/kotlin/compileKotlin/last-build.bin
Normal file
BIN
kotlin/hello-world/build/kotlin/compileKotlin/last-build.bin
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user