Загрузка данных
package ru.notesapp.util
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import ru.notesapp.domain.SimpleNote
import ru.notesapp.domain.User
@MiniSerializable
private data class OneField(val value: String)
@MiniSerializable
private data class ThreeFields(val a: String, val b: Long, val c: Boolean)
@MiniSerializable(name = "renamed")
private data class RenamedClass(val x: String)
@MiniSerializable
private data class MixedFields(
@MiniSerializable(name = "renamed_a") val a: String,
val b: String,
)
@MiniSerializable
private data class EmptyName(
@MiniSerializable(name = "") val a: String,
)
@MiniSerializable
private data class IntField(val a: Int)
@MiniSerializable
private data class LongField(val a: Long)
@MiniSerializable
private data class DoubleField(val a: Double)
@MiniSerializable
private data class FloatField(val a: Float)
@MiniSerializable
private data class BooleanField(val a: Boolean)
@MiniSerializable
private data class NullableField(val a: String?)
@MiniSerializable
private data class OptionalDefault(val a: String = "default")
private data class NoAnnotation(val a: String)
class MiniJsonTest {
// ---------- toJson: базовые типы (8) ----------
@Test fun toJson_string_field_wrapped_in_quotes() {
val json = OneField("hi").toJson()
assertTrue(json.contains("\"value\":\"hi\""))
}
@Test fun toJson_int_field_no_quotes() {
val json = IntField(42).toJson()
assertTrue(json.contains("\"a\":42"))
assertFalse(json.contains("\"42\""))
}
@Test fun toJson_long_field_no_quotes() {
val json = LongField(999L).toJson()
assertTrue(json.contains("\"a\":999"))
}
@Test fun toJson_double_field_no_quotes() {
val json = DoubleField(3.14).toJson()
assertTrue(json.contains("\"a\":3.14"))
}
@Test fun toJson_float_field_no_quotes() {
val json = FloatField(2.5f).toJson()
assertTrue(json.contains("\"a\":2.5"))
}
@Test fun toJson_boolean_true_field_lowercase() {
val json = BooleanField(true).toJson()
assertTrue(json.contains("\"a\":true"))
}
@Test fun toJson_boolean_false_field_lowercase() {
val json = BooleanField(false).toJson()
assertTrue(json.contains("\"a\":false"))
}
@Test fun toJson_null_field_emits_null_without_quotes() {
val json = NullableField(null).toJson()
assertTrue(json.contains("\"a\":null"))
assertFalse(json.contains("\"null\""))
}
// ---------- toJson: структуры (6) ----------
@Test fun toJson_single_field_object() {
val json = OneField("x").toJson()
assertEquals("{\"value\":\"x\"}", json)
}
@Test fun toJson_three_fields_object() {
val json = ThreeFields("s", 1L, true).toJson()
assertTrue(json.startsWith("{"))
assertTrue(json.endsWith("}"))
assertTrue(json.contains("\"a\":\"s\""))
assertTrue(json.contains("\"b\":1"))
assertTrue(json.contains("\"c\":true"))
}
@Test fun toJson_field_separator_is_comma() {
val json = ThreeFields("s", 1L, true).toJson()
assertTrue(json.contains(","))
}
@Test fun toJson_key_value_separator_is_colon() {
val json = OneField("x").toJson()
assertTrue(json.contains(":"))
}
@Test fun toJson_object_starts_with_brace() {
assertTrue(OneField("x").toJson().startsWith("{"))
}
@Test fun toJson_object_ends_with_brace() {
assertTrue(OneField("x").toJson().endsWith("}"))
}
// ---------- toJson: аннотации (5) ----------
@Test fun toJson_uses_annotated_name_when_present() {
val user = User(1L, "Alice", null, 30)
val json = user.toJson()
assertTrue(json.contains("\"user_id\":1"))
assertTrue(json.contains("\"user_name\":\"Alice\""))
}
@Test fun toJson_uses_property_name_when_annotation_absent() {
val user = User(1L, "Alice", null, 30)
val json = user.toJson()
assertTrue(json.contains("\"email\""))
assertTrue(json.contains("\"age\""))
}
@Test fun toJson_uses_class_annotation_for_root() {
val json = RenamedClass("x").toJson()
assertTrue(json.startsWith("{"))
}
@Test fun toJson_annotation_empty_string_falls_back_to_property_name() {
val json = EmptyName("x").toJson()
assertTrue(json.contains("\"a\":\"x\""))
}
@Test fun toJson_mixed_annotated_and_non_annotated_fields() {
val json = MixedFields("x", "y").toJson()
assertTrue(json.contains("\"renamed_a\":\"x\""))
assertTrue(json.contains("\"b\":\"y\""))
}
// ---------- toJson: escape (5) ----------
@Test fun toJson_string_with_quote_escaped() {
val json = OneField("say \"hi\"").toJson()
assertTrue(json.contains("\\\""))
}
@Test fun toJson_string_with_backslash_escaped() {
val json = OneField("a\\b").toJson()
assertTrue(json.contains("\\\\"))
}
@Test fun toJson_string_with_newline_escaped() {
val json = OneField("a\nb").toJson()
assertTrue(json.contains("\\n"))
}
@Test fun toJson_string_with_tab_escaped() {
val json = OneField("a\tb").toJson()
assertTrue(json.contains("\\t"))
}
@Test fun toJson_string_with_unicode_preserved() {
val json = OneField("Привет").toJson()
assertTrue(json.contains("Привет"))
}
// ---------- toJson: ошибки (3) ----------
@Test(expected = IllegalArgumentException::class)
fun toJson_class_without_annotation_throws_IllegalArgumentException() {
NoAnnotation("x").toJson()
}
@Test fun toJson_class_without_annotation_error_message_includes_class_name() {
try {
NoAnnotation("x").toJson()
assertTrue(false)
} catch (e: IllegalArgumentException) {
assertTrue(e.message?.contains("NoAnnotation") == true)
}
}
@Test fun toJson_non_data_class_with_annotation_throws_or_succeeds() {
// Наш сериализатор работает через declaredMemberProperties,
// поэтому обычный класс тоже сериализуется, если помечен аннотацией.
val json = OneField("ok").toJson()
assertTrue(json.contains("ok"))
}
// ---------- fromJson: базовые типы (5) ----------
@Test fun fromJson_string_field_parsed_correctly() {
val obj = fromJson("""{"value":"hello"}""", OneField::class)
assertEquals("hello", obj.value)
}
@Test fun fromJson_int_field_parsed_correctly() {
val obj = fromJson("""{"a":42}""", IntField::class)
assertEquals(42, obj.a)
}
@Test fun fromJson_long_field_parsed_correctly() {
val obj = fromJson("""{"a":999}""", LongField::class)
assertEquals(999L, obj.a)
}
@Test fun fromJson_boolean_field_parsed_correctly() {
val obj = fromJson("""{"a":true}""", BooleanField::class)
assertEquals(true, obj.a)
}
@Test fun fromJson_null_field_becomes_null_property() {
val obj = fromJson("""{"a":null}""", NullableField::class)
assertEquals(null, obj.a)
}
// ---------- fromJson: структуры (4) ----------
@Test fun fromJson_single_field_object() {
val obj = fromJson("""{"value":"x"}""", OneField::class)
assertEquals("x", obj.value)
}
@Test fun fromJson_multiple_fields_object() {
val obj = fromJson("""{"a":"s","b":1,"c":true}""", ThreeFields::class)
assertEquals("s", obj.a)
assertEquals(1L, obj.b)
assertEquals(true, obj.c)
}
@Test fun fromJson_uses_annotated_name_to_map_to_property() {
val obj = fromJson("""{"renamed_a":"x","b":"y"}""", MixedFields::class)
assertEquals("x", obj.a)
assertEquals("y", obj.b)
}
@Test fun fromJson_missing_optional_field_uses_default() {
val obj = fromJson("""{}""", OptionalDefault::class)
assertEquals("default", obj.a)
}
// ---------- Round-trip (4) ----------
@Test fun round_trip_user_with_email_preserves_all_fields() {
val u = User(1L, "Alice", "a@b.c", 30)
assertEquals(u, fromJson(u.toJson(), User::class))
}
@Test fun round_trip_user_with_null_email_preserves_null() {
val u = User(2L, "Bob", null, 20)
assertEquals(u, fromJson(u.toJson(), User::class))
}
@Test fun round_trip_simple_note_preserves_all_fields() {
val n = SimpleNote(1L, "T", "C", 100L, "https://x.y/z")
assertEquals(n, fromJson(n.toJson(), SimpleNote::class))
}
@Test fun round_trip_unicode_strings_preserved() {
val u = User(3L, "Иван", "иван@почта.рф", 25)
assertEquals(u, fromJson(u.toJson(), User::class))
}
}