Skip to content

Commit

Permalink
Unit Test for getNoteTags and adding tags validation on Js
Browse files Browse the repository at this point in the history
  • Loading branch information
Haz3-jolt authored and lukstbit committed Feb 27, 2025
1 parent b653143 commit b64a565
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 2 deletions.
13 changes: 12 additions & 1 deletion AnkiDroid/src/main/assets/scripts/js-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ class AnkiDroidJS {
Object.keys(jsApiList).forEach(method => {
if (method === "ankiAddTagToNote") {
AnkiDroidJS.prototype[method] = async function (noteId, tag) {
console.warn("ankiAddTagToNote is deprecated. Use ankiSetNoteTags instead.");
console.warn("ankiAddTagToNote is deprecated. Use ankiSetNoteTags instead");
const endpoint = jsApiList[method];
const data = JSON.stringify({ noteId, tag });
return await this.handleRequest(endpoint, data);
Expand All @@ -130,6 +130,17 @@ Object.keys(jsApiList).forEach(method => {
}
if (method === "ankiSetNoteTags") {
AnkiDroidJS.prototype[method] = async function (noteId, tags) {
let hasSpaces = false;
for (let i = 0; i < tags.length; i++) {
tags[i] = tags[i].trim();
if (tags[i].includes(" ") || tags[i].includes("\u3000")) {
tags[i] = tags[i].replace(" ", "_").replace("\u3000", "_");
hasSpaces = true;
}
}
if (hasSpaces) {
console.warn("Spaces in tags have been converted to underscores");
}
const endpoint = jsApiList[method];
const data = JSON.stringify({ noteId, tags });
return await this.handleRequest(endpoint, data);
Expand Down
8 changes: 7 additions & 1 deletion AnkiDroid/src/main/java/com/ichi2/anki/AnkiDroidJsAPI.kt
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ open class AnkiDroidJsAPI(
* @param returnDefaultValues `true` if default values should be returned (if non-[Reviewer])
* @return
*/
@NeedsTest("setNoteTags: Test that tags are set for all edge cases")
open suspend fun handleJsApiRequest(
methodName: String,
bytes: ByteArray,
Expand Down Expand Up @@ -383,7 +384,12 @@ open class AnkiDroidJsAPI(
val tags = jsonObject.getJSONArray("tags")
withCol {
fun Note.setTagsFromList(tagList: List<String>) {
val tagsAsString = this@withCol.tags.join(tagList)
val sanitizedTags = tagList.map { it.trim() }
val spaces = "\\s|\u3000".toRegex()
if (sanitizedTags.any { it.contains(spaces) }) {
throw IllegalArgumentException("Tags cannot contain spaces")
}
val tagsAsString = this@withCol.tags.join(sanitizedTags)
setTagsFromStr(this@withCol, tagsAsString)
}

Expand Down
42 changes: 42 additions & 0 deletions AnkiDroid/src/test/java/com/ichi2/anki/AnkiDroidJsAPITest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.ichi2.utils.BASIC_MODEL_NAME
import net.ankiweb.rsdroid.withoutUnicodeIsolation
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert.assertThat
import org.json.JSONArray
import org.json.JSONObject
import org.junit.Ignore
import org.junit.Test
Expand Down Expand Up @@ -418,6 +419,31 @@ class AnkiDroidJsAPITest : RobolectricTest() {
assertEquals(CardType.New, cardAfterReset.type, "Card type after reset")
}

@Test
fun ankiGetNoteTagsTest() =
runTest {
val n =
addBasicNote("Front", "Back").update {
tags = mutableListOf("tag1", "tag2", "tag3")
}

val reviewer: Reviewer = startReviewer()
waitForAsyncTasksToComplete()

val jsapi = reviewer.jsApi

// test get tags for note
val expectedTags = n.tags
val response = getDataFromRequest("getNoteTags", jsapi, jsonObjectOf("noteId" to n.id))
val jsonResponse = JSONObject(response)
val actualTags = JSONArray(jsonResponse.getString("value"))

assertEquals(expectedTags.size, actualTags.length())
for (i in 0 until actualTags.length()) {
assertEquals(expectedTags[i], actualTags.getString(i))
}
}

companion object {
fun jsApiContract(data: String = ""): ByteArray =
JSONObject()
Expand Down Expand Up @@ -451,5 +477,21 @@ class AnkiDroidJsAPITest : RobolectricTest() {
jsAPI
.handleJsApiRequest(methodName, jsApiContract(apiData), false)
.decodeToString()

suspend fun getDataFromRequest(
methodName: String,
jsAPI: AnkiDroidJsAPI,
apiData: JSONObject,
): String =
jsAPI
.handleJsApiRequest(methodName, jsApiContract(apiData.toString()), false)
.decodeToString()
}
}

private fun jsonObjectOf(vararg pairs: Pair<String, Any>): JSONObject =
JSONObject().apply {
for ((key, value) in pairs) {
put(key, value)
}
}
7 changes: 7 additions & 0 deletions AnkiDroid/src/test/java/com/ichi2/testutils/TestClass.kt
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,13 @@ interface TestClass {
col.decks.save(deckConfig)
}

/** Helper method to update a note */
fun Note.update(block: Note.() -> Unit): Note {
block(this)
col.updateNote(this)
return this
}

/** Helper method to all cards of a note */
fun Note.updateCards(update: Card.() -> Unit): Note {
cards().forEach { it.update(update) }
Expand Down

0 comments on commit b64a565

Please sign in to comment.