package com.github.fge.grappa.misc;
import com.github.fge.grappa.parsers.BaseParser;
import com.github.fge.grappa.rules.Rule;
import com.google.common.collect.Range;
import org.mockito.ArgumentCaptor;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.Random;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.same;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.only;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
public final class RangeMatcherBuilderTest
{
private static final Random RANDOM = new Random(System.currentTimeMillis());
@SuppressWarnings("InstanceVariableMayNotBeInitialized")
private Rule rule;
@SuppressWarnings("InstanceVariableMayNotBeInitialized")
private BaseParser<Object> parser;
@SuppressWarnings("InstanceVariableMayNotBeInitialized")
private TestBuilder builder;
@SuppressWarnings({ "unchecked", "UnsecureRandomNumberGeneration" })
@BeforeMethod
public void initParser()
{
rule = mock(Rule.class);
parser = mock(BaseParser.class);
builder = spy(new TestBuilder(parser, rule));
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void minDelegateTest()
{
final int cycles = nextInt();
final ArgumentCaptor<Range> captor
= ArgumentCaptor.forClass(Range.class);
builder.min(cycles);
verify(builder).range(captor.capture());
final Range<Integer> range = captor.getValue();
assertThat(range).isEqualTo(Range.atLeast(cycles));
}
@Test(dependsOnMethods = "minDelegateTest")
public void minTest()
{
final int cycles = nextInt();
builder.range(Range.atLeast(cycles));
verify(builder).boundedDown(cycles);
verifyZeroInteractions(parser);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void maxDelegateTest()
{
final int cycles = nextInt();
final ArgumentCaptor<Range> captor
= ArgumentCaptor.forClass(Range.class);
builder.max(cycles);
verify(builder).range(captor.capture());
final Range<Integer> range = captor.getValue();
assertThat(range).isEqualTo(Range.atMost(cycles));
}
@Test(dependsOnMethods = "maxDelegateTest")
public void maxTest()
{
final int cycles = 3;
builder.max(cycles);
verify(builder).boundedUp(cycles);
verifyZeroInteractions(parser);
}
@Test(dependsOnMethods = "maxDelegateTest")
public void maxZeroTest()
{
builder.range(Range.atMost(0));
verify(builder, never()).boundedUp(anyInt());
verify(parser, only()).empty();
}
@Test(dependsOnMethods = "maxDelegateTest")
public void maxOneTest()
{
builder.range(Range.atMost(1));
verify(builder, never()).boundedUp(anyInt());
verify(parser, only()).optional(same(rule));
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void singleArgumentTimeDelegateTest()
{
final int cycles = nextInt();
builder.times(cycles);
final ArgumentCaptor<Range> captor
= ArgumentCaptor.forClass(Range.class);
verify(builder).range(captor.capture());
final Range<Integer> range = captor.getValue();
assertThat(range).isEqualTo(Range.singleton(cycles));
}
@Test(dependsOnMethods = "singleArgumentTimeDelegateTest")
public void singleArgumentTimesTest()
{
final int cycles = 3;
builder.times(cycles);
verify(builder).exactly(cycles);
verifyZeroInteractions(parser);
}
@Test(dependsOnMethods = "singleArgumentTimeDelegateTest")
public void timesZeroTest()
{
builder.times(0);
verify(builder, never()).exactly(anyInt());
verify(parser, only()).empty();
}
@Test(dependsOnMethods = "singleArgumentTimeDelegateTest")
public void timesOneTest()
{
final Rule actual = builder.times(1);
verify(builder, never()).exactly(anyInt());
verifyZeroInteractions(parser);
assertThat(actual).isSameAs(rule);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void twoArgumentsTimesDelegateTest()
{
final int minCycles = nextInt() / 2;
final int maxCycles = minCycles + 1;
builder.times(minCycles, maxCycles);
final ArgumentCaptor<Range> captor
= ArgumentCaptor.forClass(Range.class);
verify(builder).range(captor.capture());
final Range<Integer> range = captor.getValue();
assertThat(range).isEqualTo(Range.closed(minCycles, maxCycles));
}
@Test(dependsOnMethods = "twoArgumentsTimesDelegateTest")
public void twoArgumentsTimesTest()
{
final int minCycles = 3;
final int maxCycles = 5;
builder.times(minCycles, maxCycles);
verify(builder).boundedBoth(minCycles, maxCycles);
verifyZeroInteractions(parser);
}
@Test(dependsOnMethods = "twoArgumentsTimesDelegateTest")
public void twoArgumentsTimesZeroTest()
{
builder.times(0, 0);
verify(builder, never()).boundedBoth(anyInt(), anyInt());
verify(parser, only()).empty();
}
@Test(dependsOnMethods = "twoArgumentsTimesDelegateTest")
public void twoArgumentsTimesZeroOneTest()
{
builder.times(0, 1);
verify(builder, never()).boundedBoth(anyInt(), anyInt());
verify(parser, only()).optional(same(rule));
}
@Test(dependsOnMethods = "twoArgumentsTimesDelegateTest")
public void twoArgumentsTimesOneTest()
{
final Rule actual = builder.times(1, 1);
verify(builder, never()).boundedBoth(anyInt(), anyInt());
verifyZeroInteractions(parser);
assertThat(actual).isSameAs(rule);
}
@SuppressWarnings("ClassWithOnlyPrivateConstructors")
private static class TestBuilder
extends RangeMatcherBuilder<Object>
{
private TestBuilder(final BaseParser<Object> parser, final Rule rule)
{
super(parser, rule);
}
@Override
protected Rule boundedDown(final int minCycles)
{
return null;
}
@Override
protected Rule boundedUp(final int maxCycles)
{
return null;
}
@Override
protected Rule exactly(final int nrCycles)
{
return null;
}
@Override
protected Rule boundedBoth(final int minCycles, final int maxCycles)
{
return null;
}
}
private static int nextInt(final int minValue)
{
int ret;
do {
ret = RANDOM.nextInt();
} while (ret < minValue);
return ret;
}
private static int nextInt()
{
return nextInt(0);
}
}