diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1cdbc4b --- /dev/null +++ b/.gitignore @@ -0,0 +1,44 @@ +# Gradle files +.gradle/ +build/ + +# Local configuration file +local.properties + +# Android Studio generated files +*.iml +.idea/ + +# Compiled class files +*.class + +# Log files +*.log + +# Android generated files +bin/ +gen/ +out/ + +# Dependency directories +/captures +.externalNativeBuild +.cxx + +# macOS system files +.DS_Store + +# Backup files +*.bak +*.swp + +# Kotlin build artifacts +*.jar +*.war +*.ear + +# Virtual machine crash logs +hs_err_pid* + +# Android Profiling +*.hprof \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..28d71c2 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,55 @@ +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") + id("kotlin-kapt") +} + +android { + namespace = "com.todoapp" + compileSdk = 33 + + defaultConfig { + applicationId = "com.todoapp" + minSdk = 24 + targetSdk = 33 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } +} + +dependencies { + // Room Database + implementation("androidx.room:room-runtime:2.5.1") + implementation("androidx.room:room-ktx:2.5.1") + kapt("androidx.room:room-compiler:2.5.1") + + // Kotlin standard library + implementation("org.jetbrains.kotlin:kotlin-stdlib:1.8.20") + + // Testing + testImplementation("junit:junit:4.13.2") + testImplementation("org.jetbrains.kotlin:kotlin-test:1.8.20") + + // Android testing + androidTestImplementation("androidx.test.ext:junit:1.1.5") + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") +} \ No newline at end of file diff --git a/app/src/main/java/com/todoapp/data/entity/Todo.kt b/app/src/main/java/com/todoapp/data/entity/Todo.kt new file mode 100644 index 0000000..e1b100f --- /dev/null +++ b/app/src/main/java/com/todoapp/data/entity/Todo.kt @@ -0,0 +1,50 @@ +package com.todoapp.data.entity + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import java.time.LocalDateTime + +/** + * Room database entity representing a Todo item. + * + * @property id Unique identifier for the Todo item + * @property title Title of the Todo item + * @property description Detailed description of the Todo item + * @property isCompleted Indicates whether the Todo item is completed + * @property createdAt Timestamp of when the Todo item was created + * @property dueDate Optional due date for the Todo item + */ +@Entity(tableName = "todos") +data class Todo( + @PrimaryKey(autoGenerate = true) + val id: Int = 0, + + @ColumnInfo(name = "title") + val title: String, + + @ColumnInfo(name = "description") + val description: String? = null, + + @ColumnInfo(name = "is_completed") + val isCompleted: Boolean = false, + + @ColumnInfo(name = "created_at") + val createdAt: LocalDateTime = LocalDateTime.now(), + + @ColumnInfo(name = "due_date") + val dueDate: LocalDateTime? = null +) { + /** + * Validates the Todo item properties. + * + * @throws IllegalArgumentException if validation fails + */ + init { + require(title.isNotBlank()) { "Title cannot be blank" } + require(title.length <= 100) { "Title cannot exceed 100 characters" } + description?.let { + require(it.length <= 500) { "Description cannot exceed 500 characters" } + } + } +} \ No newline at end of file diff --git a/app/src/test/java/com/todoapp/data/entity/TodoTest.kt b/app/src/test/java/com/todoapp/data/entity/TodoTest.kt new file mode 100644 index 0000000..05740db --- /dev/null +++ b/app/src/test/java/com/todoapp/data/entity/TodoTest.kt @@ -0,0 +1,66 @@ +package com.todoapp.data.entity + +import org.junit.Test +import java.time.LocalDateTime +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertNotNull + +class TodoTest { + + @Test + fun `create todo with valid data`() { + val todo = Todo( + title = "Test Todo", + description = "Test description" + ) + + assertNotNull(todo) + assertEquals("Test Todo", todo.title) + assertEquals("Test description", todo.description) + assertEquals(false, todo.isCompleted) + assertNotNull(todo.createdAt) + } + + @Test + fun `create todo with all properties`() { + val dueDate = LocalDateTime.now().plusDays(1) + val todo = Todo( + title = "Complete project", + description = "Finish the todo app implementation", + isCompleted = true, + dueDate = dueDate + ) + + assertEquals("Complete project", todo.title) + assertEquals("Finish the todo app implementation", todo.description) + assertEquals(true, todo.isCompleted) + assertEquals(dueDate, todo.dueDate) + } + + @Test + fun `fail to create todo with blank title`() { + assertFailsWith { + Todo(title = "") + } + } + + @Test + fun `fail to create todo with title exceeding 100 characters`() { + val longTitle = "a".repeat(101) + assertFailsWith { + Todo(title = longTitle) + } + } + + @Test + fun `fail to create todo with description exceeding 500 characters`() { + val longDescription = "a".repeat(501) + assertFailsWith { + Todo( + title = "Valid Title", + description = longDescription + ) + } + } +} \ No newline at end of file