Skip to content

Latest commit

 

History

History
291 lines (212 loc) · 7.24 KB

README.adoc

File metadata and controls

291 lines (212 loc) · 7.24 KB

Jamal Mock module

Using this module, you can mock built-in macros. The reason to mock a built-in macro is mainly for testing purposes. When you develop a macro package collecting information from different sources

  • those may not be available at all in the test environment

  • may function in the test environment differently,

  • may be expensive to set up an environment where these built-in macros function as needed for the test.

The solution is to mock the built-in macros.

The primary goal developing this module was to provide mocking possibility for the Java::Geci macros. That way you can develop the code generator templates in IntelliJ using the Asciidoc plugin. When the built-in macros of Java::Geci are mocked you can see the generated code in the WYSIWYG editor.

To use this module, you have to add the dependency to your Maven project, as:

<dependency>
    <groupId>com.javax0.jamal</groupId>
    <artifactId>jamal-mock</artifactId>
    <version>2.6.1-SNAPSHOT</version>
</dependency>

or use the maven:load macro to load the dependency from Maven Central.

Macros in this library

mock

Mock can be used to create a mock for a built-in macro. The actual macro may or may not exist prior. It will be created by the mock macro and defined in the current scope overriding the existing macro or shadowing any defined on higher scopes. Any built-in macro can be mocked, even core macros like if, import, comment.

The reason to mock a built-in macro is to test some macro code in a test environment where the original macro is not available or does not have its environment to function properly.

The use of the macro is simple. You have to define the name of the macro you want to mock and the output.

Example 1. simple mock
Jamal source
{@mock (macro=w)ajaja}{@w}

outputs .output

ajaja

You can override existing macros, even the core built-in ones. The mocks are only available on the current scope.

Example 2. mock locality
Jamal source
{#ident {@mock (macro=comment)comment is overridden}{@comment}}{@comment is not overridden here}

outputs .output

comment is overridden

You can also define multiple responses for a single mock. These responses will be used in the other they are defined.

Example 3. repeated mock
Jamal source
{@mock (macro=ww)1}{@mock (macro=ww)2}{@ww}{@ww}

outputs .output

12

If you use a mock more times it has defined values it will result syntax error.

Example 4. mock exhausted
Jamal source
{@try! {@mock (macro=z)1}{@z}{@z}}

outputs .output

Mock z has exhausted after 1 uses.

Exhausted mock shadowing a defined built-in macro will not throw an exception though. It will simply use the original macro.

Example 5. mock exhausted
Jamal source
{@mock (macro=ident)exhausted}\
{@mock (macro=ident)macros}\
{@ident whatever is here, mocked} {@ident second time also mocked} {@ident are not mocked anymore}

outputs .output

exhausted macros are not mocked anymore

If you want to use a mock multiple times resulting the same value you can use the repeat option.

Example 6. mock repeated
Jamal source
{@mock (macro=w repeat=2)A}{@w}{@w}

outputs .output

AA

In addition to the repeat option it is also possible to use the infinite option meaning: repeat as many times as needed.

Example 7. mock infinite
Jamal source
{@mock (macro=w infinite)X}{@w}{@w}{@w}{@w}{@w}{@w}{@w}{@w}{@w}

outputs .output

XXXXXXXXX

You can also define multiple mocks for the same macro and give a regular expression to each. When the regular expression matches the input of the macro the one will be used. If there are more than one mock that would match the input then the one first defined and not exhausted yet are used.

Example 8. mock infinite
Jamal source
{@mock (macro=q when=".*bee.*")bee}{@comment defined first, but used second}
{@mock (macro=q when=".*apple.*")apple}
{@q this is an apple and}
{@q there is a bee}

outputs .output

apple
bee

In the next section, we will describe all these options in details (reference) and also the formal argument how a mock response is selected.

Options of mock

  • macro (alias id) the identifier of the macro. This an option is mandatory and has to define the identifier of the macro to be mocked.

  • when regular expression when to apply the mock. This option is not mandatory. In case it is specified, the mock response will only be used when the input of the macro matches the regular expression specified. If the option is missing, the mock response will always be matched and used when it gets activated regardless of the input of the macro.

  • repeat (alias times) how many times the mock can be used. Can specify how many times the mock can be used. It is an error to use a negative number. You can use zero to switch off the mock response in your text temporarily without deleting it.

  • inf (aliases infinite, forever) if the mock be used infinite number of times. Can be used to specify that the mock response can be used unlimited number of times.

When the mock macro is used the input of the macro least the options between the ( and ) characters will be used as a response. A new use of the mock macro for the same macro name will add a new response to the mock. The responses are used in the order they are defined.

Every mock response has a counter and a regular expression selector.

  • The counter starts from one unless the option repeat specifies a different number or the option infinite is used. In case the mock response is set to infinite the counter starts from "infinite".

  • The regular expression selector can be defined using the option when. The response will only be used when the input of the macro mocked matches the regular expression. The regular expression should match the whole input and not only part of it. If you want to match only a part of it, you should use a regular expression that starts and ends with the .* pattern fragment.

    The default pattern matches every use.

When a mock response is needed the selection algorithm starts from the first response defined and progresses towards the last. It will select the response whose regular expression selector matches the input of the macro and the counter has not reached zero. When a response is selected the counter is decreased.

It is an error specifying a new response for a macro following an infinitely repeatable response without selector.

Mocking mock

As an extreme, though not practical use you can mock the macro mock itself. The example below mocks the macro mock, then it is used, therefore the macro ident is not mocked. After that the macro comment is mocked again, as the mocking of mock is exhausted.

Example 9. Mocking mock
Jamal source
{@mock (macro=mock)mock the mock once}{@mock (macro=ident)}{@mock (macro=comment)this is a comment}
{#ident not mocked}
{#comment mocked, does not matter what I write here}

outputs .output

mock the mock once
not mocked
this is a comment