Example 1
## Code Snippet
- DebtsModel.kt
```kotlin
private fun getTodayDateInteger(): Int {
val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault())
return dateFormat.format(Date())
}
```
- DebtsAdapter.kt
```kotlin
fun getDatePassed(debtDate: String): Int {
val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault())
val dateString = dateFormat.format(Date())
val dateSplit = dateString.split("-")
val debtDateSplit = debtDate.split("-")
....
return daysBetween.toInt()
}
```
```kotlin
private fun getTodayDateInteger(): Int {
val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault())
val dateString = dateFormat.format(Date())
val dateSplit = dateString.split("-")
....
return ((yearInt * 10000) + (monthInt * 100) + dayInt)
}
```
## Code Description
In the three code snippets above we can see that the three functions are made for the same goal: to retrieve the date today. These two functions are in two different classes and although the one below changes the date into an integer form, the first function could pass the string date and then change it into an int without calling the `SimpleDateFormat` function again.
## Flaw Reason
This defies the DRY (Don't Repeat Yourself) principle and could be a problem in the future if let's say we want to change the format of the date into `dd.MM.yyy`, we could not get the saved data like we wanted it to be or even an error.
Example 2
## Code Snippet
- AddDebtDetails.kt
```kotlin
binding.saveBtn.setOnClickListener {
val debtorName = binding.addCreditorName.text.toString()
val debtAmount = binding.debtSum.text.toString()
val debtCurrency = binding.currencySpinner.selectedItem.toString()
var debtDate = dateString
val isDebtor = btnState
val dateInteger = aDateInteger
....
}
```
```kotlin
binding.deleteBtn.setOnClickListener {
val builder = AlertDialog.Builder(this@AddDebtDetails)
builder.setMessage(getString(R.string.delete_popup))
.setCancelable(false)
.setPositiveButton("Yes") { _, _ ->
val debtorName = binding.addCreditorName.text.toString()
val debtAmount = binding.debtSum.text.toString()
val debtCurrency = binding.currencySpinner.selectedItem.toString()
val debtDate = dateString
val isDebtor = btnState
val dateInteger = aDateInteger
....
}
```
## Code Description
In the two code snippet, we can see that we declared the list of val twice in different `setOnClickListener`. We could have just declared all the val beforehand and called or assigned it in the `setOnClickListener`.
## Flaw Reason
This also defies the DRY principle and declaring it once beforehand would increase the development time if in the future we would want to use similar values.
Example 1
## Code Flaw
The duplicated code in this example is making the date in a specific format which is `dd-MM-yyyy` and the code block to make such a pattern is duplicated throughout the project.
## Unit Test Description
```kotlin
@RequiresApi(Build.VERSION_CODES.O)
val format: DateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy")
@RequiresApi(Build.VERSION_CODES.O)
fun isDateFormatValid(date: String): Boolean {
return try {
LocalDate.parse(date, format)
true
} catch (e: DateTimeParseException) {
false
}
}
```
The test is centered around the date formatting and will test for inputs that are not the same as the pattern or days/months that are out of range.
## Test 1
```kotlin
@Test
fun dateFormat_yearInMonth_falseReturn() {
val result = DuplicateCode.isDateFormatValid(
"23-2004-03"
)
assertThat(result).isFalse()
}
```
The test asserts false when the year is put in the month's place
## Test 2
```kotlin
@Test
fun dateFormat_dateOutOfRange_falseReturn() {
val result = DuplicateCode.isDateFormatValid(
"32-03-2004"
)
assertThat(result).isFalse()
}
```
The test asserts false when the date inputted is out of range as there is no "32nd of February"
## Test 3
```kotlin
@Test
fun dateFormat_wrongDatePattern_falseReturn() {
val result = DuplicateCode.isDateFormatValid(
"23.03.2004"
)
assertThat(result).isFalse()
}
```
The test asserts false when the "-" pattern is changed into "."
## Test 4
```kotlin
@Test
fun dateFormat_rightFormat_trueReturn() {
val result = DuplicateCode.isDateFormatValid(
"23-03-2004"
)
assertThat(result).isTrue()
}
```
The test asserts true when the date and months are not out of range and the pattern is in accordance with the determined pattern.
Example 2
## Code Flaw
The duplicated code in this example is declaring multiple variable for a Data Clump (which is also another code flaw) multiple times for saving, updating and deleting a debt.
## Unit Test Description
```kotlin
@RequiresApi(Build.VERSION_CODES.O)
val format: DateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy")
@RequiresApi(Build.VERSION_CODES.O)
fun isDebtAddedValid(
debtorName: String,
debtAmount: Int,
debtCurrency: String,
debtDate: String,
debtInteger: Int
): Boolean {
val tempDebtInteger: Int
try {
LocalDate.parse(debtDate, format)
val dateSplit = debtDate.split("-")
val dayInt = Integer.parseInt(dateSplit[0])
val monthInt = Integer.parseInt(dateSplit[1])
val yearInt = Integer.parseInt(dateSplit[2])
tempDebtInteger = (yearInt * 10000) + (monthInt * 100) + dayInt
} catch (e: DateTimeParseException) {
return false
}
if (debtInteger != tempDebtInteger) {
return false
}
if (debtorName.isEmpty() || debtAmount <= 0 || debtCurrency.isEmpty()) {
return false
}
return true
}
```
The test is centered around the required variables needed for making a new debt. Making a new debt will require the debtorName, an amount above 0, a date in the right pattern, and a debtInteger that is the date in an Integer form.
The debtInteger and debtDate were a Primitive Obsession in this project where the data is stored for the debt return deadline date. The debtInteger serves as a list where the debt with an integer closer to today's date integer will show in the top list.
## Test 1
```kotlin
@Test
fun addDebts_wrongDateFormat_falseReturn() {
val result = DuplicateCode.isDebtAddedValid(
"Joe",
23,
"ruble",
"20.03.2004",
20040320
)
assertThat(result).isFalse()
}
```
The test asserts false when the date format inputted is wrong
## Test 2
```kotlin
@Test
fun addDebts_wrongDateInteger_falseReturn() {
val result = DuplicateCode.isDebtAddedValid(
"Joe",
23,
"ruble",
"20-03-2004",
2004320
)
assertThat(result).isFalse()
}
```
The test asserts false when the date integer is inputted is different than the date in String
## Test 3
```kotlin
@Test
fun addDebts_noName_falseReturn() {
val result = DuplicateCode.isDebtAddedValid(
"",
23,
"ruble",
"20-03-2004",
20040320
)
assertThat(result).isFalse()
}
```
The test asserts false when there is no name inputted
## Test 4
```kotlin
@Test
fun addDebts_noAmount_falseReturn() {
val result = DuplicateCode.isDebtAddedValid(
"Joe",
0,
"ruble",
"20-03-2004",
20040320
)
assertThat(result).isFalse()
}
```
The test asserts false when the debtAmount is 0
## Test 5
```kotlin
@Test
fun addDebts_rightInput_trueReturn() {
val result = DuplicateCode.isDebtAddedValid(
"Joe",
23,
"ruble",
"20-03-2004",
20040320
)
assertThat(result).isTrue()
}
```
The test asserts true when the debt name and currency are not empty, the debtAmount is above 0, the debt date format is right and the debtInteger is similar to the debt date.
Example 1
## Code Snippet - DebtsModel.kt ```kotlin private fun getTodayDateInteger(): Int { val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()) return dateFormat.format(Date()) } ``` - DebtsAdapter.kt ```kotlin fun getDatePassed(debtDate: String): Int { val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()) val dateString = dateFormat.format(Date()) val dateSplit = dateString.split("-") val debtDateSplit = debtDate.split("-") .... return daysBetween.toInt() } ``` ```kotlin private fun getTodayDateInteger(): Int { val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()) val dateString = dateFormat.format(Date()) val dateSplit = dateString.split("-") .... return ((yearInt * 10000) + (monthInt * 100) + dayInt) } ``` ## Code Description In the three code snippets above we can see that the three functions are made for the same goal: to retrieve the date today. These two functions are in two different classes and although the one below changes the date into an integer form, the first function could pass the string date and then change it into an int without calling the `SimpleDateFormat` function again. ## Flaw Reason This defies the DRY (Don't Repeat Yourself) principle and could be a problem in the future if let's say we want to change the format of the date into `dd.MM.yyy`, we could not get the saved data like we wanted it to be or even an error.Example 2
## Code Snippet - AddDebtDetails.kt ```kotlin binding.saveBtn.setOnClickListener { val debtorName = binding.addCreditorName.text.toString() val debtAmount = binding.debtSum.text.toString() val debtCurrency = binding.currencySpinner.selectedItem.toString() var debtDate = dateString val isDebtor = btnState val dateInteger = aDateInteger .... } ``` ```kotlin binding.deleteBtn.setOnClickListener { val builder = AlertDialog.Builder(this@AddDebtDetails) builder.setMessage(getString(R.string.delete_popup)) .setCancelable(false) .setPositiveButton("Yes") { _, _ -> val debtorName = binding.addCreditorName.text.toString() val debtAmount = binding.debtSum.text.toString() val debtCurrency = binding.currencySpinner.selectedItem.toString() val debtDate = dateString val isDebtor = btnState val dateInteger = aDateInteger .... } ``` ## Code Description In the two code snippet, we can see that we declared the list of val twice in different `setOnClickListener`. We could have just declared all the val beforehand and called or assigned it in the `setOnClickListener`. ## Flaw Reason This also defies the DRY principle and declaring it once beforehand would increase the development time if in the future we would want to use similar values.