- weathered

This commit is contained in:
2021-04-20 20:09:32 +01:00
parent 9d053bfb60
commit b41ba10abb
212 changed files with 2453 additions and 1413 deletions

View File

@@ -1,6 +1,7 @@
package com.appttude.h_mal.atlas_weather.data.repository
import com.appttude.h_mal.atlas_weather.data.network.WeatherApi
import com.appttude.h_mal.atlas_weather.data.prefs.LOCATION_CONST
import com.appttude.h_mal.atlas_weather.data.prefs.PreferenceProvider
import com.appttude.h_mal.atlas_weather.data.room.AppDatabase
import io.mockk.MockKAnnotations
@@ -10,9 +11,8 @@ import org.junit.Before
import org.junit.Test
import kotlin.test.assertEquals
private const val MORE_THAN_FIVE_MINS = 310000L
private const val LESS_THAN_FIVE_MINS = 290000L
private const val MORE_THAN_FIVE_MINS = 330000L
private const val LESS_THAN_FIVE_MINS = 270000L
class RepositoryImplTest {
lateinit var repository: RepositoryImpl
@@ -38,7 +38,7 @@ class RepositoryImplTest {
val location = "CurrentLocation"
//Act
every { prefs.getLastSavedAt(location) } returns (System.currentTimeMillis() - LESS_THAN_FIVE_MINS)
every { prefs.getLastSavedAt("$LOCATION_CONST$location") } returns (System.currentTimeMillis() - LESS_THAN_FIVE_MINS)
//Assert
val valid: Boolean = repository.isSearchValid(location)
@@ -51,7 +51,7 @@ class RepositoryImplTest {
val location = "CurrentLocation"
//Act
every { prefs.getLastSavedAt(location) } returns (System.currentTimeMillis() - MORE_THAN_FIVE_MINS)
every { prefs.getLastSavedAt("$LOCATION_CONST$location") } returns (System.currentTimeMillis() - MORE_THAN_FIVE_MINS)
// Assert
val valid: Boolean = repository.isSearchValid(location)
@@ -64,7 +64,7 @@ class RepositoryImplTest {
val location = "CurrentLocation"
//Act
every { prefs.getLastSavedAt(location) } returns 0L
every { prefs.getLastSavedAt("$LOCATION_CONST$location") } returns 0L
// Assert
val valid: Boolean = repository.isSearchValid(location)

View File

@@ -0,0 +1,87 @@
package com.appttude.h_mal.atlas_weather.helper
import com.appttude.h_mal.atlas_weather.data.location.LocationProviderImpl
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.WeatherResponse
import com.appttude.h_mal.atlas_weather.data.repository.Repository
import com.appttude.h_mal.atlas_weather.data.repository.SettingsRepository
import com.appttude.h_mal.atlas_weather.data.room.entity.CURRENT_LOCATION
import com.appttude.h_mal.atlas_weather.data.room.entity.EntityItem
import com.appttude.h_mal.atlas_weather.model.weather.FullWeather
import com.google.gson.Gson
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.every
import io.mockk.impl.annotations.MockK
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import java.io.IOException
class ServicesHelperTest{
private val gson = Gson()
lateinit var helper: ServicesHelper
@MockK
lateinit var repository: Repository
@MockK
lateinit var settingsRepository: SettingsRepository
@MockK
lateinit var locationProvider: LocationProviderImpl
lateinit var weatherResponse: WeatherResponse
@Before
fun setUp() {
MockKAnnotations.init(this)
helper = ServicesHelper(repository, settingsRepository, locationProvider)
val json = this::class.java.classLoader!!.getResource("weather_sample.json").readText()
weatherResponse = gson.fromJson(json, WeatherResponse::class.java)
}
@Test
fun testWidgetDataAsync_successfulResponse() = runBlocking{
// Arrange
val entityItem = EntityItem(CURRENT_LOCATION, FullWeather(weatherResponse).apply {
temperatureUnit = "°C"
locationString = CURRENT_LOCATION
})
// Act
coEvery { locationProvider.getCurrentLatLong() } returns Pair(weatherResponse.lat, weatherResponse.lon)
every { repository.isSearchValid(CURRENT_LOCATION) }.returns(true)
coEvery { repository.getWeatherFromApi(weatherResponse.lat.toString(), weatherResponse.lon.toString()) }.returns(weatherResponse)
coEvery { locationProvider.getLocationNameFromLatLong(weatherResponse.lat, weatherResponse.lon) }.returns(CURRENT_LOCATION)
every { repository.saveLastSavedAt(CURRENT_LOCATION) } returns Unit
coEvery { repository.saveCurrentWeatherToRoom(entityItem) } returns Unit
// Assert
val result = helper.fetchData()
assertTrue(result)
}
@Test
fun testWidgetDataAsync_unsuccessfulResponse() = runBlocking{
// Act
coEvery { locationProvider.getCurrentLatLong() } returns Pair(0.0,0.0)
every { repository.isSearchValid(CURRENT_LOCATION) }.returns(true)
coEvery { repository.getWeatherFromApi("0.0", "0.0") } throws IOException("error")
// Assert
val result = helper.fetchData()
assertTrue(!result)
}
@Test
fun testWidgetDataAsync_invalidSearch() = runBlocking{
// Act
every { repository.isSearchValid(CURRENT_LOCATION) }.returns(false)
// Assert
val result = helper.fetchData()
assertTrue(!result)
}
}

View File

@@ -0,0 +1,320 @@
{
"lat": 51.5,
"lon": -0.12,
"timezone": "Europe/London",
"timezone_offset": 0,
"current": {
"dt": 1608391380,
"sunrise": 1608364972,
"sunset": 1608393158,
"temp": 10.53,
"feels_like": 5.17,
"pressure": 1006,
"humidity": 71,
"dew_point": 5.5,
"uvi": 0.12,
"clouds": 39,
"visibility": 10000,
"wind_speed": 6.2,
"wind_deg": 210,
"weather": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10d"
}
],
"rain": {
"1h": 0.19
}
},
"daily": [
{
"dt": 1608375600,
"sunrise": 1608364972,
"sunset": 1608393158,
"temp": {
"day": 11.78,
"min": 9.1,
"max": 12.31,
"night": 9.1,
"eve": 10.27,
"morn": 10.8
},
"feels_like": {
"day": 6.46,
"night": 5.08,
"eve": 5.58,
"morn": 4.63
},
"pressure": 1005,
"humidity": 69,
"dew_point": 6.42,
"wind_speed": 6.37,
"wind_deg": 217,
"weather": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10d"
}
],
"clouds": 97,
"pop": 0.98,
"rain": 1.69,
"uvi": 0.53
},
{
"dt": 1608462000,
"sunrise": 1608451406,
"sunset": 1608479581,
"temp": {
"day": 9.9,
"min": 7.41,
"max": 10.52,
"night": 7.41,
"eve": 8.83,
"morn": 8.59
},
"feels_like": {
"day": 4.19,
"night": 3.99,
"eve": 4.55,
"morn": 4.79
},
"pressure": 1013,
"humidity": 64,
"dew_point": 3.48,
"wind_speed": 6.12,
"wind_deg": 226,
"weather": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10d"
}
],
"clouds": 8,
"pop": 0.58,
"rain": 0.65,
"uvi": 0.45
},
{
"dt": 1608548400,
"sunrise": 1608537838,
"sunset": 1608566008,
"temp": {
"day": 11.06,
"min": 7.01,
"max": 13.57,
"night": 13.2,
"eve": 12.68,
"morn": 8.59
},
"feels_like": {
"day": 6.32,
"night": 9.99,
"eve": 9.75,
"morn": 4.64
},
"pressure": 1005,
"humidity": 91,
"dew_point": 9.69,
"wind_speed": 6.7,
"wind_deg": 185,
"weather": [
{
"id": 501,
"main": "Rain",
"description": "moderate rain",
"icon": "10d"
}
],
"clouds": 100,
"pop": 1,
"rain": 7.85,
"uvi": 0.21
},
{
"dt": 1608634800,
"sunrise": 1608624266,
"sunset": 1608652438,
"temp": {
"day": 12.97,
"min": 11.7,
"max": 13.21,
"night": 11.7,
"eve": 12.37,
"morn": 12.93
},
"feels_like": {
"day": 11.39,
"night": 10.49,
"eve": 10.96,
"morn": 9.65
},
"pressure": 1012,
"humidity": 83,
"dew_point": 10.31,
"wind_speed": 2.38,
"wind_deg": 214,
"weather": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10d"
}
],
"clouds": 100,
"pop": 1,
"rain": 3.25,
"uvi": 0.34
},
{
"dt": 1608721200,
"sunrise": 1608710690,
"sunset": 1608738871,
"temp": {
"day": 12.28,
"min": 10.12,
"max": 12.62,
"night": 10.12,
"eve": 10.12,
"morn": 11.73
},
"feels_like": {
"day": 7.48,
"night": 6.73,
"eve": 6.6,
"morn": 8.15
},
"pressure": 1006,
"humidity": 64,
"dew_point": 5.76,
"wind_speed": 5.45,
"wind_deg": 224,
"weather": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10d"
}
],
"clouds": 97,
"pop": 0.94,
"rain": 2.52,
"uvi": 0.52
},
{
"dt": 1608811200,
"sunrise": 1608797112,
"sunset": 1608825307,
"temp": {
"day": 7.3,
"min": 4.66,
"max": 8.32,
"night": 4.66,
"eve": 5.76,
"morn": 5.85
},
"feels_like": {
"day": 0.36,
"night": -1.25,
"eve": -0.31,
"morn": -2.46
},
"pressure": 1020,
"humidity": 60,
"dew_point": 0.15,
"wind_speed": 7.09,
"wind_deg": 5,
"weather": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10d"
}
],
"clouds": 85,
"pop": 0.52,
"rain": 0.6,
"uvi": 1
},
{
"dt": 1608897600,
"sunrise": 1608883530,
"sunset": 1608911747,
"temp": {
"day": 4.12,
"min": 2.2,
"max": 4.63,
"night": 2.97,
"eve": 3.44,
"morn": 2.28
},
"feels_like": {
"day": -0.33,
"night": -0.43,
"eve": -0.1,
"morn": -2.82
},
"pressure": 1033,
"humidity": 70,
"dew_point": -3.09,
"wind_speed": 3.35,
"wind_deg": 334,
"weather": [
{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01d"
}
],
"clouds": 0,
"pop": 0,
"uvi": 1
},
{
"dt": 1608984000,
"sunrise": 1608969944,
"sunset": 1608998190,
"temp": {
"day": 6.03,
"min": 2.76,
"max": 6.92,
"night": 6.92,
"eve": 6.45,
"morn": 3.59
},
"feels_like": {
"day": 0.49,
"night": -0.96,
"eve": -0.28,
"morn": -0.44
},
"pressure": 1024,
"humidity": 69,
"dew_point": 0.84,
"wind_speed": 5.25,
"wind_deg": 251,
"weather": [
{
"id": 804,
"main": "Clouds",
"description": "overcast clouds",
"icon": "04d"
}
],
"clouds": 100,
"pop": 0,
"uvi": 1
}
]
}

View File

@@ -1,66 +0,0 @@
package com.appttude.h_mal.atlas_weather.viewmodel
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.WeatherResponse
import com.appttude.h_mal.atlas_weather.data.repository.Repository
import com.appttude.h_mal.atlas_weather.data.room.entity.EntityItem
import com.appttude.h_mal.atlas_weather.utils.Event
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.RelaxedMockK
import io.mockk.mockk
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TestRule
import kotlin.test.assertEquals
class MainViewModelTest{
@get:Rule
var rule: TestRule = InstantTaskExecutorRule()
lateinit var mainViewModel: MainViewModel
@MockK(relaxed = true)
lateinit var repository: Repository
@MockK
lateinit var locationProvider: LocationProvider
@RelaxedMockK
lateinit var mockedLiveData: LiveData<EntityItem>
@Before
fun setUp() {
MockKAnnotations.init(this)
mainViewModel = MainViewModel(locationProvider, repository)
every { repository.loadCurrentWeatherFromRoom("CurrentLocation") } answers { mockedLiveData }
}
@Test
fun fetchData_workingLocation_successfulOperation() = runBlocking{
val observer = mockk<Observer<Event<Boolean>>>(relaxed = true)
val mockResponse = mockk<WeatherResponse>()
mainViewModel.operationState.observeForever(observer)
// Act
every { observer.onChanged(Event(false)) }
every { locationProvider.getLatLong() } returns Pair(0.00, 0.00)
coEvery { repository.getWeatherFromApi("0.00", "0.00") } returns mockResponse
// Assert
mainViewModel.fetchData()
delay(50)
assertEquals(mainViewModel.operationState.value?.getContentIfNotHandled(), false)
}
}

View File

@@ -0,0 +1,75 @@
package com.appttude.h_mal.atlas_weather.viewmodel
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import com.appttude.h_mal.atlas_weather.data.location.LocationProviderImpl
import com.appttude.h_mal.atlas_weather.data.repository.Repository
import com.appttude.h_mal.atlas_weather.data.room.entity.CURRENT_LOCATION
import io.mockk.MockKAnnotations
import io.mockk.impl.annotations.MockK
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
class WorldViewModelTest {
@get:Rule
val rule = InstantTaskExecutorRule()
lateinit var viewModel: WorldViewModel
@MockK(relaxed = true)
lateinit var repository: Repository
@MockK
lateinit var locationProvider: LocationProviderImpl
@Before
fun setUp() {
MockKAnnotations.init(this)
viewModel = WorldViewModel(locationProvider, repository)
}
@Test
fun name() {
val location = CURRENT_LOCATION
viewModel.fetchDataForSingleLocation(location)
assertEquals(viewModel.operationRefresh.getOrAwaitValue()?.getContentIfNotHandled(), true)
}
}
/* Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
fun <T> LiveData<T>.getOrAwaitValue(
time: Long = 2,
timeUnit: TimeUnit = TimeUnit.SECONDS
): T {
var data: T? = null
val latch = CountDownLatch(1)
val observer = object : Observer<T> {
override fun onChanged(o: T?) {
data = o
latch.countDown()
this@getOrAwaitValue.removeObserver(this)
}
}
this.observeForever(observer)
// Don't wait indefinitely if the LiveData is not set.
if (!latch.await(time, timeUnit)) {
throw TimeoutException("LiveData value was never set.")
}
@Suppress("UNCHECKED_CAST")
return data as T
}

View File

@@ -0,0 +1,317 @@
{
"lat": 51.5,
"lon": -0.12,
"timezone": "Europe/London",
"timezone_offset": 0,
"current": {
"dt": 1608394319,
"sunrise": 1608364972,
"sunset": 1608393158,
"temp": 9.42,
"feels_like": 4.9,
"pressure": 1007,
"humidity": 91,
"dew_point": 8.03,
"uvi": 0,
"clouds": 33,
"visibility": 10000,
"wind_speed": 5.8,
"wind_deg": 215,
"weather": [
{
"id": 802,
"main": "Clouds",
"description": "scattered clouds",
"icon": "03n"
}
]
},
"daily": [
{
"dt": 1608375600,
"sunrise": 1608364972,
"sunset": 1608393158,
"temp": {
"day": 11.78,
"min": 9.1,
"max": 12.31,
"night": 9.1,
"eve": 9.8,
"morn": 10.8
},
"feels_like": {
"day": 6.46,
"night": 5.08,
"eve": 5.47,
"morn": 4.63
},
"pressure": 1005,
"humidity": 69,
"dew_point": 6.42,
"wind_speed": 6.37,
"wind_deg": 217,
"weather": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10d"
}
],
"clouds": 97,
"pop": 0.98,
"rain": 1.55,
"uvi": 0.53
},
{
"dt": 1608462000,
"sunrise": 1608451406,
"sunset": 1608479581,
"temp": {
"day": 9.9,
"min": 7.41,
"max": 10.52,
"night": 7.41,
"eve": 8.83,
"morn": 8.59
},
"feels_like": {
"day": 4.19,
"night": 3.99,
"eve": 4.55,
"morn": 4.79
},
"pressure": 1013,
"humidity": 64,
"dew_point": 3.48,
"wind_speed": 6.12,
"wind_deg": 226,
"weather": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10d"
}
],
"clouds": 8,
"pop": 0.58,
"rain": 0.65,
"uvi": 0.45
},
{
"dt": 1608548400,
"sunrise": 1608537838,
"sunset": 1608566008,
"temp": {
"day": 11.06,
"min": 7.01,
"max": 13.57,
"night": 13.2,
"eve": 12.68,
"morn": 8.59
},
"feels_like": {
"day": 6.32,
"night": 9.99,
"eve": 9.75,
"morn": 4.64
},
"pressure": 1005,
"humidity": 91,
"dew_point": 9.69,
"wind_speed": 6.7,
"wind_deg": 185,
"weather": [
{
"id": 501,
"main": "Rain",
"description": "moderate rain",
"icon": "10d"
}
],
"clouds": 100,
"pop": 1,
"rain": 7.85,
"uvi": 0.21
},
{
"dt": 1608634800,
"sunrise": 1608624266,
"sunset": 1608652438,
"temp": {
"day": 12.97,
"min": 11.7,
"max": 13.21,
"night": 11.7,
"eve": 12.37,
"morn": 12.93
},
"feels_like": {
"day": 11.39,
"night": 10.49,
"eve": 10.96,
"morn": 9.65
},
"pressure": 1012,
"humidity": 83,
"dew_point": 10.31,
"wind_speed": 2.38,
"wind_deg": 214,
"weather": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10d"
}
],
"clouds": 100,
"pop": 1,
"rain": 3.25,
"uvi": 0.34
},
{
"dt": 1608721200,
"sunrise": 1608710690,
"sunset": 1608738871,
"temp": {
"day": 12.28,
"min": 10.12,
"max": 12.62,
"night": 10.12,
"eve": 10.12,
"morn": 11.73
},
"feels_like": {
"day": 7.48,
"night": 6.73,
"eve": 6.6,
"morn": 8.15
},
"pressure": 1006,
"humidity": 64,
"dew_point": 5.76,
"wind_speed": 5.45,
"wind_deg": 224,
"weather": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10d"
}
],
"clouds": 97,
"pop": 0.94,
"rain": 2.52,
"uvi": 0.52
},
{
"dt": 1608811200,
"sunrise": 1608797112,
"sunset": 1608825307,
"temp": {
"day": 7.3,
"min": 4.66,
"max": 8.32,
"night": 4.66,
"eve": 5.76,
"morn": 5.85
},
"feels_like": {
"day": 0.36,
"night": -1.25,
"eve": -0.31,
"morn": -2.46
},
"pressure": 1020,
"humidity": 60,
"dew_point": 0.15,
"wind_speed": 7.09,
"wind_deg": 5,
"weather": [
{
"id": 500,
"main": "Rain",
"description": "light rain",
"icon": "10d"
}
],
"clouds": 85,
"pop": 0.52,
"rain": 0.6,
"uvi": 1
},
{
"dt": 1608897600,
"sunrise": 1608883530,
"sunset": 1608911747,
"temp": {
"day": 4.12,
"min": 2.2,
"max": 4.63,
"night": 2.97,
"eve": 3.44,
"morn": 2.28
},
"feels_like": {
"day": -0.33,
"night": -0.43,
"eve": -0.1,
"morn": -2.82
},
"pressure": 1033,
"humidity": 70,
"dew_point": -3.09,
"wind_speed": 3.35,
"wind_deg": 334,
"weather": [
{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01d"
}
],
"clouds": 0,
"pop": 0,
"uvi": 1
},
{
"dt": 1608984000,
"sunrise": 1608969944,
"sunset": 1608998190,
"temp": {
"day": 6.03,
"min": 2.76,
"max": 6.92,
"night": 6.92,
"eve": 6.45,
"morn": 3.59
},
"feels_like": {
"day": 0.49,
"night": -0.96,
"eve": -0.28,
"morn": -0.44
},
"pressure": 1024,
"humidity": 69,
"dew_point": 0.84,
"wind_speed": 5.25,
"wind_deg": 251,
"weather": [
{
"id": 804,
"main": "Clouds",
"description": "overcast clouds",
"icon": "04d"
}
],
"clouds": 100,
"pop": 0,
"uvi": 1
}
]
}