All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax0.jamal.mock.Mock Maven / Gradle / Ivy

The newest version!
package javax0.jamal.mock;

import javax0.jamal.api.BadSyntax;
import javax0.jamal.api.Input;
import javax0.jamal.api.Macro;
import javax0.jamal.api.MacroRegister;
import javax0.jamal.api.Processor;
import javax0.jamal.tools.Scanner;

import java.util.Optional;
import java.util.regex.Pattern;

public class Mock implements Macro, Scanner {
    @Override
    public String evaluate(final Input in, final Processor processor) throws BadSyntax {
        final var scanner = newScanner(in, processor);
        // snippet mock_options
        final var id = scanner.str(null, "macro", "id"); //| the identifier of the macro.
        //|This an option is mandatory and has to define the identifier of the macro to be mocked.
        final var when = scanner.str(null, "when").optional(); //| 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.
        final var repeat = scanner.number(null, "repeat", "times").defaultValue(1); //| 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.
        final var infinite = scanner.bool(null, "inf", "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.
        // end snippet
        scanner.done();

        BadSyntax.when(repeat.isPresent() && infinite.isPresent(), "You cannot use options 'repeat' and 'infinite' at the same time.");
        BadSyntax.when(repeat.isPresent() && repeat.get() < 0, "The option 'repeat' should be non-negative.");
        if (repeat.isPresent() && repeat.get() == 0) {
            processor.logger().log(System.Logger.Level.WARNING, in.getPosition(), "Repeat is zero.");
        }
        final Pattern inputCheck = when.isPresent() ? Pattern.compile(when.get()) : null;

        final MockImplementation mock = getMockImplementation(id.get(), processor.getRegister());
        mock.response(in.toString(), when.isPresent(), inputCheck, infinite.is(), repeat.get());
        return "";
    }

    /**
     * Get an already existing mock implementation to add the new response to, or create a new one if no prior exists.
     * If the mock implementation is newly created it will also be registered in the macro register, so that Jamal
     * will find it by the id when it is used. If the macro shadowed existed and is on the same scope as the mock, then
     * it will be overwritten by the mock. When the mock exhaust Jamal still invokes the mock implementation and that
     * code calls the original macro, which is not in the register anymore.
     *
     * @param id       the identifier of the macro to be mocked
     * @param register the macro register
     * @return the already existing mock or a newly created one
     */
    private MockImplementation getMockImplementation(final String id, final MacroRegister register) {
        final var existingMock = getMockIfExists(id, register);
        final MockImplementation mock;
        if (existingMock.isPresent()) {
            mock = existingMock.get();
        } else {
            mock = new MockImplementation(id, register.getMacro(id).orElse(null));
            register.define(mock);
        }
        return mock;
    }

    /**
     * Get an existing mock implementation or return empty if one with the given id does not exist.
     *
     * @param id       the identifier of the macro to be mocked and thus the id of the mock.
     * @param register the macro register where we look for the already existing mock.
     * @return the mock implementation macro or empty
     */
    private Optional getMockIfExists(final String id, final MacroRegister register) {
        return register.getMacroLocal(id)
                .filter(m -> m instanceof MockImplementation).map(m -> (MockImplementation) m);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy