- Remove old api and response

This commit is contained in:
2024-09-30 10:57:03 +01:00
parent 8507116e5a
commit 79c123021a
31 changed files with 236 additions and 719 deletions

View File

@@ -67,7 +67,7 @@ open class BaseTest<A : Activity>(
} }
testApp = testApp =
InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as TestAppClass InstrumentationRegistry.getInstrumentation().targetContext.applicationContext
runBlocking { runBlocking {
beforeLaunch() beforeLaunch()
} }

View File

@@ -60,7 +60,7 @@ open class BaseTestRobot {
.atPosition(position).perform(click()) .atPosition(position).perform(click())
} }
fun <VH : ViewHolder> scrollToRecyclerItem(recyclerId: Int, text: String): ViewInteraction? { fun <VH : ViewHolder> scrollToRecyclerItem(recyclerId: Int, text: String): ViewInteraction {
return matchView(recyclerId) return matchView(recyclerId)
.perform( .perform(
// scrollTo will fail the test if no item matches. // scrollTo will fail the test if no item matches.
@@ -73,7 +73,7 @@ open class BaseTestRobot {
fun <VH : ViewHolder> scrollToRecyclerItem( fun <VH : ViewHolder> scrollToRecyclerItem(
recyclerId: Int, recyclerId: Int,
resIdForString: Int resIdForString: Int
): ViewInteraction? { ): ViewInteraction {
return matchView(recyclerId) return matchView(recyclerId)
.perform( .perform(
// scrollTo will fail the test if no item matches. // scrollTo will fail the test if no item matches.
@@ -86,7 +86,7 @@ open class BaseTestRobot {
fun <VH : ViewHolder> scrollToRecyclerItemByPosition( fun <VH : ViewHolder> scrollToRecyclerItemByPosition(
recyclerId: Int, recyclerId: Int,
position: Int position: Int
): ViewInteraction? { ): ViewInteraction {
return matchView(recyclerId) return matchView(recyclerId)
.perform( .perform(
// scrollTo will fail the test if no item matches. // scrollTo will fail the test if no item matches.

View File

@@ -7,7 +7,7 @@ import androidx.test.platform.app.InstrumentationRegistry
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
import com.appttude.h_mal.atlas_weather.data.location.MockLocationProvider import com.appttude.h_mal.atlas_weather.data.location.MockLocationProvider
import com.appttude.h_mal.atlas_weather.data.network.NetworkModule import com.appttude.h_mal.atlas_weather.data.network.NetworkModule
import com.appttude.h_mal.atlas_weather.data.network.WeatherApi import com.appttude.h_mal.atlas_weather.data.network.NewWeatherApi
import com.appttude.h_mal.atlas_weather.data.network.interceptors.MockingNetworkInterceptor import com.appttude.h_mal.atlas_weather.data.network.interceptors.MockingNetworkInterceptor
import com.appttude.h_mal.atlas_weather.data.network.interceptors.NetworkConnectionInterceptor import com.appttude.h_mal.atlas_weather.data.network.interceptors.NetworkConnectionInterceptor
import com.appttude.h_mal.atlas_weather.data.network.interceptors.QueryParamsInterceptor import com.appttude.h_mal.atlas_weather.data.network.interceptors.QueryParamsInterceptor
@@ -28,8 +28,8 @@ class TestAppClass : AppClass() {
IdlingRegistry.getInstance().register(idlingResources) IdlingRegistry.getInstance().register(idlingResources)
} }
override fun createNetworkModule(): WeatherApi { override fun createNetworkModule(): NewWeatherApi {
return NetworkModule().invoke<WeatherApi>( return NetworkModule().invoke<NewWeatherApi>(
mockingNetworkInterceptor, mockingNetworkInterceptor,
NetworkConnectionInterceptor(this), NetworkConnectionInterceptor(this),
QueryParamsInterceptor(), QueryParamsInterceptor(),

View File

@@ -6,6 +6,7 @@ import androidx.test.filters.SmallTest
import com.appttude.h_mal.atlas_weather.BaseTest import com.appttude.h_mal.atlas_weather.BaseTest
import com.appttude.h_mal.atlas_weather.ui.MainActivity import com.appttude.h_mal.atlas_weather.ui.MainActivity
import com.appttude.h_mal.atlas_weather.utils.Stubs import com.appttude.h_mal.atlas_weather.utils.Stubs
import com.appttude.h_mal.atlas_weather.utils.baseUrl
import com.appttude.h_mal.monoWeather.robot.furtherInfoScreen import com.appttude.h_mal.monoWeather.robot.furtherInfoScreen
import com.appttude.h_mal.monoWeather.robot.settingsScreen import com.appttude.h_mal.monoWeather.robot.settingsScreen
import com.appttude.h_mal.monoWeather.robot.weatherScreen import com.appttude.h_mal.monoWeather.robot.weatherScreen
@@ -18,8 +19,8 @@ import tools.fastlane.screengrab.Screengrab
class SnapshotCaptureTest : BaseTest<MainActivity>(MainActivity::class.java) { class SnapshotCaptureTest : BaseTest<MainActivity>(MainActivity::class.java) {
override fun beforeLaunch() { override fun beforeLaunch() {
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Metric) stubEndpoint(baseUrl, Stubs.New)
stubLocation("London", 51.51, -0.13) stubLocation("London", 51.5064, -0.12721)
clearPrefs() clearPrefs()
} }

View File

@@ -11,6 +11,7 @@ import org.junit.Test
class HomePageNoDataUITest : BaseTest<MainActivity>(MainActivity::class.java) { class HomePageNoDataUITest : BaseTest<MainActivity>(MainActivity::class.java) {
override fun beforeLaunch() { override fun beforeLaunch() {
// Todo: change this
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.InvalidKey, 400) stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.InvalidKey, 400)
} }

View File

@@ -4,6 +4,7 @@ package com.appttude.h_mal.monoWeather.tests
import com.appttude.h_mal.atlas_weather.BaseTest import com.appttude.h_mal.atlas_weather.BaseTest
import com.appttude.h_mal.atlas_weather.ui.MainActivity import com.appttude.h_mal.atlas_weather.ui.MainActivity
import com.appttude.h_mal.atlas_weather.utils.Stubs import com.appttude.h_mal.atlas_weather.utils.Stubs
import com.appttude.h_mal.atlas_weather.utils.baseUrl
import com.appttude.h_mal.monoWeather.robot.ContainerRobot.Tab.WORLD import com.appttude.h_mal.monoWeather.robot.ContainerRobot.Tab.WORLD
import com.appttude.h_mal.monoWeather.robot.addLocation import com.appttude.h_mal.monoWeather.robot.addLocation
import com.appttude.h_mal.monoWeather.robot.container import com.appttude.h_mal.monoWeather.robot.container
@@ -14,7 +15,8 @@ import org.junit.Test
class WorldPageUITest : BaseTest<MainActivity>(MainActivity::class.java) { class WorldPageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
override fun beforeLaunch() { override fun beforeLaunch() {
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Metric) stubEndpoint(baseUrl, Stubs.New)
stubLocation("London", 51.5064, -0.12721)
} }
@Test @Test
@@ -26,6 +28,7 @@ class WorldPageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
clickFab() clickFab()
} }
addLocation { addLocation {
// Todo: change this
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Sydney) stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Sydney)
stubLocation("Sydney", -33.89, -151.12) stubLocation("Sydney", -33.89, -151.12)
setLocation("Sydney") setLocation("Sydney")

View File

@@ -9,8 +9,6 @@ import retrofit2.http.Query
interface NewWeatherApi : Api { interface NewWeatherApi : Api {
// Todo: change the location
// Todo: add endpoint for lat/long
@GET("{location}") @GET("{location}")
suspend fun getFromApi( suspend fun getFromApi(
@Query("contentType") exclude: String = "json", @Query("contentType") exclude: String = "json",

View File

@@ -1,20 +0,0 @@
package com.appttude.h_mal.atlas_weather.data.network
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.WeatherResponse
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Query
interface WeatherApi : Api {
@GET("onecall?")
suspend fun getFromApi(
@Query("lat") query: String,
@Query("lon") lon: String,
@Query("exclude") exclude: String = "minutely",
@Query("units") units: String = "metric"
): Response<WeatherResponse>
}

View File

@@ -1,48 +0,0 @@
package com.appttude.h_mal.atlas_weather.data.network.response.forecast
import com.google.gson.annotations.SerializedName
data class Current(
@field:SerializedName("sunrise")
val sunrise: Int? = null,
@field:SerializedName("temp")
val temp: Double? = null,
@field:SerializedName("visibility")
val visibility: Int? = null,
@field:SerializedName("uvi")
val uvi: Double? = null,
@field:SerializedName("pressure")
val pressure: Int? = null,
@field:SerializedName("clouds")
val clouds: Int? = null,
@field:SerializedName("feels_like")
val feelsLike: Double? = null,
@field:SerializedName("dt")
val dt: Int? = null,
@field:SerializedName("wind_deg")
val windDeg: Int? = null,
@field:SerializedName("dew_point")
val dewPoint: Double? = null,
@field:SerializedName("sunset")
val sunset: Int? = null,
@field:SerializedName("weather")
val weather: List<WeatherItem?>? = null,
@field:SerializedName("humidity")
val humidity: Int? = null,
@field:SerializedName("wind_speed")
val windSpeed: Double? = null
)

View File

@@ -1,51 +0,0 @@
package com.appttude.h_mal.atlas_weather.data.network.response.forecast
import com.google.gson.annotations.SerializedName
data class DailyItem(
@field:SerializedName("sunrise")
val sunrise: Int? = null,
@field:SerializedName("temp")
val temp: Temp? = null,
@field:SerializedName("uvi")
val uvi: Double? = null,
@field:SerializedName("pressure")
val pressure: Int? = null,
@field:SerializedName("clouds")
val clouds: Int? = null,
@field:SerializedName("feels_like")
val feelsLike: FeelsLike? = null,
@field:SerializedName("dt")
val dt: Int? = null,
@field:SerializedName("pop")
val pop: Double? = null,
@field:SerializedName("wind_deg")
val windDeg: Int? = null,
@field:SerializedName("dew_point")
val dewPoint: Double? = null,
@field:SerializedName("sunset")
val sunset: Int? = null,
@field:SerializedName("weather")
val weather: List<WeatherItem?>? = null,
@field:SerializedName("humidity")
val humidity: Int? = null,
@field:SerializedName("wind_speed")
val windSpeed: Double? = null,
@field:SerializedName("rain")
val rain: Double? = null
)

View File

@@ -1,18 +0,0 @@
package com.appttude.h_mal.atlas_weather.data.network.response.forecast
import com.google.gson.annotations.SerializedName
data class FeelsLike(
@field:SerializedName("eve")
val eve: Double? = null,
@field:SerializedName("night")
val night: Double? = null,
@field:SerializedName("day")
val day: Double? = null,
@field:SerializedName("morn")
val morn: Double? = null
)

View File

@@ -1,48 +0,0 @@
package com.appttude.h_mal.atlas_weather.data.network.response.forecast
import com.google.gson.annotations.SerializedName
data class Hour(
@field:SerializedName("sunrise")
val sunrise: Int? = null,
@field:SerializedName("temp")
val temp: Double? = null,
@field:SerializedName("visibility")
val visibility: Int? = null,
@field:SerializedName("uvi")
val uvi: Double? = null,
@field:SerializedName("pressure")
val pressure: Int? = null,
@field:SerializedName("clouds")
val clouds: Int? = null,
@field:SerializedName("feels_like")
val feelsLike: Double? = null,
@field:SerializedName("dt")
val dt: Int? = null,
@field:SerializedName("wind_deg")
val windDeg: Int? = null,
@field:SerializedName("dew_point")
val dewPoint: Double? = null,
@field:SerializedName("sunset")
val sunset: Int? = null,
@field:SerializedName("weather")
val weather: List<WeatherItem?>? = null,
@field:SerializedName("humidity")
val humidity: Int? = null,
@field:SerializedName("wind_speed")
val windSpeed: Double? = null
)

View File

@@ -1,24 +0,0 @@
package com.appttude.h_mal.atlas_weather.data.network.response.forecast
import com.google.gson.annotations.SerializedName
data class Response(
@field:SerializedName("current")
val current: Current? = null,
@field:SerializedName("timezone")
val timezone: String? = null,
@field:SerializedName("timezone_offset")
val timezoneOffset: Int? = null,
@field:SerializedName("daily")
val daily: List<DailyItem?>? = null,
@field:SerializedName("lon")
val lon: Double? = null,
@field:SerializedName("lat")
val lat: Double? = null
)

View File

@@ -1,24 +0,0 @@
package com.appttude.h_mal.atlas_weather.data.network.response.forecast
import com.google.gson.annotations.SerializedName
data class Temp(
@field:SerializedName("min")
val min: Double? = null,
@field:SerializedName("max")
val max: Double? = null,
@field:SerializedName("eve")
val eve: Double? = null,
@field:SerializedName("night")
val night: Double? = null,
@field:SerializedName("day")
val day: Double? = null,
@field:SerializedName("morn")
val morn: Double? = null
)

View File

@@ -1,18 +0,0 @@
package com.appttude.h_mal.atlas_weather.data.network.response.forecast
import com.google.gson.annotations.SerializedName
data class WeatherItem(
@field:SerializedName("icon")
val icon: String? = null,
@field:SerializedName("description")
val description: String? = null,
@field:SerializedName("main")
val main: String? = null,
@field:SerializedName("id")
val id: Int? = null
)

View File

@@ -1,28 +0,0 @@
package com.appttude.h_mal.atlas_weather.data.network.response.forecast
import com.google.gson.annotations.SerializedName
data class WeatherResponse(
@field:SerializedName("current")
val current: Current? = null,
@field:SerializedName("timezone")
val timezone: String? = null,
@field:SerializedName("timezone_offset")
val timezoneOffset: Int? = null,
@field:SerializedName("hourly")
val hourly: List<Hour>? = null,
@field:SerializedName("daily")
val daily: List<DailyItem>? = null,
@field:SerializedName("lon")
val lon: Double = 0.00,
@field:SerializedName("lat")
val lat: Double = 0.00
)

View File

@@ -0,0 +1,36 @@
package com.appttude.h_mal.atlas_weather.data.network.response.weather
import com.google.gson.annotations.SerializedName
data class CurrentConditions(
@SerializedName("datetime") var datetime: String? = null,
@SerializedName("datetimeEpoch") var datetimeEpoch: Int? = null,
@SerializedName("temp") var temp: Double? = null,
@SerializedName("feelslike") var feelslike: Double? = null,
@SerializedName("humidity") var humidity: Double? = null,
@SerializedName("dew") var dew: Double? = null,
@SerializedName("precip") var precip: Double? = null,
@SerializedName("precipprob") var precipprob: Double? = null,
@SerializedName("snow") var snow: Int? = null,
@SerializedName("snowdepth") var snowdepth: Int? = null,
@SerializedName("preciptype") var preciptype: ArrayList<String> = arrayListOf(),
@SerializedName("windgust") var windgust: Double? = null,
@SerializedName("windspeed") var windspeed: Double? = null,
@SerializedName("winddir") var winddir: Double? = null,
@SerializedName("pressure") var pressure: Double? = null,
@SerializedName("visibility") var visibility: Double? = null,
@SerializedName("cloudcover") var cloudcover: Double? = null,
@SerializedName("solarradiation") var solarradiation: Double? = null,
@SerializedName("solarenergy") var solarenergy: Double? = null,
@SerializedName("uvindex") var uvindex: Int? = null,
@SerializedName("conditions") var conditions: String? = null,
@SerializedName("icon") var icon: String? = null,
@SerializedName("stations") var stations: ArrayList<String> = arrayListOf(),
@SerializedName("source") var source: String? = null,
@SerializedName("sunrise") var sunrise: String? = null,
@SerializedName("sunriseEpoch") var sunriseEpoch: Int? = null,
@SerializedName("sunset") var sunset: String? = null,
@SerializedName("sunsetEpoch") var sunsetEpoch: Int? = null,
@SerializedName("moonphase") var moonphase: Double? = null
)

View File

@@ -0,0 +1,45 @@
package com.appttude.h_mal.atlas_weather.data.network.response.weather
import com.google.gson.annotations.SerializedName
data class Days(
@SerializedName("datetime") var datetime: String? = null,
@SerializedName("datetimeEpoch") var datetimeEpoch: Int? = null,
@SerializedName("tempmax") var tempmax: Double? = null,
@SerializedName("tempmin") var tempmin: Double? = null,
@SerializedName("temp") var temp: Double? = null,
@SerializedName("feelslikemax") var feelslikemax: Double? = null,
@SerializedName("feelslikemin") var feelslikemin: Double? = null,
@SerializedName("feelslike") var feelslike: Double? = null,
@SerializedName("dew") var dew: Double? = null,
@SerializedName("humidity") var humidity: Double? = null,
@SerializedName("precip") var precip: Number? = null,
@SerializedName("precipprob") var precipprob: Double? = null,
@SerializedName("precipcover") var precipcover: Double? = null,
@SerializedName("preciptype") var preciptype: ArrayList<String> = arrayListOf(),
@SerializedName("snow") var snow: Int? = null,
@SerializedName("snowdepth") var snowdepth: Int? = null,
@SerializedName("windgust") var windgust: Double? = null,
@SerializedName("windspeed") var windspeed: Double? = null,
@SerializedName("winddir") var winddir: Double? = null,
@SerializedName("pressure") var pressure: Double? = null,
@SerializedName("cloudcover") var cloudcover: Double? = null,
@SerializedName("visibility") var visibility: Double? = null,
@SerializedName("solarradiation") var solarradiation: Double? = null,
@SerializedName("solarenergy") var solarenergy: Double? = null,
@SerializedName("uvindex") var uvindex: Int? = null,
@SerializedName("severerisk") var severerisk: Int? = null,
@SerializedName("sunrise") var sunrise: String? = null,
@SerializedName("sunriseEpoch") var sunriseEpoch: Int? = null,
@SerializedName("sunset") var sunset: String? = null,
@SerializedName("sunsetEpoch") var sunsetEpoch: Int? = null,
@SerializedName("moonphase") var moonphase: Double? = null,
@SerializedName("conditions") var conditions: String? = null,
@SerializedName("description") var description: String? = null,
@SerializedName("icon") var icon: String? = null,
@SerializedName("stations") var stations: ArrayList<String> = arrayListOf(),
@SerializedName("source") var source: String? = null,
@SerializedName("hours") var hours: ArrayList<Hours> = arrayListOf()
)

View File

@@ -0,0 +1,32 @@
package com.appttude.h_mal.atlas_weather.data.network.response.weather
import com.google.gson.annotations.SerializedName
data class Hours(
@SerializedName("datetime") var datetime: String? = null,
@SerializedName("datetimeEpoch") var datetimeEpoch: Int? = null,
@SerializedName("temp") var temp: Double? = null,
@SerializedName("feelslike") var feelslike: Double? = null,
@SerializedName("humidity") var humidity: Double? = null,
@SerializedName("dew") var dew: Double? = null,
@SerializedName("precip") var precip: Number? = null,
@SerializedName("precipprob") var precipprob: Double? = null,
@SerializedName("snow") var snow: Int? = null,
@SerializedName("snowdepth") var snowdepth: Int? = null,
@SerializedName("preciptype") var preciptype: ArrayList<String> = arrayListOf(),
@SerializedName("windgust") var windgust: Double? = null,
@SerializedName("windspeed") var windspeed: Double? = null,
@SerializedName("winddir") var winddir: Double? = null,
@SerializedName("pressure") var pressure: Double? = null,
@SerializedName("visibility") var visibility: Double? = null,
@SerializedName("cloudcover") var cloudcover: Double? = null,
@SerializedName("solarradiation") var solarradiation: Double? = null,
@SerializedName("solarenergy") var solarenergy: Double? = null,
@SerializedName("uvindex") var uvindex: Int? = null,
@SerializedName("severerisk") var severerisk: Int? = null,
@SerializedName("conditions") var conditions: String? = null,
@SerializedName("icon") var icon: String? = null,
@SerializedName("stations") var stations: ArrayList<String> = arrayListOf(),
@SerializedName("source") var source: String? = null
)

View File

@@ -0,0 +1,15 @@
package com.appttude.h_mal.atlas_weather.data.network.response.weather
import com.appttude.h_mal.atlas_weather.EGLL
import com.appttude.h_mal.atlas_weather.EGWU
import com.appttude.h_mal.atlas_weather.F8628
import com.google.gson.annotations.SerializedName
data class Stations (
@SerializedName("EGWU" ) var EGWU : EGWU? = EGWU(),
@SerializedName("EGLC" ) var EGLC : EGLC? = EGLC(),
@SerializedName("EGLL" ) var EGLL : EGLL? = EGLL(),
@SerializedName("D5621" ) var D5621 : D5621? = D5621(),
@SerializedName("F8628" ) var F8628 : F8628? = F8628()
)

View File

@@ -0,0 +1,41 @@
package com.appttude.h_mal.atlas_weather.data.network.response.weather
import com.appttude.h_mal.atlas_weather.model.DataMapper
import com.appttude.h_mal.atlas_weather.model.weather.Current
import com.appttude.h_mal.atlas_weather.model.weather.DailyWeather
import com.appttude.h_mal.atlas_weather.model.weather.FullWeather
import com.google.gson.annotations.SerializedName
import com.appttude.h_mal.atlas_weather.model.weather.Hour as FullWeatherHour
data class WeatherApiResponse(
@SerializedName("queryCost") var queryCost: Int? = null,
@SerializedName("latitude") var latitude: Double? = null,
@SerializedName("longitude") var longitude: Double? = null,
@SerializedName("resolvedAddress") var resolvedAddress: String? = null,
@SerializedName("address") var address: String? = null,
@SerializedName("timezone") var timezone: String? = null,
@SerializedName("tzoffset") var tzoffset: Int? = null,
@SerializedName("description") var description: String? = null,
@SerializedName("days") var days: ArrayList<Days> = arrayListOf(),
@SerializedName("alerts") var alerts: ArrayList<String> = arrayListOf(),
// @SerializedName("stations") var stations: Stations? = Stations(),
@SerializedName("currentConditions") var currentConditions: CurrentConditions? = CurrentConditions()
): DataMapper<FullWeather> {
override fun mapData(): FullWeather {
val hours = mutableListOf(days[0].hours).apply { add(days[1].hours) }.flatten().subList(0,23).map { FullWeatherHour(it) }.toList()
val collectedDays = mutableListOf(days.subList(0,7)).flatten().map { DailyWeather(it) }.toList()
return FullWeather(
current = Current(currentConditions),
timezone = timezone,
timezoneOffset = tzoffset,
hourly = hours,
daily = collectedDays,
lat = latitude,
lon = longitude,
locationString = address,
temperatureUnit = null
)
}
}

View File

@@ -144,7 +144,7 @@ class ServicesHelper(
result.weather.let { result.weather.let {
val bitmap = it.current?.icon val bitmap = it.current?.icon
val location = locationProvider.getLocationNameFromLatLong(it.lat, it.lon) val location = locationProvider.getLocationNameFromLatLong(it.lat!!, it.lon!!)
val temp = it.current?.temp?.toInt().toString() val temp = it.current?.temp?.toInt().toString()
WidgetData(location, bitmap, temp, epoc) WidgetData(location, bitmap, temp, epoc)
@@ -181,7 +181,7 @@ class ServicesHelper(
val widgetData = result.weather.let { val widgetData = result.weather.let {
val bitmap = it.current?.icon val bitmap = it.current?.icon
val location = locationProvider.getLocationNameFromLatLong(it.lat, it.lon) val location = locationProvider.getLocationNameFromLatLong(it.lat!!, it.lon!!)
val temp = it.current?.temp?.toInt().toString() val temp = it.current?.temp?.toInt().toString()
val epoc = System.currentTimeMillis() val epoc = System.currentTimeMillis()

View File

@@ -40,8 +40,7 @@ data class Forecast(
parcel.readString(), parcel.readString(),
parcel.readString(), parcel.readString(),
parcel.readString() parcel.readString()
) { )
}
constructor(dailyWeather: DailyWeather) : this( constructor(dailyWeather: DailyWeather) : this(
dailyWeather.dt?.toDayString(), dailyWeather.dt?.toDayString(),

View File

@@ -40,8 +40,7 @@ data class WeatherDisplay(
parcel.readDouble(), parcel.readDouble(),
parcel.readDouble(), parcel.readDouble(),
parcel.readString() parcel.readString()
) { )
}
constructor(entity: EntityItem) : this( constructor(entity: EntityItem) : this(
entity.weather.current?.temp, entity.weather.current?.temp,
@@ -56,8 +55,8 @@ data class WeatherDisplay(
entity.weather.daily?.get(0)?.pop?.times(100)?.toInt()?.toString(), entity.weather.daily?.get(0)?.pop?.times(100)?.toInt()?.toString(),
entity.weather.current?.humidity?.toString(), entity.weather.current?.humidity?.toString(),
entity.weather.current?.clouds?.toString(), entity.weather.current?.clouds?.toString(),
entity.weather.lat, entity.weather.lat!!,
entity.weather.lon, entity.weather.lon!!,
entity.weather.locationString entity.weather.locationString
) )

View File

@@ -1,6 +1,5 @@
package com.appttude.h_mal.atlas_weather.model.weather package com.appttude.h_mal.atlas_weather.model.weather
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.Current
import com.appttude.h_mal.atlas_weather.data.network.response.weather.CurrentConditions import com.appttude.h_mal.atlas_weather.data.network.response.weather.CurrentConditions
import com.appttude.h_mal.atlas_weather.model.IconMapper import com.appttude.h_mal.atlas_weather.model.IconMapper
import com.appttude.h_mal.atlas_weather.utils.generateIconUrlString import com.appttude.h_mal.atlas_weather.utils.generateIconUrlString
@@ -25,27 +24,7 @@ data class Current(
val windSpeed: Double? = null val windSpeed: Double? = null
) { ) {
constructor(dailyItem: Current) : this( constructor(currentConditions: CurrentConditions?) : this(
dailyItem.dt,
dailyItem.sunrise,
dailyItem.sunset,
dailyItem.temp,
dailyItem.visibility,
dailyItem.uvi,
dailyItem.pressure,
dailyItem.clouds,
dailyItem.feelsLike,
dailyItem.windDeg,
dailyItem.dewPoint,
generateIconUrlString(dailyItem.weather?.getOrNull(0)?.icon),
dailyItem.weather?.get(0)?.description,
dailyItem.weather?.get(0)?.main,
dailyItem.weather?.get(0)?.id,
dailyItem.humidity,
dailyItem.windSpeed
)
constructor(currentConditions: CurrentConditions?): this(
dt = currentConditions?.datetimeEpoch, dt = currentConditions?.datetimeEpoch,
sunrise = currentConditions?.sunriseEpoch, sunrise = currentConditions?.sunriseEpoch,
sunset = currentConditions?.sunsetEpoch, sunset = currentConditions?.sunsetEpoch,

View File

@@ -1,6 +1,5 @@
package com.appttude.h_mal.atlas_weather.model.weather package com.appttude.h_mal.atlas_weather.model.weather
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.DailyItem
import com.appttude.h_mal.atlas_weather.data.network.response.weather.Days import com.appttude.h_mal.atlas_weather.data.network.response.weather.Days
import com.appttude.h_mal.atlas_weather.model.IconMapper import com.appttude.h_mal.atlas_weather.model.IconMapper
import com.appttude.h_mal.atlas_weather.utils.generateIconUrlString import com.appttude.h_mal.atlas_weather.utils.generateIconUrlString
@@ -29,29 +28,6 @@ data class DailyWeather(
val rain: Double? val rain: Double?
) { ) {
constructor(dailyItem: DailyItem) : this(
dailyItem.dt,
dailyItem.sunrise,
dailyItem.sunset,
dailyItem.temp?.min,
dailyItem.temp?.max,
dailyItem.temp?.day,
dailyItem.feelsLike?.day,
dailyItem.pressure,
dailyItem.humidity,
dailyItem.dewPoint,
dailyItem.windSpeed,
dailyItem.windDeg,
generateIconUrlString(dailyItem.weather?.getOrNull(0)?.icon),
dailyItem.weather?.get(0)?.description,
dailyItem.weather?.get(0)?.main,
dailyItem.weather?.get(0)?.id,
dailyItem.clouds,
dailyItem.pop,
dailyItem.uvi,
dailyItem.rain
)
constructor(days: Days) : this( constructor(days: Days) : this(
days.datetimeEpoch, days.datetimeEpoch,
days.sunriseEpoch, days.sunriseEpoch,
@@ -77,5 +53,4 @@ data class DailyWeather(
days.precip?.toDouble() days.precip?.toDouble()
) )
} }

View File

@@ -1,29 +1,15 @@
package com.appttude.h_mal.atlas_weather.model.weather package com.appttude.h_mal.atlas_weather.model.weather
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.WeatherResponse
data class FullWeather( data class FullWeather(
val current: Current? = null, val current: Current? = null,
val timezone: String? = null, val timezone: String? = null,
val timezoneOffset: Int? = null, val timezoneOffset: Int? = null,
val hourly: List<Hour>? = null, val hourly: List<Hour>? = null,
val daily: List<DailyWeather>? = null, val daily: List<DailyWeather>? = null,
val lon: Double = 0.00, val lon: Double? = null,
val lat: Double = 0.00, val lat: Double? = null,
var locationString: String? = null, var locationString: String? = null,
var temperatureUnit: String? = null var temperatureUnit: String? = null
) { )
constructor(weatherResponse: WeatherResponse) : this(
weatherResponse.current?.let { Current(it) },
weatherResponse.timezone,
weatherResponse.timezoneOffset,
weatherResponse.hourly?.subList(0, 23)?.map { Hour(it) },
weatherResponse.daily?.map { DailyWeather(it) },
weatherResponse.lon,
weatherResponse.lat
)
}

View File

@@ -4,7 +4,6 @@ import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import com.appttude.h_mal.atlas_weather.model.IconMapper import com.appttude.h_mal.atlas_weather.model.IconMapper
import com.appttude.h_mal.atlas_weather.utils.generateIconUrlString import com.appttude.h_mal.atlas_weather.utils.generateIconUrlString
import com.appttude.h_mal.atlas_weather.data.network.response.forecast.Hour as ForecastHour
import com.appttude.h_mal.atlas_weather.data.network.response.weather.Hours as WeatherHour import com.appttude.h_mal.atlas_weather.data.network.response.weather.Hours as WeatherHour
@@ -18,15 +17,9 @@ data class Hour(
parcel.readValue(Int::class.java.classLoader) as? Int, parcel.readValue(Int::class.java.classLoader) as? Int,
parcel.readValue(Double::class.java.classLoader) as? Double, parcel.readValue(Double::class.java.classLoader) as? Double,
parcel.readString() parcel.readString()
) {
}
constructor(hour: ForecastHour) : this(
hour.dt,
hour.temp,
generateIconUrlString(hour.weather?.getOrNull(0)?.icon)
) )
constructor(weatherHour: WeatherHour) : this( constructor(weatherHour: WeatherHour) : this(
weatherHour.datetimeEpoch, weatherHour.datetimeEpoch,
weatherHour.temp, weatherHour.temp,

View File

@@ -17,6 +17,7 @@ import io.mockk.mockk
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.mockito.ArgumentMatchers.anyDouble
import java.io.IOException import java.io.IOException
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFailsWith import kotlin.test.assertFailsWith
@@ -85,16 +86,18 @@ class RepositoryImplTest : BaseTest() {
@Test @Test
fun getWeatherFromApi_validLatLong_validSearch() { fun getWeatherFromApi_validLatLong_validSearch() {
//Arrange //Arrange
val lat = anyDouble().toString()
val long = anyDouble().toString()
val mockResponse = createSuccessfulRetrofitMock<WeatherApiResponse>() val mockResponse = createSuccessfulRetrofitMock<WeatherApiResponse>()
//Act //Act
//create a successful retrofit response //create a successful retrofit response
every { prefs.getUnitsType() } returns (UnitType.METRIC) every { prefs.getUnitsType() } returns (UnitType.METRIC)
coEvery { api.getFromApi(location = "") }.returns(mockResponse) coEvery { api.getFromApi(location = lat + long) }.returns(mockResponse)
// Assert // Assert
runBlocking { runBlocking {
val result = repository.getWeatherFromApi("", "") val result = repository.getWeatherFromApi(lat, long)
assertIs<WeatherApiResponse>(result) assertIs<WeatherApiResponse>(result)
} }
} }

View File

@@ -3,7 +3,7 @@ package com.appttude.h_mal.atlas_weather.viewmodel
import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.appttude.h_mal.atlas_weather.data.WeatherSource import com.appttude.h_mal.atlas_weather.data.WeatherSource
import com.appttude.h_mal.atlas_weather.data.location.LocationProviderImpl 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.network.response.weather.WeatherApiResponse
import com.appttude.h_mal.atlas_weather.data.room.entity.CURRENT_LOCATION import com.appttude.h_mal.atlas_weather.data.room.entity.CURRENT_LOCATION
import com.appttude.h_mal.atlas_weather.model.ViewState import com.appttude.h_mal.atlas_weather.model.ViewState
import com.appttude.h_mal.atlas_weather.model.types.LocationType import com.appttude.h_mal.atlas_weather.model.types.LocationType
@@ -21,10 +21,10 @@ import io.mockk.impl.annotations.RelaxedMockK
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.mockito.ArgumentMatchers
import org.mockito.ArgumentMatchers.anyList import org.mockito.ArgumentMatchers.anyList
import org.mockito.ArgumentMatchers.anyString import org.mockito.ArgumentMatchers.anyString
import java.io.IOException import java.io.IOException
import kotlin.properties.Delegates
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertIs import kotlin.test.assertIs
@@ -43,12 +43,23 @@ class WorldViewModelTest : BaseTest() {
@MockK @MockK
lateinit var locationProvider: LocationProviderImpl lateinit var locationProvider: LocationProviderImpl
private lateinit var weatherResponse: WeatherResponse private lateinit var weatherResponse: WeatherApiResponse
private var lat by Delegates.notNull<Double>()
private var long by Delegates.notNull<Double>()
private lateinit var latlon: Pair<Double, Double>
private lateinit var fullWeather: FullWeather
@Before @Before
fun setUp() { fun setUp() {
MockKAnnotations.init(this) MockKAnnotations.init(this)
weatherResponse = getTestData("weather_sample.json", WeatherResponse::class.java) weatherResponse = getTestData("new_response.json", WeatherApiResponse::class.java)
lat = weatherResponse.latitude!!
long = weatherResponse.longitude!!
latlon = Pair(lat, long)
fullWeather = weatherResponse.mapData().apply {
temperatureUnit = "°C"
locationString = CURRENT_LOCATION
}
} }
@Test @Test
@@ -58,13 +69,13 @@ class WorldViewModelTest : BaseTest() {
// Act // Act
coEvery { locationProvider.getLatLongFromLocationName(CURRENT_LOCATION) } returns Pair( coEvery { locationProvider.getLatLongFromLocationName(CURRENT_LOCATION) } returns Pair(
weatherResponse.lat, lat,
weatherResponse.lon long
) )
coEvery { coEvery {
locationProvider.getLocationNameFromLatLong( locationProvider.getLocationNameFromLatLong(
weatherResponse.lat, lat,
weatherResponse.lon, long,
LocationType.City LocationType.City
) )
}.returns(CURRENT_LOCATION) }.returns(CURRENT_LOCATION)
@@ -74,7 +85,7 @@ class WorldViewModelTest : BaseTest() {
CURRENT_LOCATION, CURRENT_LOCATION,
locationType = LocationType.City locationType = LocationType.City
) )
} returns FullWeather(weatherResponse) } returns fullWeather
// Assert // Assert
viewModel.fetchDataForSingleLocation(CURRENT_LOCATION) viewModel.fetchDataForSingleLocation(CURRENT_LOCATION)
@@ -86,17 +97,17 @@ class WorldViewModelTest : BaseTest() {
@Test @Test
fun fetchDataForSingleLocation_failedLocation_validReturn() { fun fetchDataForSingleLocation_failedLocation_validReturn() {
// Arrange // Arrange
val errorMessage = ArgumentMatchers.anyString() val errorMessage = anyString()
// Act // Act
coEvery { locationProvider.getLatLongFromLocationName(CURRENT_LOCATION) } returns Pair( coEvery { locationProvider.getLatLongFromLocationName(CURRENT_LOCATION) } returns Pair(
weatherResponse.lat, lat,
weatherResponse.lon long
) )
coEvery { coEvery {
locationProvider.getLocationNameFromLatLong( locationProvider.getLocationNameFromLatLong(
weatherResponse.lat, lat,
weatherResponse.lon, long,
LocationType.City LocationType.City
) )
} throws IOException(errorMessage) } throws IOException(errorMessage)
@@ -112,18 +123,17 @@ class WorldViewModelTest : BaseTest() {
@Test @Test
fun fetchDataForSingleLocation_failedApi_validReturn() { fun fetchDataForSingleLocation_failedApi_validReturn() {
// Arrange // Arrange
val latlon = Pair(weatherResponse.lat, weatherResponse.lon) val errorMessage = anyString()
val errorMessage = ArgumentMatchers.anyString()
// Act // Act
coEvery { locationProvider.getLatLongFromLocationName(CURRENT_LOCATION) } returns Pair( coEvery { locationProvider.getLatLongFromLocationName(CURRENT_LOCATION) } returns Pair(
weatherResponse.lat, lat,
weatherResponse.lon long
) )
coEvery { coEvery {
locationProvider.getLocationNameFromLatLong( locationProvider.getLocationNameFromLatLong(
weatherResponse.lat, lat,
weatherResponse.lon, long,
LocationType.City LocationType.City
) )
}.returns(CURRENT_LOCATION) }.returns(CURRENT_LOCATION)
@@ -146,15 +156,14 @@ class WorldViewModelTest : BaseTest() {
@Test @Test
fun fetchDataForSingleLocationSearch_validLocation_validReturn() { fun fetchDataForSingleLocationSearch_validLocation_validReturn() {
// Arrange // Arrange
val latlon = Pair(weatherResponse.lat, weatherResponse.lon)
// Act // Act
every { weatherSource.repository.getSavedLocations() } returns anyList() every { weatherSource.repository.getSavedLocations() } returns anyList()
coEvery { locationProvider.getLatLongFromLocationName(CURRENT_LOCATION) } returns latlon coEvery { locationProvider.getLatLongFromLocationName(CURRENT_LOCATION) } returns latlon
coEvery { coEvery {
locationProvider.getLocationNameFromLatLong( locationProvider.getLocationNameFromLatLong(
weatherResponse.lat, lat,
weatherResponse.lon, long,
LocationType.City LocationType.City
) )
}.returns(CURRENT_LOCATION) }.returns(CURRENT_LOCATION)
@@ -164,7 +173,7 @@ class WorldViewModelTest : BaseTest() {
CURRENT_LOCATION, CURRENT_LOCATION,
locationType = LocationType.City locationType = LocationType.City
) )
} returns FullWeather(weatherResponse).apply { locationString = CURRENT_LOCATION } } returns fullWeather.apply { locationString = CURRENT_LOCATION }
// Assert // Assert
viewModel.fetchDataForSingleLocationSearch(CURRENT_LOCATION) viewModel.fetchDataForSingleLocationSearch(CURRENT_LOCATION)
@@ -192,7 +201,6 @@ class WorldViewModelTest : BaseTest() {
@Test @Test
fun fetchDataForSingleLocationSearch_retrievedLocationExists_validError() { fun fetchDataForSingleLocationSearch_retrievedLocationExists_validError() {
// Arrange // Arrange
val latlon = Pair(weatherResponse.lat, weatherResponse.lon)
val retrievedLocation = anyString() val retrievedLocation = anyString()
// Act // Act
@@ -200,8 +208,7 @@ class WorldViewModelTest : BaseTest() {
coEvery { locationProvider.getLatLongFromLocationName(CURRENT_LOCATION) } returns latlon coEvery { locationProvider.getLatLongFromLocationName(CURRENT_LOCATION) } returns latlon
coEvery { coEvery {
locationProvider.getLocationNameFromLatLong( locationProvider.getLocationNameFromLatLong(
weatherResponse.lat, lat, long,
weatherResponse.lon,
LocationType.City LocationType.City
) )
}.returns(CURRENT_LOCATION) }.returns(CURRENT_LOCATION)
@@ -211,7 +218,7 @@ class WorldViewModelTest : BaseTest() {
CURRENT_LOCATION, CURRENT_LOCATION,
locationType = LocationType.City locationType = LocationType.City
) )
} returns FullWeather(weatherResponse).apply { locationString = retrievedLocation } } returns fullWeather.apply { locationString = retrievedLocation }
// Assert // Assert
viewModel.fetchDataForSingleLocationSearch(CURRENT_LOCATION) viewModel.fetchDataForSingleLocationSearch(CURRENT_LOCATION)

View File

@@ -1,317 +0,0 @@
{
"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
}
]
}