Skip to content

Commit

Permalink
Merge branch 'pjhn' into step2
Browse files Browse the repository at this point in the history
  • Loading branch information
Pjhn authored Jul 28, 2024
2 parents e4c2b83 + 9411703 commit 12a0ad6
Show file tree
Hide file tree
Showing 20 changed files with 772 additions and 10 deletions.
37 changes: 37 additions & 0 deletions app/src/androidTest/java/campus/tech/kakao/map/MapActivityTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package campus.tech.kakao.map

import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.matcher.IntentMatchers
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import campus.tech.kakao.map.presentation.MapActivity
import campus.tech.kakao.map.presentation.SearchActivity
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class MapActivityTest {
@get:Rule
var activityScenarioRule = ActivityScenarioRule(MapActivity::class.java)

@Test
fun testActivityLaunch() {

onView(withId(R.id.mapView)).check(matches(isDisplayed()))
onView(withId(R.id.searchView)).check(matches(isDisplayed()))
}

@Test
fun testSearchedResultOnMap() {
Intents.init()
onView(withId(R.id.searchView)).perform(click())
Intents.intended(IntentMatchers.hasComponent(SearchActivity::class.java.name))
Intents.release()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package campus.tech.kakao.map

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import campus.tech.kakao.map.data.PlaceRepositoryImpl
import campus.tech.kakao.map.domain.model.Place
import campus.tech.kakao.map.util.PlaceContract
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class RepositoryImplTest {

private lateinit var repository: PlaceRepositoryImpl
private lateinit var context: Context

@Before
fun setUp() {
context = ApplicationProvider.getApplicationContext()
context.deleteDatabase(PlaceContract.DATABASE_NAME)
repository = PlaceRepositoryImpl.getInstance(context)
}

@After
fun after() {
repository.close()
context.deleteDatabase(PlaceContract.DATABASE_NAME)
}

@Test
fun testInsertAndGetPlaces() {
val place1 = Place("1", "Place1", "Address1", "Category1", "10.0", "20.0")
val place2 = Place("2", "Place2", "Address2", "Category2", "30.0", "40.0")
val places = listOf(place1, place2)

repository.updatePlaces(places)

val result = repository.getAllPlaces()
assertEquals(2, result.size)
assertEquals("Place1", result[0].place)
assertEquals("Place2", result[1].place)
}

@Test
fun testSearchPlaces() {
val place1 = Place("1", "Gangnam", "Address1", "Category1", "10.0", "20.0")
val place2 = Place("2", "Gangbuk", "Address2", "Category2", "30.0", "40.0")
val places = listOf(place1, place2)

repository.updatePlaces(places)

val result = repository.getPlaces("Gang")
assertEquals(2, result.size)
assertEquals("Gangnam", result[0].place)
assertEquals("Gangbuk", result[1].place)
}

@Test
fun testLogs() {
val log1 = Place("1", "Log1", "", "", "", "")
val log2 = Place("2", "Log2", "", "", "", "")
val logs = listOf(log1, log2)

repository.updateLogs(logs)

var result = repository.getLogs()
assertEquals(2, result.size)
assertEquals("Log1", result[0].place)
assertEquals("Log2", result[1].place)

repository.removeLog("1")
result = repository.getLogs()
assertEquals(1, result.size)
assertEquals("Log2", result[0].place)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package campus.tech.kakao.map

import android.content.Context
import android.content.SharedPreferences
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.replaceText
import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.ext.junit.rules.ActivityScenarioRule
import campus.tech.kakao.map.presentation.MapActivity
import campus.tech.kakao.map.presentation.SearchActivity
import campus.tech.kakao.map.presentation.adapter.SearchedPlaceAdapter
import org.hamcrest.CoreMatchers.instanceOf
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class SearchActivityTest {

private lateinit var sharedPreferences: SharedPreferences
private lateinit var context: Context

@get:Rule
var activityScenarioRule = ActivityScenarioRule(SearchActivity::class.java)

@Before
fun setUp() {
context = ApplicationProvider.getApplicationContext()
sharedPreferences = context.getSharedPreferences("mockk", Context.MODE_PRIVATE)
Intents.init()
}

@After
fun after() {
sharedPreferences.edit().clear().apply()
Intents.release()
}

@Test
fun testSearchAndVerifyMapActivityLaunched() {
onView(withId(R.id.edtSearch)).perform(click()).perform(replaceText("부산대"))

Thread.sleep(1200L)
onView(withId(R.id.recyclerPlace))
.perform(
RecyclerViewActions.actionOnHolderItem(
instanceOf(SearchedPlaceAdapter.LocationViewHolder::class.java), click()
).atPosition(3)
)

Intents.intended(hasComponent(MapActivity::class.java.name))
}
}
5 changes: 3 additions & 2 deletions app/src/main/java/campus/tech/kakao/map/PlaceApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ import android.view.View
import com.kakao.vectormap.KakaoMapSdk
import dagger.hilt.android.HiltAndroidApp


@HiltAndroidApp
class PlaceApplication: Application() {

override fun onCreate() {
super.onCreate()
appInstance = this

initKakaoMapSdk()
}

private fun initKakaoMapSdk(){

val key = getString(R.string.kakao_api_key)
KakaoMapSdk.init(this, key)
}
Expand All @@ -35,6 +35,7 @@ class PlaceApplication: Application() {

return actNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
actNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)

}
}
}
130 changes: 130 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/data/PlaceRepositoryImpl.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package campus.tech.kakao.map.data

import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import androidx.lifecycle.viewModelScope
import campus.tech.kakao.map.BuildConfig
import campus.tech.kakao.map.PlaceApplication
import campus.tech.kakao.map.data.net.KakaoApiClient
import campus.tech.kakao.map.util.PlaceContract
import campus.tech.kakao.map.domain.model.Place
import campus.tech.kakao.map.domain.repository.PlaceRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class PlaceRepositoryImpl(context: Context):
SQLiteOpenHelper(context, PlaceContract.DATABASE_NAME, null, 1),
PlaceRepository {

override fun onCreate(db: SQLiteDatabase?) {
db?.execSQL(PlaceContract.CREATE_QUERY)
db?.execSQL(PlaceContract.CREATE_LOG_QUERY)
}

override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
db?.execSQL(PlaceContract.DROP_QUERY)
db?.execSQL(PlaceContract.DROP_LOG_QUERY)
onCreate(db)
}
override suspend fun getPlaces(keyword: String): List<Place> =
withContext(Dispatchers.IO){
val resultPlaces = mutableListOf<Place>()
for (page in 1..3) {
val response = KakaoApiClient.api.getSearchKeyword(
key = BuildConfig.KAKAO_REST_API_KEY,
query = keyword,
size = 15,
page = page
)
if (response.isSuccessful) {
response.body()?.documents?.let { resultPlaces.addAll(it) }
} else throw RuntimeException("통신 에러 발생")
}
updatePlaces(resultPlaces)
resultPlaces
}
override suspend fun updatePlaces(places: List<Place>) {
val db = writableDatabase

db.execSQL(PlaceContract.DELETE_QUERY)
places.forEach {
val values = ContentValues().apply {
put(PlaceContract.COLUMN_ID, it.id)
put(PlaceContract.COLUMN_NAME, it.place)
put(PlaceContract.COLUMN_LOCATION, it.address)
put(PlaceContract.COLUMN_TYPE, it.category)
put(PlaceContract.COLUMN_X_POS, it.xPos)
put(PlaceContract.COLUMN_Y_POS, it.yPos)
}
db.insert(PlaceContract.TABLE_NAME, null, values)
}
}

override fun getPlaceById(id: String): Place? {
val cursor = readableDatabase.query(
PlaceContract.TABLE_NAME,
null, "${PlaceContract.COLUMN_ID} = ?", arrayOf(id), null, null, null
)
var place: Place? = null
cursor?.use {
if (it.moveToFirst()) {
val name = it.getString(it.getColumnIndexOrThrow(PlaceContract.COLUMN_NAME))
val address = it.getString(it.getColumnIndexOrThrow(PlaceContract.COLUMN_LOCATION))
val type = it.getString(it.getColumnIndexOrThrow(PlaceContract.COLUMN_TYPE))
val xPos = it.getString(it.getColumnIndexOrThrow(PlaceContract.COLUMN_X_POS))
val yPos = it.getString(it.getColumnIndexOrThrow(PlaceContract.COLUMN_Y_POS))
place = Place(id, name, address, type, xPos, yPos)
}
}
return place
}

override fun updateLogs(logs: List<Place>) {
val db = writableDatabase
db.execSQL(PlaceContract.DELETE_LOG_QUERY)
logs.forEach { placeLog ->
val values = ContentValues().apply {
put(PlaceContract.COLUMN_LOG_ID, placeLog.id)
put(PlaceContract.COLUMN_LOG_NAME, placeLog.place)
}
db.insert(PlaceContract.TABLE_LOG_NAME, null, values)
}
}

override fun removeLog(id: String) {
val db = writableDatabase
db.delete(PlaceContract.TABLE_LOG_NAME, "${PlaceContract.COLUMN_LOG_ID}=?", arrayOf(id))
}

override fun getLogs(): List<Place> {
val logs = mutableListOf<Place>()
val cursor = readableDatabase.query(
PlaceContract.TABLE_LOG_NAME,
null, null, null, null, null, null
)
cursor?.use {
while (it.moveToNext()) {
val name = it.getString(it.getColumnIndexOrThrow(PlaceContract.COLUMN_LOG_NAME))
val id = it.getString(it.getColumnIndexOrThrow(PlaceContract.COLUMN_LOG_ID))
logs.add(Place(id,name, "", "", "",""))
}
}
return logs
}

companion object {

@Volatile
private var INSTANCE: PlaceRepositoryImpl? = null

fun getInstance(context: Context): PlaceRepositoryImpl {
return INSTANCE ?: synchronized(this) {
INSTANCE ?: PlaceRepositoryImpl(context.applicationContext).also { INSTANCE = it }
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ data class PlaceEntity(
fun toPlace() = Place(id, place, address, type, xPos, yPos)
}


@Entity(tableName = "logs")
data class PlaceLogEntity(
@PrimaryKey val id: String,
val place: String
) {
fun toPlace() = Place(id, place, "", "", "", "")
}
}

20 changes: 20 additions & 0 deletions app/src/main/java/campus/tech/kakao/map/data/net/KakaoApiClient.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package campus.tech.kakao.map.data.net


import campus.tech.kakao.map.BuildConfig
import campus.tech.kakao.map.domain.model.ResultSearchKeyword
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object KakaoApiClient {
private const val BASE_URL = "https://dapi.kakao.com/"

val api: KakaoApi by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(KakaoApi::class.java)
}
}
Loading

0 comments on commit 12a0ad6

Please sign in to comment.