diff --git a/README.md b/README.md index b4b1377..31e19a8 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,29 @@ --- +πŸ›  κΈ°λŠ₯ λͺ©λ‘ +- [x] μ •λ‹΅ 맀칭 + - [x] νŒλ³„ κ²°κ³ΌλŠ” νƒ€μΌλ‘œ μ•Œλ €μ€€λ‹€. + - [x] 정닡은 `words.txt`의 ((ν˜„μž¬ λ‚ μ§œ - 2021λ…„ 6μ›” 19일) % `words.txt`의 단어 개수) 번째의 단어이닀. + - [x] 맀칭 κ²°κ³Ό + - [x] ν”Œλ ˆμ΄μ–΄ λ‹΅κ³Ό μ •λ‹΅ 사이 ν•œ κΈ€μžμ˜ 슀펠과 μœ„μΉ˜κ°€ 같은 경우 `μ΄ˆλ‘μƒ‰ 타일`둜 λ‚˜νƒ€λ‚Έλ‹€. + - [x] ν”Œλ ˆμ΄μ–΄ λ‹΅κ³Ό μ •λ‹΅ 사이 ν•œ κΈ€μžμ˜ μŠ€νŽ μ€ κ°™μ§€λ§Œ μœ„μΉ˜κ°€ λ‹€λ₯Έ 경우 `λ…Έλž€μƒ‰ 타일`둜 λ‚˜νƒ€λ‚Έλ‹€. + - [x] ν”Œλ ˆμ΄μ–΄ λ‹΅κ³Ό μ •λ‹΅ 사이 ν•œ κΈ€μžμ˜ 슀펠과 μœ„μΉ˜κ°€ λͺ¨λ‘ λ‹€λ₯Έ 경우 `νšŒμƒ‰ 타일`둜 λ‚˜νƒ€λ‚Έλ‹€. +- [x] 타일 + - [x] μ΄ˆλ‘μƒ‰, λ…Έλž€μƒ‰, νšŒμƒ‰ +- [x] 단어 + - [x] λ‹¨μ–΄λŠ” 5κΈ€μžμ΄λ‹€. + - [x] λ‹¨μ–΄λŠ” μ˜λ‹¨μ–΄μ΄λ‹€. +- [x] κ²Œμž„ + - [x] μ΅œλŒ€ 6λ²ˆκΉŒμ§€ λ‹΅μ•ˆμ„ μ œμΆœν•  수 μžˆλ‹€. + - [x] 정닡은 `words.txt`의 ((ν˜„μž¬ λ‚ μ§œ - 2021λ…„ 6μ›” 19일) % `words.txt`의 단어 개수) 번째의 단어이닀. + - [x] λ‹¨μ–΄λŠ” `words.txt`에 ν¬ν•¨λœ 단어여야 ν•œλ‹€. + - [x] λ‹΅μ•ˆμ„ 6번 μ œμΆœν•˜λ©΄ κ²Œμž„μ„ μ’…λ£Œν•œλ‹€. + - [x] 6번 μ•ˆμ— 정닡을 λ§žμΆ”λ©΄ μ’…λ£Œν•œλ‹€. + - [x] ν”Œλ ˆμ΄μ–΄λŠ” 닡을 μž…λ ₯ν•œλ‹€. + - [x] 닡을 μž…λ ₯ν• λ•Œλ§ˆλ‹€ 맀칭된 λˆ„μ  타일을 λ°˜ν™˜ν•œλ‹€. + - [x] κ²Œμž„μ΄ μ’…λ£Œλ˜λ©΄ μ‹œλ„νšŸμˆ˜λ₯Ό λ°˜ν™˜ν•œλ‹€. + ## πŸš€ κΈ°λŠ₯ μš”κ΅¬ 사항 선풍적인 인기λ₯Ό λŒμ—ˆλ˜ μ˜μ–΄ 단어 λ§žμΆ”κΈ° κ²Œμž„μ΄λ‹€. diff --git a/src/main/kotlin/study/Introduce.kt b/src/main/kotlin/study/Introduce.kt new file mode 100644 index 0000000..a836dc3 --- /dev/null +++ b/src/main/kotlin/study/Introduce.kt @@ -0,0 +1,8 @@ +package study + +import study.person.Person +import study.person.PersonBuilder + +fun introduce(builder: PersonBuilder.() -> Unit): Person { + return PersonBuilder().apply(builder).build() +} diff --git a/src/main/kotlin/study/language/Language.kt b/src/main/kotlin/study/language/Language.kt new file mode 100644 index 0000000..ef45ee5 --- /dev/null +++ b/src/main/kotlin/study/language/Language.kt @@ -0,0 +1,3 @@ +package study.language + +data class Language(val name: String, val level: Int) diff --git a/src/main/kotlin/study/language/LanguageBuilder.kt b/src/main/kotlin/study/language/LanguageBuilder.kt new file mode 100644 index 0000000..17758d2 --- /dev/null +++ b/src/main/kotlin/study/language/LanguageBuilder.kt @@ -0,0 +1,14 @@ +package study.language + +class LanguageBuilder { + + var languages: MutableList = mutableListOf() + + infix fun String.level(level: Int) { + languages.add(Language(this, level)) + } + + fun build(): MutableList { + return languages + } +} diff --git a/src/main/kotlin/study/person/Person.kt b/src/main/kotlin/study/person/Person.kt new file mode 100644 index 0000000..642878c --- /dev/null +++ b/src/main/kotlin/study/person/Person.kt @@ -0,0 +1,11 @@ +package study.person + +import study.language.Language +import study.skill.Skill + +data class Person( + val name: String, + val company: String, + val skills: MutableList, + val languages: MutableList +) diff --git a/src/main/kotlin/study/person/PersonBuilder.kt b/src/main/kotlin/study/person/PersonBuilder.kt new file mode 100644 index 0000000..796a2a2 --- /dev/null +++ b/src/main/kotlin/study/person/PersonBuilder.kt @@ -0,0 +1,34 @@ +package study.person + +import study.language.Language +import study.language.LanguageBuilder +import study.skill.Skill +import study.skill.SkillBuilder + +class PersonBuilder { + + lateinit var name: String + lateinit var company: String + lateinit var skills: MutableList + lateinit var languages: MutableList + + fun name(value: String) { + name = value + } + + fun company(value: String) { + company = value + } + + fun skills(builder: SkillBuilder.() -> Unit) { + skills = SkillBuilder().apply(builder).build() + } + + fun languages(builder: LanguageBuilder.() -> Unit) { + languages = LanguageBuilder().apply(builder).build() + } + + fun build(): Person { + return Person(name, company, skills, languages) + } +} diff --git a/src/main/kotlin/study/skill/Skill.kt b/src/main/kotlin/study/skill/Skill.kt new file mode 100644 index 0000000..0037ce8 --- /dev/null +++ b/src/main/kotlin/study/skill/Skill.kt @@ -0,0 +1,7 @@ +package study.skill + +sealed class Skill + +data class SoftSkill(val value: String) : Skill() + +data class HardSkill(val value: String) : Skill() diff --git a/src/main/kotlin/study/skill/SkillBuilder.kt b/src/main/kotlin/study/skill/SkillBuilder.kt new file mode 100644 index 0000000..b67409a --- /dev/null +++ b/src/main/kotlin/study/skill/SkillBuilder.kt @@ -0,0 +1,18 @@ +package study.skill + +class SkillBuilder { + + var skills: MutableList = mutableListOf() + + fun soft(value: String) { + skills.add(SoftSkill(value)) + } + + fun hard(value: String) { + skills.add(HardSkill(value)) + } + + fun build(): MutableList { + return skills + } +} diff --git a/src/main/kotlin/wordle/Application.kt b/src/main/kotlin/wordle/Application.kt new file mode 100644 index 0000000..008a9d1 --- /dev/null +++ b/src/main/kotlin/wordle/Application.kt @@ -0,0 +1,35 @@ +package wordle + +import wordle.domain.Game +import wordle.domain.GameResult +import wordle.domain.Word +import wordle.domain.Words +import wordle.domain.WordsReader +import wordle.view.InputView +import wordle.view.OutputView +import java.time.LocalDate + +fun main() { + + val wordsReader = WordsReader("words.txt") + val words = Words(wordsReader.words) + val game = Game(words, LocalDate.now()) + val gameResult = GameResult(game.maxRound) + + OutputView.printInitMessage(game.maxRound) + play(game, gameResult) +} + +private fun play(game: Game, gameResult: GameResult) { + return try { + while (!game.isOver) { + val playerWord = Word(InputView.requestAnswer()) + val matchResult = game.matchResult(playerWord) + gameResult.add(matchResult) + OutputView.printGameResult(game.isOver, game.count, game.maxRound, gameResult) + } + } catch (exception: IllegalArgumentException) { + OutputView.printErrorMessage(exception.message) + play(game, gameResult) + } +} diff --git a/src/main/kotlin/wordle/domain/Game.kt b/src/main/kotlin/wordle/domain/Game.kt new file mode 100644 index 0000000..f83c0fc --- /dev/null +++ b/src/main/kotlin/wordle/domain/Game.kt @@ -0,0 +1,46 @@ +package wordle.domain + +import java.time.LocalDate + +class Game(val words: Words, val date: LocalDate) { + + var count: Int = 0 + private set + var isOver: Boolean = false + private set + val maxRound: Int + get() = MAX_ROUND + + fun matchResult(playerWord: Word): Tiles { + require(words.contains(playerWord)) { "[ERROR] words.txt에 μžˆλŠ” 단어λ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”." } + val answer = words.findAnswer(date) + val tiles = playerWord.value.withIndex() + .mapIndexedNotNull { index, value -> + matchSpell(value.value, index, answer) + } + count++ + val newTiles = Tiles(tiles) + updateIsOver(newTiles) + return newTiles + } + + private fun updateIsOver(newTiles: Tiles) { + if (count >= MAX_ROUND || newTiles.isAllGreen()) { + isOver = true + } + } + + private fun matchSpell(spell: Char, index: Int, answer: Word): Tile { + if (answer.sameIndexAndSpell(index, spell)) { + return Tile.GREEN + } + if (answer.contains(spell)) { + return Tile.YELLOW + } + return Tile.GRAY + } + + companion object { + private const val MAX_ROUND = 6 + } +} diff --git a/src/main/kotlin/wordle/domain/GameResult.kt b/src/main/kotlin/wordle/domain/GameResult.kt new file mode 100644 index 0000000..5a6a788 --- /dev/null +++ b/src/main/kotlin/wordle/domain/GameResult.kt @@ -0,0 +1,11 @@ +package wordle.domain + +class GameResult(size: Int) { + + var gameResult: MutableList = ArrayList(size) + private set + + fun add(tiles: Tiles) { + this.gameResult.add(tiles) + } +} diff --git a/src/main/kotlin/wordle/domain/Tile.kt b/src/main/kotlin/wordle/domain/Tile.kt new file mode 100644 index 0000000..648023c --- /dev/null +++ b/src/main/kotlin/wordle/domain/Tile.kt @@ -0,0 +1,12 @@ +package wordle.domain + +enum class Tile(val symbol: String) { + + GRAY("⬜"), + GREEN("\uD83D\uDFE9"), + YELLOW("\uD83D\uDFE8"); + + fun isGreen(): Boolean { + return this == GREEN + } +} diff --git a/src/main/kotlin/wordle/domain/Tiles.kt b/src/main/kotlin/wordle/domain/Tiles.kt new file mode 100644 index 0000000..52dfa7e --- /dev/null +++ b/src/main/kotlin/wordle/domain/Tiles.kt @@ -0,0 +1,8 @@ +package wordle.domain + +data class Tiles(val tiles: List) { + + fun isAllGreen(): Boolean { + return tiles.all { it.isGreen() } + } +} diff --git a/src/main/kotlin/wordle/domain/Word.kt b/src/main/kotlin/wordle/domain/Word.kt new file mode 100644 index 0000000..aa27164 --- /dev/null +++ b/src/main/kotlin/wordle/domain/Word.kt @@ -0,0 +1,23 @@ +package wordle.domain + +import java.util.regex.Pattern + +data class Word(val value: String) { + + init { + require(isRightSize()) { "[ERROR] 5κΈ€μžμ˜ 단어λ₯Ό μž…λ ₯ν•˜μ„Έμš”." } + require(isAlphabet()) { "[ERROR] μ˜μ–΄ 단어λ₯Ό μž…λ ₯ν•˜μ„Έμš”." } + } + + private fun isRightSize(): Boolean = value.length == SIZE + + private fun isAlphabet(): Boolean = Pattern.matches("^[a-zA-Z]*$", value) + + fun sameIndexAndSpell(index: Int, spell: Char): Boolean = value[index] == spell + + fun contains(spell: Char): Boolean = value.contains(spell) + + companion object { + private const val SIZE = 5 + } +} diff --git a/src/main/kotlin/wordle/domain/Words.kt b/src/main/kotlin/wordle/domain/Words.kt new file mode 100644 index 0000000..9fdb390 --- /dev/null +++ b/src/main/kotlin/wordle/domain/Words.kt @@ -0,0 +1,20 @@ +package wordle.domain + +import java.time.LocalDate +import java.time.temporal.ChronoUnit + +class Words(private val words: List) { + + fun findAnswer(current: LocalDate): Word { + val answerIndex = ChronoUnit.DAYS.between(BASE_DATE, current) + return words[answerIndex.toInt() % words.size] + } + + fun contains(word: Word): Boolean { + return words.contains(word) + } + + companion object { + private val BASE_DATE = LocalDate.of(2021, 6, 19) + } +} diff --git a/src/main/kotlin/wordle/domain/WordsReader.kt b/src/main/kotlin/wordle/domain/WordsReader.kt new file mode 100644 index 0000000..6739925 --- /dev/null +++ b/src/main/kotlin/wordle/domain/WordsReader.kt @@ -0,0 +1,16 @@ +package wordle.domain + +import java.io.File + +class WordsReader(private val path: String) { + + val words: List + get() = getWords(path) + + companion object { + private fun getWords(path: String): List { + return File(ClassLoader.getSystemResource(path).file).readLines() + .map { Word(it) } + } + } +} diff --git a/src/main/kotlin/wordle/view/InputView.kt b/src/main/kotlin/wordle/view/InputView.kt new file mode 100644 index 0000000..3ab438e --- /dev/null +++ b/src/main/kotlin/wordle/view/InputView.kt @@ -0,0 +1,10 @@ +package wordle.view + +object InputView { + + fun requestAnswer(): String { + println() + println("정닡을 μž…λ ₯ν•΄ μ£Όμ„Έμš”.") + return readln() + } +} diff --git a/src/main/kotlin/wordle/view/OutputView.kt b/src/main/kotlin/wordle/view/OutputView.kt new file mode 100644 index 0000000..b91650c --- /dev/null +++ b/src/main/kotlin/wordle/view/OutputView.kt @@ -0,0 +1,33 @@ +package wordle.view + +import wordle.domain.GameResult +import wordle.domain.Tiles + +object OutputView { + + fun printInitMessage(maxRound: Int) { + println("WORDLE을 ${maxRound}번 λ§Œμ— 맞좰 λ³΄μ„Έμš”.") + println("μ‹œλ„μ˜ κ²°κ³ΌλŠ” νƒ€μΌμ˜ 색 λ³€ν™”λ‘œ λ‚˜νƒ€λ‚©λ‹ˆλ‹€.") + } + + fun printGameResult(isOver: Boolean, count: Int, maxRound: Int, gameResult: GameResult) { + if (isOver) { + println("$count/$maxRound") + } + println() + gameResult.gameResult + .forEach { + printTiles(it) + println() + } + } + + private fun printTiles(tiles: Tiles) { + tiles.tiles + .forEach { print(it.symbol) } + } + + fun printErrorMessage(message: String?) { + println(message) + } +} diff --git a/src/test/kotlin/study/Introduce.kt b/src/test/kotlin/study/Introduce.kt new file mode 100644 index 0000000..fa64a72 --- /dev/null +++ b/src/test/kotlin/study/Introduce.kt @@ -0,0 +1,40 @@ +package study + +import io.kotest.matchers.collections.shouldContainExactly +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test +import study.language.Language +import study.skill.HardSkill +import study.skill.SoftSkill + +class Introduce { + + @Test + fun `μžκΈ°μ†Œκ°œ`() { + val person = introduce { + name("제둜") + company("μš°μ•„ν•œν…Œν¬μ½”μŠ€") + skills { + soft("A passion for problem solving") + soft("common communication skills") + hard("Kotlin") + } + languages { + "Korean" level 2 + "English" level 1 + } + } + + person.name shouldBe "제둜" + person.company shouldBe "μš°μ•„ν•œν…Œν¬μ½”μŠ€" + person.skills shouldContainExactly listOf( + SoftSkill("A passion for problem solving"), + SoftSkill("common communication skills"), + HardSkill("Kotlin") + ) + person.languages shouldContainExactly listOf( + Language("Korean", 2), + Language("English", 1) + ) + } +} diff --git a/src/test/kotlin/wordle/domain/GameTest.kt b/src/test/kotlin/wordle/domain/GameTest.kt new file mode 100644 index 0000000..5907e05 --- /dev/null +++ b/src/test/kotlin/wordle/domain/GameTest.kt @@ -0,0 +1,113 @@ +package wordle.domain + +import io.kotest.assertions.throwables.shouldThrow +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertAll +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource +import wordle.domain.Tile.GRAY +import wordle.domain.Tile.GREEN +import wordle.domain.Tile.YELLOW +import java.time.LocalDate + +internal class GameTest { + + @Test + @DisplayName("ν”Œλ ˆμ΄μ˜ 단어가 words에 ν¬ν•¨λ˜μ–΄μžˆμ§€ μ•Šλ‹€λ©΄ μ˜ˆμ™Έλ₯Ό λ˜μ Έμ•Ό ν•œλ‹€.") + fun containsWord() { + // given + val wordsReader = WordsReader("words.txt") + val words = Words(wordsReader.words) + val game = Game(words, LocalDate.of(2021, 6, 19)) + + // when + + // then + shouldThrow { game.matchResult(Word("xxxxx")) } + } + + @ParameterizedTest + @MethodSource("validParameters") + @DisplayName("ν”Œλ ˆμ΄μ–΄μ˜ λ‹΅κ³Ό 정닡을 λ§€μΉ­ν•œλ‹€.") + fun matchAnswer(word: Word, expectedTiles: Tiles) { + // given + val wordsReader = WordsReader("words.txt") + val words = Words(wordsReader.words) + val game = Game(words, LocalDate.of(2021, 6, 19)) + + // when + val actualTiles = game.matchResult(word) + + // then + assertThat(actualTiles).isEqualTo(expectedTiles) + } + + @Test + @DisplayName("μ •λ‹΅ 맀칭을 6번 μ§„ν–‰ν•˜λ©΄ κ²Œμž„μ€ μ’…λ£Œλ˜μ–΄μ•Ό ν•œλ‹€.") + fun gameOver() { + // given + val wordsReader = WordsReader("words.txt") + val words = Words(wordsReader.words) + val game = Game(words, LocalDate.of(2021, 6, 19)) + + // when + repeat(6) { game.matchResult(Word("scare")) } + + // then + assertAll( + { assertThat(game.isOver).isTrue }, + { assertThat(game.count).isEqualTo(6) } + ) + } + + @Test + @DisplayName("정닡을 λ§žμΆ”λ©΄ κ²Œμž„μ€ μ’…λ£Œλ˜μ–΄μ•Ό ν•œλ‹€.") + fun gameOverMatch() { + // given + val wordsReader = WordsReader("words.txt") + val words = Words(wordsReader.words) + val game = Game(words, LocalDate.of(2021, 6, 19)) + + // when + repeat(3) { game.matchResult(Word("scare")) } + game.matchResult(Word("cigar")) + + // then + assertAll( + { assertThat(game.isOver).isTrue }, + { assertThat(game.count).isEqualTo(4) } + ) + } + + @Test + @DisplayName("정닡을 λͺ» λ§žμΆ”λ©΄ κ²Œμž„μ€ μ’…λ£Œλ˜μ§€ μ•ŠλŠ”λ‹€.") + fun gameOverMisMatch() { + // given + val wordsReader = WordsReader("words.txt") + val words = Words(wordsReader.words) + val game = Game(words, LocalDate.of(2021, 6, 19)) + + // when + repeat(3) { game.matchResult(Word("scare")) } + + // then + assertAll( + { assertThat(game.isOver).isFalse }, + { assertThat(game.count).isEqualTo(3) } + ) + } + + companion object { + @JvmStatic + fun validParameters() = listOf( + Arguments.of(Word("cigar"), Tiles(listOf(GREEN, GREEN, GREEN, GREEN, GREEN))), + Arguments.of(Word("scare"), Tiles(listOf(GRAY, YELLOW, YELLOW, YELLOW, GRAY))), + Arguments.of(Word("solar"), Tiles(listOf(GRAY, GRAY, GRAY, GREEN, GREEN))), + Arguments.of(Word("tiger"), Tiles(listOf(GRAY, GREEN, GREEN, GRAY, GREEN))), + Arguments.of(Word("query"), Tiles(listOf(GRAY, GRAY, GRAY, YELLOW, GRAY))) + ) + } +} diff --git a/src/test/kotlin/wordle/domain/WordTest.kt b/src/test/kotlin/wordle/domain/WordTest.kt new file mode 100644 index 0000000..112ca10 --- /dev/null +++ b/src/test/kotlin/wordle/domain/WordTest.kt @@ -0,0 +1,28 @@ +package wordle.domain + +import io.kotest.assertions.throwables.shouldThrow +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +internal class WordTest { + + @Test + @DisplayName("단어λ₯Ό 정상 생성해야 ν•œλ‹€.") + fun createWord() { + val word = Word("model") + assertThat(word.value).isEqualTo("model") + } + + @Test + @DisplayName("단어가 5κΈ€μžκ°€ μ•„λ‹ˆλΌλ©΄ μ˜ˆμ™Έλ₯Ό λ˜μ§„λ‹€.") + fun validateSize() { + shouldThrow { Word("models") } + } + + @Test + @DisplayName("단어가 μ•ŒνŒŒλ²³μ΄ μ•„λ‹ˆλΌλ©΄ μ˜ˆμ™Έλ₯Ό λ˜μ§„λ‹€.") + fun validateAlphabet() { + shouldThrow { Word("λͺ¨λΈμž…λ‹ˆλ‹€") } + } +} diff --git a/src/test/kotlin/wordle/domain/WordsReaderTest.kt b/src/test/kotlin/wordle/domain/WordsReaderTest.kt new file mode 100644 index 0000000..f0c4adb --- /dev/null +++ b/src/test/kotlin/wordle/domain/WordsReaderTest.kt @@ -0,0 +1,20 @@ +package wordle.domain + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +internal class WordsReaderTest { + + @Test + @DisplayName("/words.txt의 단어λ₯Ό λ°›μ•„μ˜¨λ‹€.") + fun getWordsResponse() { + val wordsReader = WordsReader("words.txt") + val words = wordsReader.words + assertThat(words.size).isEqualTo(WORDS_SIZE) + } + + companion object { + private const val WORDS_SIZE = 2309 + } +} diff --git a/src/test/kotlin/wordle/domain/WordsTest.kt b/src/test/kotlin/wordle/domain/WordsTest.kt new file mode 100644 index 0000000..9cbb4b5 --- /dev/null +++ b/src/test/kotlin/wordle/domain/WordsTest.kt @@ -0,0 +1,44 @@ +package wordle.domain + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import java.time.LocalDate + +internal class WordsTest { + + @Test + @DisplayName("정닡단어λ₯Ό 가져와야 ν•œλ‹€.") + fun getAnswerWord() { + val wordsReader = WordsReader("words.txt") + val words = Words(wordsReader.words) + val answerWord = words.findAnswer(LocalDate.of(2021, 6, 19)) + assertThat(answerWord).isEqualTo(Word("cigar")) + } + + @Test + @DisplayName("words에 ν¬ν•¨λœ 단어이면 true μ—¬μ•Ό ν•œλ‹€.") + fun shouldContainsWords() { + // given + val wordsReader = WordsReader("words.txt") + val words = Words(wordsReader.words) + val value = "rebut" + // when + val hasWord = words.contains(Word(value)) + // then + assertThat(hasWord).isTrue + } + + @Test + @DisplayName("words에 ν¬ν•¨λœ 단어가 μ•„λ‹ˆλ©΄ false μ—¬μ•Ό ν•œλ‹€.") + fun failShouldContainsWords() { + // given + val wordsReader = WordsReader("words.txt") + val words = Words(wordsReader.words) + val value = "xxxxx" + // when + val hasWord = words.contains(Word(value)) + // then + assertThat(hasWord).isFalse + } +}