TestLogger.java

1
package com.renomad.minum.logging;
2
3
import com.renomad.minum.state.Constants;
4
import com.renomad.minum.utils.MyThread;
5
6
import java.util.List;
7
import java.util.Locale;
8
import java.util.Queue;
9
import java.util.concurrent.ExecutorService;
10
import java.util.concurrent.locks.ReentrantLock;
11
12
/**
13
 * This implementation of {@link Logger} has a few
14
 * extra functions that only apply to tests, like {@link #test(String)}
15
 */
16
public final class TestLogger extends Logger {
17
18
    private final Queue<String> recentLogLines;
19
    public static final int MAX_CACHE_SIZE = 30;
20
    private final ReentrantLock loggingLock;
21
    private int testCount = 0;
22
23
    /**
24
     * See {@link TestLogger}
25
     */
26
    public TestLogger(Constants constants, ExecutorService executorService, String name) {
27
        super(constants, executorService, name);
28
        this.recentLogLines = new TestLoggerQueue(MAX_CACHE_SIZE);
29
        this.loggingLock = new ReentrantLock();
30
    }
31
32
    /**
33
     * A helper to get the string message value out of a
34
     * {@link ThrowingSupplier}
35
     */
36
    private String extractMessage(ThrowingSupplier<String, Exception> msg) {
37
        String receivedMessage;
38
        try {
39
            receivedMessage = msg.get();
40
        } catch (Exception ex) {
41
            receivedMessage = "EXCEPTION DURING GET: " + ex;
42
        }
43 1 1. extractMessage : replaced return value with "" for com/renomad/minum/logging/TestLogger::extractMessage → KILLED
        return receivedMessage;
44
    }
45
46
    /**
47
     * Keeps a record of the recently-added log messages, which is
48
     * useful for some tests.
49
     */
50
    private void addToCache(ThrowingSupplier<String, Exception> msg) {
51
        // put log messages into the tail of the queue
52
        String message = extractMessage(msg);
53 1 1. addToCache : negated conditional → KILLED
        String safeMessage = message == null ? "(null message)" : message;
54
        recentLogLines.add(safeMessage);
55
    }
56
57
    @Override
58
    public void logDebug(ThrowingSupplier<String, Exception> msg) {
59 1 1. logDebug : removed call to java/util/concurrent/locks/ReentrantLock::lock → KILLED
        loggingLock.lock();
60
        try {
61
            addToCache(msg);
62
            super.logDebug(msg);
63
        } finally {
64 1 1. logDebug : removed call to java/util/concurrent/locks/ReentrantLock::unlock → TIMED_OUT
            loggingLock.unlock();
65
        }
66
    }
67
68
    @Override
69
    public void logTrace(ThrowingSupplier<String, Exception> msg) {
70 1 1. logTrace : removed call to java/util/concurrent/locks/ReentrantLock::lock → KILLED
        loggingLock.lock();
71
        try {
72
            addToCache(msg);
73
            super.logTrace(msg);
74
        } finally {
75 1 1. logTrace : removed call to java/util/concurrent/locks/ReentrantLock::unlock → KILLED
            loggingLock.unlock();
76
        }
77
    }
78
79
    @Override
80
    public void logAudit(ThrowingSupplier<String, Exception> msg) {
81 1 1. logAudit : removed call to java/util/concurrent/locks/ReentrantLock::lock → KILLED
        loggingLock.lock();
82
        try {
83
            addToCache(msg);
84
            super.logAudit(msg);
85
        } finally {
86 1 1. logAudit : removed call to java/util/concurrent/locks/ReentrantLock::unlock → KILLED
            loggingLock.unlock();
87
        }
88
    }
89
90
    @Override
91
    public void logAsyncError(ThrowingSupplier<String, Exception> msg) {
92 1 1. logAsyncError : removed call to java/util/concurrent/locks/ReentrantLock::lock → KILLED
        loggingLock.lock();
93
        try {
94
            addToCache(msg);
95
            super.logAsyncError(msg);
96
        } finally {
97 1 1. logAsyncError : removed call to java/util/concurrent/locks/ReentrantLock::unlock → TIMED_OUT
            loggingLock.unlock();
98
        }
99
    }
100
101
    /**
102
     * Provides an ability to search over the recent past log messages,
103
     * case-insensitively.
104
     * @param lines number of lines of log messages to look back through,
105
     *              up to {@link #MAX_CACHE_SIZE}
106
     */
107
    public String findFirstMessageThatContains(String value, int lines) {
108
        List<String> values = findMessage(value, lines, recentLogLines);
109
        List<String> logsBeingSearched = logLinesToSearch(lines, recentLogLines);
110
        return checkValidityOfResults(value, values, logsBeingSearched);
111
    }
112
113
    /**
114
     * This is used in {@link #findFirstMessageThatContains(String, int)} to
115
     * handle exceptional situations with the results.  Specifically, exceptions
116
     * are:
117
     * <ol>
118
     *    <li>If there were no results found</li>
119
     *    <li>If there were multiple results found</li>
120
     * </ol>
121
     */
122
    static String checkValidityOfResults(String value, List<String> values, List<String> recentLogLines) {
123
        int size = values.size();
124 1 1. checkValidityOfResults : negated conditional → KILLED
        if (size == 0) {
125
            throw new TestLoggerException(value + " was not found in \n\t" + String.join("\n\t", recentLogLines));
126 2 1. checkValidityOfResults : changed conditional boundary → KILLED
2. checkValidityOfResults : negated conditional → KILLED
        } else if (size >= 2) {
127
            throw new TestLoggerException("multiple values of "+value+" found in: " + recentLogLines);
128
        } else {
129 1 1. checkValidityOfResults : replaced return value with "" for com/renomad/minum/logging/TestLogger::checkValidityOfResults → KILLED
            return values.getFirst();
130
        }
131
    }
132
133
    /**
134
     * Whether the given string exists in the log messages. May
135
     * exist multiple times.
136
     * @param value a string to search in the log
137
     * @param lines how many lines back to examine
138
     * @return whether this string was found, even if there
139
     *      were multiple places it was found.
140
     */
141
    public boolean doesMessageExist(String value, int lines) {
142
        if (! findMessage(value, lines, recentLogLines).isEmpty()) {
143 1 1. doesMessageExist : replaced boolean return with false for com/renomad/minum/logging/TestLogger::doesMessageExist → KILLED
            return true;
144
        } else {
145
            List<String> logsBeingSearched = logLinesToSearch(lines, recentLogLines);
146
            throw new TestLoggerException(value + " was not found in \n\t" + String.join("\n\t", logsBeingSearched));
147
        }
148
    }
149
150
    /**
151
     * Whether the given string exists in the log messages. May
152
     * exist multiple times.
153
     * @param value a string to search in the log
154
     * @return whether or not this string was found, even if there
155
     * were multiple places it was found.
156
     */
157
    public boolean doesMessageExist(String value) {
158
        return doesMessageExist(value, 3);
159
    }
160
161
    static List<String> findMessage(String value, int lines, Queue<String> recentLogLines) {
162 2 1. findMessage : changed conditional boundary → KILLED
2. findMessage : negated conditional → KILLED
        if (lines > MAX_CACHE_SIZE) {
163
            throw new TestLoggerException(String.format("Can only get up to %s lines from the log", MAX_CACHE_SIZE));
164
        }
165 2 1. findMessage : negated conditional → KILLED
2. findMessage : changed conditional boundary → KILLED
        if (lines <= 0) {
166
            throw new TestLoggerException("number of recent log lines must be a positive number");
167
        }
168
        MyThread.sleep(20);
169
        var lineList = logLinesToSearch(lines, recentLogLines);
170 3 1. lambda$findMessage$0 : replaced boolean return with false for com/renomad/minum/logging/TestLogger::lambda$findMessage$0 → KILLED
2. findMessage : replaced return value with Collections.emptyList for com/renomad/minum/logging/TestLogger::findMessage → KILLED
3. lambda$findMessage$0 : replaced boolean return with true for com/renomad/minum/logging/TestLogger::lambda$findMessage$0 → KILLED
        return lineList.stream().filter(x -> x.toLowerCase(Locale.ROOT).contains(value.toLowerCase(Locale.ROOT))).toList();
171
172
    }
173
174
    private static List<String> logLinesToSearch(int lines, Queue<String> recentLogLines) {
175 1 1. logLinesToSearch : Replaced integer subtraction with addition → KILLED
        var fromIndex = Math.max(recentLogLines.size() - lines, 0);
176 1 1. logLinesToSearch : replaced return value with Collections.emptyList for com/renomad/minum/logging/TestLogger::logLinesToSearch → KILLED
        return recentLogLines.stream().toList().subList(fromIndex, recentLogLines.size());
177
    }
178
179
    /**
180
     * Looks back through the last 3 log messages for one that
181
     * contains the provided value.  Returns the whole line if
182
     * found and an exception if not found.
183
     * <p>
184
     *     See {@link #findFirstMessageThatContains(String, int)} if you
185
     *     want to search through more than 3.  However, it is only
186
     *     possible to search up to {@link #MAX_CACHE_SIZE}
187
     * </p>
188
     */
189
    public String findFirstMessageThatContains(String value) {
190
        return findFirstMessageThatContains(value, 3);
191
    }
192
193
    /**
194
     * A helper function to log a test title prefixed with "TEST:"
195
     * <br>
196
     * Also collects data about the previously-run test
197
     */
198
    public void test(String msg) {
199
        // put together some pretty-looking text graphics to show the suiteName of our test in log
200 1 1. test : removed call to java/util/concurrent/locks/ReentrantLock::lock → KILLED
        loggingLock.lock();
201
        try {
202
            final var baseLength = 11;
203 1 1. test : Replaced integer addition with subtraction → KILLED
            final var dashes = "-".repeat(msg.length() + baseLength);
204
205 1 1. test : removed call to com/renomad/minum/queue/AbstractActionQueue::enqueue → KILLED
            loggingActionQueue.enqueue("Testlogger#test("+msg+")", () -> {
206 1 1. lambda$test$1 : Replaced integer addition with subtraction → KILLED
                testCount += 1;
207
                System.out.printf("%n+%s+%n| TEST %d: %s |%n+%s+%n%n", dashes, testCount, msg, dashes);
208
                recentLogLines.add(msg);
209
            });
210
        } finally {
211 1 1. test : removed call to java/util/concurrent/locks/ReentrantLock::unlock → KILLED
            loggingLock.unlock();
212
        }
213
    }
214
215
    public int getTestCount() {
216 1 1. getTestCount : replaced int return with 0 for com/renomad/minum/logging/TestLogger::getTestCount → KILLED
        return testCount;
217
    }
218
219
    @Override
220
    public String toString() {
221 1 1. toString : replaced return value with "" for com/renomad/minum/logging/TestLogger::toString → KILLED
        return "TestLogger using queue: " + super.loggingActionQueue.toString();
222
    }
223
224
}

Mutations

43

1.1
Location : extractMessage
Killed by : com.renomad.minum.logging.TestLoggerTests.test_TestLogger_NullMessage(com.renomad.minum.logging.TestLoggerTests)
replaced return value with "" for com/renomad/minum/logging/TestLogger::extractMessage → KILLED

53

1.1
Location : addToCache
Killed by : com.renomad.minum.web.SocketWrapperTests.testSendingSingleByte(com.renomad.minum.web.SocketWrapperTests)
negated conditional → KILLED

59

1.1
Location : logDebug
Killed by : com.renomad.minum.web.FullSystemTests.test_CloseCore(com.renomad.minum.web.FullSystemTests)
removed call to java/util/concurrent/locks/ReentrantLock::lock → KILLED

64

1.1
Location : logDebug
Killed by : none
removed call to java/util/concurrent/locks/ReentrantLock::unlock → TIMED_OUT

70

1.1
Location : logTrace
Killed by : com.renomad.minum.web.SocketWrapperTests.testSendingSingleByte(com.renomad.minum.web.SocketWrapperTests)
removed call to java/util/concurrent/locks/ReentrantLock::lock → KILLED

75

1.1
Location : logTrace
Killed by : com.renomad.minum.web.SocketWrapperTests.testSendingSingleByte(com.renomad.minum.web.SocketWrapperTests)
removed call to java/util/concurrent/locks/ReentrantLock::unlock → KILLED

81

1.1
Location : logAudit
Killed by : com.renomad.minum.FunctionalTests
removed call to java/util/concurrent/locks/ReentrantLock::lock → KILLED

86

1.1
Location : logAudit
Killed by : com.renomad.minum.FunctionalTests
removed call to java/util/concurrent/locks/ReentrantLock::unlock → KILLED

92

1.1
Location : logAsyncError
Killed by : com.renomad.minum.web.WebFrameworkTests.test_readStaticFile_IOException(com.renomad.minum.web.WebFrameworkTests)
removed call to java/util/concurrent/locks/ReentrantLock::lock → KILLED

97

1.1
Location : logAsyncError
Killed by : none
removed call to java/util/concurrent/locks/ReentrantLock::unlock → TIMED_OUT

124

1.1
Location : checkValidityOfResults
Killed by : com.renomad.minum.logging.TestLoggerTests.test_findFirstMessage_CheckValidity_NotFound(com.renomad.minum.logging.TestLoggerTests)
negated conditional → KILLED

126

1.1
Location : checkValidityOfResults
Killed by : com.renomad.minum.logging.TestLoggerTests.test_findFirstMessage_CheckValidity_TooMany(com.renomad.minum.logging.TestLoggerTests)
changed conditional boundary → KILLED

2.2
Location : checkValidityOfResults
Killed by : com.renomad.minum.logging.TestLoggerTests.test_findFirstMessage_CheckValidity_TooMany(com.renomad.minum.logging.TestLoggerTests)
negated conditional → KILLED

129

1.1
Location : checkValidityOfResults
Killed by : com.renomad.minum.utils.ThrowingRunnableTests
replaced return value with "" for com/renomad/minum/logging/TestLogger::checkValidityOfResults → KILLED

143

1.1
Location : doesMessageExist
Killed by : com.renomad.minum.logging.TestLoggerTests.test_TestLogger_NullMessage(com.renomad.minum.logging.TestLoggerTests)
replaced boolean return with false for com/renomad/minum/logging/TestLogger::doesMessageExist → KILLED

162

1.1
Location : findMessage
Killed by : com.renomad.minum.security.TheBrigTests
changed conditional boundary → KILLED

2.2
Location : findMessage
Killed by : com.renomad.minum.logging.TestLoggerTests.test_findMessage_EdgeCase_NegativeValue(com.renomad.minum.logging.TestLoggerTests)
negated conditional → KILLED

165

1.1
Location : findMessage
Killed by : com.renomad.minum.logging.TestLoggerTests.test_findMessage_EdgeCase_NegativeValue(com.renomad.minum.logging.TestLoggerTests)
negated conditional → KILLED

2.2
Location : findMessage
Killed by : com.renomad.minum.security.TheBrigTests
changed conditional boundary → KILLED

170

1.1
Location : lambda$findMessage$0
Killed by : com.renomad.minum.logging.TestLoggerTests.test_findMessage(com.renomad.minum.logging.TestLoggerTests)
replaced boolean return with false for com/renomad/minum/logging/TestLogger::lambda$findMessage$0 → KILLED

2.2
Location : findMessage
Killed by : com.renomad.minum.logging.TestLoggerTests.test_findMessage(com.renomad.minum.logging.TestLoggerTests)
replaced return value with Collections.emptyList for com/renomad/minum/logging/TestLogger::findMessage → KILLED

3.3
Location : lambda$findMessage$0
Killed by : com.renomad.minum.logging.TestLoggerTests.test_findMessage(com.renomad.minum.logging.TestLoggerTests)
replaced boolean return with true for com/renomad/minum/logging/TestLogger::lambda$findMessage$0 → KILLED

175

1.1
Location : logLinesToSearch
Killed by : com.renomad.minum.logging.TestLoggerTests.test_findMessage(com.renomad.minum.logging.TestLoggerTests)
Replaced integer subtraction with addition → KILLED

176

1.1
Location : logLinesToSearch
Killed by : com.renomad.minum.logging.TestLoggerTests.test_findMessage(com.renomad.minum.logging.TestLoggerTests)
replaced return value with Collections.emptyList for com/renomad/minum/logging/TestLogger::logLinesToSearch → KILLED

200

1.1
Location : test
Killed by : com.renomad.minum.logging.TestLoggerTests.test_test(com.renomad.minum.logging.TestLoggerTests)
removed call to java/util/concurrent/locks/ReentrantLock::lock → KILLED

203

1.1
Location : test
Killed by : com.renomad.minum.FunctionalTests
Replaced integer addition with subtraction → KILLED

205

1.1
Location : test
Killed by : com.renomad.minum.logging.TestLoggerTests.test_test(com.renomad.minum.logging.TestLoggerTests)
removed call to com/renomad/minum/queue/AbstractActionQueue::enqueue → KILLED

206

1.1
Location : lambda$test$1
Killed by : com.renomad.minum.logging.TestLoggerTests.test_test(com.renomad.minum.logging.TestLoggerTests)
Replaced integer addition with subtraction → KILLED

211

1.1
Location : test
Killed by : com.renomad.minum.FunctionalTests
removed call to java/util/concurrent/locks/ReentrantLock::unlock → KILLED

216

1.1
Location : getTestCount
Killed by : com.renomad.minum.logging.TestLoggerTests.test_test(com.renomad.minum.logging.TestLoggerTests)
replaced int return with 0 for com/renomad/minum/logging/TestLogger::getTestCount → KILLED

221

1.1
Location : toString
Killed by : com.renomad.minum.web.RequestTests.test_Request_ToString(com.renomad.minum.web.RequestTests)
replaced return value with "" for com/renomad/minum/logging/TestLogger::toString → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0