Skip to content

Commit

Permalink
add rangeLimit to JinjavaConfig (1000 by default)
Browse files Browse the repository at this point in the history
  • Loading branch information
ylacaute committed Apr 29, 2021
1 parent 8fcfe60 commit 27cf68c
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 12 deletions.
14 changes: 14 additions & 0 deletions src/main/java/com/hubspot/jinjava/JinjavaConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
**********************************************************************/
package com.hubspot.jinjava;

import static com.hubspot.jinjava.lib.fn.Functions.DEFAULT_RANGE_LIMIT;

import com.hubspot.jinjava.el.JinjavaInterpreterResolver;
import com.hubspot.jinjava.interpret.Context;
import com.hubspot.jinjava.interpret.Context.Library;
Expand Down Expand Up @@ -56,6 +58,7 @@ public class JinjavaConfig {
private final long maxStringLength;
private final int maxListSize;
private final int maxMapSize;
private final int rangeLimit;
private final InterpreterFactory interpreterFactory;
private TokenScannerSymbols tokenScannerSymbols;
private final ELResolver elResolver;
Expand Down Expand Up @@ -107,6 +110,7 @@ private JinjavaConfig(Builder builder) {
maxStringLength = builder.maxStringLength;
maxListSize = builder.maxListSize;
maxMapSize = builder.maxMapSize;
rangeLimit = builder.rangeLimit;
interpreterFactory = builder.interpreterFactory;
tokenScannerSymbols = builder.tokenScannerSymbols;
elResolver = builder.elResolver;
Expand Down Expand Up @@ -142,6 +146,10 @@ public int getMaxMapSize() {
return maxMapSize;
}

public int getRangeLimit() {
return rangeLimit;
}

public RandomNumberGeneratorStrategy getRandomNumberGeneratorStrategy() {
return randomNumberGenerator;
}
Expand Down Expand Up @@ -233,6 +241,7 @@ public static class Builder {
RandomNumberGeneratorStrategy.THREAD_LOCAL;
private boolean validationMode = false;
private long maxStringLength = 0;
private int rangeLimit = DEFAULT_RANGE_LIMIT;
private InterpreterFactory interpreterFactory = new JinjavaInterpreterFactory();
private TokenScannerSymbols tokenScannerSymbols = new DefaultTokenScannerSymbols();
private ELResolver elResolver = JinjavaInterpreterResolver.DEFAULT_RESOLVER_READ_ONLY;
Expand Down Expand Up @@ -343,6 +352,11 @@ public Builder withMaxMapSize(int maxMapSize) {
return this;
}

public Builder withRangeLimit(int rangeLimit) {
this.rangeLimit = rangeLimit;
return this;
}

public Builder withInterperterFactory(InterpreterFactory interperterFactory) {
this.interpreterFactory = interperterFactory;
return this;
Expand Down
26 changes: 17 additions & 9 deletions src/main/java/com/hubspot/jinjava/lib/fn/Functions.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.hubspot.jinjava.lib.fn;

import static com.hubspot.jinjava.interpret.JinjavaInterpreter.getCurrent;
import static com.hubspot.jinjava.util.Logging.ENGINE_LOG;
import static java.util.Objects.requireNonNull;

import com.google.common.collect.Lists;
import com.hubspot.jinjava.JinjavaConfig;
Expand Down Expand Up @@ -34,7 +36,7 @@ public class Functions {
public static final String STRING_TO_TIME_FUNCTION = "stringToTime";
public static final String STRING_TO_DATE_FUNCTION = "stringToDate";

public static final int RANGE_LIMIT = 1000;
public static final int DEFAULT_RANGE_LIMIT = 1000;

@JinjavaDoc(
value = "Only usable within blocks, will render the contents of the parent block by calling super.",
Expand All @@ -50,7 +52,7 @@ public class Functions {
}
)
public static String renderSuperBlock() {
JinjavaInterpreter interpreter = JinjavaInterpreter.getCurrent();
JinjavaInterpreter interpreter = getCurrent();
LengthLimitingStringBuilder result = new LengthLimitingStringBuilder(
interpreter.getConfig().getMaxOutputSize()
);
Expand Down Expand Up @@ -386,15 +388,21 @@ public static int movePointerToJustBeforeLastWord(int pointer, String s) {
"With two parameters, the range will start at the first value and increment by 1 up to (but not including) the second value. " +
"The third parameter specifies the step increment. All values can be negative. Impossible ranges will return an empty list. " +
"Ranges can generate a maximum of " +
RANGE_LIMIT +
" values.",
DEFAULT_RANGE_LIMIT +
" values by default, but this integer value is configurable.",
params = {
@JinjavaParam(value = "start", type = "number", defaultValue = "0"),
@JinjavaParam(value = "end", type = "number"),
@JinjavaParam(value = "step", type = "number", defaultValue = "1")
}
)
public static List<Integer> range(Object arg1, Object... args) {
int rangeLimit = requireNonNull(
JinjavaInterpreter.getCurrent(),
"No JinjavaInterpreter instance available to use range function"
)
.getConfig()
.getRangeLimit();
List<Integer> result = new ArrayList<>();

int start = 0;
Expand All @@ -404,19 +412,19 @@ public static List<Integer> range(Object arg1, Object... args) {
switch (args.length) {
case 0:
if (NumberUtils.isNumber(arg1.toString())) {
end = NumberUtils.toInt(arg1.toString(), RANGE_LIMIT);
end = NumberUtils.toInt(arg1.toString(), rangeLimit);
}
break;
case 1:
start = NumberUtils.toInt(arg1.toString());
if (args[0] != null && NumberUtils.isNumber(args[0].toString())) {
end = NumberUtils.toInt(args[0].toString(), start + RANGE_LIMIT);
end = NumberUtils.toInt(args[0].toString(), start + rangeLimit);
}
break;
default:
start = NumberUtils.toInt(arg1.toString());
if (args[0] != null && NumberUtils.isNumber(args[0].toString())) {
end = NumberUtils.toInt(args[0].toString(), start + RANGE_LIMIT);
end = NumberUtils.toInt(args[0].toString(), start + rangeLimit);
}
if (args[1] != null) {
step = NumberUtils.toInt(args[1].toString(), 1);
Expand All @@ -433,7 +441,7 @@ public static List<Integer> range(Object arg1, Object... args) {
}

for (int i = start; i < end; i += step) {
if (result.size() >= RANGE_LIMIT) {
if (result.size() >= rangeLimit) {
break;
}
result.add(i);
Expand All @@ -444,7 +452,7 @@ public static List<Integer> range(Object arg1, Object... args) {
}

for (int i = start; i > end; i += step) {
if (result.size() >= RANGE_LIMIT) {
if (result.size() >= rangeLimit) {
break;
}
result.add(i);
Expand Down
54 changes: 51 additions & 3 deletions src/test/java/com/hubspot/jinjava/lib/fn/RangeFunctionTest.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,42 @@
package com.hubspot.jinjava.lib.fn;

import static com.hubspot.jinjava.interpret.JinjavaInterpreter.pushCurrent;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import com.hubspot.jinjava.Jinjava;
import com.hubspot.jinjava.JinjavaConfig;
import com.hubspot.jinjava.LegacyOverrides;
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
import java.util.Arrays;
import java.util.Collections;
import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class RangeFunctionTest {
private JinjavaConfig config;

@Before
public void beforeEach() {
config = JinjavaConfig.newBuilder().build();
Jinjava jinjava = new Jinjava(config);
pushCurrent(new JinjavaInterpreter(jinjava.newInterpreter()));
}

@After
public void afterEach() {
JinjavaInterpreter.popCurrent();
}

@Test
public void interpreterInstanceIsMandatory() {
JinjavaInterpreter.popCurrent();
assertThatThrownBy(() -> Functions.range(1))
.isInstanceOf(NullPointerException.class)
.hasMessage("No JinjavaInterpreter instance available to use range function");
}

@Test
public void itGeneratesSimpleRanges() {
Expand Down Expand Up @@ -43,9 +73,27 @@ public void itHandlesBadValues() {
}

@Test
public void itTruncatesHugeRanges() {
assertThat(Functions.range(2, 200000000).size()).isEqualTo(Functions.RANGE_LIMIT);
public void itTruncatesRangeToDefaultRangeLimit() {
int defaultRangeLimit = config.getRangeLimit();
assertThat(defaultRangeLimit).isEqualTo(Functions.DEFAULT_RANGE_LIMIT);
assertThat(Functions.range(2, 200000000).size()).isEqualTo(defaultRangeLimit);
assertThat(Functions.range(Long.MAX_VALUE - 1, Long.MAX_VALUE).size())
.isEqualTo(defaultRangeLimit);
}

@Test
public void itTruncatesRangeToCustomRangeLimit() {
JinjavaInterpreter.popCurrent();
int customRangeLimit = 10;
JinjavaConfig customConfig = JinjavaConfig
.newBuilder()
.withRangeLimit(customRangeLimit)
.build();
pushCurrent(new JinjavaInterpreter(new Jinjava(customConfig).newInterpreter()));
assertThat(customConfig.getRangeLimit()).isEqualTo(customRangeLimit);

assertThat(Functions.range(20).size()).isEqualTo(customRangeLimit);
assertThat(Functions.range(Long.MAX_VALUE - 1, Long.MAX_VALUE).size())
.isEqualTo(Functions.RANGE_LIMIT);
.isEqualTo(customRangeLimit);
}
}

0 comments on commit 27cf68c

Please sign in to comment.