Skip to content

Commit b64a565

Browse files
Haz3-joltlukstbit
authored andcommitted
Unit Test for getNoteTags and adding tags validation on Js
1 parent b653143 commit b64a565

File tree

4 files changed

+68
-2
lines changed

4 files changed

+68
-2
lines changed

AnkiDroid/src/main/assets/scripts/js-api.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ class AnkiDroidJS {
121121
Object.keys(jsApiList).forEach(method => {
122122
if (method === "ankiAddTagToNote") {
123123
AnkiDroidJS.prototype[method] = async function (noteId, tag) {
124-
console.warn("ankiAddTagToNote is deprecated. Use ankiSetNoteTags instead.");
124+
console.warn("ankiAddTagToNote is deprecated. Use ankiSetNoteTags instead");
125125
const endpoint = jsApiList[method];
126126
const data = JSON.stringify({ noteId, tag });
127127
return await this.handleRequest(endpoint, data);
@@ -130,6 +130,17 @@ Object.keys(jsApiList).forEach(method => {
130130
}
131131
if (method === "ankiSetNoteTags") {
132132
AnkiDroidJS.prototype[method] = async function (noteId, tags) {
133+
let hasSpaces = false;
134+
for (let i = 0; i < tags.length; i++) {
135+
tags[i] = tags[i].trim();
136+
if (tags[i].includes(" ") || tags[i].includes("\u3000")) {
137+
tags[i] = tags[i].replace(" ", "_").replace("\u3000", "_");
138+
hasSpaces = true;
139+
}
140+
}
141+
if (hasSpaces) {
142+
console.warn("Spaces in tags have been converted to underscores");
143+
}
133144
const endpoint = jsApiList[method];
134145
const data = JSON.stringify({ noteId, tags });
135146
return await this.handleRequest(endpoint, data);

AnkiDroid/src/main/java/com/ichi2/anki/AnkiDroidJsAPI.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ open class AnkiDroidJsAPI(
206206
* @param returnDefaultValues `true` if default values should be returned (if non-[Reviewer])
207207
* @return
208208
*/
209+
@NeedsTest("setNoteTags: Test that tags are set for all edge cases")
209210
open suspend fun handleJsApiRequest(
210211
methodName: String,
211212
bytes: ByteArray,
@@ -383,7 +384,12 @@ open class AnkiDroidJsAPI(
383384
val tags = jsonObject.getJSONArray("tags")
384385
withCol {
385386
fun Note.setTagsFromList(tagList: List<String>) {
386-
val tagsAsString = this@withCol.tags.join(tagList)
387+
val sanitizedTags = tagList.map { it.trim() }
388+
val spaces = "\\s|\u3000".toRegex()
389+
if (sanitizedTags.any { it.contains(spaces) }) {
390+
throw IllegalArgumentException("Tags cannot contain spaces")
391+
}
392+
val tagsAsString = this@withCol.tags.join(sanitizedTags)
387393
setTagsFromStr(this@withCol, tagsAsString)
388394
}
389395

AnkiDroid/src/test/java/com/ichi2/anki/AnkiDroidJsAPITest.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import com.ichi2.utils.BASIC_MODEL_NAME
2828
import net.ankiweb.rsdroid.withoutUnicodeIsolation
2929
import org.hamcrest.CoreMatchers.equalTo
3030
import org.hamcrest.MatcherAssert.assertThat
31+
import org.json.JSONArray
3132
import org.json.JSONObject
3233
import org.junit.Ignore
3334
import org.junit.Test
@@ -418,6 +419,31 @@ class AnkiDroidJsAPITest : RobolectricTest() {
418419
assertEquals(CardType.New, cardAfterReset.type, "Card type after reset")
419420
}
420421

422+
@Test
423+
fun ankiGetNoteTagsTest() =
424+
runTest {
425+
val n =
426+
addBasicNote("Front", "Back").update {
427+
tags = mutableListOf("tag1", "tag2", "tag3")
428+
}
429+
430+
val reviewer: Reviewer = startReviewer()
431+
waitForAsyncTasksToComplete()
432+
433+
val jsapi = reviewer.jsApi
434+
435+
// test get tags for note
436+
val expectedTags = n.tags
437+
val response = getDataFromRequest("getNoteTags", jsapi, jsonObjectOf("noteId" to n.id))
438+
val jsonResponse = JSONObject(response)
439+
val actualTags = JSONArray(jsonResponse.getString("value"))
440+
441+
assertEquals(expectedTags.size, actualTags.length())
442+
for (i in 0 until actualTags.length()) {
443+
assertEquals(expectedTags[i], actualTags.getString(i))
444+
}
445+
}
446+
421447
companion object {
422448
fun jsApiContract(data: String = ""): ByteArray =
423449
JSONObject()
@@ -451,5 +477,21 @@ class AnkiDroidJsAPITest : RobolectricTest() {
451477
jsAPI
452478
.handleJsApiRequest(methodName, jsApiContract(apiData), false)
453479
.decodeToString()
480+
481+
suspend fun getDataFromRequest(
482+
methodName: String,
483+
jsAPI: AnkiDroidJsAPI,
484+
apiData: JSONObject,
485+
): String =
486+
jsAPI
487+
.handleJsApiRequest(methodName, jsApiContract(apiData.toString()), false)
488+
.decodeToString()
454489
}
455490
}
491+
492+
private fun jsonObjectOf(vararg pairs: Pair<String, Any>): JSONObject =
493+
JSONObject().apply {
494+
for ((key, value) in pairs) {
495+
put(key, value)
496+
}
497+
}

AnkiDroid/src/test/java/com/ichi2/testutils/TestClass.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,13 @@ interface TestClass {
241241
col.decks.save(deckConfig)
242242
}
243243

244+
/** Helper method to update a note */
245+
fun Note.update(block: Note.() -> Unit): Note {
246+
block(this)
247+
col.updateNote(this)
248+
return this
249+
}
250+
244251
/** Helper method to all cards of a note */
245252
fun Note.updateCards(update: Card.() -> Unit): Note {
246253
cards().forEach { it.update(update) }

0 commit comments

Comments
 (0)