Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/get cities has lowest fruit veg prices comparing salaries paid #33

Open
wants to merge 62 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
752f907
create the class GetCitiesHasLowestFruitVegPricesComparingSalariesPaid
Momen-Mustafa Feb 10, 2023
87880fd
create test class and write test fakes
Momen-Mustafa Feb 10, 2023
d28aa8b
create a new constructor to accept list of CityEntity
Momen-Mustafa Feb 10, 2023
8961a5d
finish first test case
Momen-Mustafa Feb 10, 2023
ec1cb28
add fake data
Asiasama710 Feb 10, 2023
e7bc714
testing git cities and years to buy apartment
Feb 10, 2023
e080824
implementation get cities and years to buy apartment
Feb 10, 2023
db5edf1
correct first test case
Momen-Mustafa Feb 10, 2023
ce9fae4
edit test class and move its file to the folder test
Momen-Mustafa Feb 11, 2023
2d94ab8
add test throw exception when salary is zero
Feb 11, 2023
5129c13
Merge remote-tracking branch 'origin/develop' into feature/get_cities…
Momen-Mustafa Feb 11, 2023
23733f5
edit test class and move fake data to another file
Momen-Mustafa Feb 11, 2023
8cd471a
rename test cases and add extension format
Feb 11, 2023
f035466
created 4 tests
Saif-Alhaider Feb 11, 2023
b4c5668
finish the functionality of this class
Momen-Mustafa Feb 11, 2023
d064c4b
add two test case for get cities names sorted by cheapest banana prices
Asiasama710 Feb 11, 2023
b6de999
Remove second fake data. Then, edit the function class by removing th…
Momen-Mustafa Feb 11, 2023
766f8ae
finished the execute function also edited wrong spelling word
Saif-Alhaider Feb 11, 2023
9b179e8
get cities names and sorted by cheapest banana prices
Asiasama710 Feb 11, 2023
4bee648
simplified regex expression
Saif-Alhaider Feb 11, 2023
a8c427e
edit the private function excludeNullFruitVegPrices
Momen-Mustafa Feb 12, 2023
ecc39d8
add extension in util folder
Feb 12, 2023
06675ed
edited some tests
Saif-Alhaider Feb 12, 2023
724ca85
complete test cases for get cities name sorted by cheapest banana price
Feb 12, 2023
4622b58
replit fake data source to fake data
Feb 12, 2023
8f7f825
Add Class GetHighestCarbonatedDrinksPricesInteractor
amna97alaa Feb 12, 2023
0031479
refactored functions names
Saif-Alhaider Feb 12, 2023
08573f0
added extension function for sentence formatting
Saif-Alhaider Feb 12, 2023
3ee4829
renamed the files
Saif-Alhaider Feb 12, 2023
661ccec
replit compact function to return type function and add ectenstion to…
Feb 12, 2023
bc1b104
Add GetTopTenCoutriesHaveHighCarbonatedDrinksPrices Class
amna97alaa Feb 12, 2023
3430f0a
Merge pull request #5 from Asiasama710/feature/calculate_years_needed…
Asiasama710 Feb 12, 2023
25b08b4
Merge remote-tracking branch 'origin/develop' into feature/get_countr…
Asiasama710 Feb 12, 2023
af1101a
add additional test cases
banankmh Feb 12, 2023
4d011be
refactor code
Asiasama710 Feb 12, 2023
e52f17d
add another test cases
banankmh Feb 12, 2023
86ff5a9
Merge pull request #3 from Asiasama710/feature/get_country_cities_ave…
Asiasama710 Feb 13, 2023
ba605e8
add test cases for get top fashion cities
Feb 13, 2023
bc35054
implementation method for get top fashion cities
Feb 13, 2023
44e7ed4
Merge remote-tracking branch 'origin/develop' into feature/get_top_fi…
Feb 13, 2023
5ff3214
Add GetTopTenCoutriesHaveHighCarbonatedDrinksPrices Class
amna97alaa Feb 13, 2023
4e6f598
fix all test cases
amna97alaa Feb 13, 2023
3ef0a0e
Merge remote-tracking branch 'origin/develop' into feature/countries-…
amna97alaa Feb 13, 2023
db4e515
add calculate clothes prices methode && refactor code && add unneces…
Asiasama710 Feb 13, 2023
ba56032
refactor code
Asiasama710 Feb 13, 2023
e9a1993
Merge remote-tracking branch 'origin/develop' into feature/get_cities…
Asiasama710 Feb 13, 2023
43255a0
Merge pull request #6 from Asiasama710/feature/get_cities_names_sorte…
Asiasama710 Feb 13, 2023
40dfc5e
Merge remote-tracking branch 'origin/develop' into feature/get_top_fi…
Asiasama710 Feb 13, 2023
45a8809
Merge pull request #9 from Asiasama710/feature/get_top_fifth_fashion_…
Asiasama710 Feb 13, 2023
9c89b32
Merge remote-tracking branch 'origin/develop' into feature/countries-…
Asiasama710 Feb 13, 2023
16641d9
refactor code and merge develop on branch
Asiasama710 Feb 13, 2023
b3430f6
Merge pull request #7 from Asiasama710/feature/countries-high-prices-…
Asiasama710 Feb 13, 2023
8e6c22b
Merge remote-tracking branch 'origin/develop' into feature/get_cities…
Asiasama710 Feb 13, 2023
9bb9ca0
refactor code
Asiasama710 Feb 13, 2023
98153be
edit the class GetLowCostFruitVegetableCitiesWithHighSalariesInteract…
Momen-Mustafa Feb 15, 2023
c22dade
resolve the issue of inputting number more than the capacity of the d…
banankmh Feb 15, 2023
ced52c0
consider the case if the user puts zero or negative numbers
Momen-Mustafa Feb 15, 2023
2d7ba44
consider the case if the user puts zero or negative numbers
Momen-Mustafa Feb 15, 2023
3c62e62
consider the case if the user puts zero or negative numbers
Momen-Mustafa Feb 15, 2023
869b5b9
consider the case if the user puts zero or negative numbers
Momen-Mustafa Feb 15, 2023
fb851f2
add four test cases
banankmh Feb 15, 2023
39d91cb
use scope function in two private functions
Momen-Mustafa Feb 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,6 @@ bin/
.vscode/

### Mac OS ###
.DS_Store
.DS_Store
/.idea/uiDesigner.xml
/.idea/kotlinc.xml
4 changes: 4 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .idea/.name

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/kotlinc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "1.6.20"
application

}


group = "org.the-chance"
version = "1.0-SNAPSHOT"

Expand All @@ -13,7 +15,11 @@ repositories {
}

dependencies {
implementation("junit:junit:4.13.1")
implementation("org.testng:testng:7.1.0")
testImplementation(kotlin("test"))
testImplementation("org.junit.jupiter:junit-jupiter:5.8.1")
testImplementation("org.mockito:mockito-core:3.3.3")
}

tasks.test {
Expand All @@ -22,8 +28,10 @@ tasks.test {

tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"

}

application {
mainClass.set("MainKt")

}
40 changes: 37 additions & 3 deletions src/main/kotlin/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,54 @@ import dataSource.utils.CsvParser
import interactor.CostOfLivingDataSource
import interactor.GetCityHasCheapestInternetConnectionInteractor
import interactor.GetHighestSalaryAverageCititesNamesInteractor
import interactor.GetTopCountriesHaveHighCarbonatedDrinksPricesInterctor
import interactor.GetCitiesAndYearsToBuyApartmentInteractor
import interactor.GetTopFashionCitiesInteractor
import interactor.GetCitiesNamesSortedByCheapestBananaPricesInteractor
import interactor.*

fun main() {
val csvParser = CsvParser()
val dataSource: CostOfLivingDataSource = CsvDataSource(csvParser)

val getTopCountriesWithHighTaxOnCarbonatedDrinks= GetTopCountriesHaveHighCarbonatedDrinksPricesInterctor(dataSource)
println(getTopCountriesWithHighTaxOnCarbonatedDrinks.execute(limit = 10))
printSeparationLine()

val getHighestSalaryAverageCities = GetHighestSalaryAverageCititesNamesInteractor(dataSource)
println(getHighestSalaryAverageCities.execute(limit = 10))
printSeparationLine()

val getCityHasCheapestInternetConnectionInteractor = GetCityHasCheapestInternetConnectionInteractor(dataSource)
println(getCityHasCheapestInternetConnectionInteractor.execute())
val getTopFashionCities = GetTopFashionCitiesInteractor(dataSource)
println(getTopFashionCities.execute(limit = 5))
printSeparationLine()

val getCitiesNamesSortedByCheapestBananaPricesInteractor = GetCitiesNamesSortedByCheapestBananaPricesInteractor(dataSource)
println(getCitiesNamesSortedByCheapestBananaPricesInteractor.execute("Caracas","Accra","Giza"))
printSeparationLine()

val getCitiesAndYearsToBuyApartment = GetCitiesAndYearsToBuyApartmentInteractor(dataSource)
println(getCitiesAndYearsToBuyApartment.execute(limit = 10))
printSeparationLine()

val getCountryCitiesAverageSalary = GetCountryCitiesAverageSalaryInteractor(dataSource)
println(getCountryCitiesAverageSalary.execute("Syria"))
printSeparationLine()

val getLowCostFruitVegetableCitiesWithHighSalaries = GetLowCostFruitVegetableCitiesWithHighSalariesInteractor(dataSource)
println(getLowCostFruitVegetableCitiesWithHighSalaries.execute(10))
printSeparationLine()


val getCityHasCheapestInternetConnection = GetCityHasCheapestInternetConnectionInteractor(dataSource)
println(getCityHasCheapestInternetConnection.execute())
printSeparationLine()



}
private fun printSeparationLine(){

private fun printSeparationLine() {
print("\n_______________________________\n")
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package interactor

import interactor.util.Constants.ONE_HUNDRED_SQUARE_METER
import interactor.util.Constants.TWELVE_MONTH
import model.CityEntity
import interactor.util.toFormat
import interactor.util.toYear

class GetCitiesAndYearsToBuyApartmentInteractor(
private val dataSource: CostOfLivingDataSource
) {

fun execute(limit: Int): List<Pair<String, String>> {
return dataSource
.getAllCitiesData()
.filter(::excludeNullValueAndLowQualityData)
.sortedBy(::calculateYearsNeededToBuyApartment)
.take(limit)
.map { Pair(it.cityName, calculateYearsNeededToBuyApartment(it).toYear()) }
}


private fun excludeNullValueAndLowQualityData(city: CityEntity): Boolean {
return city.let {
it.dataQuality &&
it.averageMonthlyNetSalaryAfterTax != null &&
it.realEstatesPrices.pricePerSquareMeterToBuyApartmentOutsideOfCentre != null
}
}

private fun calculateYearsNeededToBuyApartment(city: CityEntity): Float {
return with(city) {
((realEstatesPrices.pricePerSquareMeterToBuyApartmentOutsideOfCentre?.times(ONE_HUNDRED_SQUARE_METER))?.div(
(averageMonthlyNetSalaryAfterTax?.times(TWELVE_MONTH)!!)
))?.toFormat() ?: 0f
}
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package interactor

import model.CityEntity


class GetCitiesNamesSortedByCheapestBananaPricesInteractor(
private val dataSource: CostOfLivingDataSource
) {
fun execute(vararg cities: String): List<String> {
return dataSource
.getAllCitiesData()
.filter { excludeNullBananaPricesAndLowQualityData(it) }
.filter { compereCitiesNamesWithInputCities(cities, it.cityName) }
.sortedBy { it.fruitAndVegetablesPrices.banana1kg }
.map { it.cityName }
}

private fun compereCitiesNamesWithInputCities(inputCity: Array<out String>, city: String): Boolean {
return inputCity.map { it.toLowerCase().trim() }.contains(city.toLowerCase())
}

private fun excludeNullBananaPricesAndLowQualityData(city: CityEntity): Boolean {
return city.fruitAndVegetablesPrices.banana1kg != null
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package interactor

import interactor.util.Constants.COUNTRY_WAS_NOT_FOUND
import interactor.util.formatSentence
import model.CityEntity

class GetCountryCitiesAverageSalaryInteractor(
private val dataSource: CostOfLivingDataSource,
) {

fun execute(country: String): List<Pair<String, Float>> {
val citiesSalaries = dataSource.getAllCitiesData()
.filter { searchCountry(it, country) && excludeNullSalariesAndLowQualityData(it) }
.map { Pair(it.cityName, it.averageMonthlyNetSalaryAfterTax!!) }
if (citiesSalaries.isEmpty()) throw Exception(COUNTRY_WAS_NOT_FOUND)

return citiesSalaries
}

private fun excludeNullSalariesAndLowQualityData(city: CityEntity): Boolean {
return city.averageMonthlyNetSalaryAfterTax != null && city.dataQuality
}

private fun searchCountry(city: CityEntity, country: String): Boolean {
return city.country.formatSentence() == country.formatSentence()
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class GetHighestSalaryAverageCititesNamesInteractor(
private val dataSource: CostOfLivingDataSource,
) {

fun execute(limit: Int): List<String> {
fun execute(limit: Int): List<String?> {
return dataSource
.getAllCitiesData()
.filter(::excludeNullSalariesAndLowQualityData)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package interactor

import model.CityEntity
import model.FruitAndVegetablesPrices



class GetLowCostFruitVegetableCitiesWithHighSalariesInteractor(
private val dataSource: CostOfLivingDataSource
) {

fun execute(limit: Int): List<String> {
return dataSource.getAllCitiesData()
.filter(::excludeNullSalariesAndNullFruitVegPrices)
.sortedBy { calculateFruitVegTotalPrice(it.fruitAndVegetablesPrices).div(it.averageMonthlyNetSalaryAfterTax!!) }
.takeUnless { limit<=0 || limit > it.count() }!!
.take(limit)
.map { it.cityName }
}
private fun excludeNullSalariesAndNullFruitVegPrices(city: CityEntity): Boolean {
return city.averageMonthlyNetSalaryAfterTax != null &&
with(city.fruitAndVegetablesPrices){
this.apples1kg!= null && this.banana1kg!= null && this.lettuceOneHead!= null &&
this.onion1kg!= null && this.oranges1kg!= null && this.potato1kg!= null &&
this.tomato1kg!= null
}

}

private fun calculateFruitVegTotalPrice(fruitAndVegetablesPrices: FruitAndVegetablesPrices): Float =
with(fruitAndVegetablesPrices){
return this.apples1kg!! + this.banana1kg!!+ this.lettuceOneHead!!+ this.onion1kg!!+ this.oranges1kg!!+
this.potato1kg!!+ this.tomato1kg!!
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package interactor

import model.CityEntity

class GetTopCountriesHaveHighCarbonatedDrinksPricesInterctor(
private val dataSource: CostOfLivingDataSource
) {
fun execute(limit: Int): List<Pair<String, Float?>> {
return dataSource.getAllCitiesData()
.filter(::exceptionNullDrinkPriceAndQualityData)
.sortedByDescending { it.drinksPrices.cokePepsiAThirdOfLiterBottleInRestaurants }
.take(if (limit > 0) limit else 0)
.map { Pair(it.country, it.drinksPrices.cokePepsiAThirdOfLiterBottleInRestaurants) }
}

private fun exceptionNullDrinkPriceAndQualityData(city: CityEntity): Boolean {
return city.drinksPrices.cokePepsiAThirdOfLiterBottleInRestaurants != null
&& city.dataQuality
}
}
33 changes: 33 additions & 0 deletions src/main/kotlin/interactor/GetTopFashionCitiesInteractor.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package interactor

import model.CityEntity

class GetTopFashionCitiesInteractor(
private val dataSource: CostOfLivingDataSource,
) {
fun execute(limit: Int): List<String> {
return dataSource.getAllCitiesData()
.filter(::excludeNullPrices)
.sortedBy(::calculateClothesPrices)
.take(limit)
.map { it.cityName }
}

private fun excludeNullPrices(city: CityEntity): Boolean {
return with(city.clothesPrices) {
this.onePairOfJeansLevis50oneOrSimilar != null &&
this.onePairOfNikeRunningShoesMidRange != null &&
this.oneSummerDressInAChainStoreZaraHAndM != null
}
}

private fun calculateClothesPrices(city: CityEntity): Float {
return with(city.clothesPrices) {
onePairOfJeansLevis50oneOrSimilar!! +
oneSummerDressInAChainStoreZaraHAndM!! +
onePairOfNikeRunningShoesMidRange!!
}
}
}


8 changes: 8 additions & 0 deletions src/main/kotlin/interactor/util/Constants.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package interactor.util

object Constants {
const val TWELVE_MONTH = 12
const val ONE_HUNDRED_SQUARE_METER = 100
const val COUNTRY_WAS_NOT_FOUND = "country was not found !"

}
14 changes: 14 additions & 0 deletions src/main/kotlin/interactor/util/Extension.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package interactor.util


fun Float.toFormat(limit: Int = 1): Float {
return String.format("%.${limit}f", this).toFloat()
}

fun String.formatSentence(): String {
return this.lowercase().trim().replace(Regex(" +"), " ")
}

fun Float.toYear(): String {
return if (this >= 2.0) "$this years" else "$this year"
}
Loading