/* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2019 Niels Basjes * * 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 * * https://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 nl.basjes.parse.core; import nl.basjes.parse.core.exceptions.DissectionFailure; import org.junit.Test; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import static nl.basjes.parse.core.Casts.DOUBLE_ONLY; import static nl.basjes.parse.core.Casts.LONG_ONLY; import static nl.basjes.parse.core.Casts.NO_CASTS; import static nl.basjes.parse.core.Casts.STRING_ONLY; import static nl.basjes.parse.core.Casts.STRING_OR_DOUBLE; import static nl.basjes.parse.core.Casts.STRING_OR_LONG; import static nl.basjes.parse.core.Casts.STRING_OR_LONG_OR_DOUBLE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class ParserCastsTest { public static class TestDissector extends Dissector { public TestDissector() { // Empty } @Override public void dissect(Parsable<?> parsable, final String inputname) throws DissectionFailure { parsable.addDissection(inputname, "OUTPUT_TYPE", "string_null", (String)null); parsable.addDissection(inputname, "OUTPUT_TYPE", "string_good", "123"); parsable.addDissection(inputname, "OUTPUT_TYPE", "long_null", (String)null); parsable.addDissection(inputname, "OUTPUT_TYPE", "long_bad", "Something"); parsable.addDissection(inputname, "OUTPUT_TYPE", "long_good", "123"); parsable.addDissection(inputname, "OUTPUT_TYPE", "double_null", (String)null); parsable.addDissection(inputname, "OUTPUT_TYPE", "double_bad", "Something"); parsable.addDissection(inputname, "OUTPUT_TYPE", "double_good", "123"); parsable.addDissection(inputname, "OUTPUT_TYPE", "string_long_null", (String)null); parsable.addDissection(inputname, "OUTPUT_TYPE", "string_double_null", (String)null); parsable.addDissection(inputname, "OUTPUT_TYPE", "multi_null", (String)null); parsable.addDissection(inputname, "OUTPUT_TYPE", "string_long_good", "123"); parsable.addDissection(inputname, "OUTPUT_TYPE", "string_double_good", "123"); parsable.addDissection(inputname, "OUTPUT_TYPE", "multi_good", "123"); } @Override public String getInputType() { return "INPUT_TYPE"; } @Override public List<String> getPossibleOutput() { List<String> result = new ArrayList<>(); result.add("OUTPUT_TYPE:string_null"); result.add("OUTPUT_TYPE:string_good"); result.add("OUTPUT_TYPE:long_null"); result.add("OUTPUT_TYPE:long_bad"); result.add("OUTPUT_TYPE:long_good"); result.add("OUTPUT_TYPE:double_null"); result.add("OUTPUT_TYPE:double_bad"); result.add("OUTPUT_TYPE:double_good"); result.add("OUTPUT_TYPE:string_long_null"); result.add("OUTPUT_TYPE:string_double_null"); result.add("OUTPUT_TYPE:multi_null"); result.add("OUTPUT_TYPE:string_long_good"); result.add("OUTPUT_TYPE:string_double_good"); result.add("OUTPUT_TYPE:multi_good"); return result; } private static final Map<String, EnumSet<Casts>> PREPARE_FOR_DISSECT_MAP = new HashMap<>(); static { PREPARE_FOR_DISSECT_MAP.put("string_null", STRING_ONLY); PREPARE_FOR_DISSECT_MAP.put("string_good", STRING_ONLY); PREPARE_FOR_DISSECT_MAP.put("long_null", LONG_ONLY); PREPARE_FOR_DISSECT_MAP.put("long_bad", LONG_ONLY); PREPARE_FOR_DISSECT_MAP.put("long_good", LONG_ONLY); PREPARE_FOR_DISSECT_MAP.put("double_null", DOUBLE_ONLY); PREPARE_FOR_DISSECT_MAP.put("double_bad", DOUBLE_ONLY); PREPARE_FOR_DISSECT_MAP.put("double_good", DOUBLE_ONLY); PREPARE_FOR_DISSECT_MAP.put("string_long_null", STRING_OR_LONG); PREPARE_FOR_DISSECT_MAP.put("string_double_null", STRING_OR_DOUBLE); PREPARE_FOR_DISSECT_MAP.put("multi_null", STRING_OR_LONG_OR_DOUBLE); PREPARE_FOR_DISSECT_MAP.put("string_long_good", STRING_OR_LONG); PREPARE_FOR_DISSECT_MAP.put("string_double_good", STRING_OR_DOUBLE); PREPARE_FOR_DISSECT_MAP.put("multi_good", STRING_OR_LONG_OR_DOUBLE); } @Override public EnumSet<Casts> prepareForDissect(String inputname, String outputname) { return PREPARE_FOR_DISSECT_MAP.getOrDefault(outputname, NO_CASTS); } } public static class TestParser<RECORD> extends Parser<RECORD> { public TestParser(final Class<RECORD> clazz) { super(clazz); addDissector(new TestDissector()); setRootType("INPUT_TYPE"); } } public static class TestRecord { private int count = 0; @Field({"OUTPUT_TYPE:string_null", "OUTPUT_TYPE:string_long_null", "OUTPUT_TYPE:string_double_null", "OUTPUT_TYPE:multi_null"}) public void setStringNull(String value) { assertEquals(null, value); count++; } @Field({"OUTPUT_TYPE:string_good", "OUTPUT_TYPE:string_long_good", "OUTPUT_TYPE:string_double_good", "OUTPUT_TYPE:multi_good"}) public void setStringGood(String value) { assertEquals("123", value); count++; } @Field({"OUTPUT_TYPE:long_null", "OUTPUT_TYPE:long_bad", "OUTPUT_TYPE:string_long_null", "OUTPUT_TYPE:multi_null"}) public void setLongNull(Long value) { assertEquals(null, value); count++; } @Field({"OUTPUT_TYPE:long_good", "OUTPUT_TYPE:string_long_good", "OUTPUT_TYPE:multi_good"}) public void setLongGood(Long value) { assertEquals(Long.valueOf(123L), value); count++; } @Field({"OUTPUT_TYPE:double_null", "OUTPUT_TYPE:double_bad", "OUTPUT_TYPE:string_double_null", "OUTPUT_TYPE:multi_null"}) public void setDoubleNull(Double value) { assertEquals(null, value); count++; } @Field({"OUTPUT_TYPE:double_good", "OUTPUT_TYPE:string_double_good", "OUTPUT_TYPE:multi_good"}) public void setDoubleGood(Double value) { assertEquals(123D, value, 0.0001D); count++; } @SuppressWarnings("UnusedParameters") @Field({"OUTPUT_TYPE:long_null", "OUTPUT_TYPE:long_bad", "OUTPUT_TYPE:long_good", "OUTPUT_TYPE:string_long_null", "OUTPUT_TYPE:string_long_good"}) public void setLongWrongSignature(String name, Double value) { fail("This setter uses Double but that is not allowed for \""+name+"\" "); } @SuppressWarnings("UnusedParameters") @Field({"OUTPUT_TYPE:double_null", "OUTPUT_TYPE:double_bad", "OUTPUT_TYPE:double_good", "OUTPUT_TYPE:string_double_null", "OUTPUT_TYPE:string_double_good"}) public void setDoubleWrongSignature(String name, Long value) { fail("This setter uses Long but that is not allowed for \""+name+"\" "); } } @Test public void testValidCasting() throws Exception { Parser<TestRecord> parser = new TestParser<>(TestRecord.class); TestRecord output = new TestRecord(); parser.parse(output, "Something"); assertEquals(22, output.count); Map<String, EnumSet<Casts>> allCasts = parser.getAllCasts(); assertEquals(STRING_ONLY, allCasts.get("OUTPUT_TYPE:string_good")); assertEquals(LONG_ONLY, allCasts.get("OUTPUT_TYPE:long_good")); assertEquals(DOUBLE_ONLY, allCasts.get("OUTPUT_TYPE:double_good")); assertEquals(STRING_OR_LONG, allCasts.get("OUTPUT_TYPE:string_long_good")); assertEquals(STRING_OR_DOUBLE, allCasts.get("OUTPUT_TYPE:string_double_good")); assertEquals(STRING_OR_LONG_OR_DOUBLE, allCasts.get("OUTPUT_TYPE:multi_good")); assertEquals(STRING_ONLY, parser.getCasts("OUTPUT_TYPE:string_good")); assertEquals(LONG_ONLY, parser.getCasts("OUTPUT_TYPE:long_good")); assertEquals(DOUBLE_ONLY, parser.getCasts("OUTPUT_TYPE:double_good")); assertEquals(STRING_OR_LONG, parser.getCasts("OUTPUT_TYPE:string_long_good")); assertEquals(STRING_OR_DOUBLE, parser.getCasts("OUTPUT_TYPE:string_double_good")); assertEquals(STRING_OR_LONG_OR_DOUBLE, parser.getCasts("OUTPUT_TYPE:multi_good")); } }