Skip to content

Commit

Permalink
Merge pull request #611 from dimagi/ctsims/backmerge_2370_master
Browse files Browse the repository at this point in the history
CommCare 2.37.0 -> Master Backmerge
  • Loading branch information
wpride authored Jul 18, 2017
2 parents d66a0a4 + 132873a commit fe3aca9
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,11 @@ private void init(String profileRef) throws InstallCancelledException,
installAppFromReference(profileRef);
}

public void installAppFromReference(String profileReference) throws UnresolvedResourceException,
public void installAppFromReference(String profileReference)
throws UnresolvedResourceException,
UnfullfilledRequirementsException, InstallCancelledException {
ResourceManager.installAppResources(platform, profileReference, this.table, true);
ResourceManager.installAppResources(platform, profileReference, this.table, true,
Resource.RESOURCE_AUTHORITY_LOCAL);
}

public void initEnvironment() {
Expand Down
23 changes: 20 additions & 3 deletions src/main/java/org/commcare/cases/util/StringUtils.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package org.commcare.cases.util;

import org.commcare.modern.util.Pair;
import org.javarosa.core.util.ArrayUtilities;

import java.text.Normalizer;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
Expand Down Expand Up @@ -45,9 +48,9 @@ public synchronized static String normalize(String input) {
//if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
normalized = Normalizer.normalize(input, Normalizer.Form.NFD);
//} else {
//TODO: I doubt it's worth it, but in theory we could run
//some other normalization for the minority of pre-API9
//devices.
//TODO: I doubt it's worth it, but in theory we could run
//some other normalization for the minority of pre-API9
//devices.
//}

String output = diacritics.matcher(normalized).replaceAll("").toLowerCase();
Expand Down Expand Up @@ -134,4 +137,18 @@ private static int LevenshteinDistance(String s0, String s1) {
// the distance is the cost for transforming all letters in both strings
return cost[len0 - 1];
}

/**
* Converts a string to a list of Characters.
*/
public static ArrayList<Character> toList(String str) {

ArrayList<Character> myArrayList = new ArrayList<>(str.length());

for (int i = 0; i < str.length(); i++) {
myArrayList.add(i, str.charAt(i));
}

return myArrayList;
}
}
10 changes: 5 additions & 5 deletions src/main/java/org/commcare/resources/ResourceManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ public ResourceManager(CommCarePlatform platform,
* version numbers?
*/
public static void installAppResources(CommCarePlatform platform, String profileReference,
ResourceTable global, boolean forceInstall)
ResourceTable global, boolean forceInstall,
int authorityForProfile)
throws UnfullfilledRequirementsException,
UnresolvedResourceException,
InstallCancelledException {
Expand All @@ -64,11 +65,10 @@ public static void installAppResources(CommCarePlatform platform, String profile
global.getResourceWithId(CommCarePlatform.APP_PROFILE_RESOURCE_ID);

if (profile == null) {
// grab the local profile and parse it
// Create a stub for the profile resource that points to the authority and location
// from which we will install it
Vector<ResourceLocation> locations = new Vector<>();
locations.addElement(new ResourceLocation(Resource.RESOURCE_AUTHORITY_LOCAL, profileReference));

// We need a way to identify this version...
locations.addElement(new ResourceLocation(authorityForProfile, profileReference));
Resource r = new Resource(Resource.RESOURCE_VERSION_UNKNOWN,
CommCarePlatform.APP_PROFILE_RESOURCE_ID,
locations, "Application Descriptor");
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/javarosa/xpath/expr/FunctionUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public class FunctionUtils {
funcList.put(XPathUuidFunc.NAME, XPathUuidFunc.class);
funcList.put(XPathIdCompressFunc.NAME, XPathIdCompressFunc.class);
funcList.put(XPathJoinChunkFunc.NAME, XPathJoinChunkFunc.class);
funcList.put(XPathChecksumFunc.NAME, XPathChecksumFunc.class);
funcList.put(XPathSortFunc.NAME, XPathSortFunc.class);
funcList.put(XPathSortByFunc.NAME, XPathSortByFunc.class);
}
Expand Down
101 changes: 101 additions & 0 deletions src/main/java/org/javarosa/xpath/expr/XPathChecksumFunc.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package org.javarosa.xpath.expr;


import org.commcare.cases.util.StringUtils;
import org.javarosa.core.model.condition.EvaluationContext;
import org.javarosa.core.model.instance.DataInstance;
import org.javarosa.core.util.ArrayUtilities;
import org.javarosa.xpath.XPathUnsupportedException;
import org.javarosa.xpath.parser.XPathSyntaxException;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

public class XPathChecksumFunc extends XPathFuncExpr {
public static final String NAME = "checksum";
private static final int EXPECTED_ARG_COUNT = 2;

public static final String ALGORITHM_KEY_VERHOEFF = "verhoeff";

public XPathChecksumFunc() {
name = NAME;
expectedArgCount = EXPECTED_ARG_COUNT;
}

public XPathChecksumFunc(XPathExpression[] args) throws XPathSyntaxException {
super(NAME, args, EXPECTED_ARG_COUNT, true);
}

@Override
public Object evalBody(DataInstance model, EvaluationContext evalContext, Object[] evaluatedArgs) {
return checksum(evaluatedArgs[0], evaluatedArgs[1]);
}

/**
* @param o1 algorithm type used to calculate checksum. We only support 'verhoeff' for now.
* @param o2 input we are calculating checksum for
* @return checksum of {@code o2} calculated using {@code o1} type algorithm
*/
private static String checksum(Object o1, Object o2) {
String algorithmKey = FunctionUtils.toString(o1);
String input = FunctionUtils.toString(o2);

switch (algorithmKey) {
case ALGORITHM_KEY_VERHOEFF:
return verhoeffChecksum(input);
default:
throw new XPathUnsupportedException("Bad algorithm key " + algorithmKey + ". We only support 'verhoeff' as algorithm key right now.");
}
}

/**
* Calculates Verhoeff checksum for the given {@code input} string <p>
*
* @param input input string to calculate verhoeff checksum for
* @return Verhoeff checksum value for {@code input}
* @see <a href="https://en.wikibooks.org/wiki/Algorithm_Implementation/Checksums/Verhoeff_Algorithm#Java">Based on Verhoeff checksum implementation here</a>
*/
private static String verhoeffChecksum(String input) {

// The multiplication table
int[][] op = new int[][]{
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
{1, 2, 3, 4, 0, 6, 7, 8, 9, 5},
{2, 3, 4, 0, 1, 7, 8, 9, 5, 6},
{3, 4, 0, 1, 2, 8, 9, 5, 6, 7},
{4, 0, 1, 2, 3, 9, 5, 6, 7, 8},
{5, 9, 8, 7, 6, 0, 4, 3, 2, 1},
{6, 5, 9, 8, 7, 1, 0, 4, 3, 2},
{7, 6, 5, 9, 8, 2, 1, 0, 4, 3},
{8, 7, 6, 5, 9, 3, 2, 1, 0, 4},
{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
};

// The permutation table
int[][] p = new int[][]{
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
{1, 5, 7, 6, 2, 8, 3, 0, 9, 4},
{5, 8, 0, 3, 7, 9, 6, 1, 4, 2},
{8, 9, 1, 6, 0, 4, 3, 5, 2, 7},
{9, 4, 5, 3, 1, 2, 6, 8, 7, 0},
{4, 2, 8, 6, 5, 7, 3, 9, 0, 1},
{2, 7, 9, 3, 8, 0, 6, 4, 1, 5},
{7, 0, 4, 6, 9, 1, 3, 2, 5, 8}
};

// The inverse table
int[] inv = {0, 4, 3, 2, 1, 5, 6, 7, 8, 9};

ArrayList<Character> inputList = StringUtils.toList(input);
Collections.reverse(inputList);

int check = 0;
for (int i = 0; i < inputList.size(); i++) {
check = op[check][p[((i + 1) % 8)][Character.getNumericValue(inputList.get(i))]];
}

return Integer.toString(inv[check]);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ private static XPathFuncExpr buildFuncExpr(String name, XPathExpression[] args)
return new XPathJoinChunkFunc(args);
case "id-compress":
return new XPathIdCompressFunc(args);
case "checksum":
return new XPathChecksumFunc(args);
case "sort":
return new XPathSortFunc(args);
case "sort-by":
Expand Down
18 changes: 11 additions & 7 deletions src/test/java/org/javarosa/xpath/test/XPathEvalTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ private void assertExceptionExpected(boolean exceptionExpected, Object expected,
}

@Test
public void testTypeCoercion(){
public void testTypeCoercion() {
Object str = FunctionUtils.InferType("notadouble");
Assert.assertTrue("'notadouble' coerced to the wrong type, "
+ str.getClass().toString(), str instanceof String);
Expand Down Expand Up @@ -541,6 +541,10 @@ public void doTests() {
testEval("id-compress(0, 'CD','','ABCDE',1)", null, ec, new XPathException());
testEval("id-compress(0, 'CD','CD','ABCDE',1)", null, ec, new XPathException());

testEval("checksum('verhoeff','41310785898')", null, null, "4");
testEval("checksum('verhoeff','66671496237')", null, null, "3");
testEval("checksum('verhoefffff','41310785898')", null, null, new XPathUnsupportedException());

//Variables
EvaluationContext varContext = getVariableContext();
testEval("$var_float_five", null, varContext, new Double(5.0));
Expand Down Expand Up @@ -643,24 +647,24 @@ public void testOverrideNow() {
ec.addFunctionHandler(new IFunctionHandler() {
@Override
public String getName() {
return "now";
return "now";
}

@Override
public Vector getPrototypes() {
Vector<Class[]> p = new Vector<>();
p.addElement(new Class[0]);
return p;
Vector<Class[]> p = new Vector<>();
p.addElement(new Class[0]);
return p;
}

@Override
public boolean rawArgs() {
return false;
return false;
}

@Override
public Object eval(Object[] args, EvaluationContext ec) {
return "pass";
return "pass";
}
});

Expand Down

0 comments on commit fe3aca9

Please sign in to comment.