/*
* Lilith - a log event viewer.
* Copyright (C) 2007-2016 Joern Huxhorn
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright 2007-2016 Joern Huxhorn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.huxhorn.lilith.data.logging;
import de.huxhorn.sulky.formatting.SafeString;
import java.util.Arrays;
public class MessageFormatterUseCases
{
public static UseCase[] generateUseCases()
{
Integer i1 = 1;
Integer i2 = 2;
Integer i3 = 3;
//noinspection ThrowableInstanceNeverThrown
Throwable t = new FooThrowable("FooThrowable");
Integer[] p1 = new Integer[]{i2, i3};
Object[] multiArray = new Object[]{null, p1};
Object[] multiArrayRecursive = new Object[]{null, p1};
multiArrayRecursive[0] = multiArrayRecursive;
multiArray[0] = multiArrayRecursive;
String multiArrayRecId = SafeString.identityToString(multiArrayRecursive);
String multiArrayRec = SafeString.RECURSION_PREFIX + multiArrayRecId + SafeString.RECURSION_SUFFIX;
Integer[] ia0 = new Integer[]{i1, i2, i3};
Integer[] ia1 = new Integer[]{10, 20, 30};
Object[][] multiOA = new Object[][]{ia0, ia1};
Object[][][] multiOATwice = new Object[][][]{multiOA, multiOA};
Object[] cyclicA = new Object[1];
cyclicA[0] = cyclicA;
String cyclicAId = SafeString.identityToString(cyclicA);
Object[] recArray;
Object[] cyclicB = new Object[2];
{
cyclicB[0] = i1;
Object[] c = new Object[]{i3, cyclicB};
Object[] b = new Object[]{i2, c};
recArray = b;
cyclicB[1] = b;
}
String cyclicBRecId = SafeString.identityToString(recArray);
Object[] cyclicC = new Object[3];
{
cyclicC[0] = i1;
Object[] c = new Object[]{i3, cyclicC};
Object[] b = new Object[]{i2, c};
recArray = b;
cyclicC[1] = b;
cyclicC[2] = t;
}
String cyclicCRecId = SafeString.identityToString(recArray);
String cyclicARec = SafeString.RECURSION_PREFIX + cyclicAId + SafeString.RECURSION_SUFFIX;
String cyclicBRec = SafeString.RECURSION_PREFIX + cyclicBRecId + SafeString.RECURSION_SUFFIX;
String cyclicCRec = SafeString.RECURSION_PREFIX + cyclicCRecId + SafeString.RECURSION_SUFFIX;
return new UseCase[]{
new UseCase("Null message", null, new Object[]{}, 0, null),
new UseCase("Null message", null, new Object[]{i1, i2, i3, t}, 0, null, t),
new UseCase("Null params", "Value is {}.", new Object[]{null}, 1, "Value is null."),
new UseCase("Null params", "Val1 is {}, val2 is {}.", new Object[]{null, null}, 2, "Val1 is null, val2 is null."),
new UseCase("Null params", "Val1 is {}, val2 is {}.", new Object[]{i1, null}, 2, "Val1 is 1, val2 is null."),
new UseCase("Null params", "Val1 is {}, val2 is {}.", new Object[]{null, i2}, 2, "Val1 is null, val2 is 2."),
new UseCase("Null params", "Val1 is {}, val2 is {}, val3 is {}", new Object[]{null, null, null}, 3, "Val1 is null, val2 is null, val3 is null"),
new UseCase("Null params", "Val1 is {}, val2 is {}, val3 is {}", new Object[]{null, i2, i3}, 3, "Val1 is null, val2 is 2, val3 is 3"),
new UseCase("Null params", "Val1 is {}, val2 is {}, val3 is {}", new Object[]{null, null, i3}, 3, "Val1 is null, val2 is null, val3 is 3"),
new UseCase("One param", "Value is {}.", new Object[]{i3}, 1, "Value is 3."),
new UseCase("One param", "Value is {", new Object[]{i3}, 0, "Value is {"),
new UseCase("One param", "{} is larger than 2.", new Object[]{i3}, 1, "3 is larger than 2."),
new UseCase("One param", "No subst", new Object[]{i3}, 0, "No subst"),
new UseCase("One param", "Incorrect {subst", new Object[]{i3}, 0, "Incorrect {subst"),
new UseCase("One param", "Value is {bla} {}", new Object[]{i3}, 1, "Value is {bla} 3"),
new UseCase("One param", "Value is \\{bla} {}", new Object[]{i3}, 1, "Value is \\{bla} 3"),
new UseCase("One param", "Escaped \\{} subst", new Object[]{i3}, 0, "Escaped {} subst"),
new UseCase("One param", "{Escaped", new Object[]{i3}, 0, "{Escaped"),
new UseCase("One param", "\\{}Escaped", new Object[]{i3}, 0, "{}Escaped"),
new UseCase("One param", "File name is {{}}.", new Object[]{"App folder.zip"}, 1, "File name is {App folder.zip}."),
new UseCase("One param", "File name is C:\\\\{}.", new Object[]{"App folder.zip"}, 1, "File name is C:\\App folder.zip."),
new UseCase("Two params", "Value {} is smaller than {}.", new Object[]{i1, i2}, 2, "Value 1 is smaller than 2."),
new UseCase("Two params", "Value {} is smaller than {}", new Object[]{i1, i2}, 2, "Value 1 is smaller than 2"),
new UseCase("Two params", "{}{}", new Object[]{i1, i2}, 2, "12"),
new UseCase("Special One param", "Val1={}, Val2={", new Object[]{i1, i2}, new String[]{"[1, 2]"}, 1, "Val1=[1, 2], Val2={", null),
new UseCase("Special One param", "Value {} is smaller than \\{}", new Object[]{i1, i2}, new String[]{"[1, 2]"}, 1, "Value [1, 2] is smaller than {}", null),
new UseCase("Special One param", "Value {} is smaller than \\{} tail", new Object[]{i1, i2}, new String[]{"[1, 2]"}, 1, "Value [1, 2] is smaller than {} tail", null),
new UseCase("Special One param", "Value {} is smaller than \\{", new Object[]{i1, i2}, new String[]{"[1, 2]"}, 1, "Value [1, 2] is smaller than \\{", null),
new UseCase("Special One param", "Value {} is smaller than {tail", new Object[]{i1, i2}, new String[]{"[1, 2]"}, 1, "Value [1, 2] is smaller than {tail", null),
new UseCase("Special One param", "Value \\{} is smaller than {}", new Object[]{i1, i2}, new String[]{"[1, 2]"}, 1, "Value {} is smaller than [1, 2]", null),
new UseCase("Null Array", "msg0", null, 0, "msg0"),
new UseCase("Null Array", "msg1 {}", null, 1, "msg1 {}"),
new UseCase("Null Array", "msg2 {} {}", null, 2, "msg2 {} {}"),
new UseCase("Null Array", "msg3 {} {} {}", null, 3, "msg3 {} {} {}"),
new UseCase("Array", "Value {} is smaller than {} and {}.", new Object[]{i1, i2, i3}, 3, "Value 1 is smaller than 2 and 3."),
new UseCase("Array", "{}{}{}", new Object[]{i1, i2, i3}, 3, "123"),
new UseCase("Array", "Value {} is smaller than {}.", new Object[]{i1, i2, i3}, 2, "Value 1 is smaller than 2."),
new UseCase("Array", "Value {} is smaller than {}", new Object[]{i1, i2, i3}, 2, "Value 1 is smaller than 2"),
new UseCase("Array", "Val={}, {, Val={}", new Object[]{i1, i2, i3}, 2, "Val=1, {, Val=2"),
new UseCase("Array", "Val={}, \\{, Val={}", new Object[]{i1, i2, i3}, 2, "Val=1, \\{, Val=2"),
new UseCase("Special One param", "Val1={}, Val2={", new Object[]{i1, i2, i3}, new String[]{"[1, 2, 3]"}, 1, "Val1=[1, 2, 3], Val2={", null),
new UseCase("Array & Throwable", "Value {} is smaller than {} and {}.", new Object[]{i1, i2, i3, t}, 3, "Value 1 is smaller than 2 and 3.", t),
new UseCase("Array & Throwable", "{}{}{}", new Object[]{i1, i2, i3, t}, 3, "123", t),
new UseCase("Array & Throwable", "Value {} is smaller than {}.", new Object[]{i1, i2, i3, t}, 2, "Value 1 is smaller than 2.", t),
new UseCase("Array & Throwable", "Value {} is smaller than {}", new Object[]{i1, i2, i3, t}, 2, "Value 1 is smaller than 2", t),
new UseCase("Array & Throwable", "Val={}, {, Val={}", new Object[]{i1, i2, i3, t}, 2, "Val=1, {, Val=2", t),
new UseCase("Array & Throwable", "Val1={}, Val2={", new Object[]{i1, i2, i3, t}, 1, "Val1=1, Val2={", t),
new UseCase("ArrayValues", "{}{}", new Object[]{i1, new Integer[]{i2, i3}, t}, 2, "1[2, 3]", t),
new UseCase("ArrayValues", "{}{}", new Object[]{"a", new Integer[]{i2, i3}, t}, 2, "a[2, 3]", t),
new UseCase("ArrayValues", "{}{}", new Object[]{"a", new byte[]{1, 2}, t}, new String[]{"a", "[0x01, 0x02]"}, 2, "a[0x01, 0x02]", t),
new UseCase("ArrayValues", "{}{}", new Object[]{"a", new int[]{1, 2}, t}, 2, "a[1, 2]", t),
new UseCase("ArrayValues", "{}{}", new Object[]{"a", new float[]{1, 2}, t}, 2, "a[1.0, 2.0]", t),
new UseCase("ArrayValues", "{}{}", new Object[]{"a", new double[]{1, 2}, t}, 2, "a[1.0, 2.0]", t), // missing short, long, boolean, char
new UseCase("MultiDimensionalArrayValues", "{}{}", new Object[]{"a", new Integer[][]{ia0, ia1}, t}, 2, "a[[1, 2, 3], [10, 20, 30]]", t),
new UseCase("MultiDimensionalArrayValues", "{}{}", new Object[]{"a", new int[][]{{1, 2}, {10, 20}}, t}, 2, "a[[1, 2], [10, 20]]", t),
new UseCase("MultiDimensionalArrayValues", "{}{}", new Object[]{"a", new float[][]{{1, 2}, {10, 20}}, t}, 2, "a[[1.0, 2.0], [10.0, 20.0]]", t),
new UseCase("MultiDimensionalArrayValues", "{}{}", new Object[]{"a", new double[][]{{1, 2}, {10, 20}}, t}, 2, "a[[1.0, 2.0], [10.0, 20.0]]", t),
new UseCase("MultiDimensionalArrayValues", "{}{}", new Object[]{"a", multiOA, t}, 2, "a[[1, 2, 3], [10, 20, 30]]", t),
new UseCase("MultiDimensionalArrayValues", "{}{}", new Object[]{"a", multiOATwice, t}, 2, "a[[[1, 2, 3], [10, 20, 30]], [[1, 2, 3], [10, 20, 30]]]", t),
new UseCase("CyclicArrays", "{}", new Object[]{cyclicA, t}, new String[]{"[" + cyclicARec + "]"}, 1, "[" + cyclicARec + "]", t),
new UseCase("CyclicArrays", "{}{}", cyclicB, new String[]{"1", "[2, [3, [1, " + cyclicBRec + "]]]"}, 2, "1[2, [3, [1, " + cyclicBRec + "]]]", null),
new UseCase("CyclicArrays", "{}{}", cyclicC, new String[]{"1", "[2, [3, [1, " + cyclicCRec + ", FooThrowable]]]"}, 2, "1[2, [3, [1, " + cyclicCRec + ", FooThrowable]]]", t),
new UseCase("CyclicArrays", "{}{}{}", cyclicC, new String[]{"1", "[2, [3, [1, " + cyclicCRec + ", FooThrowable]]]", "FooThrowable"}, 3, "1[2, [3, [1, " + cyclicCRec + ", FooThrowable]]]FooThrowable", null),
new UseCase("Array & Used Throwable", "Value {} is smaller than {} and {}. Also: {}!", new Object[]{i1, i2, i3, t}, 4, "Value 1 is smaller than 2 and 3. Also: " + t.toString() + "!"),
new UseCase("Array & Used Throwable", "{}{}{}{}", new Object[]{i1, i2, i3, t}, 4, "123" + t.toString()),
new UseCase("Escaping", "Value {} is smaller than \\\\{}", new Object[]{i1, i2, i3, t}, 2, "Value 1 is smaller than \\2", t),
new UseCase("Escaping", "Value {} is smaller than \\\\{} tail", new Object[]{i1, i2, i3, t}, 2, "Value 1 is smaller than \\2 tail", t),
new UseCase("Escaping", "Value {} is smaller than \\\\{", new Object[]{i1, i2, i3, t}, 1, "Value 1 is smaller than \\\\{", t),
new UseCase("Escaping", "Value {} is smaller than \\\\{tail", new Object[]{i1, i2, i3, t}, 1, "Value 1 is smaller than \\\\{tail", t),
new UseCase("Escaping", "Value \\\\{} is smaller than {}", new Object[]{i1, i2, i3, t}, 2, "Value \\1 is smaller than 2", t),
new UseCase("Escaping", "\\\\{}", new Object[]{i1, i2, i3, t}, 1, "\\1", t),
new UseCase("Escaping", "\\\\\\{}", new Object[]{i1, i2, i3, t}, 0, "\\{}", t),
new UseCase("Escaping", "\\\\\\\\{}", new Object[]{i1, i2, i3, t}, 1, "\\\\1", t),
new UseCase("Escaping", "\\{}", new Object[]{i1, i2, i3, t}, 0, "{}", t),
new UseCase("ArrayValues", "{}{}", new Object[]{i1, p1}, 2, i1 + Arrays.toString(p1)),
new UseCase("ArrayValues", "{}{}", new Object[]{"a", p1}, 2, "a" + Arrays.toString(p1)),
new UseCase("ArrayValues", "{}{}", new Object[]{"a", new byte[]{1, 2}}, new String[]{"a", "[0x01, 0x02]"}, 2, "a[0x01, 0x02]", null),
new UseCase("ArrayValues", "{}{}", new Object[]{"a", new short[]{1, 2}}, 2, "a" + Arrays.toString(new short[]{1, 2})),
new UseCase("ArrayValues", "{}{}", new Object[]{"a", new int[]{1, 2}}, 2, "a" + Arrays.toString(new int[]{1, 2})),
new UseCase("ArrayValues", "{}{}", new Object[]{"a", new long[]{1, 2}}, 2, "a" + Arrays.toString(new long[]{1, 2})),
new UseCase("ArrayValues", "{}{}", new Object[]{"a", new float[]{1, 2}}, 2, "a" + Arrays.toString(new float[]{1, 2})),
new UseCase("ArrayValues", "{}{}", new Object[]{"a", new double[]{1, 2}}, 2, "a" + Arrays.toString(new double[]{1, 2})),
new UseCase("ArrayValues", "{}{}", new Object[]{"a", new boolean[]{true, false}}, 2, "a" + Arrays.toString(new boolean[]{true, false})),
new UseCase("ArrayValues", "{}{}", new Object[]{"a", new char[]{'b', 'c'}}, 2, "a" + Arrays.toString(new char[]{'b', 'c'})),
new UseCase("ArrayValues", "{}{}", multiArray, new String[]{"[" + multiArrayRec + ", " + Arrays.toString(p1) + "]", Arrays.toString(p1)}, 2, "[" + multiArrayRec + ", " + Arrays.toString(p1) + "]" + Arrays.toString(p1), null),
new UseCase("SpecialOneArgument", "Special {}", new Object[]{"One", "Two", "Three"}, new String[]{"['One', 'Two', 'Three']"}, 1, "Special ['One', 'Two', 'Three']", null),
};
}
public static class UseCase
{
private final String messagePattern;
private final Object[] arguments;
private final int numberOfPlaceholders;
private final String expectedResult;
private final Throwable throwable;
private final String[] argumentStrings;
private final String section;
public UseCase(String section, String messagePattern, Object[] arguments, int numberOfPlaceholders, String expectedResult)
{
this(section, messagePattern, arguments, numberOfPlaceholders, expectedResult, null);
}
public UseCase(String section, String messagePattern, Object[] arguments, int numberOfPlaceholders, String expectedResult, Throwable throwable)
{
this.section = section;
this.messagePattern = messagePattern;
this.arguments = arguments;
this.numberOfPlaceholders = numberOfPlaceholders;
this.expectedResult = expectedResult;
this.throwable = throwable;
String[] argStrings = null;
if (arguments != null)
{
if (throwable != null)
{
argStrings = new String[arguments.length - 1];
}
else
{
argStrings = new String[arguments.length];
}
for (int i = 0; i < argStrings.length; i++)
{
argStrings[i] = getStringFor(arguments[i]);
}
}
this.argumentStrings = argStrings;
}
public UseCase(String section, String messagePattern, Object[] arguments, String[] argumentStrings, int numberOfPlaceholders, String expectedResult, Throwable throwable)
{
this.section = section;
this.messagePattern = messagePattern;
this.arguments = arguments;
this.numberOfPlaceholders = numberOfPlaceholders;
this.expectedResult = expectedResult;
this.throwable = throwable;
this.argumentStrings = argumentStrings;
}
/**
* I can't think of a better way to test this...
*
* @param o the Object to get a String for
* @return the String for the given Object
*/
private String getStringFor(Object o)
{
if (o == null)
{
return "null";
}
if (o instanceof String)
{
return (String) o;
}
if (o.getClass().isArray())
{
if (o instanceof short[])
{
return Arrays.toString((short[]) o);
}
if (o instanceof int[])
{
return Arrays.toString((int[]) o);
}
if (o instanceof long[])
{
return Arrays.toString((long[]) o);
}
if (o instanceof float[])
{
return Arrays.toString((float[]) o);
}
if (o instanceof double[])
{
return Arrays.toString((double[]) o);
}
else if (o instanceof boolean[])
{
return Arrays.toString((boolean[]) o);
}
else if (o instanceof char[])
{
return Arrays.toString((char[]) o);
}
else
{
return Arrays.deepToString((Object[]) o);
}
}
return o.toString();
}
public String getMessagePattern()
{
return messagePattern;
}
public Object[] getArguments()
{
return arguments;
}
public int getNumberOfPlaceholders()
{
return numberOfPlaceholders;
}
public String getExpectedResult()
{
return expectedResult;
}
public Throwable getThrowable()
{
return throwable;
}
public String[] getArgumentStrings()
{
return argumentStrings;
}
public MessageFormatter.ArgumentResult getArgumentResult()
{
MessageFormatter.ArgumentResult result = null;
if(argumentStrings != null)
{
result = new MessageFormatter.ArgumentResult(argumentStrings, throwable);
}
return result;
}
/**
* For informational purpose only.
*
* @return the section this usecase is part of.
*/
public String getSection()
{
return section;
}
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UseCase useCase = (UseCase) o;
if (numberOfPlaceholders != useCase.numberOfPlaceholders) return false;
// Probably incorrect - comparing Object[] arrays with Arrays.equals
if (!Arrays.equals(arguments, useCase.arguments)) return false;
if (expectedResult != null ? !expectedResult.equals(useCase.expectedResult) : useCase.expectedResult != null)
{
return false;
}
if (messagePattern != null ? !messagePattern.equals(useCase.messagePattern) : useCase.messagePattern != null)
{
return false;
}
if (throwable != null ? !throwable.equals(useCase.throwable) : useCase.throwable != null) return false;
return true;
}
public int hashCode()
{
int result;
result = (messagePattern != null ? messagePattern.hashCode() : 0);
result = 31 * result + (arguments != null ? Arrays.hashCode(arguments) : 0);
result = 31 * result + numberOfPlaceholders;
result = 31 * result + (expectedResult != null ? expectedResult.hashCode() : 0);
result = 31 * result + (throwable != null ? throwable.hashCode() : 0);
return result;
}
@Override
public String toString()
{
StringBuilder result = new StringBuilder();
result.append("UseCase[");
result.append("section=").append(section);
result.append(", ");
result.append("messagePattern=");
if (messagePattern == null)
{
result.append("null");
}
else
{
result.append("'").append(messagePattern).append("'");
}
result.append(", ");
result.append("arguments=");
if (arguments == null)
{
result.append("null");
}
else
{
result.append("[");
boolean isFirst = true;
for (Object argument : arguments)
{
if (isFirst)
{
isFirst = false;
}
else
{
result.append(", ");
}
result.append(argument);
}
result.append("]");
}
result.append(", ");
result.append("argumentStrings=");
if (argumentStrings == null)
{
result.append("null");
}
else
{
result.append("[");
boolean isFirst = true;
for (String argument : argumentStrings)
{
if (isFirst)
{
isFirst = false;
}
else
{
result.append(", ");
}
result.append(argument);
}
result.append("]");
}
result.append(", ");
result.append("numberOfPlaceholders=").append(numberOfPlaceholders);
result.append(", ");
result.append("expectedResult=");
if (expectedResult == null)
{
result.append("null");
}
else
{
result.append("'").append(expectedResult).append("'");
}
result.append(", ");
result.append("throwable=").append(throwable);
result.append("]");
return result.toString();
}
}
public static class FooThrowable
extends RuntimeException
{
private static final long serialVersionUID = 9140989200041952994L;
public FooThrowable(String s)
{
super(s);
}
@Override
public String toString()
{
return "" + getMessage();
}
}
}