/*
* The MIT License
*
* Copyright (c) 2016 Steven G. Brown
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.plugins.timestamper.action;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import hudson.plugins.timestamper.format.ElapsedTimestampFormat;
import hudson.plugins.timestamper.format.SystemTimestampFormat;
import nl.jqno.equalsverifier.EqualsVerifier;
import nl.jqno.equalsverifier.Warning;
/**
* Unit test for the {@link TimestampsActionQuery} class.
*
* @author Steven G. Brown
*/
@RunWith(Parameterized.class)
public class TimestampsActionQueryTest {
private static final Optional<Integer> NO_ENDLINE = Optional.absent();
private static final Optional<String> NO_TIMEZONE = Optional.absent();
private static final TimestampsActionQuery DEFAULT = new TimestampsActionQuery(0, NO_ENDLINE,
Collections.singletonList(new PrecisionTimestampFormat(3)), false, false);
/**
* @return the test data
*/
@Parameters(name = "{0}")
public static Collection<Object[]> data() {
List<Object[]> testCases = new ArrayList<Object[]>();
// No query
testCases.add(new Object[] { "", DEFAULT });
testCases.add(new Object[] { null, DEFAULT });
// Precision format
for (int precision = 0; precision <= 9; precision++) {
testCases
.add(new Object[] { "precision=" + precision, new TimestampsActionQuery(0, NO_ENDLINE,
Collections.singletonList(new PrecisionTimestampFormat(precision)), false, false) });
}
List<String> precisionStrings = Arrays.asList("seconds", "milliseconds", "microseconds",
"nanoseconds");
for (int i = 0; i < precisionStrings.size(); i++) {
testCases.add(new Object[] { "precision=" + precisionStrings.get(i),
new TimestampsActionQuery(0, NO_ENDLINE,
Collections.singletonList(new PrecisionTimestampFormat(i * 3)), false, false) });
}
testCases
.addAll(Arrays.asList(new Object[][] { { "precision=-1", IllegalArgumentException.class },
{ "precision=invalid", NumberFormatException.class } }));
// Time format
testCases.add(new Object[] { "time=dd:HH:mm:ss",
new TimestampsActionQuery(0, NO_ENDLINE,
Collections.singletonList(
new SystemTimestampFormat("dd:HH:mm:ss", NO_TIMEZONE, Locale.getDefault())),
false, false) });
testCases.add(new Object[] { "time=dd:HH:mm:ss&timeZone=GMT+10",
new TimestampsActionQuery(0, NO_ENDLINE, Collections.singletonList(
new SystemTimestampFormat("dd:HH:mm:ss", Optional.of("GMT+10"), Locale.getDefault())),
false, false) });
testCases.add(new Object[] { "time=dd:HH:mm:ss&timeZone=GMT-10",
new TimestampsActionQuery(0, NO_ENDLINE, Collections.singletonList(
new SystemTimestampFormat("dd:HH:mm:ss", Optional.of("GMT-10"), Locale.getDefault())),
false, false) });
testCases.add(new Object[] { "time=EEEE, d MMMM&locale=en",
new TimestampsActionQuery(0, NO_ENDLINE,
Collections.singletonList(
new SystemTimestampFormat("EEEE, d MMMM", NO_TIMEZONE, Locale.ENGLISH)),
false, false) });
testCases.add(new Object[] { "time=EEEE, d MMMM&locale=de",
new TimestampsActionQuery(0, NO_ENDLINE,
Collections.singletonList(
new SystemTimestampFormat("EEEE, d MMMM", NO_TIMEZONE, Locale.GERMAN)),
false, false) });
// Elapsed format
testCases.add(new Object[] { "elapsed=s.SSS", new TimestampsActionQuery(0, NO_ENDLINE,
Collections.singletonList(new ElapsedTimestampFormat("s.SSS")), false, false) });
// Multiple formats
testCases.add(new Object[] { "precision=0&precision=1",
new TimestampsActionQuery(0, NO_ENDLINE,
ImmutableList.of(new PrecisionTimestampFormat(0), new PrecisionTimestampFormat(1)),
false, false) });
testCases.add(new Object[] { "time=dd:HH:mm:ss&elapsed=s.SSS",
new TimestampsActionQuery(0, NO_ENDLINE,
ImmutableList.of(
new SystemTimestampFormat("dd:HH:mm:ss", NO_TIMEZONE, Locale.getDefault()),
new ElapsedTimestampFormat("s.SSS")),
false, false) });
// Start line and end line
List<Optional<Integer>> lineValues = ImmutableList.of(Optional.of(-1), Optional.of(0),
Optional.of(1), Optional.<Integer>absent());
for (Optional<Integer> startLine : lineValues) {
for (Optional<Integer> endLine : lineValues) {
List<String> params = new ArrayList<String>();
if (startLine.isPresent()) {
params.add("startLine=" + startLine.get());
}
if (endLine.isPresent()) {
params.add("endLine=" + endLine.get());
}
String query = Joiner.on('&').join(params);
if (!query.isEmpty()) {
testCases.add(new Object[] { query, new TimestampsActionQuery(startLine.or(0), endLine,
DEFAULT.timestampFormats, false, false) });
}
}
}
testCases.add(new Object[] { "startLine=invalid", NumberFormatException.class });
testCases.add(new Object[] { "endLine=invalid", NumberFormatException.class });
// Append log line
Map<String, Boolean> appendLogParams = ImmutableMap.of("appendLog", true, "appendLog=true",
true, "appendLog=false", false);
for (Map.Entry<String, Boolean> mapEntry : appendLogParams.entrySet()) {
String appendLogParam = mapEntry.getKey();
boolean appendLog = mapEntry.getValue();
testCases.add(new Object[] { appendLogParam,
new TimestampsActionQuery(0, NO_ENDLINE, DEFAULT.timestampFormats, appendLog, false) });
testCases.add(
new Object[] { "precision=0&" + appendLogParam, new TimestampsActionQuery(0, NO_ENDLINE,
Collections.singletonList(new PrecisionTimestampFormat(0)), appendLog, false) });
testCases.add(
new Object[] { appendLogParam + "&precision=0", new TimestampsActionQuery(0, NO_ENDLINE,
Collections.singletonList(new PrecisionTimestampFormat(0)), appendLog, false) });
}
// Current time
Map<String, Boolean> currentTimeParams = ImmutableMap.of("currentTime", true,
"currentTime=true", true, "currentTime=false", false);
for (Map.Entry<String, Boolean> mapEntry : currentTimeParams.entrySet()) {
String currentTimeParam = mapEntry.getKey();
boolean currentTime = mapEntry.getValue();
testCases.add(new Object[] { currentTimeParam,
new TimestampsActionQuery(0, NO_ENDLINE, DEFAULT.timestampFormats, false, currentTime) });
testCases.add(
new Object[] { "precision=0&" + currentTimeParam, new TimestampsActionQuery(0, NO_ENDLINE,
Collections.singletonList(new PrecisionTimestampFormat(0)), false, currentTime) });
testCases.add(
new Object[] { currentTimeParam + "&precision=0", new TimestampsActionQuery(0, NO_ENDLINE,
Collections.singletonList(new PrecisionTimestampFormat(0)), false, currentTime) });
}
return testCases;
}
/**
*/
@Parameter(0)
public String queryString;
/**
*/
@Parameter(1)
public Object expectedResult;
/**
*/
@Rule
public ExpectedException thrown = ExpectedException.none();
/**
*/
@Test
public void testCreate() {
if (expectedResult instanceof Class<?>) {
@SuppressWarnings("unchecked")
Class<? extends Throwable> expectedThrowable = (Class<? extends Throwable>) expectedResult;
thrown.expect(expectedThrowable);
}
TimestampsActionQuery query = TimestampsActionQuery.create(queryString);
assertThat(query, is(expectedResult));
}
/**
* @throws Exception
*/
@Test
public void testCreate_changeCaseOfQueryParameterNames() throws Exception {
queryString = changeCaseOfQueryParameterNames(queryString);
testCreate();
}
/**
*/
@Test
public void testEqualsAndHashCode() {
EqualsVerifier.forClass(TimestampsActionQuery.class).suppress(Warning.NULL_FIELDS).verify();
}
/**
* Change the case of all query parameter names.
*
* @param query
* @return the modified query
*/
private String changeCaseOfQueryParameterNames(String query) {
if (Strings.isNullOrEmpty(query)) {
return query;
}
Pattern paramNamePattern = Pattern.compile("(^|\\&)(.+?)(\\=|\\&|$)");
Matcher m = paramNamePattern.matcher(query);
StringBuffer sb = new StringBuffer();
while (m.find()) {
String name = m.group();
name = (name.toLowerCase().equals(name) ? name.toUpperCase() : name.toLowerCase());
m.appendReplacement(sb, name);
}
m.appendTail(sb);
String result = sb.toString();
if (result.equals(query)) {
throw new IllegalStateException("Invalid test. No changes made to query: " + query);
}
return result;
}
}