Marcell-Juhasz / secret-diary

0 stars 1 forks source link

maybe issue with SharedPreferences #26

Closed RedJocker closed 1 year ago

RedJocker commented 1 year ago

from tester report

If your SharedReferences is not clear at the beginning if you have done testing on your own and not cleared the with editor.clear() you are failing to pass the test. Only after implementing editor.clear() I was able to pass.

RedJocker commented 1 year ago

I asked tester for more clarifications on this issue

RedJocker commented 1 year ago

messages I just exchanged with tester (first message at bottom):


mauricio rodriguez [3 minutos atrás]

@charymyratgarryyev Ok, we will try to investigate to find something wrong. I don't think the problem is related to your manual testing because tests run in a different environment it does not run in devices it runs everything in jvm, so the state of whatever device real or emulated you have should not have any influence in tests. But maybe something else is happening.

--

Charymyrat Garryyev [18 minutos atrás]

@mauriciorodriguez235 As far as I can remember the issue happened on the one before the successful one, in the submission of Nov 18, 2022, 4:05:47 AM.

--

Charymyrat Garryyev [22 minutos atrás]

@mauriciorodriguez235 Ok, I have attached a screenshot of stage 4 submissions. Can you take a look at it, and tell me what should I do next?

--

mauricio rodriguez [41 minutos atrás]

@charymyratgarryyev there is a submissions tab right next to description tab. All your submissions should be listed there with their id number. You can check the code of a particular submission clicking on it

--

Charymyrat Garryyev [uma hora atrás]

@mauriciorodriguez235 It will be really hard to recreate the same situation if there is no way to somehow get my exact submitted code. Is there any way for me to get the exact code that I submitted for stage 4?

Can I somehow backtrack the stage codes?

--

mauricio rodriguez [uma hora atrás]

@charymyratgarryyev can you reproduce that issue again? If you can please make a new submission with that code so that we have the same code to test.

--

Charymyrat Garryyev [uma hora atrás]

@mauriciorodriguez235 Hi! Yes, I have looked at the comments on the report. What happened was that before the submission of stage4 I checked it on my physical device, simply I run the app on my Android device, so the file for the SharedProferences was not empty, The app worked on my phone as per stage required, so then I tried to pass the test, but it could not pass the test. Only after I have used editor.clear() I have managed to pass the stage. As for the part of the specific submission to look into, I think I don't have it.

--

mauricio rodriguez [5 horas atrás]

@charymyratgarryyev Hi I have just commented on you report asking for more clarification on the issue on stage4. Marcell that is in charge of fixing was not able to reproduce that

RedJocker commented 1 year ago

his code was mostly on the MainActivity and this is his code for that on the submission he has mentioned:

package org.hyperskill.secretdiary

import android.annotation.SuppressLint
import android.os.Bundle
import android.view.KeyEvent
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import android.widget.Toast
import android.app.AlertDialog
import android.content.Context
import android.content.SharedPreferences
import androidx.appcompat.app.AppCompatActivity

import kotlinx.datetime.*
import java.text.SimpleDateFormat
import java.util.*

const val PREF_DIARY = "PREF_DIARY"

class MainActivity : AppCompatActivity() {

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val sharedPref = getSharedPreferences(PREF_DIARY, Context.MODE_PRIVATE)
        val editor = sharedPref.edit()
        val keyForSF = "KEY_DIARY_TEXT"

        val strFromSF = sharedPref.getString(keyForSF, null)
        var mutListFromSF = strFromSF?.split("\n\n")?.toMutableList()
        if (mutListFromSF != null) {
            println("mutListFromSF = $mutListFromSF with ${mutListFromSF.size}")
            if (strFromSF != null) {
                println("strFromSF = $strFromSF with ${strFromSF.length}")
            }
        }
        println("mutListFromSF = $mutListFromSF")

        val etNewWriting = findViewById<EditText>(R.id.etNewWriting)
        val tvDiary = findViewById<TextView>(R.id.tvDiary)
        if (strFromSF != null) {
            tvDiary.text = strFromSF.trim()
        }

        val btnSave = findViewById<Button>(R.id.btnSave)
        val btnUndo = findViewById<Button>(R.id.btnUndo)

        var notesMutList = mutableListOf<String>()

        btnSave.setOnClickListener {
            val text = etNewWriting.text
            if (text.isNullOrBlank()) {
                val toastText: String = "Empty or blank input cannot be saved"
                val duration = Toast.LENGTH_SHORT
                val toast = Toast.makeText(applicationContext, toastText, duration)
                toast.show()
                println("if statement")
            } else {
                val milliseconds = Clock.System.now().toEpochMilliseconds()
                val date = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(milliseconds).toString()
                val singleNoteStr = "${date}\n${etNewWriting.text.trim()}"
                val notesUntilMoment = if (tvDiary.text != null) {
                    singleNoteStr + "\n\n" + tvDiary.text
                } else singleNoteStr

                editor.apply {
                    putString(keyForSF, notesUntilMoment)
                    apply()
                }

                tvDiary.text = sharedPref.getString(keyForSF, null)
                println(tvDiary.text)

                if (mutListFromSF != null) {
                    println("mutListFromSF = $mutListFromSF with ${mutListFromSF!!.size}")
                }
                println("mutListFromSF = $mutListFromSF")

                etNewWriting.setText("")
            }
        }

        btnUndo.setOnClickListener {
            AlertDialog.Builder(this)
                .setTitle("Remove last note")
                .setMessage("Do you really want to remove the last writing? This operation cannot be undone!")
                .setPositiveButton(android.R.string.yes) {_, _ ->

                    val strFromSF = sharedPref.getString(keyForSF, null)?.trim()
                    var mutListFromSF = strFromSF?.split("\n\n")?.toMutableList()
                    if (mutListFromSF != null) {
                        println("mutListFromSF = $mutListFromSF with ${mutListFromSF.size}, ${mutListFromSF[0].isBlank()}")
                    }
                    println("mutListFromSF = $mutListFromSF")

                    if (mutListFromSF != null) {
                        println("mutListFromSF = $mutListFromSF with ${mutListFromSF!!.size}")
                        notesMutList = mutListFromSF?.toMutableList()!!
                        if (notesMutList.isNotEmpty()) notesMutList.removeAt(0)
                        mutListFromSF = notesMutList
                        tvDiary.text = notesMutList.joinToString("\n\n").trim()
                        editor.apply {
                            putString(keyForSF, tvDiary.text.toString())
                            apply()
                        }
                    }

                    if (tvDiary.text.toString().isBlank()) {
                        editor.clear()
                    }
                }
                .setNegativeButton(android.R.string.no, null)
                .show()
        }
    }
}
RedJocker commented 1 year ago

and the code he passed the stage4 with:

package org.hyperskill.secretdiary

import android.annotation.SuppressLint
import android.os.Bundle
import android.view.KeyEvent
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import android.widget.Toast
import android.app.AlertDialog
import android.content.Context
import android.content.SharedPreferences
import androidx.appcompat.app.AppCompatActivity

import kotlinx.datetime.*
import java.text.SimpleDateFormat
import java.util.*

const val PREF_DIARY = "PREF_DIARY"

class MainActivity : AppCompatActivity() {

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val sharedPref = getSharedPreferences(PREF_DIARY, Context.MODE_PRIVATE)
        val editor = sharedPref.edit()
        val keyForSF = "KEY_DIARY_TEXT"

        val strFromSF = sharedPref.getString(keyForSF, null)
        var mutListFromSF = strFromSF?.split("\n\n")?.toMutableList()
        if (mutListFromSF != null) {
            println("mutListFromSF = $mutListFromSF with ${mutListFromSF.size}")
            if (strFromSF != null) {
                println("strFromSF = $strFromSF with ${strFromSF.length}")
            }
        }
        println("mutListFromSF = $mutListFromSF")

        val etNewWriting = findViewById<EditText>(R.id.etNewWriting)
        val tvDiary = findViewById<TextView>(R.id.tvDiary)
        if (strFromSF != null) {
            tvDiary.text = strFromSF.trim()
        }

        val btnSave = findViewById<Button>(R.id.btnSave)
        val btnUndo = findViewById<Button>(R.id.btnUndo)

        var notesMutList = mutableListOf<String>()

        btnSave.setOnClickListener {
            val text = etNewWriting.text
            if (text.isNullOrBlank()) {
                val toastText: String = "Empty or blank input cannot be saved"
                val duration = Toast.LENGTH_SHORT
                val toast = Toast.makeText(applicationContext, toastText, duration)
                toast.show()
                println("if statement")
            } else {
                val milliseconds = Clock.System.now().toEpochMilliseconds()
                val date = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(milliseconds).toString()
                val singleNoteStr = "${date}\n${etNewWriting.text.trim()}"
                val notesUntilMoment = if (tvDiary.text != null) {
                    singleNoteStr + "\n\n" + tvDiary.text
                } else singleNoteStr

                editor.apply {
                    putString(keyForSF, notesUntilMoment.trim())
                    apply()
                }

                tvDiary.text = sharedPref.getString(keyForSF, null)?.trim()
                println(tvDiary.text)

                if (mutListFromSF != null) {
                    println("mutListFromSF = $mutListFromSF with ${mutListFromSF!!.size}")
                }
                println("mutListFromSF = $mutListFromSF")

                etNewWriting.setText("")
            }
        }

        btnUndo.setOnClickListener {
            AlertDialog.Builder(this)
                .setTitle("Remove last note")
                .setMessage("Do you really want to remove the last writing? This operation cannot be undone!")
                .setPositiveButton(android.R.string.yes) {_, _ ->

                    val strFromSF = sharedPref.getString(keyForSF, null)?.trim()
                    var mutListFromSF = strFromSF?.split("\n\n")?.toMutableList()
                    if (mutListFromSF != null) {
                        val mutL = mutableListOf<String>()
                        println("mutListFromSF = $mutListFromSF with ${mutListFromSF.size}, ${mutListFromSF[0].isBlank()}")
                        println("mutL = $mutL with ${mutL.size}")
                    }
                    println("mutListFromSF = $mutListFromSF")

                    if (mutListFromSF != null) {
                        println("mutListFromSF = $mutListFromSF with ${mutListFromSF!!.size}")
                        notesMutList = mutListFromSF?.toMutableList()!!
                        if (notesMutList.isNotEmpty()) notesMutList.removeAt(0)
                        mutListFromSF = notesMutList
                        tvDiary.text = notesMutList.joinToString("\n\n").trim()
                        editor.apply {
                            putString(keyForSF, tvDiary.text.toString().trim())
                            apply()
                        }
                    }

                    if (tvDiary.text.toString().isBlank()) {
                        println("it is blank")
                        editor.clear()
                        editor.apply()
                    }
                }
                .setNegativeButton(android.R.string.no, null)
                .show()
        }
    }
}
Marcell-Juhasz commented 1 year ago

I found the problem.

Briefly: The tester added two empty lines to the end of the diary, this is why the code did not work. Not because of the SharedPreferences.

When I submit the "wrong" (the first one) code by clicking "Check" on the Task tab in AS, it gives an error message and you can see the "expected" and the "actual" output. The "actual" has two extra empty lines, because of this code snippet: tvDiary.text = notesMutList.joinToString("\n\n")

Besides the clearing of the SharedPreferences, there is another difference between the two codes. In the "correct" (the second one) code the tester used the "trim()" function that removes those empty lines. This is what made the code pass, not the editor.clear()

RedJocker commented 1 year ago

so it is not a problem with tests right?

Marcell-Juhasz commented 1 year ago

Yes, the tests work well as they don't accept if the user extends their solution with extra whitespace characters at the end of the string. Since the test give the user a clear message( output difference comparison) from which they can easily find out what is wrong with their output, I guess it's acceptable to require the exact output from the user.

RedJocker commented 1 year ago

ok