From a6df745daaa82a131c221e25326eabeacb72b8ce Mon Sep 17 00:00:00 2001 From: Bram van de Kerkhof Date: Wed, 11 May 2016 15:33:14 +0200 Subject: [PATCH] Rewrote ChapterRecognition to Kotlin. (#293) --- .../tachiyomi/util/ChapterRecognition.java | 205 --------- .../tachiyomi/util/ChapterRecognition.kt | 140 ++++++ .../tachiyomi/ChapterRecognitionTest.java | 198 -------- .../tachiyomi/ChapterRecognitionTest.kt | 421 ++++++++++++++++++ 4 files changed, 561 insertions(+), 403 deletions(-) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/util/ChapterRecognition.java create mode 100644 app/src/main/java/eu/kanade/tachiyomi/util/ChapterRecognition.kt delete mode 100644 app/src/test/java/eu/kanade/tachiyomi/ChapterRecognitionTest.java create mode 100644 app/src/test/java/eu/kanade/tachiyomi/ChapterRecognitionTest.kt diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/ChapterRecognition.java b/app/src/main/java/eu/kanade/tachiyomi/util/ChapterRecognition.java deleted file mode 100644 index bd4f40802..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/util/ChapterRecognition.java +++ /dev/null @@ -1,205 +0,0 @@ -package eu.kanade.tachiyomi.util; - -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import eu.kanade.tachiyomi.data.database.models.Chapter; -import eu.kanade.tachiyomi.data.database.models.Manga; - -public final class ChapterRecognition { - - private static final Pattern cleanWithToken = Pattern.compile("ch[^0-9]?\\s*(\\d+[\\.,]?\\d+)($|\\b)"); - private static final Pattern uncleanWithToken = Pattern.compile("ch[^0-9]?\\s*(\\d+[\\.,]?\\d*)"); - private static final Pattern withAlphaPostfix = Pattern.compile("(\\d+[\\.,]?\\d*\\s*)([a-z])($|\\b)"); - private static final Pattern cleanNumber = Pattern.compile("(\\d+[\\.,]?\\d+)($|\\b)"); - private static final Pattern uncleanNumber = Pattern.compile("(\\d+[\\.,]?\\d*)"); - private static final Pattern withColon = Pattern.compile("(\\d+[\\.,]?\\d*\\s*:)([^\\d]|$)"); - private static final Pattern startingNumber = Pattern.compile("^(\\d+[\\.,]?\\d*)"); - - private static final Pattern pUnwanted = - Pattern.compile("(\\b|\\d)(v|ver|vol|version|volume)\\.?\\s*\\d+\\b"); - private static final Pattern pPart = - Pattern.compile("(\\b|\\d)part\\s*\\d+.+"); - - private ChapterRecognition() throws InstantiationException { - throw new InstantiationException("This class is not for instantiation"); - } - - public static void parseChapterNumber(Chapter chapter, Manga manga) { - if (chapter.chapter_number != -1) - return; - - String name = chapter.name.toLowerCase(); - Matcher matcher; - - // Safest option, the chapter has a token prepended and nothing at the end of the number - matcher = cleanWithToken.matcher(name); - if (matcher.find()) { - chapter.chapter_number = Float.parseFloat(matcher.group(1)); - return; - } - - // a number with a single alpha prefix is parsed as sub-chapter - matcher = withAlphaPostfix.matcher(name); - if (matcher.find()) { - chapter.chapter_number = Float.parseFloat(matcher.group(1)) + parseAlphaPostFix(matcher.group(2)); - return; - } - - // the chapter has a token prepended and something at the end of the number - matcher = uncleanWithToken.matcher(name); - if (matcher.find()) { - chapter.chapter_number = Float.parseFloat(matcher.group(1)); - return; - } - - // Remove anything related to the volume or version - name = pUnwanted.matcher(name).replaceAll("$1"); - - List occurrences; - - // If there's only one number, use it - matcher = uncleanNumber.matcher(name); - occurrences = getAllOccurrences(matcher); - if (occurrences.size() == 1) { - chapter.chapter_number = occurrences.get(0); - return; - } - - // If it has a colon, the chapter number should be that one - matcher = withColon.matcher(name); - occurrences = getAllOccurrences(matcher); - if (occurrences.size() == 1) { - chapter.chapter_number = occurrences.get(0); - return; - } - - // Prefer numbers without anything appended - matcher = cleanNumber.matcher(name); - occurrences = getAllOccurrences(matcher); - if (occurrences.size() == 1) { - chapter.chapter_number = occurrences.get(0); - return; - } - - // This can lead to issues if two numbers are separated by an space - name = name.replaceAll("\\s+", ""); - - // Try to remove the manga name from the chapter, and try again - String mangaName = replaceIrrelevantCharacters(manga.title); - String nameWithoutManga = difference(mangaName, name).trim(); - if (!nameWithoutManga.isEmpty()) { - matcher = uncleanNumber.matcher(nameWithoutManga); - occurrences = getAllOccurrences(matcher); - if (occurrences.size() == 1) { - chapter.chapter_number = occurrences.get(0); - return; - } - } - - // TODO more checks (maybe levenshtein?) - - // try splitting the name in parts an pick the first valid one - String[] nameParts = chapter.name.split("-"); - Chapter dummyChapter = Chapter.create(); - if (nameParts.length > 1) { - for (String part : nameParts) { - dummyChapter.name = part; - parseChapterNumber(dummyChapter, manga); - if (dummyChapter.chapter_number >= 0) { - chapter.chapter_number = dummyChapter.chapter_number; - return; - } - } - } - - // Strip anything after "part xxx" and try that - matcher = pPart.matcher(name); - if (matcher.find()) { - name = pPart.matcher(name).replaceAll("$1"); - dummyChapter.name = name; - parseChapterNumber(dummyChapter, manga); - if (dummyChapter.chapter_number >= 0) { - chapter.chapter_number = dummyChapter.chapter_number; - return; - } - } - - - // check for a number either at the start or right after the manga title - matcher = startingNumber.matcher(name); - if (matcher.find()) { - chapter.chapter_number = Float.parseFloat(matcher.group(1)); - return; - } - matcher = startingNumber.matcher(nameWithoutManga); - if (matcher.find()) { - chapter.chapter_number = Float.parseFloat(matcher.group(1)); - return; - } - } - - /** - * x.a -> x.1, x.b -> x.2, etc - */ - private static float parseAlphaPostFix(String postfix) { - char alpha = postfix.charAt(0); - return Float.parseFloat("0." + Integer.toString((int)alpha - 96)); - } - - public static List getAllOccurrences(Matcher matcher) { - List occurences = new ArrayList<>(); - while (matcher.find()) { - // Match again to get only numbers from the captured text - String text = matcher.group(); - Matcher m = uncleanNumber.matcher(text); - if (m.find()) { - try { - Float value = Float.parseFloat(m.group(1).replaceAll(",", ".")); - if (!occurences.contains(value)) { - occurences.add(value); - } - } catch (NumberFormatException e) { /* Do nothing */ } - } - } - return occurences; - } - - public static String replaceIrrelevantCharacters(String str) { - return str.replaceAll("\\s+", "").toLowerCase(); - } - - public static String difference(String str1, String str2) { - if (str1 == null) { - return str2; - } - if (str2 == null) { - return str1; - } - int at = indexOfDifference(str1, str2); - if (at == -1) { - return ""; - } - return str2.substring(at); - } - public static int indexOfDifference(String str1, String str2) { - if (str1 == str2) { - return -1; - } - if (str1 == null || str2 == null) { - return 0; - } - int i; - for (i = 0; i < str1.length() && i < str2.length(); ++i) { - if (str1.charAt(i) != str2.charAt(i)) { - break; - } - } - if (i < str2.length() || i < str1.length()) { - return i; - } - return -1; - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/ChapterRecognition.kt b/app/src/main/java/eu/kanade/tachiyomi/util/ChapterRecognition.kt new file mode 100644 index 000000000..31c133d63 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/util/ChapterRecognition.kt @@ -0,0 +1,140 @@ +package eu.kanade.tachiyomi.util + +import eu.kanade.tachiyomi.data.database.models.Chapter +import eu.kanade.tachiyomi.data.database.models.Manga + +/** + * -R> = regex conversion. + */ +object ChapterRecognition { + /** + * All cases with Ch.xx + * Mokushiroku Alice Vol.1 Ch. 4: Misrepresentation -R> 4 + */ + private val basic = Regex("""(?<=ch\.)([0-9]+)(\.[0-9]+)?(\.?[a-z]+)?""") + + /** + * Regex used when only one number occurrence + * Example: Bleach 567: Down With Snowwhite -R> 567 + */ + private val occurrence = Regex("""([0-9]+)(\.[0-9]+)?(\.?[a-z]+)?""") + + /** + * Regex used when manga title removed + * Example: Solanin 028 Vol. 2 -> 028 Vol.2 -> 028Vol.2 -R> 028 + */ + private val withoutMange = Regex("""^([0-9]+)(\.[0-9]+)?(\.?[a-z]+)?""") + + /** + * Regex used to remove unwanted tags + * Example Prison School 12 v.1 vol004 version1243 volume64 -R> Prison School 12 + */ + private val unwanted = Regex("""(?:(v|ver|vol|version|volume).?[0-9]+)""") + + private val unwantedWhiteSpace = Regex("""(\s)(extra|special|omake)""") + + fun parseChapterNumber(chapter: Chapter, manga: Manga) { + //If chapter number is known return. + if (chapter.chapter_number != -1f) + return + + // Get chapter title with lower case + var name = chapter.name.toLowerCase() + + // Remove comma's from chapter. + name = name.replace(',', '.') + + // Remove unwanted white spaces. + unwantedWhiteSpace.findAll(name).let { + it.forEach { occurrence -> name = name.replace(occurrence.value, occurrence.value.trim()) } + } + + // Remove unwanted tags. + unwanted.findAll(name).let { + it.forEach { occurrence -> name = name.replace(occurrence.value, "") } + } + + // Check base case ch.xx + if (updateChapter(basic.find(name), chapter)) + return + + // Check one number occurrence. + val occurrences: MutableList = arrayListOf() + occurrence.findAll(name).let { + it.forEach { occurrence -> occurrences.add(occurrence) } + } + + if (occurrences.size == 1) { + if (updateChapter(occurrences[0], chapter)) + return + } + + // Remove manga title from chapter title. + val nameWithoutManga = name.replace(manga.title.toLowerCase(), "").trim() + + // Check if first value is number after title remove. + if (updateChapter(withoutMange.find(nameWithoutManga), chapter)) + return + + // Take the first number encountered. + if (updateChapter(occurrence.find(nameWithoutManga), chapter)) + return + } + + /** + * Check if volume is found and update chapter + * @param match result of regex + * @param chapter chapter object + * @return true if volume is found + */ + fun updateChapter(match: MatchResult?, chapter: Chapter): Boolean { + match?.let { + val initial = it.groups[1]?.value?.toFloat()!! + val subChapterDecimal = it.groups[2]?.value + val subChapterAlpha = it.groups[3]?.value + val addition = checkForDecimal(subChapterDecimal, subChapterAlpha) + chapter.chapter_number = initial.plus(addition) + return true + } + return false + } + + /** + * Check for decimal in received strings + * @param decimal decimal value of regex + * @param alpha alpha value of regex + * @return decimal/alpha float value + */ + fun checkForDecimal(decimal: String?, alpha: String?): Float { + if (!decimal.isNullOrEmpty()) + return decimal?.toFloat()!! + + if (!alpha.isNullOrEmpty()) { + if (alpha!!.contains("extra")) + return .99f + + if (alpha.contains("omake")) + return .98f + + if (alpha.contains("special")) + return .97f + + if (alpha[0].equals('.') ) { + // Take value after (.) + return parseAlphaPostFix(alpha[1]) + } else { + return parseAlphaPostFix(alpha[0]) + } + } + + return .0f + } + + /** + * x.a -> x.1, x.b -> x.2, etc + */ + private fun parseAlphaPostFix(alpha: Char): Float { + return ("0." + Integer.toString(alpha.toInt() - 96)).toFloat() + } + +} diff --git a/app/src/test/java/eu/kanade/tachiyomi/ChapterRecognitionTest.java b/app/src/test/java/eu/kanade/tachiyomi/ChapterRecognitionTest.java deleted file mode 100644 index 6235e298d..000000000 --- a/app/src/test/java/eu/kanade/tachiyomi/ChapterRecognitionTest.java +++ /dev/null @@ -1,198 +0,0 @@ -package eu.kanade.tachiyomi; - -import org.junit.Before; -import org.junit.Test; - -import eu.kanade.tachiyomi.data.database.models.Chapter; -import eu.kanade.tachiyomi.data.database.models.Manga; -import eu.kanade.tachiyomi.util.ChapterRecognition; - -import static org.assertj.core.api.Assertions.assertThat; - - -public class ChapterRecognitionTest { - - Manga randomManga; - - private Chapter createChapter(String title) { - Chapter chapter = Chapter.create(); - chapter.name = title; - return chapter; - } - - @Before - public void setUp() { - randomManga = new Manga(); - randomManga.title = "Something"; - } - - @Test - public void testWithOneDigit() { - Chapter c = createChapter("Ch.3: Self-proclaimed Genius"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(3f); - } - - @Test - public void testWithVolumeBefore() { - Chapter c = createChapter("Vol.1 Ch.4: Misrepresentation"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(4f); - } - - @Test - public void testWithVolumeAndVersionNumber() { - Chapter c = createChapter("Vol.1 Ch.3 (v2) Read Online"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(3f); - } - - @Test - public void testWithVolumeAndNumberInTitle() { - Chapter c = createChapter("Vol.15 Ch.90: Here Blooms the Daylily, Part 4"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(90f); - } - - @Test - public void testWithVolumeAndSpecialChapter() { - Chapter c = createChapter("Vol.10 Ch.42.5: Homecoming (Beginning)"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(42.5f); - } - - @Test - public void testWithJustANumber() { - Chapter c = createChapter("Homecoming (Beginning) 42"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(42f); - } - - @Test - public void testWithJustASpecialChapter() { - Chapter c = createChapter("Homecoming (Beginning) 42.5"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(42.5f); - } - - @Test - public void testWithNumberinMangaTitle() { - Chapter c = createChapter("3x3 Eyes 96"); - Manga m = new Manga(); - m.title = "3x3 Eyes"; - ChapterRecognition.parseChapterNumber(c, m); - assertThat(c.chapter_number).isEqualTo(96f); - } - - @Test - public void testWithColonAtTheEnd() { - Chapter c = createChapter("Chapter 5: 365 days"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(5f); - } - - @Test - public void testWithZeros() { - Chapter c = createChapter("Vol.001 Ch.003: Kaguya Doesn't Know Much"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(3f); - } - - @Test - public void testRange() { - Chapter c = createChapter("Ch.191-200 Read Online"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(191f); - } - - @Test - public void testWithKeywordChAtTheEndOfTheManga() { - // It should be 567, not 67 (ch is a keyword to get the chapter number) - Chapter c = createChapter("Bleach 567: Down With Snowwhite"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(567f); - } - - @Test - public void testWithVersionBefore() { - // It should be 84, not 2084 - Chapter c = createChapter("Onepunch-Man Punch Ver002 084 : Creeping Darkness"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(84f); - } - - @Test - public void testWithVersionBeforeAndAnotherNumber() { - Chapter c = createChapter("Onepunch-Man Punch Ver002 086 : Creeping Darkness [3]"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(86f); - } - - @Test - public void testWithVolumeAfterChapter() { - Chapter c = createChapter("Solanin 028 Vol. 2"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(28f); - } - - @Test - public void testWithVolumeAttachedToChapter() { - Chapter c = createChapter("Ansatsu Kyoushitsu 011v002: Assembly Time"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(11f); - } - - @Test - public void testWithNumberInChapterTitle() { - Chapter c = createChapter("Ansatsu Kyoushitsu 099 Present Time - 2nd Hour"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(99f); - } - - @Test - public void testAlphaSubChapters() { - Chapter c = createChapter("Asu No Yoichi 19a"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(19.1f); - c = createChapter("Asu No Yoichi 19b"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(19.2f); - } - - @Test - public void testChapterWithArcNumber() { - Chapter c = createChapter("Manga title 123 - Vol 016 Arc title 002"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(123f); - } - - @Test - public void testChapterWithChapterPrefixAfterPart() { - Chapter c = createChapter("Tokyo ESP 027: Part 002: Chapter 001"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(027f); - } - - @Test - public void testUnparsable() { - Chapter c = createChapter("Foo"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(-1f); - } - - @Test - public void testChapterWithTime() { - Chapter c = createChapter("Fairy Tail 404: 00:00"); - ChapterRecognition.parseChapterNumber(c, randomManga); - assertThat(c.chapter_number).isEqualTo(404f); - } - - @Test - public void testPlainNumberInTitle() { - Chapter c = createChapter("Kuroko no Basket 002 Monday at 840 on the Rooftop"); - Manga manga = new Manga(); - manga.title = "Kuroko no Basket"; - ChapterRecognition.parseChapterNumber(c, manga); - assertThat(c.chapter_number).isEqualTo(2f); - } -} diff --git a/app/src/test/java/eu/kanade/tachiyomi/ChapterRecognitionTest.kt b/app/src/test/java/eu/kanade/tachiyomi/ChapterRecognitionTest.kt new file mode 100644 index 000000000..ef4dc35da --- /dev/null +++ b/app/src/test/java/eu/kanade/tachiyomi/ChapterRecognitionTest.kt @@ -0,0 +1,421 @@ +package eu.kanade.tachiyomi + +import eu.kanade.tachiyomi.data.database.models.Chapter +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.util.ChapterRecognition +import org.assertj.core.api.Assertions.assertThat +import org.junit.Before +import org.junit.Test + +class ChapterRecognitionTest { + /** + * The manga containing manga title + */ + lateinit var manga: Manga + + /** + * The chapter containing chapter name + */ + lateinit var chapter: Chapter + + /** + * Set chapter title + * @param name name of chapter + * @return chapter object + */ + private fun createChapter(name: String): Chapter { + chapter = Chapter.create() + chapter.name = name + return chapter + } + + /** + * Set manga title + * @param title title of manga + * @return manga object + */ + private fun createManga(title: String): Manga { + manga.title = title + return manga + } + + /** + * Called before test + */ + @Before fun setup() { + manga = Manga().apply { title = "random" } + chapter = Chapter.create() + } + + /** + * Ch.xx base case + */ + @Test fun ChCaseBase() { + createManga("Mokushiroku Alice") + + createChapter("Mokushiroku Alice Vol.1 Ch.4: Misrepresentation") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(4f) + } + + /** + * Ch.xx.x base case + */ + @Test fun ChCaseDecimal() { + createManga("Mokushiroku Alice") + + createChapter("Mokushiroku Alice Vol.1 Ch.4.1: Misrepresentation") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(4.1f) + + createChapter("Mokushiroku Alice Vol.1 Ch.4.4: Misrepresentation") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(4.4f) + } + + /** + * Ch.xx.a base case + */ + @Test fun ChCaseAlpha() { + createManga("Mokushiroku Alice") + + createChapter("Mokushiroku Alice Vol.1 Ch.4.a: Misrepresentation") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(4.1f) + + createChapter("Mokushiroku Alice Vol.1 Ch.4.b: Misrepresentation") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(4.2f) + + createChapter("Mokushiroku Alice Vol.1 Ch.4.extra: Misrepresentation") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(4.99f) + } + + /** + * Name containing one number base case + */ + @Test fun OneNumberCaseBase() { + createManga("Bleach") + + createChapter("Bleach 567 Down With Snowwhite") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(567f) + } + + /** + * Name containing one number and decimal case + */ + @Test fun OneNumberCaseDecimal() { + createManga("Bleach") + + createChapter("Bleach 567.1 Down With Snowwhite") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(567.1f) + + createChapter("Bleach 567.4 Down With Snowwhite") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(567.4f) + } + + /** + * Name containing one number and alpha case + */ + @Test fun OneNumberCaseAlpha() { + createManga("Bleach") + + createChapter("Bleach 567.a Down With Snowwhite") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(567.1f) + + createChapter("Bleach 567.b Down With Snowwhite") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(567.2f) + + createChapter("Bleach 567.extra Down With Snowwhite") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(567.99f) + } + + /** + * Chapter containing manga title and number base case + */ + @Test fun MangaTitleCaseBase() { + createManga("Solanin") + + createChapter("Solanin 028 Vol. 2") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(28f) + } + + /** + * Chapter containing manga title and number decimal case + */ + @Test fun MangaTitleCaseDecimal() { + createManga("Solanin") + + createChapter("Solanin 028.1 Vol. 2") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(28.1f) + + createChapter("Solanin 028.4 Vol. 2") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(28.4f) + } + + /** + * Chapter containing manga title and number alpha case + */ + @Test fun MangaTitleCaseAlpha() { + createManga("Solanin") + + createChapter("Solanin 028.a Vol. 2") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(28.1f) + + createChapter("Solanin 028.b Vol. 2") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(28.2f) + + createChapter("Solanin 028.extra Vol. 2") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(28.99f) + } + + /** + * Extreme base case + */ + @Test fun ExtremeCaseBase() { + createManga("Onepunch-Man") + + createChapter("Onepunch-Man Punch Ver002 028") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(28f) + } + + /** + * Extreme base case decimal + */ + @Test fun ExtremeCaseDecimal() { + createManga("Onepunch-Man") + + createChapter("Onepunch-Man Punch Ver002 028.1") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(28.1f) + + createChapter("Onepunch-Man Punch Ver002 028.4") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(28.4f) + } + + /** + * Extreme base case alpha + */ + @Test fun ExtremeCaseAlpha() { + createManga("Onepunch-Man") + + createChapter("Onepunch-Man Punch Ver002 028.a") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(28.1f) + + createChapter("Onepunch-Man Punch Ver002 028.b") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(28.2f) + + createChapter("Onepunch-Man Punch Ver002 028.extra") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(28.99f) + } + + /** + * Chapter containing .v2 + */ + @Test fun dotV2Case() { + createChapter("Vol.1 Ch.5v.2: Alones") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(5f) + } + + /** + * Check for case with number in manga title + */ + @Test fun numberInMangaTitleCase() { + createManga("Ayame 14") + createChapter("Ayame 14 1 - The summer of 14") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(1f) + } + + /** + * Case with space between ch. x + */ + @Test fun spaceAfterChapterCase() { + createManga("Mokushiroku Alice") + createChapter("Mokushiroku Alice Vol.1 Ch. 4: Misrepresentation") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(4f) + } + + /** + * Chapter containing mar(ch) + */ + @Test fun marchInChapterCase() { + createManga("Ayame 14") + createChapter("Vol.1 Ch.1: March 25 (First Day Cohabiting)") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(1f) + } + + /** + * Chapter containing range + */ + @Test fun rangeInChapterCase() { + createChapter("Ch.191-200 Read Online") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(191f) + } + + /** + * Chapter containing multiple zeros + */ + @Test fun multipleZerosCase() { + createChapter("Vol.001 Ch.003: Kaguya Doesn't Know Much") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(3f) + } + + /** + * Chapter with version before number + */ + @Test fun chapterBeforeNumberCase() { + createManga("Onepunch-Man") + createChapter("Onepunch-Man Punch Ver002 086 : Creeping Darkness [3]") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(86f) + } + + /** + * Case with version attached to chapter number + */ + @Test fun vAttachedToChapterCase() { + createManga("Ansatsu Kyoushitsu") + createChapter("Ansatsu Kyoushitsu 011v002: Assembly Time") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(11f) + } + + /** + * Case where the chapter title contains the chapter + * But wait it's not actual the chapter number. + */ + @Test fun NumberAfterMangaTitleWithChapterInChapterTitleCase() { + createChapter("Tokyo ESP 027: Part 002: Chapter 001") + createManga("Tokyo ESP") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(027f) + } + + /** + * unParsable chapter + */ + @Test fun unParsableCase() { + createChapter("Foo") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(-1f) + } + + /** + * chapter with time in title + */ + @Test fun timeChapterCase() { + createChapter("Fairy Tail 404: 00:00") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(404f) + } + + /** + * chapter with alpha without dot + */ + @Test fun alphaWithoutDotCase() { + createChapter("Asu No Yoichi 19a") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(19.1f) + } + + /** + * Chapter title containing extra and vol + */ + @Test fun chapterContainingExtraCase() { + createManga("Fairy Tail") + + createChapter("Fairy Tail 404.extravol002") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(404.99f) + + createChapter("Fairy Tail 404 extravol002") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(404.99f) + + createChapter("Fairy Tail 404.evol002") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(404.5f) + } + + /** + * Chapter title containing omake (japanese extra) and vol + */ + @Test fun chapterContainingOmakeCase() { + createManga("Fairy Tail") + + createChapter("Fairy Tail 404.omakevol002") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(404.98f) + + createChapter("Fairy Tail 404 omakevol002") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(404.98f) + + createChapter("Fairy Tail 404.ovol002") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(404.15f) + } + + /** + * Chapter title containing special and vol + */ + @Test fun chapterContainingSpecialCase() { + createManga("Fairy Tail") + + createChapter("Fairy Tail 404.specialvol002") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(404.97f) + + createChapter("Fairy Tail 404 specialvol002") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(404.97f) + + createChapter("Fairy Tail 404.svol002") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(404.19f) + } + + /** + * Chapter title containing comma's + */ + @Test fun chapterContainingCommasCase() { + createManga("One Piece") + + createChapter("One Piece 300,a") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(300.1f) + + createChapter("One Piece Ch,123,extra") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(123.99f) + + createChapter("One Piece the sunny, goes swimming 024,005") + ChapterRecognition.parseChapterNumber(chapter, manga) + assertThat(chapter.chapter_number).isEqualTo(24.005f) + } + +}