improve and fix spectest to document formats

This commit is contained in:
Jonathan Shook 2022-06-27 23:38:03 -05:00
parent 334fb54fc8
commit 3d2061125d
30 changed files with 643 additions and 163 deletions

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.types;
package io.nosqlbench.nb.spectest.api;
import io.nosqlbench.nb.spectest.core.STNodeAssembly;

View File

@ -14,19 +14,19 @@
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.types;
package io.nosqlbench.nb.spectest.api;
import com.vladsch.flexmark.util.ast.Node;
import io.nosqlbench.nb.spectest.core.SpecTest;
import io.nosqlbench.nb.spectest.core.STBuilder;
import io.nosqlbench.nb.spectest.loaders.STNodePredicate;
import io.nosqlbench.nb.spectest.loaders.STNodePredicates;
import io.nosqlbench.nb.spectest.traversal.STNodePredicate;
import io.nosqlbench.nb.spectest.traversal.STNodePredicates;
import java.nio.file.Path;
public interface STBuilderFacets {
interface All extends WantsPaths, WantsPathsOrScannersOrValidators, WantsScannersOrValidators {}
interface All extends WantsPaths, WantsPathsOrScannersOrValidators, WantsScannersOrValidators, WantsDebuggingOptions {}
interface WantsPaths {
/**
@ -94,7 +94,10 @@ public interface STBuilderFacets {
* is resumed on the next element not included in the result.</P>
*
* <P>The predicates can be one of the types supported by {@link STNodePredicate}
* and {@link STNodePredicates}.</P>
* and {@link STNodePredicates}. These can be wrapped in structural predicate form
* by using the helpers from {@link io.nosqlbench.nb.spectest.traversal.STPredicateVerbs},
* particularly with an import like
* <pre>{@code import static io.nosqlbench.nb.spectest.traversal.STPredicateVerbs.*;}</pre></P>
*
* @param predicates The pattern to match
* @return this SpecTestBuilder for builder method chaining
@ -102,10 +105,13 @@ public interface STBuilderFacets {
WantsValidatorsOrDone matchNodes(Object... predicates);
}
interface WantsValidatorsOrDone extends Done{
Done validators(STAssemblyValidator... validators);
interface WantsValidatorsOrDone extends WantsDebuggingOptions {
WantsDebuggingOptions validators(STAssemblyValidator... validators);
}
interface WantsDebuggingOptions extends Done {
Done debug();
}
interface Done {
SpecTest build();
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.types;
package io.nosqlbench.nb.spectest.api;
import com.vladsch.flexmark.util.ast.Node;
import io.nosqlbench.nb.spectest.core.STNodeAssembly;

View File

@ -14,10 +14,10 @@
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.types;
package io.nosqlbench.nb.spectest.api;
import io.nosqlbench.nb.spectest.core.STNodeAssembly;
import io.nosqlbench.nb.spectest.loaders.STNodePredicates;
import io.nosqlbench.nb.spectest.traversal.STNodePredicates;
import java.nio.file.Path;
import java.util.List;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.types;
package io.nosqlbench.nb.spectest.api;
import io.nosqlbench.nb.spectest.core.STNodeAssembly;

View File

@ -17,10 +17,10 @@
package io.nosqlbench.nb.spectest.core;
import io.nosqlbench.nb.spectest.loaders.STDefaultLoader;
import io.nosqlbench.nb.spectest.loaders.STNodePredicate;
import io.nosqlbench.nb.spectest.types.STAssemblyValidator;
import io.nosqlbench.nb.spectest.types.STBuilderFacets;
import io.nosqlbench.nb.spectest.types.STPathLoader;
import io.nosqlbench.nb.spectest.traversal.STNodePredicate;
import io.nosqlbench.nb.spectest.api.STAssemblyValidator;
import io.nosqlbench.nb.spectest.api.STBuilderFacets;
import io.nosqlbench.nb.spectest.api.STPathLoader;
import java.nio.file.Path;
import java.util.ArrayList;
@ -32,6 +32,7 @@ public abstract class STBuilder implements STBuilderFacets.All {
protected List<Path> paths = new ArrayList<>();
protected List<STPathLoader> scanners = new ArrayList<>();
protected List<STAssemblyValidator> validators = new ArrayList<>();
protected boolean debug;
@Override
public STBuilderFacets.WantsPathsOrScannersOrValidators paths(Path... paths) {
@ -56,9 +57,14 @@ public abstract class STBuilder implements STBuilderFacets.All {
}
@Override
public STBuilderFacets.Done validators(STAssemblyValidator... validators) {
public STBuilderFacets.WantsDebuggingOptions validators(STAssemblyValidator... validators) {
this.validators.addAll(Arrays.asList(validators));
return this;
}
@Override
public STBuilderFacets.Done debug() {
this.debug=true;
return this;
}
}

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.core;
public interface STDebug {
void applyDebugging(boolean enabled);
static void applyDebugging(boolean enabled, Object maybeDebuggable) {
if (maybeDebuggable instanceof STDebug d) {
d.applyDebugging(enabled);
}
}
}

View File

@ -16,29 +16,24 @@
package io.nosqlbench.nb.spectest.core;
import io.nosqlbench.nb.spectest.testtypes.STNodeReference;
import io.nosqlbench.nb.spectest.testmodels.STNodeReference;
import java.nio.file.Path;
public class STNameAndCodeTuple implements STNodeReference {
private final STNode nameNode;
private final STNode dataNode;
public STNameAndCodeTuple(STNode nameNode, STNode dataNode) {
this.nameNode = nameNode;
this.dataNode = dataNode;
}
public record STNameAndCodeTuple(
STNode nameNode,
STNode dataNode
) implements STNodeReference {
public String getDesc() {
return nameNode.getDesc();
}
public String getName() {
return nameNode.text.toString();
return nameNode.getText();
}
public String getData() {
return dataNode.text.toString();
return dataNode.getText();
}
@Override

View File

@ -35,13 +35,17 @@ public final class STNode {
private final Path path;
private final int line;
private final Node refnode;
public CharSequence info;
public CharSequence text;
private final CharSequence text;
public STNode(Supplier<CharSequence> desc, Node dataNode, Path path) {
this.description = desc.get().toString();
this.text = dataNode.getFirstChild().getChars();
this.line = dataNode.getFirstChild().getLineNumber();
if (dataNode.getFirstChild()!=null) {
this.text = dataNode.getFirstChild().getChars();
this.line = dataNode.getFirstChild().getLineNumber();
} else {
this.text = "";
this.line = dataNode.getLineNumber();
}
this.path = path;
this.refnode = dataNode;
}
@ -96,7 +100,6 @@ public final class STNode {
if (!Objects.equals(description, that.description)) return false;
if (!Objects.equals(path, that.path)) return false;
if (!Objects.equals(refnode, that.refnode)) return false;
if (!Objects.equals(info, that.info)) return false;
return Objects.equals(text, that.text);
}
@ -106,8 +109,11 @@ public final class STNode {
result = 31 * result + (path != null ? path.hashCode() : 0);
result = 31 * result + line;
result = 31 * result + (refnode != null ? refnode.hashCode() : 0);
result = 31 * result + (info != null ? info.hashCode() : 0);
result = 31 * result + (text != null ? text.hashCode() : 0);
return result;
}
public String getText() {
return text.toString();
}
}

View File

@ -17,7 +17,7 @@
package io.nosqlbench.nb.spectest.core;
import com.vladsch.flexmark.util.ast.Node;
import io.nosqlbench.nb.spectest.testtypes.STNamedCodeTuples;
import io.nosqlbench.nb.spectest.testmodels.STNamedCodeTuples;
import java.nio.file.Path;
import java.security.InvalidParameterException;
@ -75,7 +75,7 @@ public class STNodeAssembly extends ArrayList<STNode> {
public String getAsText(int index) {
assertRange(index);
return get(index).text.toString();
return get(index).getText();
}
public Path getPath() {

View File

@ -19,9 +19,9 @@ package io.nosqlbench.nb.spectest.core;
import com.vladsch.flexmark.ext.yaml.front.matter.YamlFrontMatterExtension;
import com.vladsch.flexmark.parser.Parser;
import io.nosqlbench.nb.spectest.loaders.STFileScanner;
import io.nosqlbench.nb.spectest.types.STAssemblyValidator;
import io.nosqlbench.nb.spectest.types.STBuilderFacets;
import io.nosqlbench.nb.spectest.types.STPathLoader;
import io.nosqlbench.nb.spectest.api.STAssemblyValidator;
import io.nosqlbench.nb.spectest.api.STBuilderFacets;
import io.nosqlbench.nb.spectest.api.STPathLoader;
import java.nio.file.Path;
import java.util.LinkedHashSet;
@ -73,11 +73,17 @@ public class SpecTest implements Runnable {
private final List<Path> paths;
private final List<STPathLoader> pathLoaders;
private final List<STAssemblyValidator> validators;
private final boolean debug;
private SpecTest(List<Path> paths, List<STPathLoader> pathLoaders, List<STAssemblyValidator> validators) {
private SpecTest(List<Path> paths, List<STPathLoader> pathLoaders, List<STAssemblyValidator> validators, boolean debug) {
this.paths = paths;
this.pathLoaders = pathLoaders;
this.validators = validators;
this.debug = debug;
if (debug) {
pathLoaders.forEach(p -> STDebug.applyDebugging(debug,p));
validators.forEach(p -> STDebug.applyDebugging(debug,p));
}
}
@Override
@ -99,7 +105,6 @@ public class SpecTest implements Runnable {
testables.add(assembly);
}
}
}
}
@ -117,7 +122,7 @@ public class SpecTest implements Runnable {
private static class Builder extends STBuilder {
@Override
public SpecTest build() {
return new SpecTest(paths,scanners,validators);
return new SpecTest(paths,scanners,validators,debug);
}
}
}

View File

@ -18,64 +18,34 @@ package io.nosqlbench.nb.spectest.loaders;
import com.vladsch.flexmark.ext.yaml.front.matter.YamlFrontMatterExtension;
import com.vladsch.flexmark.parser.Parser;
import io.nosqlbench.nb.spectest.api.STNodeLoader;
import io.nosqlbench.nb.spectest.api.STPathLoader;
import io.nosqlbench.nb.spectest.core.STDebug;
import io.nosqlbench.nb.spectest.core.STNodeAssembly;
import io.nosqlbench.nb.spectest.types.STAssemblyValidator;
import io.nosqlbench.nb.spectest.types.STNodeLoader;
import io.nosqlbench.nb.spectest.types.STPathLoader;
import io.nosqlbench.nb.spectest.traversal.STNodePredicates;
import java.nio.file.Path;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* <P>This scanner looks for testable specifications which are matched as a sequence of
* 3 2-tuples, described in {@link YamlSpecValidator}. The required markdown structure for
* this looks like:
* <PRE>{@code
* ## call form with defaults
*
* *yaml:*
* ```yaml
* name: TEMPLATE(myname,thedefault)
* ```
*
* *json:*
* ```json5
* {
* "name": "thedefault"
* }
* ```
*
* *ops:*
* ```json5
* []
* ```
* }</PRE>
* </P>
*
* <P>Specifically, the emphasis and colon paragraph blocks indicate the naming of the elements, and the
* fenced code sections represent the content. The name elements are not matched for the name specifically,
* although the {@link STAssemblyValidator} which consumes these {@link STNodeAssembly}s will interpret them
* as described above.
* </P>
*
*/
public class STDefaultLoader implements STPathLoader {
public class STDefaultLoader implements STPathLoader, STDebug {
private final STNodePredicates predicates;
private static final Parser parser = Parser.builder().extensions(List.of(YamlFrontMatterExtension.create())).build();
private boolean debug;
public STDefaultLoader(Object... predicates) {
if (predicates.length==0) {
throw new InvalidParameterException("An empty spec scanner is invalid.");
}
if ((predicates.length % 2) != 0) {
throw new InvalidParameterException("You can only provide predicates in sequences of 2-tuples, where" +
"each even index is a naming element and each odd index is the associated test content. " +
"But " + predicates.length + " were provided: " + Arrays.toString(predicates));
}
// No longer valid?
// if ((predicates.length % 2) != 0) {
// throw new InvalidParameterException("You can only provide predicates in sequences of 2-tuples, where" +
// "each even index is a naming element and each odd index is the associated test content. " +
// "But " + predicates.length + " were provided: " + Arrays.toString(predicates));
// }
this.predicates = new STNodePredicates(predicates);
}
@ -84,13 +54,19 @@ public class STDefaultLoader implements STPathLoader {
List<STNodeAssembly> assemblies = new ArrayList<>();
List<Path> matchingPaths = STFileScanner.findMatching(specPath);
STNodeLoader nodeLoader = new STDefaultNodeLoader(predicates);
STDebug.applyDebugging(debug,nodeLoader);
for (Path matchingPath : matchingPaths) {
List<STNodeAssembly> found = nodeLoader.apply(matchingPath, null);
assemblies.addAll(found);
}
return assemblies;
}
@Override
public void applyDebugging(boolean enabled) {
this.debug =enabled;
STDebug.applyDebugging(enabled,predicates);
}
}

View File

@ -20,9 +20,11 @@ import com.vladsch.flexmark.ext.yaml.front.matter.YamlFrontMatterExtension;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.ast.Document;
import com.vladsch.flexmark.util.ast.Node;
import io.nosqlbench.nb.spectest.api.STNodeLoader;
import io.nosqlbench.nb.spectest.core.STDebug;
import io.nosqlbench.nb.spectest.core.STNode;
import io.nosqlbench.nb.spectest.core.STNodeAssembly;
import io.nosqlbench.nb.spectest.types.STNodeLoader;
import io.nosqlbench.nb.spectest.traversal.STNodePredicates;
import java.io.IOException;
import java.nio.file.Files;
@ -32,10 +34,11 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class STDefaultNodeLoader implements STNodeLoader {
public class STDefaultNodeLoader implements STNodeLoader, STDebug {
private final STNodePredicates predicates;
private final Parser parser = Parser.builder().extensions(List.of(YamlFrontMatterExtension.create())).build();
private boolean debug;
public STDefaultNodeLoader(Object... predicates) {
@ -55,8 +58,8 @@ public class STDefaultNodeLoader implements STNodeLoader {
public List<STNodeAssembly> apply(Path path, Node node) {
List<STNodeAssembly> assemblies = new ArrayList<>();
if (node==null) {
if (path==null) {
if (node == null) {
if (path == null) {
throw new InvalidParameterException("You must provide at least a path.");
}
try {
@ -67,7 +70,7 @@ public class STDefaultNodeLoader implements STNodeLoader {
}
}
if (node instanceof Document d) {
node=d.getFirstChild();
node = d.getFirstChild();
}
STHeadingScanner headings = new STHeadingScanner(" > ");
@ -79,11 +82,25 @@ public class STDefaultNodeLoader implements STNodeLoader {
if (optionalStanza.isPresent()) {
List<Node> found = optionalStanza.get();
List<STNode> stnodes = found.stream().map(n -> new STNode(headings, n, path)).toList();
STNodeAssembly testassy = new STNodeAssembly(stnodes.toArray(new STNode[0]));
List<STNode> stnodes = found.stream()
.map(
n -> new STNode(headings, n, path)
)
.toList();
STNodeAssembly testassy = new STNodeAssembly(
stnodes.toArray(
new STNode[0]
)
);
node = found.get(found.size() - 1);
headings.index();
assemblies.add(testassy);
if (debug) {
summarize(testassy);
}
}
if (node != null) {
node = node.getNext();
@ -92,4 +109,26 @@ public class STDefaultNodeLoader implements STNodeLoader {
return assemblies;
}
private void summarize(STNodeAssembly testassy) {
for (STNode stNode : testassy) {
String nodeClass = stNode.getRefNode().getClass().getSimpleName();
String text = stNode.getRefNode().getChars().toString();
String[] lines = text.split("\n");
String header =lines[0].substring(0,Math.min(lines[0].length(),39));
if (lines[0].length()>39) {
header=header+"...";
}
if (!header.endsWith("\n")) {
header = header+"\n";
}
System.out.format("%-20s|%-40s|(%-3d lines)\n",nodeClass,header.replaceAll("\n","\\n"),lines.length);
}
}
@Override
public void applyDebugging(boolean enabled) {
this.debug = enabled;
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.testtypes;
package io.nosqlbench.nb.spectest.testmodels;
import com.vladsch.flexmark.util.ast.Node;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.testtypes;
package io.nosqlbench.nb.spectest.testmodels;
import io.nosqlbench.nb.spectest.core.STNameAndCodeTuple;
import io.nosqlbench.nb.spectest.core.STNode;
@ -67,7 +67,7 @@ public class STNamedCodeTuples {
public String getTypeSignature() {
StringBuilder sb = new StringBuilder();
for (STNameAndCodeTuple tuple : tuples) {
sb.append(tuple.getDesc()).append("->");
sb.append(tuple.getName()).append("->");
}
sb.setLength(sb.length()-"->".length());
return sb.toString().replaceAll("[^-a-zA-Z0-9<> _]", "");

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.testtypes;
package io.nosqlbench.nb.spectest.testmodels;
public class STNamedNodes {

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.testtypes;
package io.nosqlbench.nb.spectest.testmodels;
import java.nio.file.Path;

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.traversal;
import com.vladsch.flexmark.util.ast.Node;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class STAndPredicate implements Predicate<Node> {
private final List<STNodePredicate> predicates = new ArrayList<>();
public STAndPredicate(Object... specs) {
for (Object predicate : specs) {
predicates.add(new STNodePredicate(predicate));
}
}
@Override
public boolean test(Node node) {
for (int i = 0; i < predicates.size(); i++) {
STNodePredicate predicate = predicates.get(i);
if (!predicate.test(node)) {
return false;
}
}
return true;
}
@Override
public String toString() {
return "AND(" + predicates.stream().map(Object::toString).collect(Collectors.joining(","))+")";
}
}

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.traversal;
/**
* A symblic reference to an earlier argument in the same list, to avoid duplication and expose
* uniformity in a visual way.
* @param argidx The argument index (0-based) of the previous argument to reference
*/
public record STArgumentRef(int argidx) {
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.traversal;
import com.vladsch.flexmark.util.ast.Node;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* Match if all the predicates match when tested pair-wise across the AST nodes, traversing
* strictly across by sibling nodes, and not following beyond the current parent.
* @return true if all siblings match
*/
public class STBreadthFirstPredicate implements Predicate<Node> {
private final List<STNodePredicate> predicates = new ArrayList<>();
public STBreadthFirstPredicate(Object... specs) {
for (Object predicate : specs) {
predicates.add(new STNodePredicate(predicate));
}
}
@Override
public boolean test(Node node) {
Node focus = null;
Node parent = node.getParent();
for (int i = 0; i < predicates.size(); i++) {
if (focus==null) {
focus = node;
} else {
focus = focus.getNext();
if (focus==null || parent!=focus.getParent()) {
return false;
}
}
STNodePredicate predicate = predicates.get(i);
if (!predicate.test(focus)) {
return false;
}
}
return true;
}
@Override
public String toString() {
return "BREADTH(" + predicates.stream().map(Object::toString).collect(Collectors.joining(","))+")";
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.traversal;
import com.vladsch.flexmark.util.ast.Node;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class STDeepMatchAnyPredicate implements Predicate<Node> {
private final List<STNodePredicate> predicates = new ArrayList<>();
public STDeepMatchAnyPredicate(Object... specs) {
for (Object predicate : specs) {
predicates.add(new STNodePredicate(predicate));
}
}
@Override
public boolean test(Node node) {
for (STNodePredicate predicate: predicates) {
Node focus = node;
while (focus!=null) {
if (predicate.test(focus)) {
return true;
}
focus = focus.getFirstChild();
}
}
return false;
}
@Override
public String toString() {
return "DEEPANY(" + predicates.stream().map(Object::toString).collect(Collectors.joining(",")) + ")";
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.traversal;
import com.vladsch.flexmark.util.ast.Node;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class STDepthFirstPredicate implements Predicate<Node> {
private final List<STNodePredicate> predicates = new ArrayList<>();
public STDepthFirstPredicate(Object... specs) {
for (Object predicate : specs) {
predicates.add(new STNodePredicate(predicate));
}
}
@Override
public boolean test(Node node) {
Node focus = null;
for (int i = 0; i < predicates.size(); i++) {
if (focus == null) {
focus = node;
} else {
focus = focus.getFirstChild();
if (focus==null) {
return false;
}
}
STNodePredicate predicate = predicates.get(i);
if (!predicate.test(focus)) {
return false;
}
}
return true;
}
@Override
public String toString() {
return "DEPTH(" + predicates.stream().map(Object::toString).collect(Collectors.joining(",")) + ")";
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.traversal;
import com.vladsch.flexmark.util.ast.Node;
import java.util.function.Predicate;
final class STNodeClassPredicate implements Predicate<Node> {
private final Class<? extends Node> matchingClass;
public STNodeClassPredicate(Class<? extends Node> matchingClass) {
this.matchingClass = matchingClass;
}
@Override
public boolean test(Node node) {
Class<? extends Node> classToMatch = node.getClass();
boolean matches = matchingClass.equals(classToMatch);
return matches;
}
@Override
public String toString() {
return "CLASS(" + matchingClass.getSimpleName() + ")";
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.traversal;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.sequence.BasedSequence;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
final class STNodePatternPredicate implements Predicate<Node> {
private final Pattern pattern;
public STNodePatternPredicate(Pattern pattern) {
this.pattern = pattern;
}
public STNodePatternPredicate(String pattern) {
String newPattern = (pattern.matches("^[a-zA-Z0-9]") ? ".*" : "") + pattern + (pattern.matches("[a-zA-Z0-9]$") ? ".*" : "");
Pattern compiled = Pattern.compile(newPattern, Pattern.MULTILINE | Pattern.DOTALL);
this.pattern = compiled;
}
@Override
public boolean test(Node node) {
if (node == null) {
return false;
}
BasedSequence chars = node.getChars();
Matcher matcher = pattern.matcher(chars);
boolean matches = matcher.matches();
return matches;
}
@Override
public String toString() {
return "PATTERN(" + this.pattern.pattern() + ")";
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.loaders;
package io.nosqlbench.nb.spectest.traversal;
import com.vladsch.flexmark.ast.Paragraph;
import com.vladsch.flexmark.util.ast.Node;
@ -22,7 +22,6 @@ import com.vladsch.flexmark.util.sequence.BasedSequence;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
@ -57,57 +56,21 @@ public class STNodePredicate implements Predicate<Node>, Supplier<Node> {
private Predicate<Node> resolvePredicate(Object object) {
if (object instanceof Predicate predicate) {
Paragraph paragraph = new Paragraph(BasedSequence.of("test paragraph"));
Paragraph paragraph = new Paragraph(BasedSequence.of("type checking"));
// assert no runtime type casting issues
predicate.test(paragraph);
return predicate;
} else if (object instanceof Class c) {
return new ClassPredicate(c);
return new STNodeClassPredicate(c);
} else if (object instanceof Pattern p) {
return new PatternPredicate(p);
return new STNodePatternPredicate(p);
} else if (object instanceof CharSequence cs) {
return new PatternPredicate(cs.toString());
return new STNodePatternPredicate(cs.toString());
} else {
throw new RuntimeException("no Node predicate for type " + object.getClass().getSimpleName());
}
}
private final static class ClassPredicate implements Predicate<Node> {
private final Class<? extends Node> matchingClass;
public ClassPredicate(Class<? extends Node> matchingClass) {
this.matchingClass = matchingClass;
}
@Override
public boolean test(Node node) {
Class<? extends Node> classToMatch = node.getClass();
boolean matches = matchingClass.equals(classToMatch);
return matches;
}
}
private final static class PatternPredicate implements Predicate<Node> {
private final Pattern pattern;
private PatternPredicate(Pattern pattern) {
this.pattern = pattern;
}
private PatternPredicate(String pattern) {
String newPattern = (pattern.matches("^[a-zA-Z0-9]") ? ".*" : "") + pattern + (pattern.matches("[a-zA-Z0-9]$") ? ".*" : "");
Pattern compiled = Pattern.compile(newPattern, Pattern.MULTILINE | Pattern.DOTALL);
this.pattern = compiled;
}
@Override
public boolean test(Node node) {
BasedSequence chars = node.getChars();
Matcher matcher = pattern.matcher(chars);
boolean matches = matcher.matches();
return matches;
}
}
@Override
public boolean test(Node node) {
this.found = null;
@ -122,4 +85,9 @@ public class STNodePredicate implements Predicate<Node>, Supplier<Node> {
public Node get() {
return this.found;
}
@Override
public String toString() {
return this.predicate.toString();
}
}

View File

@ -14,9 +14,10 @@
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.loaders;
package io.nosqlbench.nb.spectest.traversal;
import com.vladsch.flexmark.util.ast.Node;
import io.nosqlbench.nb.spectest.core.STDebug;
import java.security.InvalidParameterException;
import java.util.ArrayList;
@ -24,6 +25,7 @@ import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* <P>{@link STNodePredicates} is a convenient wrapper around {@link STNodePredicate}
@ -36,25 +38,20 @@ import java.util.function.Predicate;
* a regular expression which would match "__a__" or "__b__" and then two more subsequent
* matches against similar content, for a total of 3 consecutive matching nodes.</p>
*/
public class STNodePredicates implements Function<Node, Optional<List<Node>>> {
final List<Predicate<Node>> predicates;
final List<Node> found = new ArrayList<>();
public STNodePredicates(STNodePredicates predicates) {
this.predicates = predicates.predicates;
}
public class STNodePredicates implements Function<Node, Optional<List<Node>>>, STDebug {
private final List<Predicate<Node>> predicates = new ArrayList<>();
private final List<Node> found = new ArrayList<>();
private boolean debug;
public STNodePredicates(Object... predicateSpecs) {
this.predicates = new ArrayList<Predicate<Node>>(predicateSpecs.length);
for (int i = 0; i < predicateSpecs.length; i++) {
if (predicateSpecs[i] instanceof STNodePredicates pspecs) {
predicates.addAll(pspecs.predicates);
} else if (predicateSpecs[i] instanceof Number number) {
if (i > number.intValue()) {
predicates.add(predicates.get(number.intValue()));
} else if (predicateSpecs[i] instanceof STArgumentRef number) {
if (i > number.argidx()) {
predicates.add(predicates.get(number.argidx()));
} else {
throw new InvalidParameterException("predicate reference at " + i + " references invalid position at " + number.intValue());
throw new InvalidParameterException("predicate reference at " + i + " references invalid position at " + number.argidx());
}
} else {
predicates.add(new STNodePredicate(predicateSpecs[i]));
@ -88,4 +85,13 @@ public class STNodePredicates implements Function<Node, Optional<List<Node>>> {
return true;
}
@Override
public String toString() {
return this.predicates.stream().map(Object::toString).collect(Collectors.joining(","))+")";
}
@Override
public void applyDebugging(boolean enabled) {
this.debug = enabled;
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.traversal;
import com.vladsch.flexmark.util.ast.Node;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class STPairWisePredicate implements Predicate<List<Node>> {
private final List<STNodePredicate> predicates = new ArrayList<>();
public STPairWisePredicate(Object... specs) {
for (Object predicate : specs) {
predicates.add(new STNodePredicate(predicate));
}
}
@Override
public boolean test(List<Node> nodes) {
for (int i = 0; i < predicates.size(); i++) {
if (!predicates.get(i).test(nodes.get(i))) {
return false;
}
}
return true;
}
@Override
public String toString() {
return "PAIRWISE(" + predicates.stream().map(Object::toString).collect(Collectors.joining(","))+")";
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2022 nosqlbench
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.nosqlbench.nb.spectest.traversal;
public class STPredicateVerbs {
/**
* see {@link STBreadthFirstPredicate} for details.
*/
public static STBreadthFirstPredicate breadth(Object... specs) {
return new STBreadthFirstPredicate(specs);
}
public static STDepthFirstPredicate depth(Object... specs) {
return new STDepthFirstPredicate(specs);
}
public static STPairWisePredicate pairwise(Object... specs) {
return new STPairWisePredicate(specs);
}
public static STAndPredicate and(Object... specs) {
return new STAndPredicate(specs);
}
public static STDeepMatchAnyPredicate deepany(Object... specs) {
return new STDeepMatchAnyPredicate(specs);
}
public static STArgumentRef ref(int ref) {
return new STArgumentRef(ref);
}
}

View File

@ -16,7 +16,7 @@
package io.nosqlbench.nb.spectest;
import io.nosqlbench.nb.spectest.loaders.STNodePredicate;
import io.nosqlbench.nb.spectest.traversal.STNodePredicate;
import org.junit.jupiter.api.Test;
import java.util.function.Predicate;

View File

@ -21,22 +21,23 @@ import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.ast.Document;
import io.nosqlbench.nb.spectest.core.STNodeAssembly;
import io.nosqlbench.nb.spectest.loaders.STDefaultNodeLoader;
import io.nosqlbench.nb.spectest.loaders.STNodePredicates;
import io.nosqlbench.nb.spectest.types.STNodeLoader;
import io.nosqlbench.nb.spectest.traversal.STNodePredicates;
import io.nosqlbench.nb.spectest.api.STNodeLoader;
import org.junit.jupiter.api.Test;
import java.util.List;
import static io.nosqlbench.nb.spectest.traversal.STPredicateVerbs.ref;
import static org.assertj.core.api.Assertions.assertThat;
public class STNodePredicatesTest {
@Test
public void testBackReferences() {
STNodePredicates predicateShouldMatch1 = new STNodePredicates(".*__\\w__.*", 0, 0);
STNodePredicates predicateShouldMatch2 = new STNodePredicates("__\\w__", 0, 0);
STNodePredicates predicateShouldNotMatch3 = new STNodePredicates("^__\\w__", 0, 0);
STNodePredicates predicateShouldNotMatch4 = new STNodePredicates("^__\\w__$", 0, 0);
STNodePredicates predicateShouldMatch1 = new STNodePredicates(".*__\\w__.*", ref(0), ref(0));
STNodePredicates predicateShouldMatch2 = new STNodePredicates("__\\w__", ref(0), ref(0));
STNodePredicates predicateShouldNotMatch3 = new STNodePredicates("^__\\w__", ref(0), ref(0));
STNodePredicates predicateShouldNotMatch4 = new STNodePredicates("^__\\w__$", ref(0), ref(0));
String testMarkdown = """
paragraph contents with __a__.