Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Commit

Permalink
Bug 814599 - RFE: %x validation should support positional printf stri…
Browse files Browse the repository at this point in the history
…ngs (eg %1)
  • Loading branch information
Patrick Huang committed Jul 2, 2012
1 parent 3cb21a0 commit 30bb7ed
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 20 deletions.
Expand Up @@ -25,6 +25,7 @@

import org.zanata.webtrans.client.resources.ValidationMessages;

import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.regexp.shared.MatchResult;
import com.google.gwt.regexp.shared.RegExp;

Expand All @@ -35,31 +36,42 @@
**/
public class PrintfVariablesValidation extends ValidationAction
{
public PrintfVariablesValidation(final ValidationMessages messages)
{
super(messages.printfVariablesValidatorName(), messages.printfVariablesValidatorDescription(), true, messages);
}

private static final String GLOBAL_FLAG = "g";

// derived from translate toolkit printf style variable matching regex. See:
// http://translate.svn.sourceforge.net/viewvc/translate/src/trunk/translate/filters/checks.py?revision=17978&view=markup
private final static String varRegex = "%((?:\\d+\\$|\\(\\w+\\))?[+#-]*(\\d+)?(\\.\\d+)?(hh|h|ll|l|L|z|j|t)?[\\w%])";
// private final static String varRegex = "%[\\w]+";
private static final String VAR_REGEX = "%((?:\\d+\\$|\\(\\w+\\))?[+#-]*(\\d+)?(\\.\\d+)?(hh|h|ll|l|L|z|j|t)?[\\w%])";

// regex to find out whether the variable has position
private static final RegExp POSITIONAL_REG_EXP = RegExp.compile("%(\\d+\\$)\\w+");


public PrintfVariablesValidation(final ValidationMessages messages)
{
super(messages.printfVariablesValidatorName(), messages.printfVariablesValidatorDescription(), true, messages);
}

@Override
public void doValidate(String source, String target)
{
ArrayList<String> sourceVars = findVars(source);
ArrayList<String> targetVars = findVars(target);

List<String> missing = listMissing(sourceVars, targetVars);
Log.info("source vars: " + sourceVars);
Log.info("target vars: " + targetVars);

ArrayList<String> targetAfterStrip = stripPositionIfApplicable(targetVars);
Log.info("target after stripping position: " + targetAfterStrip);

List<String> missing = listMissing(sourceVars, targetAfterStrip);
if (!missing.isEmpty())
{
addError(getMessages().varsMissing(missing));
}

// missing from source = added
missing = listMissing(targetVars, sourceVars);
missing = listMissing(targetAfterStrip, sourceVars);
if (!missing.isEmpty())
{
addError(getMessages().varsAdded(missing));
Expand All @@ -68,21 +80,70 @@ public void doValidate(String source, String target)

private List<String> listMissing(ArrayList<String> baseVars, ArrayList<String> testVars)
{
ArrayList<String> remainingVars = new ArrayList<String>();
remainingVars.addAll(testVars);
ArrayList<String> remainingVars = new ArrayList<String>(testVars);

ArrayList<String> unmatched = new ArrayList<String>();

for (String var : baseVars)
{
if (!remainingVars.remove(var))
{
unmatched.add(var);
}
}
return unmatched;
}

private static ArrayList<String> stripPositionIfApplicable(ArrayList<String> variables)
{
ArrayList<String> copyOfVariables = new ArrayList<String>(variables);

boolean hasPosition = false;
for (String testVar : variables)
{
MatchResult result = POSITIONAL_REG_EXP.exec(testVar);
if (result != null)
{
hasPosition = true;
String positionAndDollar = result.getGroup(1);
int position = extractPositionIndex(positionAndDollar);
if (position >= 0 && position < variables.size())
{
copyOfVariables.set(position, testVar.replace(positionAndDollar, ""));
}
else
{
Log.warn("positional variable has invalid position. Ignore position strip.");
return variables;
}
}
else if (hasPosition)
{
Log.warn("encounter mixed positional and unpositional variables. Ignore position strip.");
return variables;
}
}
return copyOfVariables;
}

private static int extractPositionIndex(String positionAndDollar)
{
try
{
return Integer.valueOf(positionAndDollar.substring(0, positionAndDollar.length() - 1)) - 1;
}
catch (Exception e)
{
Log.warn("cannot extract position index from " + positionAndDollar);
return -1;
}
}

private ArrayList<String> findVars(String inString)
{
ArrayList<String> vars = new ArrayList<String>();
// compile each time to reset index
RegExp varRegExp = RegExp.compile(varRegex, "g");
RegExp varRegExp = RegExp.compile(VAR_REGEX, GLOBAL_FLAG);
MatchResult result = varRegExp.exec(inString);
while (result != null)
{
Expand Down
Expand Up @@ -20,26 +20,27 @@
*/
package org.zanata.webtrans.shared.validation;

import java.util.List;

import org.easymock.Capture;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.zanata.webtrans.client.resources.ValidationMessages;
import org.zanata.webtrans.shared.validation.action.PrintfVariablesValidation;

import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;

import java.util.List;

import org.easymock.Capture;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.zanata.webtrans.client.resources.ValidationMessages;
import org.zanata.webtrans.shared.validation.action.PrintfVariablesValidation;

/**
*
* @author Alex Eng <a href="mailto:aeng@redhat.com">aeng@redhat.com</a>
Expand Down Expand Up @@ -267,6 +268,68 @@ public void checkWithRealWorldExamples()

assertThat(capturedVarsMissing.getValue(), hasItems("%s", "%d", "%-25s", "%r"));
}

@Test
public void validPositionalVariables() {
printfVariablesValidation = new PrintfVariablesValidation(mockMessages);
String source = "%s: Read error at byte %s, while reading %lu byte";
String target = "%1$s:Read error while reading %3$lu bytes,at %2$s";
printfVariablesValidation.validate(source, target);

assertThat(printfVariablesValidation.hasError(), is(false));
assertThat(printfVariablesValidation.getError().size(), is(0));

assertThat(capturedVarsAdded.hasCaptured(), is(false));
assertThat(capturedVarsMissing.hasCaptured(), is(false));
}

@Test
public void mixPositionalVariablesWithNotPositionalWillValidateAsIs() {
printfVariablesValidation = new PrintfVariablesValidation(mockMessages);
String source = "%s: Read error at byte %s, while reading %lu byte";
String target = "%1$s:Read error while reading %lu bytes,at %2$s";
printfVariablesValidation.validate(source, target);

assertThat(printfVariablesValidation.hasError(), is(true));
assertThat(printfVariablesValidation.getError().size(), is(2));

assertThat(capturedVarsAdded.hasCaptured(), is(true));
assertThat(capturedVarsAdded.getValue(), contains("%1$s" , "%2$s"));
assertThat(capturedVarsMissing.hasCaptured(), is(true));
assertThat(capturedVarsMissing.getValue(), contains("%s", "%s"));
}

@Test
public void invalidPositionalVariablesWillValidateAsIs() {
printfVariablesValidation = new PrintfVariablesValidation(mockMessages);
String source = "%s: Read error at byte %s, while reading %lu byte";
String target = "%3$s:Read error while reading %99$lu bytes,at %2$s";
printfVariablesValidation.validate(source, target);

assertThat(printfVariablesValidation.hasError(), is(true));
assertThat(printfVariablesValidation.getError().size(), is(2));

assertThat(capturedVarsAdded.hasCaptured(), is(true));
assertThat(capturedVarsAdded.getValue(), contains("%3$s", "%99$lu", "%2$s"));
assertThat(capturedVarsMissing.hasCaptured(), is(true));
assertThat(capturedVarsMissing.getValue(), contains("%s", "%s", "%lu"));
}

@Test
public void invalidPositionalVariablesWillValidateAsIs2() {
printfVariablesValidation = new PrintfVariablesValidation(mockMessages);
String source = "%s: Read error at byte %s, while reading %lu byte";
String target = "%31$s:Read error while reading %99$lu bytes,at %2$s";
printfVariablesValidation.validate(source, target);

assertThat(printfVariablesValidation.hasError(), is(true));
assertThat(printfVariablesValidation.getError().size(), is(2));

assertThat(capturedVarsAdded.hasCaptured(), is(true));
assertThat(capturedVarsAdded.getValue(), contains("%31$s", "%99$lu", "%2$s"));
assertThat(capturedVarsMissing.hasCaptured(), is(true));
assertThat(capturedVarsMissing.getValue(), contains("%s", "%s", "%lu"));
}
}


Expand Down

0 comments on commit 30bb7ed

Please sign in to comment.