cucumber stepdef matching multiple regex arguments - gherkin

I am trying to write a step def that matches multiple String values with double quotes:
When I have a HeaderUtil
Then header is generated with fields matching patterns
"""
"\"%s\":\"%s\""
"""
or
"""
"\"%s\":%s"
"""
This stepdef will see that the serialized fields match one of the above patterns in the generated string.
I am looking to have a stepdefinition that will have two arguments that matches one or the other pattern.
Currently, I am getting a parser error:
Caused by: gherkin.lexer.LexingError: Lexing error on line 8: '""" \
"""
"\"%s\":%s"
"""
Is there a way more than one multiline parameter can be passed in a step definition?

I guess it's referenced to this topic of Cucumber Documentation and Custom parameter types
Custom parameter types
You can define custom parameter types to represent types from your own domain. Doing this has the following benefits:
Automatic conversion to custom types
Document and evolve your ubiquitous domain language
Enforce certain patterns
Imagine we want a parameter to match the colors red, blue or yellow (but nothing else). Let's assume a Color class is already defined. This is how we would define a custom color parameter type:
parameterTypeRegistry.defineParameterType(new ParameterType<>(
"color", // name
"red|blue|yellow", // regexp
Color.class, // type
new SingleTransformer<>(new Function<String, Color>() {
#Override
public Color apply(String s) {
return new Color(s);
}
}), // transform
false, // useForSnippets
false // preferForRegexpMatch));

Related

How do I mutate captures in a Grammar object?

I'm trying to modify the values in a parsed Grammar object with this:
method mutate(Match:D $match --> Match:D) {
for $match.values -> $line {
when $line<content><header-toc><header><taskwiki-content><taskwiki-divider> {
say 'here';
$line<content><header-toc><header><taskwiki-content><taskwiki-divider>.replace-with('');
say $line; # has not been modified;
}
};
return $match;
}
I'm not getting any errors but the $match object is not affected by the replace-with method I'm running.
How do I mutate captures in a Grammar object?
You can't. (Well, you can hang data off them via make, but you can't do what you're thinking you can do.)
A Match object stores the result of a match against some string, and any captures are just .from, .to indexes into that original string.
For example, if you write "bar".match(/a/), the resulting Match object stores the .match method's invocant "bar", and has a .from of 1 and a .to of 2 which represents the captured "a" substring.
The original string remains immutable, and the captured substrings are "virtual" as it were, with nothing you can mutate.
foo.replace-with('');
replace-with does not modify its invocant. It just returns a value (a new string).
Quoting the replace-with doc, with my added bold emphasis:
Returns the invocant string where the Match object is replaced by $replacement.
Note that it's not "the invocant Match object".
The .replace-with method is returning a new string that's a copy of the original input string that was matched against to produce the Match object, with the bit that was matched replaced by the string supplied as the .replace-with method's argument.

Parsing of YAML file with Jackson fails if value starts with special character

I am trying to parse the following YAML-content:
template:
amplitude: 5
noise: +-0.01
This fails with this exception:
com.fasterxml.jackson.databind.JsonMappingException: empty String (through reference chain: ... ->my.package.Template["noise"])
The class Template contains a property noise of type FlexValue. I made a custom JsonDeserializer that is responsible to parse the values for properties of this type. The notation allows somewhat fancy expressions, hence the name FlexValue for the type. The value in this example, "+-0.01", is a valid input for the deserializer. However, it seems like the deserializer isn't even called. The exception seems to be thrown before that.
Here is the relevant class definition of my custom deserializer:
class FlexValueParser : JsonDeserializer<FlexValue>() {
override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): FlexValue {
//...
}
}
The custom deserializer is registered as follows:
#JsonDeserialize(using = FlexValueParser::class)
class FlexValue {
// ...
}
This setup seems to work fine. It does on other types as well, which are parsed differently.
If I prepend a "0" before "+-", which is also a valid input, it works:
template:
amplitude: 5
noise: 0+-0.01
Is "+-" a special cahracter in YAML that causes Jackson to fail parsing it, because it tries to do something else than I expect? I expect it to treat the input "+-0.01" as a String because it doesn't represent a valid number input.
The same problem occurs, when I use noise: ~0.01, which is also a valid input for my deserializer. The same exception is thrown on this and can be avoided by prepending a "0" before the curly "~".
Can someone give me a hint on this?
Found the source of the problem, which had nothing to do with Jackson or YAML. Closing this question therefore.

Kotlin clarification about # symbol and return postfixes

I am confused about the meaning usage of the next syntax.
What does exactly do placing the postfixes "async" and "lazy" after a "return"?
return async
return lazy
What does the "#" symbol mean here?
return#async
return#lazy
return#withContext
About the "#" symbol, does it have a special naming in Kotlin? so I can better locate all the ways to use it in the documentation?
What is the difference between adding # and not using it? so:
"return async" vs "return#async"
What does exactly do placing the postfixes "async" and "lazy" after a "return"?
This is not special syntax in Kotlin with the specific words "async" or "lazy". So it is not really a "postfix for the return keyword". After a space, what follows the return is always the value that you want to return:
return 42 returns the value 42
return async returns the value of the expression async (which is probably a variable that has been declared earlier in the code)
return async { 42 } returns the value of the expression async { 42 }.
The meaning of the expression async { 42 } here is unrelated to the return in itself. You could see the same expression assigned to a variable for instance: val deferred = async { 42 }. async is simply a library function from the kotlinx.coroutines library (it's just my guess by the way, maybe the code you've seen declares variables/functions of this name, but it's hard to tell without more context). Have a look at the doc of the async function here if you're interested.
What does the "#" symbol mean here?
The return keyword by default returns from the closest enclosing function declared with the fun keyword. Lambdas don't count, because they are not declared with fun.
Therefore, return-ing from inside a lambda will by default (without #) return from an enclosing function rather than just the "local" lambda (as opposed to what happens in Java). This is why we call them non-local returns.
Using a qualified return with a label (return#label) allows to change this default behaviour and specify what you want to return from explicitly.
See the doc about return at labels, it contains many examples.
The specific examples you gave:
return#async
return#lazy
return#withContext
would need a bit more context to understand them. But I assume that you have seen them used inside lambdas that are a parameter of async/lazy/withContext function calls. What follows the # here is called an implicit label which tells the compiler that this return is supposed to return from this lambda instead of returning from the closest enclosing fun.
Other notes
Note that the # symbol here is not an annotation like you could see elsewhere like #JvmDefault or #OptIn(...), it is instead a label reference.
Note that both a label and a return value can be combined: return#myLabel 42 returns the value 42 from the function qualified by the label myLabel.

Pass parameters to Junit 5 TestRunner extension

Trying to figure out how to pass some parameters to my custom implementation of TestWatcher in Junit5. The base class for all tests is set to #ExtendWith with the TestWatcher. Trying to keep it as simple as possible and I can't seem to find a straightforward answer on how to do this
I was struggling on a similar problem, basically I needed a global parameter (a separator string data) for the annotation #DisplayNameGenerator().
Because the lack of code examples of how you're trying to resolve this I'm gonna explain my approach of how to get a parameter provided by the user and see if it works for you,
I created a interface with the return of the String value that is my custom parameter that I wanted to get from the user,
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Inherited
#API(status = EXPERIMENTAL, since = "5.4")
public #interface IndicativeSentencesSeparator {
String value();
}
So this way I could create my test with this new interface, and passing the parameter but also making it optional to use, like this,
#DisplayName("My Test")
#DisplayNameGeneration(DisplayNameGenerator.IndicativeSentencesGenerator.class)
#IndicativeSentencesSeparator(" --> ")
class MyTestClass { //Some test methods and stuff }
To get the this new class in the implementation, I used the java method class.getAnnotation(classType) in the class that you're trying to extract the value, sending by parameter the class to find, in this case the interface I created.
IndicativeSentencesSeparator separator =
myTestClass.getAnnotation(IndicativeSentencesSeparator.class);
And finally to get the parameter used the getter value,
String parameter = separator.value();

Specifying a function with templates that takes and returns an arbitrary class

I'm interested in defining a function that given a class variable, generates and a new instance of the class object with a randomly selected member attribute mutated.
Context: Consider an instance, circle1, of some class, Circle, has attributes color and radius. These attributes are assigned values of red and 5, respectively. The function in question, mutate, must accept circle1 as an argument, but reject non-class arguments.
For other data types, templates provide an answer in this context. That is, templates may be used to specify generic instances of functions that can accept arguments of multiple types.
How can a generic function that accepts (and returns) an instance of any class be defined using templates?
In general, if you need to restrict what a template can take, you use template constraints. e.g.
import std.traits : isIntegral;
auto foo(T)(T t)
if(isIntegeral!T)
{
...
}
or
import std.functional : binaryFun;
auto foo(alias pred, T, U)(T t, U u)
if(is(typeof(binaryFun!pred(t, u.bar())) == bool)
{
...
}
As long the condition can be checked at compile time, you can test pretty much anything. And it can be used for function overloading as well (e.g. std.algorithm.searching.find has quite a few overloads all of which are differentiated by template constraint). The built-in __traits, the eponymous templates in std.traits, and is expressions provide quite a few tools for testing stuff at compile time and then using that information in template constraints or static if conditions.
If you specifically want to test whether something is a class, then use an is expression with == class. e.g.
auto foo(T)(T t)
if(is(T == class))
{
...
}
In general though, you'll probably want to use more specific conditions such as __traits(compiles, MyType result = t.foo(22)) or is(typeof(t.foo(22)) == MyType). So, you could have something like
auto mutate(T)(T t)
if(is(T == class) &&
__traits(compiles, t.color = red) &&
__traits(compiles, t.radius = 5))
{
...
}
If the condition is something that you want to reuse, then it can make sense to create an eponymous template - which is what's done in Phobos in places like std.range.primitives and std.range.traits. For instance, to test for an input range, std.range.primitives.isInputRange looks something like
template isInputRange(R)
{
enum bool isInputRange = is(typeof(
{
R r = R.init; // can define a range object
if (r.empty) {} // can test for empty
r.popFront(); // can invoke popFront()
auto h = r.front; // can get the front of the range
}));
}
Then code that requires an input range can use that. So, lots of functions in Phobos have stuff like
auto foo(R)(R range)
if(isInputRange!R)
{
...
}
A more concrete example would be this overload of find:
InputRange find(alias pred = "a == b", InputRange, Element)
(InputRange haystack, Element needle)
if(isInputRange!InputRange &&
is(typeof(binaryFun!pred(haystack.front, needle)) : bool))
{
...
}
Ali Çehreli's book, Programming in D, has several relevant chapters, including:
http://ddili.org/ders/d.en/templates.html
http://ddili.org/ders/d.en/cond_comp.html
http://ddili.org/ders/d.en/is_expr.html
http://ddili.org/ders/d.en/templates_more.html