<?xml version="1.0" encoding="UTF-8"?>
<test-data
    xmlns="http://pmd.sourceforge.net/rule-tests"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">

    <test-code>
        <description>OK, guard is here - log4j</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class Foo {
    private static final Logger logger = LogManager.getLogger(Foo.class);

    private void foo() {
        if ( logger.isDebugEnabled() )
            logger.debug("Debug statement:" + this);
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>ok, no error expected - apache commons logging</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;

public class Test {
    private static final Log __log = LogFactory.getLog(Test.class);
    public void test() {
        // good:
        if (__log.isDebugEnabled()) {
        __log.debug("bla" + this, e);
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Guarded call - OK - java util</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import java.util.logging.Level;
import java.util.logging.Logger;

public class Foo {

    private void foo(Logger logger) {
        if ( logger.isLoggable(Level.FINE) ) {
            logger.fine("debug message: " + this);
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>KO, missing guard 1 - log4j</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class Foo {
    private static final Logger logger = LogManager.getLogger(Foo.class);

    private void foo() {
        logger.debug("Debug statement: " + this);
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>KO, missing guard 2 - log4j</description>
        <rule-property name="logLevels">debug,trace</rule-property>
        <rule-property name="guardsMethods">isDebugEnabled,isTraceEnabled</rule-property>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class Foo {
    private static final Logger logger = LogManager.getLogger(Foo.class);

    private void foo() {
        logger.debug("Debug statement: " + this);
    }

    private void bar() {
        logger.info("No guard, but'is OK with properties configuration: " + this);
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Complex logging without guard - apache commons logging</description>
        <expected-problems>2</expected-problems>
        <code><![CDATA[
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;

public class Test {
    private static final Log __log = LogFactory.getLog(Test.class);
    public void test() {

        // bad:
        __log.debug("log something" + this + " and " + "concat strings");

        // bad:
        __log.debug("log something" + this + " and " + "concat strings", e);

        // good:
        if (__log.isDebugEnabled()) {
        __log.debug("bla" + this, e);
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Complex logging with misplaced guard - apache commons logging</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
import org.apache.commons.logging.LogFactory;
import org.apache.commons.loggong.Log;

public class Test {
    private static final Log __log = LogFactory.getLog(Test.class);
    public void test() {
        if (true) {
            // bad:
            __log.debug("log something" + this + " and " + "concat strings");
            // this is useless:
            __log.isDebugEnabled();
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Unguarded call - KO - java util</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
import java.util.logging.Logger;

public class Foo {

    private void foo(Logger logger) {
        logger.fine("debug message: " + this);
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>ok #1189 GuardLogStatementRule and GuardDebugLoggingRule broken for log4j2</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;

public class Test {
    public void test(String mymarker) {
        final Logger logger = LogManager.getLogger(Test.class);
        final Marker m = MarkerManager.getMarker(mymarker);
        if (logger.isDebugEnabled(m)) {
          logger.debug(m, message + "");
        }
        if (logger.isTraceEnabled(m)) {
          logger.trace(m, message + "");
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>violation - wrong guard #1189 GuardLogStatementRule and GuardDebugLoggingRule broken for log4j2</description>
        <expected-problems>2</expected-problems>
        <expected-linenumbers>11,14</expected-linenumbers>
        <code><![CDATA[
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;

public class Test {
    public void test(String mymarker) {
        final Logger logger = LogManager.getLogger(Test.class);
        final Marker m = MarkerManager.getMarker(mymarker);
        if (logger.isTraceEnabled(m)) { // should have been isDebugEnabled
          logger.debug(m, message + "");
        }
        if (logger.isDebugEnabled(m)) { // should have been isTraceEnabled
          logger.trace(m, message + "");
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>violation - no if #1189 GuardLogStatementRule and GuardDebugLoggingRule broken for log4j2</description>
        <expected-problems>1</expected-problems>
        <expected-linenumbers>11</expected-linenumbers>
        <code><![CDATA[
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;

public class Test {
    public void test(String mymarker) {
        final Logger logger = LogManager.getLogger(Test.class);
        final Marker m = MarkerManager.getMarker(mymarker);
        logger.isDebugEnabled(m); // must be within an if
        logger.debug(m, message + "");
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#1224 GuardDebugLogging broken in 5.1.1 - missing additive statement check in log statement - apache commons logging</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;

public class Test {
    private static final Log __log = LogFactory.getLog(Test.class);
    public void test() {
        // okay:
        __log.debug("log something");

        // okay:
        __log.debug("log something with exception", e);

        // good:
        if (__log.isDebugEnabled()) {
        __log.debug("bla: " + this, e);
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#1341 pmd:GuardDebugLogging violates LOGGER.debug with format "{}" - slf4j</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class GuardDebugFalsePositive {
    private static final Logger LOGGER = LoggerFactory.getLogger("GuardDebugFalsePositive");
    public void test() {
        String tempSelector = "a";
        LOGGER.debug("MessageSelector={}" , tempSelector);
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#1203 GuardLogStatementJavaUtil issues warning for severe level not being specified as property</description>
        <rule-property name="logLevels">finest,finer,fine,info</rule-property>
        <rule-property name="guardsMethods">isLoggable</rule-property>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import java.util.logging.Logger;
import java.util.logging.Level;

public class Foo {
    Logger LOGGER;

    public void foo() {
        LOGGER.severe("This is a severe message" + this + " and concat");
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#1227 GuardLogStatementJavaUtil doesn't catch log(Level.FINE, "msg" + " msg") calls</description>
        <expected-problems>1</expected-problems>
        <expected-linenumbers>8</expected-linenumbers>
        <code><![CDATA[
import java.util.logging.Logger;
import java.util.logging.Level;

public class Foo {
    Logger LOGGER;

    public void foo() {
        LOGGER.log(Level.FINE, "This is a severe message" + this + " and concat"); // violation
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.log(Level.FINE, "This is a severe message" + this + " and concat"); // no violation
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#1347 False positive for GuardLogStatementJavaUtil with slf4j</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import org.slf4j.Logger;

public class GuardLogTest {
    Logger LOG;
    public void foo() {
        if (LOG.isInfoEnabled()) {
            LOG.info("update: After spool map size: " + 1);
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#1398 False positive for GuardLogStatementJavaUtil with Log4j</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import org.apache.log4j.Logger;

public class GuardLogTest {
    Logger LOG;
    public void foo() {
        if (LOG.isInfoEnabled()) {
            LOG.info("update: After spool map size: " + 2);
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#783 [java] GuardLogStatement regression</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import org.apache.log4j.Logger;

public class GuardLogTest {
    Logger LOGGER;
    public void foo() {
        if (!(exception instanceof IllegalArgumentException) && LOGGER.isErrorEnabled()) {
            LOGGER.error("Some error " + someObject, exception);
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Wrong guard method for java util logging</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
import java.util.logging.Logger;
import java.util.logging.Level;

public class Foo {
    Logger LOGGER;

    public void foo() {
        if (LOGGER.isLoggable(Level.INFO)) { // should have been level FINE
            LOGGER.log(Level.FINE, "This is a severe message" + this + " and concat");
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#370 rule not considering lambdas</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.function.Supplier;
public class Logger {
    private static final Logger LOGGER = new Logger();

    public void bar() {
        String msg;
        msg = "test";
        LOGGER.info(() -> "Bla " + msg + " bla"); // The lambda is free to do whatever it likes
    }

    @Override
    public void info(Supplier<String> message) {
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info(message.get());
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#869 [java] GuardLogStatement false positive with Math.log</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class GuardLogStatement {
    public void foo() {
        double confidence = 0.5;
        int depth = (int) Math.ceil(-Math.log(1 - confidence) / Math.log(2));
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#869 [java] GuardLogStatement false positive with something.error on return</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import my.ThisIsNotALogger;
public class GuardLogStatement {
    public String foo() {
        return ThisIsNotALogger.error("message " + this);
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#3155 False negatives with unguarded method calls</description>
        <expected-problems>3</expected-problems>
        <expected-linenumbers>6,7,8</expected-linenumbers>
        <code><![CDATA[
import java.util.logging.Logger;
public class Logger {
    private static final Logger LOGGER = new Logger();

    public void bar() {
        LOGGER.info("Message with param: {}", expensiveOperation()); // bad, expensiveOperation is executed regardless
        LOGGER.info("Message with param: %s", this.expensiveOperation()); // bad, expensiveOperation is executed regardless
        LOGGER.info(expensiveOperation()); // bad, expensiveOperation is executed regardless

        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("Message with param: {}", expensiveOperation());
        }
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("Message with param: %s", expensiveOperation());
        }
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info(expensiveOperation());
        }

        LOGGER.info("Message with param: {}", () -> expensiveOperation());
        LOGGER.info("Message with param: %s", () -> expensiveOperation());
        LOGGER.info(()-> expensiveOperation());
    }

    private String expensiveOperation() {
        return "...";
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>[java] GuardLogStatement: False positive with compile-time constant arguments #957</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Logger {
    private static final Logger LOGGER = new Logger();
    private static final String CONSTANT = "a constant";

    public void case1() {
        LOGGER.debug("log something" + " and " + "concat strings"); // the same as "log something and concat strings"
    }

    public void case2() {
        final String constantPrefix = "log something";
        final String constantSuffix = "concat strings";
        LOGGER.debug(constantPrefix + " and " + constantSuffix ); // the same as "log something and concat strings"
    }

    public void case3() {
        LOGGER.debug("Prefix " + CONSTANT);
    }

    public void case4() {
        LOGGER.debug("Some long string that has been " + 
            "separated into two constants. Contains value: {}", param);
    }

    private void log(int line, String key) {
        System.out.println(line + ":" + key);
    }

    public void case5(int line, String key) {
        log(line, key);
        LOGGER.debug(key);
    }

    private interface TestLambda {
        void apply(String arg1, String arg2);
    }
    private void runTestLambda(TestLambda test) {
        test.apply("one", "two");
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>false negative inside lambdas</description>
        <expected-problems>2</expected-problems>
        <expected-linenumbers>19,21</expected-linenumbers>
        <code><![CDATA[
public class Logger {
    private static final Logger LOGGER = new Logger();

    private interface TestLambda {
        void apply(String arg1, String arg2);
    }
    private void runTestLambda(TestLambda test) {
        test.apply("one", "two");
    }

    public void case1_no_violation() {
        runTestLambda((String a, String b) -> {
            LOGGER.debug(a);
        });
    }

    public void case2_violation() {
        runTestLambda((String a, String b) -> {
            LOGGER.debug(a + b);
        });
        runTestLambda((s1, s2) -> {LOGGER.debug(s1 + s2);});
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>NullPointerException applying rule GuardLogStatement (#3340)</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Logger {
    private static final Logger LOGGER = new Logger();

    public void bar() {
        LOGGER.debug();
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#4492 GuardLogStatement gives false positive when argument is a Java method reference</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class GuardLogStatementTest {
    static String foo() {
        return "foo";
    }

    public void test() {
        final Logger logger = LogManager.getLogger(GuardLogStatementTest.class);
        logger.info("Some info: {}", GuardLogStatementTest::foo);
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>GuardLogStatement should flag method reference from method / constructor calls</description>
        <expected-problems>2</expected-problems>
        <code><![CDATA[
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class GuardLogStatementTest {
    String foo() {
        return "foo";
    }

    private GuardLogStatementTest factory() {
        return new GuardLogStatementTest();
    }

    public void test() {
        final Logger logger = LogManager.getLogger(GuardLogStatementTest.class);
        logger.info("Some info: {}", new GuardLogStatementTest()::foo);
        logger.info("Some info: {}", factory()::foo);
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#5151 Field accesses do not require guards</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class GuardLogStatementTest {
    private static final Logger LOG = LogManager.getLogger(GuardLogStatementTest.class);
    private static final String MY_CONSTANT = "";
    private String my_field = "";

    public void test() {
        LOG.info(
            "Some message here : foo={}",
            GuardLogStatementTest.MY_CONSTANT
        );

        LOG.info(
            "Some message here : foo={}",
            this.my_field
        );
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#5151 Field accesses on method call returned values require guards</description>
        <expected-problems>2</expected-problems>
        <code><![CDATA[
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class GuardLogStatementTest {
    private static final Logger LOG = LogManager.getLogger(GuardLogStatementTest.class);
    private String my_field = "";

    public void test() {
        LOG.info(
            "Some message here : foo={}",
            new GuardLogStatementTest().my_field
        );

        LOG.info(
            "Some message here : foo={}",
            factory().my_field
        );
    }

    private GuardLogStatementTest factory() {
        return new GuardLogStatementTest();
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#5152 "this" do not require guards</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class GuardLogStatementTest {
    private static final Logger LOG = LogManager.getLogger(GuardLogStatementTest.class);

    public void test() {
        LOG.info(
            "Some message here : foo={}",
            this
        );
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#5153 array access to constants do not require guards</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class GuardLogStatementTest {
    private static final Logger LOG = LogManager.getLogger(GuardLogStatementTest.class);
    private final String[] foo = { "foo" };

    public void test() {
        LOG.info(
            "Some message here : foo={}",
            foo[0]
        );
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>array access with computed keys require guards</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class GuardLogStatementTest {
    private static final Logger LOG = LogManager.getLogger(GuardLogStatementTest.class);
    private final String[] foo = { "foo" };

    public void test() {
        LOG.info(
            "Some message here : foo={}",
            foo[getFooIndex()]
        );
    }

    public int getFooIndex() {
        return 0;
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#5153 array access to method returned values require guards</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class GuardLogStatementTest {
    private static final Logger LOG = LogManager.getLogger(GuardLogStatementTest.class);

    public void test() {
        LOG.info(
            "Some message here : foo={}",
            foo()[0]
        );
    }

    private String[] foo() {
        return new String[] { "foo" };
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>#3602 False positive when compile-time constant is created from external constants</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.sourceforge.pmd.lang.java.rule.bestpractices.GuardLogStatementTest;

public class MyClass {
  private static final Logger logger = LogManager.getLogger();
  public void doSomething() {
     final Object arg = new Object();
     logger.info("Problem message: {}. " + GuardLogStatementTest.TERM_MSG, arg);
  }
}
        ]]></code>
    </test-code>
</test-data>
