Feature/groups (#71)

* Basic group management

* Assign cards to groups

* Fix lint

* Fix findbugs 'dodgy code'

* Group name as unique key

* More group tests

* Import/export groups

* Implement group renaming and deleting

* Fix findBugs

* Fix chip marking in edit activity

* Group import/export tests

* Fix some state bugs

* Some last fixes

* Remove redundant if statement

* Fix findBugs

* Deduplicate code

* Cleanup

* Fix groups not showing up with new card

* Fix capture and enter button touching

* Fix dialog button look
This commit is contained in:
Sylvia van Os
2020-11-06 18:12:06 +01:00
committed by GitHub
parent c04f2c6785
commit 4bbeb27714
31 changed files with 1682 additions and 59 deletions

View File

@@ -15,7 +15,11 @@ import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -101,8 +105,6 @@ public class DatabaseTest
assertEquals(BarcodeFormat.UPC_A.toString(), loyaltyCard.barcodeType);
}
@Test
public void updateMissingGiftCard()
{
@@ -256,6 +258,161 @@ public class DatabaseTest
return (int)newId;
}
@Test
public void addRemoveOneGroup()
{
assertEquals(0, db.getGroupCount());
long id = db.insertGroup("group one");
boolean result = (id != -1);
assertTrue(result);
assertEquals(1, db.getGroupCount());
Group group = db.getGroup("group one");
assertNotNull(group);
assertEquals("group one", group._id);
result = db.deleteGroup("group one");
assertTrue(result);
assertEquals(0, db.getGroupCount());
assertNull(db.getGroup("group one"));
}
@Test
public void updateGroup()
{
long id = db.insertGroup("group one");
boolean result = (id != -1);
assertTrue(result);
assertEquals(1, db.getGroupCount());
result = db.updateGroup("group one", "group one renamed");
assertTrue(result);
assertEquals(1, db.getGroupCount());
// Group one no longer exists
Group group = db.getGroup("group one");
assertNull(group);
// But group one renamed does
Group group2 = db.getGroup("group one renamed");
assertNotNull(group2);
assertEquals("group one renamed", group2._id);
}
@Test
public void updateMissingGroup()
{
assertEquals(0, db.getGroupCount());
boolean result = db.updateGroup("group one", "new name");
assertEquals(false, result);
assertEquals(0, db.getGroupCount());
}
@Test
public void emptyGroupValues()
{
long id = db.insertGroup("");
boolean result = (id != -1);
assertFalse(result);
assertEquals(0, db.getLoyaltyCardCount());
}
@Test
public void duplicateGroupName()
{
assertEquals(0, db.getGroupCount());
long id = db.insertGroup("group one");
boolean result = (id != -1);
assertTrue(result);
assertEquals(1, db.getGroupCount());
Group group = db.getGroup("group one");
assertNotNull(group);
assertEquals("group one", group._id);
// Should fail on duplicate
long id2 = db.insertGroup("group one");
boolean result2 = (id2 != -1);
assertFalse(result2);
assertEquals(1, db.getGroupCount());
}
@Test
public void updateGroupDuplicate()
{
long id = db.insertGroup("group one");
boolean result = (id != -1);
assertTrue(result);
assertEquals(1, db.getGroupCount());
long id2 = db.insertGroup("group two");
boolean result2 = (id2 != -1);
assertTrue(result2);
assertEquals(2, db.getGroupCount());
// Should fail when trying to rename group two to one
boolean result3 = db.updateGroup("group two", "group one");
assertFalse(result3);
assertEquals(2, db.getGroupCount());
// Rename failed so both should still be the same
Group group = db.getGroup("group one");
assertNotNull(group);
assertEquals("group one", group._id);
Group group2 = db.getGroup("group two");
assertNotNull(group2);
assertEquals("group two", group2._id);
}
@Test
public void cardAddAndRemoveGroups()
{
// Create card
assertEquals(0, db.getLoyaltyCardCount());
long id = db.insertLoyaltyCard("store", "note", "cardId", BarcodeFormat.UPC_A.toString(), DEFAULT_HEADER_COLOR, DEFAULT_HEADER_TEXT_COLOR, 0);
boolean result = (id != -1);
assertTrue(result);
assertEquals(1, db.getLoyaltyCardCount());
// Create two groups to only one card
assertEquals(0, db.getGroupCount());
long gid = db.insertGroup("one");
boolean gresult = (gid != -1);
assertTrue(gresult);
long gid2 = db.insertGroup("two");
boolean gresult2 = (gid2 != -1);
assertTrue(gresult2);
assertEquals(2, db.getGroupCount());
Group group1 = db.getGroup("one");
// Card has no groups by default
List<Group> cardGroups = db.getLoyaltyCardGroups(1);
assertEquals(0, cardGroups.size());
// Add one groups to card
List<Group> groupList1 = new ArrayList<>();
groupList1.add(group1);
db.setLoyaltyCardGroups(1, groupList1);
List<Group> cardGroups1 = db.getLoyaltyCardGroups(1);
assertEquals(1, cardGroups1.size());
assertEquals(cardGroups1.get(0)._id, group1._id);
assertEquals(1, db.getGroupCardCount("one"));
assertEquals(0, db.getGroupCardCount("two"));
// Remove groups
db.setLoyaltyCardGroups(1, new ArrayList<Group>());
List<Group> cardGroups2 = db.getLoyaltyCardGroups(1);
assertEquals(0, cardGroups2.size());
assertEquals(0, db.getGroupCardCount("one"));
assertEquals(0, db.getGroupCardCount("two"));
}
@Test
public void databaseUpgradeFromVersion1()
{

View File

@@ -9,7 +9,6 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.view.View;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -17,7 +16,6 @@ import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowPackageManager;
@RunWith(RobolectricTestRunner.class)
@Config(sdk = 23)

View File

@@ -24,7 +24,9 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -100,6 +102,20 @@ public class ImportExportTest
assertEquals(cardsToAdd, db.getLoyaltyCardCount());
}
private void addGroups(int groupsToAdd)
{
// Add in reverse order to test sorting
for(int index = groupsToAdd; index > 0; index--)
{
String groupName = String.format("group, \"%4d", index);
long id = db.insertGroup(groupName);
boolean result = (id != -1);
assertTrue(result);
}
assertEquals(groupsToAdd, db.getGroupCount());
}
/**
* Check that all of the cards follow the pattern
* specified in addLoyaltyCards(), and are in sequential order
@@ -181,6 +197,29 @@ public class ImportExportTest
cursor.close();
}
/**
* Check that all of the groups follow the pattern
* specified in addGroups(), and are in sequential order
* where the smallest group's index is 1
*/
private void checkGroups()
{
Cursor cursor = db.getGroupCursor();
int index = 1;
while(cursor.moveToNext())
{
Group group = Group.toGroup(cursor);
String expectedGroupName = String.format("group, \"%4d", index);
assertEquals(expectedGroupName, group._id);
index++;
}
cursor.close();
}
/**
* Delete the contents of the database
*/
@@ -263,6 +302,96 @@ public class ImportExportTest
}
}
private List<String> groupsToGroupNames(List<Group> groups)
{
List<String> groupNames = new ArrayList<>();
for (Group group : groups) {
groupNames.add(group._id);
}
return groupNames;
}
@Test
public void multipleCardsExportImportWithGroups() throws IOException
{
final int NUM_CARDS = 10;
final int NUM_GROUPS = 3;
for(DataFormat format : DataFormat.values())
{
addLoyaltyCards(NUM_CARDS);
addGroups(NUM_GROUPS);
List<Group> emptyGroup = new ArrayList<>();
List<Group> groupsForOne = new ArrayList<>();
groupsForOne.add(db.getGroup("group, \" 1"));
List<Group> groupsForTwo = new ArrayList<>();
groupsForTwo.add(db.getGroup("group, \" 1"));
groupsForTwo.add(db.getGroup("group, \" 2"));
List<Group> groupsForThree = new ArrayList<>();
groupsForThree.add(db.getGroup("group, \" 1"));
groupsForThree.add(db.getGroup("group, \" 2"));
groupsForThree.add(db.getGroup("group, \" 3"));
List<Group> groupsForFour = new ArrayList<>();
groupsForFour.add(db.getGroup("group, \" 1"));
groupsForFour.add(db.getGroup("group, \" 2"));
groupsForFour.add(db.getGroup("group, \" 3"));
List<Group> groupsForFive = new ArrayList<>();
groupsForFive.add(db.getGroup("group, \" 1"));
groupsForFive.add(db.getGroup("group, \" 3"));
db.setLoyaltyCardGroups(1, groupsForOne);
db.setLoyaltyCardGroups(2, groupsForTwo);
db.setLoyaltyCardGroups(3, groupsForThree);
db.setLoyaltyCardGroups(4, groupsForFour);
db.setLoyaltyCardGroups(5, groupsForFive);
ByteArrayOutputStream outData = new ByteArrayOutputStream();
OutputStreamWriter outStream = new OutputStreamWriter(outData);
// Export data to CSV format
boolean result = MultiFormatExporter.exportData(db, outStream, format);
assertTrue(result);
outStream.close();
clearDatabase();
ByteArrayInputStream inData = new ByteArrayInputStream(outData.toByteArray());
InputStreamReader inStream = new InputStreamReader(inData);
// Import the CSV data
result = MultiFormatImporter.importData(db, inStream, DataFormat.CSV);
assertTrue(result);
assertEquals(NUM_CARDS, db.getLoyaltyCardCount());
assertEquals(NUM_GROUPS, db.getGroupCount());
checkLoyaltyCards();
checkGroups();
assertEquals(groupsToGroupNames(groupsForOne), groupsToGroupNames(db.getLoyaltyCardGroups(1)));
assertEquals(groupsToGroupNames(groupsForTwo), groupsToGroupNames(db.getLoyaltyCardGroups(2)));
assertEquals(groupsToGroupNames(groupsForThree), groupsToGroupNames(db.getLoyaltyCardGroups(3)));
assertEquals(groupsToGroupNames(groupsForFour), groupsToGroupNames(db.getLoyaltyCardGroups(4)));
assertEquals(groupsToGroupNames(groupsForFive), groupsToGroupNames(db.getLoyaltyCardGroups(5)));
assertEquals(emptyGroup, db.getLoyaltyCardGroups(6));
assertEquals(emptyGroup, db.getLoyaltyCardGroups(7));
assertEquals(emptyGroup, db.getLoyaltyCardGroups(8));
assertEquals(emptyGroup, db.getLoyaltyCardGroups(9));
assertEquals(emptyGroup, db.getLoyaltyCardGroups(10));
// Clear the database for the next format under test
clearDatabase();
}
}
@Test
public void importExistingCardsNotReplace() throws IOException
{
@@ -395,7 +524,7 @@ public class ImportExportTest
}
@Test
public void importWithoutColors() throws IOException
public void importWithoutColorsV1() throws IOException
{
String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
@@ -427,7 +556,7 @@ public class ImportExportTest
}
@Test
public void importWithoutNullColors() throws IOException
public void importWithoutNullColorsV1() throws IOException
{
String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
@@ -461,7 +590,7 @@ public class ImportExportTest
}
@Test
public void importWithoutInvalidColors() throws IOException
public void importWithoutInvalidColorsV1() throws IOException
{
String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
@@ -485,7 +614,7 @@ public class ImportExportTest
}
@Test
public void importWithNoBarcodeType() throws IOException
public void importWithNoBarcodeTypeV1() throws IOException
{
String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
@@ -519,7 +648,7 @@ public class ImportExportTest
}
@Test
public void importWithStarredField() throws IOException
public void importWithStarredFieldV1() throws IOException
{
String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
@@ -555,7 +684,7 @@ public class ImportExportTest
@Test
public void importWithNoStarredField() throws IOException
public void importWithNoStarredFieldV1() throws IOException
{
String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +
@@ -589,7 +718,7 @@ public class ImportExportTest
}
@Test
public void importWithInvalidStarField() throws IOException
public void importWithInvalidStarFieldV1() throws IOException
{
String csvText = "";
csvText += DBHelper.LoyaltyCardDbIds.ID + "," +

View File

@@ -2,28 +2,28 @@ package protect.card_locker;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import com.google.android.material.tabs.TabLayout;
import com.google.zxing.BarcodeFormat;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.android.controller.ActivityController;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -60,9 +60,10 @@ public class MainActivityTest
final Menu menu = shadowOf(activity).getOptionsMenu();
assertTrue(menu != null);
// The settings, search and add button should be present
assertEquals(menu.size(), 4);
// The settings, import/export, groups, search and add button should be present
assertEquals(menu.size(), 5);
assertEquals("Search", menu.findItem(R.id.action_search).getTitle().toString());
assertEquals("Groups", menu.findItem(R.id.action_manage_groups).getTitle().toString());
assertEquals("Import/Export", menu.findItem(R.id.action_import_export).getTitle().toString());
assertEquals("About", menu.findItem(R.id.action_about).getTitle().toString());
assertEquals("Settings", menu.findItem(R.id.action_settings).getTitle().toString());
@@ -165,6 +166,54 @@ public class MainActivityTest
assertEquals("storeB",cursor.getString(cursor.getColumnIndex("store")));
}
@Test
public void testGroups()
{
ActivityController activityController = Robolectric.buildActivity(MainActivity.class).create();
Activity mainActivity = (Activity)activityController.get();
activityController.start();
activityController.resume();
DBHelper db = new DBHelper(mainActivity);
TabLayout groupTabs = mainActivity.findViewById(R.id.groups);
// No group tabs by default
assertEquals(0, groupTabs.getTabCount());
// Having at least one group should create two tabs: One all and one for each group
db.insertGroup("One");
activityController.pause();
activityController.resume();
assertEquals(2, groupTabs.getTabCount());
assertEquals("All", groupTabs.getTabAt(0).getText().toString());
assertEquals("One", groupTabs.getTabAt(1).getText().toString());
// Adding another group should have them sorted alphabetically
db.insertGroup("Alphabetical two");
activityController.pause();
activityController.resume();
assertEquals(3, groupTabs.getTabCount());
assertEquals("All", groupTabs.getTabAt(0).getText().toString());
assertEquals("Alphabetical two", groupTabs.getTabAt(1).getText().toString());
assertEquals("One", groupTabs.getTabAt(2).getText().toString());
// Removing a group should also change the list
db.deleteGroup("Alphabetical two");
activityController.pause();
activityController.resume();
assertEquals(2, groupTabs.getTabCount());
assertEquals("All", groupTabs.getTabAt(0).getText().toString());
assertEquals("One", groupTabs.getTabAt(1).getText().toString());
// Removing the last group should make the tabs disappear
db.deleteGroup("One");
activityController.pause();
activityController.resume();
assertEquals(0, groupTabs.getTabCount());
}
@Test
public void testFiltering()
{
@@ -177,11 +226,17 @@ public class MainActivityTest
TextView helpText = mainActivity.findViewById(R.id.helpText);
TextView noMatchingCardsText = mainActivity.findViewById(R.id.noMatchingCardsText);
ListView list = mainActivity.findViewById(R.id.list);
TabLayout groupTabs = mainActivity.findViewById(R.id.groups);
DBHelper db = new DBHelper(mainActivity);
db.insertLoyaltyCard("The First Store", "Initial note", "cardId", BarcodeFormat.UPC_A.toString(), Color.BLACK, Color.WHITE, 0);
db.insertLoyaltyCard("The Second Store", "Secondary note", "cardId", BarcodeFormat.UPC_A.toString(), Color.BLACK, Color.WHITE, 0);
db.insertGroup("Group one");
List<Group> groups = new ArrayList<>();
groups.add(db.getGroup("Group one"));
db.setLoyaltyCardGroups(1, groups);
activityController.pause();
activityController.resume();
@@ -202,6 +257,27 @@ public class MainActivityTest
assertEquals(2, list.getCount());
// Switch to Group one
groupTabs.selectTab(groupTabs.getTabAt(1));
activityController.pause();
activityController.resume();
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
// Switch back to all groups
groupTabs.selectTab(groupTabs.getTabAt(0));
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(2, list.getCount());
mainActivity.filter = "first";
activityController.pause();
@@ -213,6 +289,27 @@ public class MainActivityTest
assertEquals(1, list.getCount());
// Switch to Group one
groupTabs.selectTab(groupTabs.getTabAt(1));
activityController.pause();
activityController.resume();
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
// Switch back to all groups
groupTabs.selectTab(groupTabs.getTabAt(0));
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
mainActivity.filter = "initial";
activityController.pause();
@@ -224,6 +321,27 @@ public class MainActivityTest
assertEquals(1, list.getCount());
// Switch to Group one
groupTabs.selectTab(groupTabs.getTabAt(1));
activityController.pause();
activityController.resume();
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
// Switch back to all groups
groupTabs.selectTab(groupTabs.getTabAt(0));
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
mainActivity.filter = "second";
activityController.pause();
@@ -235,6 +353,27 @@ public class MainActivityTest
assertEquals(1, list.getCount());
// Switch to Group one
groupTabs.selectTab(groupTabs.getTabAt(1));
activityController.pause();
activityController.resume();
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.VISIBLE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(0, list.getCount());
// Switch back to all groups
groupTabs.selectTab(groupTabs.getTabAt(0));
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
mainActivity.filter = "company";
activityController.pause();
@@ -246,6 +385,27 @@ public class MainActivityTest
assertEquals(0, list.getCount());
// Switch to Group one
groupTabs.selectTab(groupTabs.getTabAt(1));
activityController.pause();
activityController.resume();
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.VISIBLE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(0, list.getCount());
// Switch back to all groups
groupTabs.selectTab(groupTabs.getTabAt(0));
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.VISIBLE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(0, list.getCount());
mainActivity.filter = "";
activityController.pause();
@@ -256,5 +416,26 @@ public class MainActivityTest
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(2, list.getCount());
// Switch to Group one
groupTabs.selectTab(groupTabs.getTabAt(1));
activityController.pause();
activityController.resume();
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(1, list.getCount());
// Switch back to all groups
groupTabs.selectTab(groupTabs.getTabAt(0));
assertEquals(View.GONE, helpText.getVisibility());
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
assertEquals(2, list.getCount());
}
}