Skip to content

Commit 6257483

Browse files
Add unit tests for data sources, notifications, and repository
1 parent ddabe0c commit 6257483

File tree

6 files changed

+297
-0
lines changed

6 files changed

+297
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.d4rk.androidtutorials.java.data.repository;
2+
3+
import android.content.Context;
4+
import android.content.SharedPreferences;
5+
6+
import androidx.appcompat.app.AppCompatDelegate;
7+
8+
import com.d4rk.androidtutorials.java.R;
9+
10+
import org.junit.Test;
11+
12+
import static org.junit.Assert.*;
13+
import static org.mockito.ArgumentMatchers.*;
14+
import static org.mockito.Mockito.*;
15+
16+
public class DefaultMainRepositoryApplyThemeSettingsTest {
17+
18+
private static final String[] DARK_MODE_VALUES = {
19+
"MODE_NIGHT_FOLLOW_SYSTEM",
20+
"MODE_NIGHT_NO",
21+
"MODE_NIGHT_YES",
22+
"MODE_NIGHT_AUTO_BATTERY"
23+
};
24+
25+
private DefaultMainRepository createRepository(String prefValue) {
26+
Context context = mock(Context.class);
27+
SharedPreferences prefs = mock(SharedPreferences.class);
28+
when(context.getApplicationContext()).thenReturn(context);
29+
when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(prefs);
30+
when(context.getPackageName()).thenReturn("com.d4rk.androidtutorials");
31+
when(context.getString(R.string.key_theme)).thenReturn("theme");
32+
when(context.getString(R.string.default_value_theme)).thenReturn("MODE_NIGHT_FOLLOW_SYSTEM");
33+
when(prefs.getString(eq("theme"), anyString())).thenReturn(prefValue);
34+
return new DefaultMainRepository(context);
35+
}
36+
37+
@Test
38+
public void applyThemeSettingsChangesModeWhenDifferent() {
39+
DefaultMainRepository repo = createRepository("MODE_NIGHT_YES");
40+
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
41+
42+
assertTrue(repo.applyThemeSettings(DARK_MODE_VALUES));
43+
assertEquals(AppCompatDelegate.MODE_NIGHT_YES, AppCompatDelegate.getDefaultNightMode());
44+
}
45+
46+
@Test
47+
public void applyThemeSettingsNoChangeWhenSame() {
48+
DefaultMainRepository repo = createRepository("MODE_NIGHT_NO");
49+
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
50+
51+
assertFalse(repo.applyThemeSettings(DARK_MODE_VALUES));
52+
assertEquals(AppCompatDelegate.MODE_NIGHT_NO, AppCompatDelegate.getDefaultNightMode());
53+
}
54+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.d4rk.androidtutorials.java.data.repository;
2+
3+
import android.content.Context;
4+
import android.content.Intent;
5+
import android.content.SharedPreferences;
6+
import android.net.Uri;
7+
8+
import org.junit.Test;
9+
10+
import static org.junit.Assert.*;
11+
import static org.mockito.ArgumentMatchers.*;
12+
import static org.mockito.Mockito.*;
13+
14+
public class DefaultMainRepositoryBuildShortcutIntentTest {
15+
16+
private DefaultMainRepository createRepository() {
17+
Context context = mock(Context.class);
18+
SharedPreferences prefs = mock(SharedPreferences.class);
19+
when(context.getApplicationContext()).thenReturn(context);
20+
when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(prefs);
21+
when(context.getPackageName()).thenReturn("com.d4rk.androidtutorials");
22+
return new DefaultMainRepository(context);
23+
}
24+
25+
@Test
26+
public void buildShortcutIntentInstalled() {
27+
DefaultMainRepository repo = createRepository();
28+
Intent intent = repo.buildShortcutIntent(true);
29+
assertEquals(Intent.ACTION_MAIN, intent.getAction());
30+
assertTrue(intent.getCategories().contains(Intent.CATEGORY_LAUNCHER));
31+
assertEquals("com.d4rk.androidtutorials", intent.getComponent().getPackageName());
32+
assertEquals("com.d4rk.androidtutorials.MainActivity", intent.getComponent().getClassName());
33+
}
34+
35+
@Test
36+
public void buildShortcutIntentNotInstalled() {
37+
DefaultMainRepository repo = createRepository();
38+
Intent intent = repo.buildShortcutIntent(false);
39+
assertEquals(Intent.ACTION_VIEW, intent.getAction());
40+
assertEquals(Uri.parse("https://play.google.com/store/apps/details?id=com.d4rk.androidtutorials"), intent.getData());
41+
}
42+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.d4rk.androidtutorials.java.data.source;
2+
3+
import com.android.volley.Request;
4+
import com.android.volley.RequestQueue;
5+
import com.android.volley.VolleyError;
6+
import com.android.volley.toolbox.JsonObjectRequest;
7+
import com.d4rk.androidtutorials.java.data.model.PromotedApp;
8+
9+
import org.json.JSONObject;
10+
import org.junit.Test;
11+
import org.mockito.ArgumentCaptor;
12+
13+
import java.lang.reflect.Field;
14+
import java.util.List;
15+
16+
import static org.junit.Assert.*;
17+
import static org.mockito.Mockito.*;
18+
19+
public class DefaultHomeRemoteDataSourceTest {
20+
21+
@Test
22+
public void fetchPromotedAppsFiltersAndMapsResults() throws Exception {
23+
RequestQueue queue = mock(RequestQueue.class);
24+
ArgumentCaptor<JsonObjectRequest> captor = ArgumentCaptor.forClass(JsonObjectRequest.class);
25+
26+
DefaultHomeRemoteDataSource source = new DefaultHomeRemoteDataSource(queue, "url");
27+
28+
final List<PromotedApp>[] results = new List[2];
29+
final int[] index = {0};
30+
source.fetchPromotedApps(apps -> results[index[0]++] = apps);
31+
32+
verify(queue).add(captor.capture());
33+
JsonObjectRequest request = captor.getValue();
34+
35+
String json = "{\"data\":{\"apps\":[{\"name\":\"Name1\",\"packageName\":\"pkg1\",\"iconLogo\":\"icon1\"},{\"name\":\"Name2\",\"packageName\":\"com.d4rk.androidtutorials.other\",\"iconLogo\":\"icon2\"}]}}";
36+
JSONObject response = new JSONObject(json);
37+
38+
Field listenerField = Request.class.getDeclaredField("mListener");
39+
listenerField.setAccessible(true);
40+
@SuppressWarnings("unchecked")
41+
com.android.volley.Response.Listener<JSONObject> listener =
42+
(com.android.volley.Response.Listener<JSONObject>) listenerField.get(request);
43+
listener.onResponse(response);
44+
45+
assertEquals(1, results[0].size());
46+
PromotedApp app = results[0].get(0);
47+
assertEquals("Name1", app.name());
48+
assertEquals("pkg1", app.packageName());
49+
assertEquals("icon1", app.iconUrl());
50+
51+
Field errorField = Request.class.getDeclaredField("mErrorListener");
52+
errorField.setAccessible(true);
53+
com.android.volley.Response.ErrorListener errorListener =
54+
(com.android.volley.Response.ErrorListener) errorField.get(request);
55+
errorListener.onErrorResponse(new VolleyError());
56+
57+
assertTrue(results[1].isEmpty());
58+
}
59+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.d4rk.androidtutorials.java.data.source;
2+
3+
import android.content.res.AssetManager;
4+
5+
import com.d4rk.androidtutorials.java.data.model.QuizQuestion;
6+
7+
import org.junit.Test;
8+
9+
import java.io.ByteArrayInputStream;
10+
import java.io.IOException;
11+
import java.nio.charset.StandardCharsets;
12+
import java.util.List;
13+
14+
import static org.junit.Assert.*;
15+
import static org.mockito.Mockito.*;
16+
17+
public class DefaultQuizLocalDataSourceTest {
18+
19+
@Test
20+
public void loadQuestionsParsesFile() throws Exception {
21+
AssetManager manager = mock(AssetManager.class);
22+
String json = "[{\"question\":\"Q1\",\"options\":[\"A\",\"B\"],\"answer\":1},{\"question\":\"Q2\",\"options\":[\"C\",\"D\",\"E\"],\"answer\":0}]";
23+
when(manager.open("quiz_questions.json")).thenReturn(
24+
new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8)));
25+
26+
DefaultQuizLocalDataSource dataSource = new DefaultQuizLocalDataSource(manager);
27+
List<QuizQuestion> result = dataSource.loadQuestions();
28+
29+
assertEquals(2, result.size());
30+
QuizQuestion first = result.get(0);
31+
assertEquals("Q1", first.question());
32+
assertArrayEquals(new String[]{"A", "B"}, first.options());
33+
assertEquals(1, first.answerIndex());
34+
}
35+
36+
@Test
37+
public void loadQuestionsReturnsEmptyOnError() throws Exception {
38+
AssetManager manager = mock(AssetManager.class);
39+
when(manager.open("quiz_questions.json")).thenThrow(new IOException("missing"));
40+
41+
DefaultQuizLocalDataSource dataSource = new DefaultQuizLocalDataSource(manager);
42+
List<QuizQuestion> result = dataSource.loadQuestions();
43+
44+
assertTrue(result.isEmpty());
45+
}
46+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.d4rk.androidtutorials.java.notifications.managers;
2+
3+
import android.app.AlarmManager;
4+
import android.app.PendingIntent;
5+
import android.content.Context;
6+
7+
import org.junit.Test;
8+
import org.mockito.ArgumentCaptor;
9+
10+
import java.lang.reflect.Field;
11+
import java.util.concurrent.TimeUnit;
12+
13+
import static org.junit.Assert.*;
14+
import static org.mockito.Mockito.*;
15+
16+
public class AppUsageNotificationsManagerTest {
17+
18+
@Test
19+
public void scheduleAppUsageCheckSetsRepeatingAlarm() throws Exception {
20+
Context context = mock(Context.class);
21+
AlarmManager alarmManager = mock(AlarmManager.class);
22+
when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(alarmManager);
23+
when(context.getApplicationContext()).thenReturn(context);
24+
25+
AppUsageNotificationsManager manager = new AppUsageNotificationsManager(context);
26+
27+
PendingIntent pendingIntent = mock(PendingIntent.class);
28+
Field intentField = AppUsageNotificationsManager.class.getDeclaredField("notificationIntent");
29+
intentField.setAccessible(true);
30+
intentField.set(manager, pendingIntent);
31+
32+
Field alarmField = AppUsageNotificationsManager.class.getDeclaredField("alarmManager");
33+
alarmField.setAccessible(true);
34+
alarmField.set(manager, alarmManager);
35+
36+
long now = System.currentTimeMillis();
37+
manager.scheduleAppUsageCheck();
38+
39+
ArgumentCaptor<Long> triggerCaptor = ArgumentCaptor.forClass(Long.class);
40+
verify(alarmManager).setRepeating(eq(AlarmManager.RTC_WAKEUP),
41+
triggerCaptor.capture(),
42+
eq(TimeUnit.DAYS.toMillis(3)),
43+
eq(pendingIntent));
44+
45+
long expected = now + TimeUnit.DAYS.toMillis(3);
46+
assertTrue(Math.abs(triggerCaptor.getValue() - expected) < TimeUnit.MINUTES.toMillis(1));
47+
}
48+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.d4rk.androidtutorials.java.notifications.managers;
2+
3+
import android.app.AlarmManager;
4+
import android.app.PendingIntent;
5+
import android.content.Context;
6+
7+
import org.junit.Test;
8+
import org.mockito.ArgumentCaptor;
9+
10+
import java.lang.reflect.Field;
11+
import java.util.concurrent.TimeUnit;
12+
13+
import static org.junit.Assert.*;
14+
import static org.mockito.Mockito.*;
15+
16+
public class QuizReminderManagerTest {
17+
18+
@Test
19+
public void scheduleDailyReminderSetsRepeatingAlarm() throws Exception {
20+
Context context = mock(Context.class);
21+
AlarmManager alarmManager = mock(AlarmManager.class);
22+
when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(alarmManager);
23+
when(context.getApplicationContext()).thenReturn(context);
24+
25+
QuizReminderManager manager = new QuizReminderManager(context);
26+
27+
PendingIntent pendingIntent = mock(PendingIntent.class);
28+
Field intentField = QuizReminderManager.class.getDeclaredField("reminderIntent");
29+
intentField.setAccessible(true);
30+
intentField.set(manager, pendingIntent);
31+
32+
Field alarmField = QuizReminderManager.class.getDeclaredField("alarmManager");
33+
alarmField.setAccessible(true);
34+
alarmField.set(manager, alarmManager);
35+
36+
long now = System.currentTimeMillis();
37+
manager.scheduleDailyReminder();
38+
39+
ArgumentCaptor<Long> triggerCaptor = ArgumentCaptor.forClass(Long.class);
40+
verify(alarmManager).setRepeating(eq(AlarmManager.RTC_WAKEUP),
41+
triggerCaptor.capture(),
42+
eq(TimeUnit.DAYS.toMillis(1)),
43+
eq(pendingIntent));
44+
45+
long expected = now + TimeUnit.DAYS.toMillis(1);
46+
assertTrue(Math.abs(triggerCaptor.getValue() - expected) < TimeUnit.MINUTES.toMillis(1));
47+
}
48+
}

0 commit comments

Comments
 (0)