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

Disable 'Save as draft' when 'Moving backwards' is disabled #5647

Merged
merged 4 commits into from
Jul 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package org.odk.collect.android.feature.settings

import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
import org.junit.runner.RunWith
import org.odk.collect.android.R
import org.odk.collect.android.support.rules.CollectTestRule
import org.odk.collect.android.support.rules.TestRuleChain

@RunWith(AndroidJUnit4::class)
class MovingBackwardsTest {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the thinking around adding this instead of adding tests to FormEntryAccessPreferencesFragmentTest?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't test disabling moving backwards in isolation (using fragment-scenario like in FormEntryAccessPreferencesFragmentTest) because that fragment displays MovingBackwardsDialog which calls a listener from ProjectPreferencesActivity and then it calls a method from FormEntryAccessPreferencesFragment, so there is that activity involved.

private val rule = CollectTestRule()

@get:Rule
var ruleChain: RuleChain = TestRuleChain.chain().around(rule)

@Test
fun whenMovingBackwardDisabledWithPreventingUsersFormBypassingIt_relatedOptionsShouldBeUpdated() {
rule.startAtMainMenu()
.openProjectSettingsDialog()
.clickSettings()
.clickAccessControl()
.clickFormEntrySettings()
.clickOnString(R.string.finalize)

// before disabling moving backward
.assertGoToPromptEnabled()
.assertGoToPromptChecked()

.assertSaveAsDraftInFormEntryEnabled()
.assertSaveAsDraftInFormEntryChecked()

.assertSaveAsDraftInFormEndDisabled()
.assertSaveAsDraftInFormEndChecked()

.assertFinalizeEnabled()
.assertFinalizeUnchecked()

.clickMovingBackwards()
.clickOnString(R.string.yes)

// after disabling moving backward - the state of the 4 related options is reversed
.assertGoToPromptDisabled()
.assertGoToPromptUnchecked()

.assertSaveAsDraftInFormEntryDisabled()
.assertSaveAsDraftInFormEntryUnchecked()

.assertSaveAsDraftInFormEndDisabled()
.assertSaveAsDraftInFormEndUnchecked()

.assertFinalizeDisabled()
.assertFinalizeChecked()
}

@Test
fun whenMovingBackwardDisabledWithoutPreventingUsersFormBypassingIt_relatedOptionsShouldNotBeUpdated() {
rule.startAtMainMenu()
.openProjectSettingsDialog()
.clickSettings()
.clickAccessControl()
.clickFormEntrySettings()
.clickMovingBackwards()
.clickOnString(R.string.no)
.assertGoToPromptEnabled()
.assertSaveAsDraftInFormEntryEnabled()
.assertSaveAsDraftInFormEndEnabled()
.assertFinalizeEnabled()
.assertGoToPromptChecked()
.assertSaveAsDraftInFormEntryChecked()
.assertSaveAsDraftInFormEndChecked()
.assertFinalizeChecked()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public void movingBackwards_shouldBeTurnedOn() {
.assertText(R.string.yes)
.assertText(R.string.no)
.clickOnString(R.string.yes)
.checkIfSaveAsDraftInFormEntryOptionIsDisabled()
.assertSaveAsDraftInFormEntryDisabled()
.pressBack(new AccessControlPage())
.pressBack(new ProjectSettingsPage())
.pressBack(new MainMenuPage())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ package org.odk.collect.android.support.pages
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isChecked
import androidx.test.espresso.matcher.ViewMatchers.isEnabled
import androidx.test.espresso.matcher.ViewMatchers.isNotChecked
import androidx.test.espresso.matcher.ViewMatchers.withClassName
import androidx.test.espresso.matcher.ViewMatchers.withText
import org.hamcrest.Matchers.endsWith
import org.hamcrest.Matchers.not
import org.odk.collect.android.R
import org.odk.collect.android.support.matchers.CustomMatchers.withIndex
Expand All @@ -31,11 +35,86 @@ class AccessControlPage : Page<AccessControlPage>() {
return this
}

fun checkIfSaveAsDraftInFormEntryOptionIsDisabled(): AccessControlPage {
fun assertGoToPromptEnabled(): AccessControlPage {
onView(withText(getTranslatedString(R.string.view_hierarchy))).check(matches(isEnabled()))
return this
}

fun assertGoToPromptDisabled(): AccessControlPage {
onView(withText(getTranslatedString(R.string.view_hierarchy))).check(matches(not(isEnabled())))
return this
}

fun assertGoToPromptChecked(): AccessControlPage {
onView(withIndex(withClassName(endsWith("CheckBox")), 3)).check(matches(isChecked()))
return this
}

fun assertGoToPromptUnchecked(): AccessControlPage {
onView(withIndex(withClassName(endsWith("CheckBox")), 3)).check(matches(isNotChecked()))
return this
}

fun assertSaveAsDraftInFormEntryEnabled(): AccessControlPage {
onView(withIndex(withText(getTranslatedString(R.string.save_mid)), 0)).check(matches(isEnabled()))
return this
}

fun assertSaveAsDraftInFormEntryDisabled(): AccessControlPage {
onView(withIndex(withText(getTranslatedString(R.string.save_mid)), 0)).check(matches(not(isEnabled())))
return this
}

fun assertSaveAsDraftInFormEntryChecked(): AccessControlPage {
onView(withIndex(withClassName(endsWith("CheckBox")), 4)).check(matches(isChecked()))
return this
}

fun assertSaveAsDraftInFormEntryUnchecked(): AccessControlPage {
onView(withIndex(withClassName(endsWith("CheckBox")), 4)).check(matches(isNotChecked()))
return this
}

fun assertSaveAsDraftInFormEndEnabled(): AccessControlPage {
onView(withIndex(withText(getTranslatedString(R.string.save_as_draft)), 1)).check(matches(isEnabled()))
return this
}

fun assertSaveAsDraftInFormEndDisabled(): AccessControlPage {
onView(withIndex(withText(getTranslatedString(R.string.save_as_draft)), 1)).check(matches(not(isEnabled())))
return this
}

fun assertSaveAsDraftInFormEndChecked(): AccessControlPage {
onView(withIndex(withClassName(endsWith("CheckBox")), 5)).check(matches(isChecked()))
return this
}

fun assertSaveAsDraftInFormEndUnchecked(): AccessControlPage {
onView(withIndex(withClassName(endsWith("CheckBox")), 5)).check(matches(isNotChecked()))
return this
}

fun assertFinalizeEnabled(): AccessControlPage {
onView(withText(getTranslatedString(R.string.finalize))).check(matches(isEnabled()))
return this
}

fun assertFinalizeDisabled(): AccessControlPage {
onView(withText(getTranslatedString(R.string.finalize))).check(matches(not(isEnabled())))
return this
}

fun assertFinalizeChecked(): AccessControlPage {
onView(withIndex(withClassName(endsWith("CheckBox")), 6)).check(matches(isChecked()))
return this
}

fun assertFinalizeUnchecked(): AccessControlPage {
onView(withIndex(withClassName(endsWith("CheckBox")), 6)).check(matches(isNotChecked()))
return this
}

fun clickOnSaveAsDraftInFormEnd(): AccessControlPage {
onView(withIndex(withText(getTranslatedString(R.string.save_mid)), 1)).perform(click())
return this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ class FormEntryAccessPreferencesFragment : BaseAdminPreferencesFragment() {
findPreference(ProtectedProjectKeys.KEY_SAVE_MID).isEnabled =
settingsProvider.getProtectedSettings().getBoolean(ProtectedProjectKeys.ALLOW_OTHER_WAYS_OF_EDITING_FORM)

findPreference(ProtectedProjectKeys.KEY_SAVE_AS_DRAFT).isEnabled = findPreference(ProtectedProjectKeys.KEY_FINALIZE).isChecked
findPreference(ProtectedProjectKeys.KEY_SAVE_AS_DRAFT).isEnabled =
settingsProvider.getProtectedSettings().getBoolean(ProtectedProjectKeys.ALLOW_OTHER_WAYS_OF_EDITING_FORM) && findPreference(ProtectedProjectKeys.KEY_FINALIZE).isChecked
findPreference(ProtectedProjectKeys.KEY_SAVE_AS_DRAFT).onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { _: Preference, newValue: Any? ->
findPreference(ProtectedProjectKeys.KEY_FINALIZE).isEnabled = newValue as Boolean
Expand All @@ -60,20 +61,27 @@ class FormEntryAccessPreferencesFragment : BaseAdminPreferencesFragment() {
fun preventOtherWaysOfEditingForm() {
settingsProvider.getProtectedSettings().save(ProtectedProjectKeys.ALLOW_OTHER_WAYS_OF_EDITING_FORM, false)
settingsProvider.getProtectedSettings().save(ProtectedProjectKeys.KEY_EDIT_SAVED, false)
settingsProvider.getProtectedSettings().save(ProtectedProjectKeys.KEY_SAVE_MID, false)
settingsProvider.getProtectedSettings().save(ProtectedProjectKeys.KEY_SAVE_AS_DRAFT, false)
settingsProvider.getProtectedSettings().save(ProtectedProjectKeys.KEY_FINALIZE, true)
settingsProvider.getProtectedSettings().save(ProtectedProjectKeys.KEY_JUMP_TO, false)
settingsProvider.getUnprotectedSettings().save(ProjectKeys.KEY_CONSTRAINT_BEHAVIOR, ProjectKeys.CONSTRAINT_BEHAVIOR_ON_SWIPE)

findPreference(ProtectedProjectKeys.KEY_JUMP_TO).isEnabled = false
findPreference(ProtectedProjectKeys.KEY_SAVE_MID).isEnabled = false
findPreference(ProtectedProjectKeys.KEY_SAVE_AS_DRAFT).isEnabled = false
findPreference(ProtectedProjectKeys.KEY_FINALIZE).isEnabled = false
findPreference(ProtectedProjectKeys.KEY_JUMP_TO).isChecked = false
findPreference(ProtectedProjectKeys.KEY_SAVE_MID).isChecked = false
findPreference(ProtectedProjectKeys.KEY_SAVE_AS_DRAFT).isChecked = false
findPreference(ProtectedProjectKeys.KEY_FINALIZE).isChecked = true
}

private fun onMovingBackwardsEnabled() {
settingsProvider.getProtectedSettings().save(ProtectedProjectKeys.ALLOW_OTHER_WAYS_OF_EDITING_FORM, true)
findPreference(ProtectedProjectKeys.KEY_JUMP_TO).isEnabled = true
findPreference(ProtectedProjectKeys.KEY_SAVE_MID).isEnabled = true
findPreference(ProtectedProjectKeys.KEY_SAVE_AS_DRAFT).isEnabled = true
findPreference(ProtectedProjectKeys.KEY_FINALIZE).isEnabled = true
}

private fun findPreference(key: String): CheckBoxPreference {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import static org.odk.collect.settings.migration.MigrationUtils.renameKey;
import static org.odk.collect.settings.migration.MigrationUtils.translateKey;
import static org.odk.collect.settings.migration.MigrationUtils.translateValue;
import static org.odk.collect.settings.migration.MigrationUtils.updateKeys;
import static java.util.Arrays.asList;

import org.odk.collect.settings.importing.SettingsMigrator;
Expand Down Expand Up @@ -167,7 +168,13 @@ public List<Migration> getProtectedMigrations() {
ProtectedProjectKeys.KEY_FINALIZE, true
),
removeKey("mark_as_finalized"),
removeKey("default_completed")
removeKey("default_completed"),
updateKeys(ProtectedProjectKeys.ALLOW_OTHER_WAYS_OF_EDITING_FORM)
.withValues(false)
.toPairs(
ProtectedProjectKeys.KEY_SAVE_AS_DRAFT, false,
ProtectedProjectKeys.KEY_FINALIZE, true
)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.odk.collect.settings.migration;

import static org.odk.collect.settings.migration.MigrationUtils.asPairs;

import org.odk.collect.shared.settings.Settings;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class KeyUpdater implements Migration {

String[] oldKeys;
Object[] tempOldValueArray;
List<Object[]> oldValueArrays = new ArrayList<>();
List<KeyValuePair[]> newKeyValuePairArrays = new ArrayList<>();

KeyUpdater(String... oldKeys) {
this.oldKeys = oldKeys;
}

public KeyUpdater withValues(Object... oldValues) {
tempOldValueArray = oldValues;
return this;
}

public KeyUpdater toPairs(Object... keysAndValues) {
oldValueArrays.add(tempOldValueArray);
newKeyValuePairArrays.add(asPairs(keysAndValues));
return this;
}

public void apply(Settings prefs) {
Map<String, ?> prefMap = prefs.getAll();
Object[] oldValues = new Object[oldKeys.length];
for (int i = 0; i < oldKeys.length; i++) {
oldValues[i] = prefMap.get(oldKeys[i]);
}
for (int i = 0; i < oldValueArrays.size(); i++) {
if (Arrays.equals(oldValues, oldValueArrays.get(i))) {
for (KeyValuePair keyValuePair : newKeyValuePairArrays.get(i)) {
prefs.save(keyValuePair.key, keyValuePair.value);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ public static KeyCombiner combineKeys(String... oldKeys) {
return new KeyCombiner(oldKeys);
}

/**
* It works like KeyCombiner BUT it does not remove the old keys
*/
public static KeyUpdater updateKeys(String... oldKeys) {
return new KeyUpdater(oldKeys);
}

public static KeyMover moveKey(String key) {
return new KeyMover(key);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,38 @@ public void when_markAsFinalized_wasEnabled_and_defaultCompleted_wasEnabled_then
assertThat(protectedSettings.contains("default_completed"), equalTo(false));
}

@Test
public void when_AllowOtherWaysOfEditingFormIsDisabled_thenSaveAsDraftShouldBeDisabledAndFinalizeShouldBeEnabled() {
initSettings(protectedSettings,
ProtectedProjectKeys.ALLOW_OTHER_WAYS_OF_EDITING_FORM, false,
ProtectedProjectKeys.KEY_SAVE_AS_DRAFT, true,
ProtectedProjectKeys.KEY_FINALIZE, false
);

runMigrations();

assertThat(protectedSettings.contains(ProtectedProjectKeys.ALLOW_OTHER_WAYS_OF_EDITING_FORM), equalTo(true));
assertThat(protectedSettings.getBoolean(ProtectedProjectKeys.ALLOW_OTHER_WAYS_OF_EDITING_FORM), equalTo(false));
assertThat(protectedSettings.getBoolean(ProtectedProjectKeys.KEY_SAVE_AS_DRAFT), equalTo(false));
assertThat(protectedSettings.getBoolean(ProtectedProjectKeys.KEY_FINALIZE), equalTo(true));
}

@Test
public void when_AllowOtherWaysOfEditingFormIsEnabled_thenDoNotUpdateSaveAsDraftOrFinalize() {
initSettings(protectedSettings,
ProtectedProjectKeys.ALLOW_OTHER_WAYS_OF_EDITING_FORM, true,
ProtectedProjectKeys.KEY_SAVE_AS_DRAFT, true,
ProtectedProjectKeys.KEY_FINALIZE, false
);

runMigrations();

assertThat(protectedSettings.contains(ProtectedProjectKeys.ALLOW_OTHER_WAYS_OF_EDITING_FORM), equalTo(true));
assertThat(protectedSettings.getBoolean(ProtectedProjectKeys.ALLOW_OTHER_WAYS_OF_EDITING_FORM), equalTo(true));
assertThat(protectedSettings.getBoolean(ProtectedProjectKeys.KEY_SAVE_AS_DRAFT), equalTo(true));
assertThat(protectedSettings.getBoolean(ProtectedProjectKeys.KEY_FINALIZE), equalTo(false));
}

private void runMigrations() {
new ODKAppSettingsMigrator(metaSettings).migrate(unprotectedSettings, protectedSettings);
}
Expand Down