Skip to content

Commit

Permalink
Added support for the normalize-space Metapath function. Had to fix a…
Browse files Browse the repository at this point in the history
… bug in the string literal handling that inconsistently caused leading and trailing quotes to be removed. Also fixed an issue with the build that was causing surefire to inconsistently handle a JUnit extension. Resolves metaschema-framework#133.
  • Loading branch information
david-waltermire committed Oct 5, 2024
1 parent e565811 commit 8d6343f
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
public class StringLiteral
extends AbstractLiteralExpression<IStringItem, String> {

private static final Pattern QUOTE_PATTERN = Pattern.compile("^'(.*)'$|^\"(.*)\"$");
private static final Pattern QUOTE_PATTERN = Pattern.compile("(?:^'(.*)'$)|(?:^\"(.*)\"$)");

/**
* Construct a new expression that always returns the same string value.
Expand All @@ -43,17 +43,7 @@ public Class<IStringItem> getBaseResultType() {
@SuppressWarnings("null")
@NonNull
private static String removeQuotes(@NonNull String value) {
Matcher matcher = QUOTE_PATTERN.matcher(value);

String retval = value;
if (matcher.matches()) {
if (matcher.group(1) != null) {
retval = matcher.group(1);
} else if (matcher.group(2) != null) {
retval = matcher.group(2);
}
}
return retval;
return value.substring(1, value.length() - 1);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ public DefaultFunctionLibrary() { // NOPMD - intentional
// https://www.w3.org/TR/xpath-functions-31/#func-months-from-duration
// https://www.w3.org/TR/xpath-functions-31/#func-node-name
// https://www.w3.org/TR/xpath-functions-31/#func-normalize-space
registerFunction(FnNormalizeSpace.SIGNATURE_NO_ARG);
registerFunction(FnNormalizeSpace.SIGNATURE_ONE_ARG);
// https://www.w3.org/TR/xpath-functions-31/#func-normalize-unicode
// https://www.w3.org/TR/xpath-functions-31/#func-not
registerFunction(FnNot.SIGNATURE);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* SPDX-FileCopyrightText: none
* SPDX-License-Identifier: CC0-1.0
*/

package gov.nist.secauto.metaschema.core.metapath.function.library;

import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
import gov.nist.secauto.metaschema.core.metapath.DynamicMetapathException;
import gov.nist.secauto.metaschema.core.metapath.ISequence;
import gov.nist.secauto.metaschema.core.metapath.MetapathConstants;
import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils;
import gov.nist.secauto.metaschema.core.metapath.function.IArgument;
import gov.nist.secauto.metaschema.core.metapath.function.IFunction;
import gov.nist.secauto.metaschema.core.metapath.item.IItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;

import java.util.List;

import edu.umd.cs.findbugs.annotations.NonNull;

/**
* Implements <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-normalize-space">fn:normalize-space</a>.
*/
public final class FnNormalizeSpace {
@NonNull
static final IFunction SIGNATURE_NO_ARG = IFunction.builder()
.name("normalize-space")
.namespace(MetapathConstants.NS_METAPATH_FUNCTIONS)
.deterministic()
.contextDependent()
.focusDependent()
.returnType(IStringItem.class)
.returnOne()
.functionHandler(FnNormalizeSpace::executeNoArg)
.build();

@NonNull
static final IFunction SIGNATURE_ONE_ARG = IFunction.builder()
.name("normalize-space")
.namespace(MetapathConstants.NS_METAPATH_FUNCTIONS)
.deterministic()
.contextIndependent()
.focusIndependent()
.argument(IArgument.builder()
.name("arg")
.type(IStringItem.class)
.zeroOrOne()
.build())
.returnType(IStringItem.class)
.returnOne()
.functionHandler(FnNormalizeSpace::executeOneArg)
.build();

private FnNormalizeSpace() {
// disable construction
}

@SuppressWarnings("unused")
@NonNull
private static ISequence<IStringItem> executeNoArg(@NonNull IFunction function,
@NonNull List<ISequence<?>> arguments,
@NonNull DynamicContext dynamicContext,
IItem focus) {

ISequence<IAnyAtomicItem> retval;
if (focus == null) {
throw new DynamicMetapathException(DynamicMetapathException.DYNAMIC_CONTEXT_ABSENT, "The context is empty");
}

return ISequence.of(FnString.fnStringItem(focus).normalizeSpace());
}

@SuppressWarnings("unused")
@NonNull
private static ISequence<IStringItem> executeOneArg(
@NonNull IFunction function,
@NonNull List<ISequence<?>> arguments,
@NonNull DynamicContext dynamicContext,
IItem focus) {

IStringItem value = FunctionUtils.asTypeOrNull(ObjectUtils.requireNonNull(arguments.get(0)).getFirstItem(true));

return value == null ? ISequence.empty() : ISequence.of(value.normalizeSpace());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public abstract class AbstractStringItem
implements IStringItem {
private static final String WHITESPACE_SEGMENT = "[ \t\r\n]";
private static final Pattern TRIM_END = Pattern.compile(WHITESPACE_SEGMENT + "++$");
private static final Pattern TRIM_START = Pattern.compile("^" + WHITESPACE_SEGMENT + "++");
private static final Pattern TRIM_START = Pattern.compile("^" + WHITESPACE_SEGMENT + "+");
private static final Pattern TRIM_MIDDLE = Pattern.compile(WHITESPACE_SEGMENT + "{2,}");

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ default int compareTo(IAnyAtomicItem other) {
return compareTo(other.asStringItem());
}

/**
* An implementation of <a href=
* "https://www.w3.org/TR/xpath-functions-31/#func-normalize-space">fn::normalize-space</a>.
*
* @return the normalized string value for this string
*/
@NonNull
IStringItem normalizeSpace();
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
public class ExpressionTestBase {
@NonNull
@RegisterExtension
private final Mockery context = new JUnit5Mockery();
final Mockery context = new JUnit5Mockery();

/**
* Get the mocking context.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* SPDX-FileCopyrightText: none
* SPDX-License-Identifier: CC0-1.0
*/

package gov.nist.secauto.metaschema.core.metapath.function.library;

import static gov.nist.secauto.metaschema.core.metapath.TestUtils.array;
import static gov.nist.secauto.metaschema.core.metapath.TestUtils.integer;
import static gov.nist.secauto.metaschema.core.metapath.TestUtils.sequence;
import static gov.nist.secauto.metaschema.core.metapath.TestUtils.string;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import gov.nist.secauto.metaschema.core.metapath.ExpressionTestBase;
import gov.nist.secauto.metaschema.core.metapath.ISequence;
import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.MetapathException;
import gov.nist.secauto.metaschema.core.metapath.MetapathExpression;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidTypeFunctionException;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.List;
import java.util.stream.Stream;

import edu.umd.cs.findbugs.annotations.NonNull;

class FnNormalizeSpaceTest
extends ExpressionTestBase {
private static Stream<Arguments> provideValues() { // NOPMD - false positive
return Stream.of(
Arguments.of(
string("The wealthy curled darlings of our nation."),
"fn:normalize-space(\" The wealthy curled darlings \n\r \t of our nation. \")"));
}

@ParameterizedTest
@MethodSource("provideValues")
void testExpression(@NonNull IStringItem expected, @NonNull String metapath) {
IStringItem result = MetapathExpression.compile(metapath)
.evaluateAs(null, MetapathExpression.ResultType.ITEM, newDynamicContext());
assertEquals(expected, result);
}

@Test
void testNoFocus() {
InvalidTypeMetapathException throwable = assertThrows(InvalidTypeMetapathException.class,
() -> {
try {
ISequence<IStringItem> result = FunctionTestBase.executeFunction(
FnNormalizeSpace.SIGNATURE_NO_ARG,
newDynamicContext(),
null,
List.of(sequence()));
} catch (MetapathException ex) {
throw ex.getCause();
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public static <R extends IItem> ISequence<R> executeFunction(

DynamicContext context = dynamicContext == null ? new DynamicContext() : dynamicContext;
ISequence<?> focusSeqence = function.isFocusDepenent()
? ObjectUtils.requireNonNull(focus, "Function call requires a focus")
? focus == null ? ISequence.empty() : focus
: ISequence.empty();
return (ISequence<R>) function.execute(
arguments == null ? CollectionUtil.emptyList() : arguments,
Expand Down
13 changes: 2 additions & 11 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,8 @@
<plugin.spotbugs.version>4.8.6.4</plugin.spotbugs.version>
<plugin.maven-surefire.version>3.5.0</plugin.maven-surefire.version>
<plugin.templating.version>3.0.0</plugin.templating.version>
<!-- The Surefire and Failsafe configurations override the <argLine>
element using the @{argLine} notation which
allows to include any argLine defined by plugins executing before them (such as
Jacoco). However, if no such
plugin executes before, the property is undefined and makes the tests fail.
Thus we define an empty property
here to make sure it doesn't fail. See also
https://issues.apache.org/jira/browse/SUREFIRE-1431
-->
<argLine />

<argLine>-Xmx1024m</argLine>
</properties>

<issueManagement>
Expand Down Expand Up @@ -651,7 +643,6 @@
<configuration>
<forkCount>1.5C</forkCount>
<reuseForks>true</reuseForks>
<argLine>@{argLine} -Xmx1024m</argLine>
<excludedEnvironmentVariables>
<excludedEnvironmentVariable>JAVA_TOOL_OPTIONS</excludedEnvironmentVariable>
</excludedEnvironmentVariables>
Expand Down

0 comments on commit 8d6343f

Please sign in to comment.