Skip to content

Commit

Permalink
Merge pull request #46 from Factotum-sdp/end/first_sprint
Browse files Browse the repository at this point in the history
End/first sprint
  • Loading branch information
schuetzcarl authored Mar 17, 2023
2 parents eaa06ec + cd12cd3 commit aee13e9
Show file tree
Hide file tree
Showing 39 changed files with 944 additions and 98 deletions.
11 changes: 11 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ android {
testCoverageEnabled true
}
}

testOptions {
unitTests.all {
useJUnitPlatform()
}
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
Expand Down Expand Up @@ -70,6 +77,10 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.0'
implementation 'androidx.recyclerview:recyclerview:1.3.0'
implementation 'androidx.test.espresso:espresso-contrib:3.5.1'
implementation 'com.google.android.gms:play-services-auth:20.4.1'
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'
testImplementation 'org.mockito:mockito-core:3.12.4'
testImplementation 'org.mockito:mockito-inline:2.13.0'
androidTestImplementation 'androidx.arch.core:core-testing:2.2.0'
implementation 'com.google.firebase:firebase-storage-ktx:20.1.0'
implementation "androidx.lifecycle:lifecycle-common-java8:2.6.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.rule.GrantPermissionRule
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiSelector
import org.hamcrest.Matchers.allOf
import org.junit.Rule
import org.junit.Test
Expand All @@ -39,6 +38,11 @@ class MainActivityTest {
// Entry view checks :
//========================================================================================

@Test
fun loginFragmentIsCorrectlyDisplayedOnFirstView() {
onView(withId(R.id.fragment_login_directors_parent)).check(matches(isDisplayed()))
}

@Test
fun appBarIsCorrectlyDisplayedOnFirstView() {
onView(withId(R.id.app_bar_main)).check(matches(isDisplayed()))
Expand Down Expand Up @@ -70,24 +74,21 @@ class MainActivityTest {
onView(withId(R.id.drawer_layout)).check(matches(DrawerMatchers.isClosed(Gravity.LEFT)))
}

@Test
fun clickOnMapsMenuItemLeadsToCorrectFragment() {
onView(withId(R.id.drawer_layout))
.perform(DrawerActions.open())
onView(withId(R.id.routeFragment))
.perform(click())
onView(withId(R.id.drawer_layout)).check(matches(DrawerMatchers.isClosed(Gravity.LEFT)))
}

@Test
fun clickOnDirectoryMenuItemLeadsToCorrectFragment() {
clickOnAMenuItemLeadsCorrectly(R.id.directoryFragment, R.id.fragment_directory_directors_parent)
clickOnAMenuItemLeadsCorrectly(
R.id.directoryFragment,
R.id.fragment_directory_directors_parent
)
}

@Test
fun clickOnRoadBookMenuItemStaysToCorrectFragment() {
onView(withId(R.id.fragment_roadbook_directors_parent)).check(matches(isDisplayed()))
clickOnAMenuItemLeadsCorrectly(R.id.roadBookFragment, R.id.fragment_roadbook_directors_parent)
//onView(withId(R.id.fragment_roadbook_directors_parent)).check(matches(isDisplayed()))
clickOnAMenuItemLeadsCorrectly(
R.id.roadBookFragment,
R.id.fragment_roadbook_directors_parent
)
}

@Test
Expand All @@ -107,18 +108,31 @@ class MainActivityTest {
Thread.sleep(5000)

// Click on the camera shutter button
val takePictureButton = device.findObject(UiSelector().description("Shutter"))
takePictureButton.click()
device.executeShellCommand("input keyevent 27")

// Use Intents.intended() to check that the captured intent matches the expected intent
Intents.intended(expectedIntent)
Intents.release()
}

@Test
fun clickOnMapsMenuItemLeadsToCorrectFragment() {
clickOnAMenuItemLeadsCorrectly(
R.id.routeFragment,
R.id.fragment_route_directors_parent
)
}

@Test
fun navigateThroughDrawerMenuWorks() {
clickOnAMenuItemLeadsCorrectly(R.id.directoryFragment, R.id.fragment_directory_directors_parent)
clickOnAMenuItemLeadsCorrectly(R.id.roadBookFragment, R.id.fragment_roadbook_directors_parent)
clickOnAMenuItemLeadsCorrectly(
R.id.directoryFragment,
R.id.fragment_directory_directors_parent
)
clickOnAMenuItemLeadsCorrectly(
R.id.roadBookFragment,
R.id.fragment_roadbook_directors_parent
)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.github.factotum_sdp.factotum.ui.login

import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.*
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.github.factotum_sdp.factotum.MainActivity
import com.github.factotum_sdp.factotum.R
import org.hamcrest.Matchers.not
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class LoginFragmentTest {

private val usernameInput = onView(withId(R.id.username))
private val passwordInput = onView(withId(R.id.password))
private val loginButton = onView(withId(R.id.login))
private val signUp = onView(withId(R.id.signup))

@get:Rule
var testRule = ActivityScenarioRule(
MainActivity::class.java
)

@Test
fun loginFormInitialStateIsEmpty() {
usernameInput.check(matches(withText("")))
passwordInput.check(matches(withText("")))
loginButton.check(matches(not(isEnabled())))
}

@Test
fun loginFormWithoutPassword() {
usernameInput.perform(typeText("[email protected]"))
loginButton.check(matches(not(isEnabled())))
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.github.factotum_sdp.factotum
package com.github.factotum_sdp.factotum.ui.maps

import android.content.Intent
import androidx.test.espresso.Espresso.onView
Expand All @@ -16,7 +16,8 @@ import androidx.test.uiautomator.By.descContains
import androidx.test.uiautomator.By.textContains
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiSelector
import com.github.factotum_sdp.factotum.ui.maps.RouteFragment
import com.github.factotum_sdp.factotum.MainActivity
import com.github.factotum_sdp.factotum.R
import junit.framework.TestCase.assertTrue
import org.hamcrest.CoreMatchers.allOf
import org.junit.Assert.assertEquals
Expand Down Expand Up @@ -47,7 +48,7 @@ class MapsFragmentTest {
device.findObject(UiSelector().textContains("->")).click()
val nextButton = onView(withId(R.id.button_next))
nextButton.perform(click())
onView(withId(R.id.maps_fragment)).check(matches(isDisplayed()))
onView(withId(R.id.fragment_maps_directors_parent)).check(matches(isDisplayed()))
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.github.factotum_sdp.factotum.R
import com.github.factotum_sdp.factotum.placeholder.DestinationRecords
import com.google.firebase.database.ktx.database
import com.google.firebase.ktx.Firebase
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
Expand All @@ -28,6 +29,15 @@ class RoadBookFragmentTest {
MainActivity::class.java
)


@Before
fun toRoadBookFragment() {
onView(withId(R.id.drawer_layout))
.perform(DrawerActions.open())
onView(withId(R.id.roadBookFragment))
.perform(click())
}

@Test
fun fabIsCorrectlyDisplayedOnFirstView() {
onView(withId(R.id.fab))
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.Factotum"
tools:targetApi="31">
tools:targetApi="33">
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@ class MainActivity : AppCompatActivity() {
// In order to keep out the NavigateUpButton which would mask the HamburgerButton
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.roadBookFragment, R.id.pictureFragment, R.id.directoryFragment, R.id.mapsFragment
R.id.roadBookFragment, R.id.pictureFragment,
R.id.directoryFragment, R.id.loginFragment, R.id.routeFragment
), drawerLayout
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)

supportActionBar?.setDisplayHomeAsUpEnabled(false)

// Bind user data displayed in the Navigation Header
setUserHeader()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.github.factotum_sdp.factotum.data

import com.github.factotum_sdp.factotum.data.model.LoggedInUser
import java.io.IOException

/**
* Class that handles authentication w/ login credentials and retrieves user information.
*/
class LoginDataSource {

fun login(username: String, password: String): Result<LoggedInUser> {
try {
val fakeUser = LoggedInUser(java.util.UUID.randomUUID().toString(), username)
return Result.Success(fakeUser)
} catch (e: Throwable) {
return Result.Error(IOException("Error logging in", e))
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.github.factotum_sdp.factotum.data

import com.github.factotum_sdp.factotum.data.model.LoggedInUser

/**
* Class that requests authentication and user information from the remote data source and
* maintains an in-memory cache of login status and user credentials information.
*/

class LoginRepository(val dataSource: LoginDataSource) {

// in-memory cache of the loggedInUser object
var user: LoggedInUser? = null
private set

val isLoggedIn: Boolean
get() = user != null

init {
// If user credentials will be cached in local storage, it is recommended it be encrypted
// @see https://developer.android.com/training/articles/keystore
user = null
}

fun login(username: String, password: String): Result<LoggedInUser> {
// handle login
val result = dataSource.login(username, password)

if (result is Result.Success) {
setLoggedInUser(result.data)
}

return result
}

private fun setLoggedInUser(loggedInUser: LoggedInUser) {
this.user = loggedInUser
// If user credentials will be cached in local storage, it is recommended it be encrypted
// @see https://developer.android.com/training/articles/keystore
}
}
18 changes: 18 additions & 0 deletions app/src/main/java/com/github/factotum_sdp/factotum/data/Result.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.github.factotum_sdp.factotum.data

/**
* A generic class that holds a value with its loading status.
* @param <T>
*/
sealed class Result<out T : Any> {

data class Success<out T : Any>(val data: T) : Result<T>()
data class Error(val exception: Exception) : Result<Nothing>()

override fun toString(): String {
return when (this) {
is Success<*> -> "Success[data=$data]"
is Error -> "Error[exception=$exception]"
}
}
}
22 changes: 13 additions & 9 deletions app/src/main/java/com/github/factotum_sdp/factotum/data/Route.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,19 @@ import com.google.android.gms.maps.model.MarkerOptions
* @param dstLat: Double. Latitude of the ending point
* @param dstLon: Double. Longitude of the ending point
*/
class Route (srcLat: Double, srcLon: Double, dstLat: Double, dstLon: Double) {
class Route(srcLat: Double, srcLon: Double, dstLat: Double, dstLon: Double) {

val src = LatLng(srcLat, srcLon)
val dst = LatLng(dstLat, dstLon)
val id = hashCode()

constructor(src: LatLng, dst: LatLng) : this(src.latitude, src.longitude, dst.latitude, dst.longitude)
constructor(src: LatLng, dst: LatLng) : this(
src.latitude,
src.longitude,
dst.latitude,
dst.longitude
)

/**
* Returns the coordinates of the start and destination of the route
*
Expand All @@ -40,13 +46,11 @@ class Route (srcLat: Double, srcLon: Double, dstLat: Double, dstLon: Double) {
* @param dst : boolean if we want to show the route destination
*/
fun addDstToMap(googleMap: GoogleMap) {
googleMap.addMarker(
MarkerOptions()
.position(this.dst)
.title("Destination of $id")
)
googleMap.addMarker(
MarkerOptions()
.position(this.dst)
.title("Destination of $id")
)
}



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.github.factotum_sdp.factotum.data.model

/**
* Data class that captures user information for logged in users retrieved from LoginRepository
*/
data class LoggedInUser(
val userId: String,
val displayName: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.github.factotum_sdp.factotum.ui.login

/**
* User details post authentication that is exposed to the UI
*/
data class LoggedInUserView(
val displayName: String
//... other data fields that may be accessible to the UI
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.github.factotum_sdp.factotum.ui.login

/**
* Data validation state of the login form.
*/
data class LoginFormState(
val usernameError: Int? = null,
val passwordError: Int? = null,
val isDataValid: Boolean = false
)
Loading

0 comments on commit aee13e9

Please sign in to comment.