• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / httpunit / 636

05 Dec 2025 03:27AM UTC coverage: 80.509%. Remained the same
636

push

github

hazendaz
Cleanup more old since tags

you guessed it, at this point going to jautodoc the rest so the warnings on builds go away ;)

3213 of 4105 branches covered (78.27%)

Branch coverage included in aggregate %.

8249 of 10132 relevant lines covered (81.42%)

0.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.86
/src/main/java/com/meterware/servletunit/JUnitServlet.java
1
/*
2
 * MIT License
3
 *
4
 * Copyright 2011-2025 Russell Gold
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
8
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
9
 * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions
12
 * of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
15
 * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
17
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18
 * DEALINGS IN THE SOFTWARE.
19
 */
20
package com.meterware.servletunit;
21

22
import jakarta.servlet.ServletException;
23
import jakarta.servlet.http.HttpServlet;
24
import jakarta.servlet.http.HttpServletRequest;
25
import jakarta.servlet.http.HttpServletResponse;
26

27
import java.io.IOException;
28
import java.io.PrintWriter;
29
import java.util.Enumeration;
30

31
import junit.framework.AssertionFailedError;
32
import junit.framework.Test;
33
import junit.framework.TestFailure;
34
import junit.framework.TestResult;
35
import junit.runner.BaseTestRunner;
36

37
/**
38
 * A servlet which can run unit tests inside a servlet context. It may be extended to provide InvocationContext-access
39
 * to such tests if a container-specific implementation of InvocationContextFactory is provided. Combined with
40
 * ServletTestCase, this would permit in-container tests of servlets in a fashion similar to that supported by
41
 * ServletUnit.
42
 **/
43
public class JUnitServlet extends HttpServlet {
44

45
    private static final long serialVersionUID = 1L;
46

47
    public JUnitServlet() {
×
48
    }
×
49

50
    protected JUnitServlet(InvocationContextFactory factory) {
1✔
51
        _factory = factory;
1✔
52
    }
1✔
53

54
    @Override
55
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
56
            throws ServletException, IOException {
57
        ResultsFormatter formatter = getResultsFormatter(request.getParameter("format"));
1✔
58
        response.setContentType(formatter.getContentType());
1✔
59
        final String testName = request.getParameter("test");
1✔
60
        if (testName == null || testName.isEmpty()) {
1!
61
            reportCannotRunTest(response.getWriter(), "No test class specified");
1✔
62
        } else {
63
            ServletTestRunner runner = new ServletTestRunner(response.getWriter(), formatter);
1✔
64
            runner.runTestSuite(testName);
1✔
65
        }
66
        response.getWriter().close();
1✔
67
    }
1✔
68

69
    private ResultsFormatter getResultsFormatter(String formatterName) {
70
        if ("text".equalsIgnoreCase(formatterName)) {
1✔
71
            return new TextResultsFormatter();
1✔
72
        }
73
        if ("xml".equalsIgnoreCase(formatterName)) {
1✔
74
            return new XMLResultsFormatter();
1✔
75
        }
76
        return new HTMLResultsFormatter();
1✔
77
    }
78

79
    private InvocationContextFactory _factory;
80

81
    private void reportCannotRunTest(PrintWriter writer, final String errorMessage) {
82
        writer.print("<html><head><title>Cannot run test</title></head><body>" + errorMessage + "</body></html>");
1✔
83
    }
1✔
84

85
    class ServletTestRunner extends BaseTestRunner {
86
        private PrintWriter _writer;
87
        private ResultsFormatter _formatter;
88

89
        public ServletTestRunner(PrintWriter writer, ResultsFormatter formatter) {
1✔
90
            ServletTestCase.setInvocationContextFactory(_factory);
1✔
91
            _writer = writer;
1✔
92
            _formatter = formatter;
1✔
93
        }
1✔
94

95
        void runTestSuite(String testClassName) {
96
            Test suite = getTest(testClassName);
1✔
97

98
            if (suite != null) {
1✔
99
                TestResult testResult = new TestResult();
1✔
100
                testResult.addListener(this);
1✔
101
                long startTime = System.currentTimeMillis();
1✔
102
                suite.run(testResult);
1✔
103
                long endTime = System.currentTimeMillis();
1✔
104
                _formatter.displayResults(_writer, testClassName, elapsedTimeAsString(endTime - startTime), testResult);
1✔
105
            }
106
        }
1✔
107

108
        @Override
109
        public void addError(Test test, Throwable throwable) {
110
        }
1✔
111

112
        @Override
113
        public void addFailure(Test test, AssertionFailedError error) {
114
        }
1✔
115

116
        @Override
117
        public void endTest(Test test) {
118
        }
1✔
119

120
        @Override
121
        protected void runFailed(String s) {
122
            reportCannotRunTest(_writer, s);
1✔
123
        }
1✔
124

125
        @Override
126
        public void startTest(Test test) {
127
        }
1✔
128

129
        @Override
130
        public void testStarted(String s) {
131
        }
×
132

133
        @Override
134
        public void testEnded(String s) {
135
        }
×
136

137
        @Override
138
        public void testFailed(int i, Test test, Throwable throwable) {
139
        }
×
140

141
    }
142

143
    static abstract class ResultsFormatter {
1✔
144

145
        private static final char LF = 10;
146
        private static final char CR = 13;
147

148
        abstract String getContentType();
149

150
        void displayResults(PrintWriter writer, String testClassName, String elapsedTimeString, TestResult testResult) {
151
            displayHeader(writer, testClassName, testResult, elapsedTimeString);
1✔
152
            displayResults(writer, testResult);
1✔
153
            displayFooter(writer);
1✔
154
        }
1✔
155

156
        protected abstract void displayHeader(PrintWriter writer, String testClassName, TestResult testResult,
157
                String elapsedTimeString);
158

159
        protected abstract void displayResults(PrintWriter writer, TestResult testResult);
160

161
        protected abstract void displayFooter(PrintWriter writer);
162

163
        protected String sgmlEscape(String s) {
164
            if (s == null) {
1!
165
                return "NULL";
×
166
            }
167
            StringBuilder result = new StringBuilder(s.length());
1✔
168
            char[] chars = s.toCharArray();
1✔
169
            for (int i = 0; i < chars.length; i++) {
1✔
170
                switch (chars[i]) {
1!
171
                    case '&':
172
                        result.append("&amp;");
×
173
                        break;
×
174
                    case '<':
175
                        result.append("&lt;");
1✔
176
                        break;
1✔
177
                    case '>':
178
                        result.append("&gt;");
1✔
179
                        break;
1✔
180
                    case LF:
181
                        if (i > 0 && chars[i - 1] == CR) {
1!
182
                            result.append(chars[i]);
×
183
                            break;
×
184
                        }
185
                    case CR:
186
                        result.append(getLineBreak());
1✔
187
                    default:
188
                        result.append(chars[i]);
1✔
189
                }
190
            }
191
            return result.toString();
1✔
192
        }
193

194
        protected String getLineBreak() {
195
            return "<br>";
1✔
196
        }
197
    }
198

199
    abstract static class DisplayedResultsFormatter extends ResultsFormatter {
1✔
200

201
        @Override
202
        protected void displayHeader(PrintWriter writer, String testClassName, TestResult testResult,
203
                String elapsedTimeString) {
204
            displayHeader(writer, testClassName, getFormatted(testResult.runCount(), "test"), elapsedTimeString,
1✔
205
                    testResult.wasSuccessful() ? "OK" : "Problems Occurred");
1✔
206
        }
1✔
207

208
        @Override
209
        protected void displayResults(PrintWriter writer, TestResult testResult) {
210
            if (!testResult.wasSuccessful()) {
1✔
211
                displayProblems(writer, "failure", testResult.failureCount(), testResult.failures());
1✔
212
                displayProblems(writer, "error", testResult.errorCount(), testResult.errors());
1✔
213
            }
214
        }
1✔
215

216
        protected abstract void displayHeader(PrintWriter writer, String testClassName, String testCountText,
217
                String elapsedTimeString, String resultString);
218

219
        protected abstract void displayProblemTitle(PrintWriter writer, String title);
220

221
        protected abstract void displayProblemDetailHeader(PrintWriter writer, int i, String testName);
222

223
        protected abstract void displayProblemDetailFooter(PrintWriter writer);
224

225
        protected abstract void displayProblemDetail(PrintWriter writer, String message);
226

227
        private void displayProblems(PrintWriter writer, String kind, int count, Enumeration enumeration) {
228
            if (count != 0) {
1✔
229
                displayProblemTitle(writer, getFormatted(count, kind));
1✔
230
                Enumeration e = enumeration;
1✔
231
                for (int i = 1; e.hasMoreElements(); i++) {
1✔
232
                    TestFailure failure = (TestFailure) e.nextElement();
1✔
233
                    displayProblemDetailHeader(writer, i, failure.failedTest().toString());
1✔
234
                    if (failure.thrownException() instanceof AssertionFailedError) {
1✔
235
                        displayProblemDetail(writer, failure.thrownException().getMessage());
1✔
236
                    } else {
237
                        displayProblemDetail(writer, BaseTestRunner.getFilteredTrace(failure.thrownException()));
1✔
238
                    }
239
                    displayProblemDetailFooter(writer);
1✔
240
                }
241
            }
242
        }
1✔
243

244
        private String getFormatted(int count, String name) {
245
            return count + " " + name + (count == 1 ? "" : "s");
1✔
246
        }
247

248
    }
249

250
    static class TextResultsFormatter extends DisplayedResultsFormatter {
1✔
251

252
        @Override
253
        String getContentType() {
254
            return "text/plain";
1✔
255
        }
256

257
        @Override
258
        protected void displayHeader(PrintWriter writer, String testClassName, String testCountText,
259
                String elapsedTimeString, String resultString) {
260
            writer.println(testClassName + " (" + testCountText + "): " + resultString);
1✔
261
        }
1✔
262

263
        @Override
264
        protected void displayFooter(PrintWriter writer) {
265
        }
1✔
266

267
        @Override
268
        protected void displayProblemTitle(PrintWriter writer, String title) {
269
            writer.println();
1✔
270
            writer.println(title + ':');
1✔
271
        }
1✔
272

273
        @Override
274
        protected void displayProblemDetailHeader(PrintWriter writer, int i, String testName) {
275
            writer.println(i + ". " + testName + ":");
1✔
276
        }
1✔
277

278
        @Override
279
        protected void displayProblemDetailFooter(PrintWriter writer) {
280
            writer.println();
1✔
281
        }
1✔
282

283
        @Override
284
        protected void displayProblemDetail(PrintWriter writer, String message) {
285
            writer.println(message);
1✔
286
        }
1✔
287
    }
288

289
    static class HTMLResultsFormatter extends DisplayedResultsFormatter {
1✔
290

291
        @Override
292
        String getContentType() {
293
            return "text/html";
1✔
294
        }
295

296
        @Override
297
        protected void displayHeader(PrintWriter writer, String testClassName, String testCountText,
298
                String elapsedTimeString, String resultString) {
299
            writer.println("<html><head><title>Test Suite: " + testClassName + "</title>");
1✔
300
            writer.println("<style type='text/css'>");
1✔
301
            writer.println("<!--");
1✔
302
            writer.println("  td.detail { font-size:smaller; vertical-align: top }");
1✔
303
            writer.println("  -->");
1✔
304
            writer.println("</style></head><body>");
1✔
305
            writer.println("<table id='results' border='1'><tr>");
1✔
306
            writer.println("<td>" + testCountText + "</td>");
1✔
307
            writer.println("<td>Time: " + elapsedTimeString + "</td>");
1✔
308
            writer.println("<td>" + resultString + "</td></tr>");
1✔
309
        }
1✔
310

311
        @Override
312
        protected void displayFooter(PrintWriter writer) {
313
            writer.println("</table>");
1✔
314
            writer.println("</body></html>");
1✔
315
        }
1✔
316

317
        @Override
318
        protected void displayProblemTitle(PrintWriter writer, String title) {
319
            writer.println("<tr><td colspan=3>" + title + "</td></tr>");
1✔
320
        }
1✔
321

322
        @Override
323
        protected void displayProblemDetailHeader(PrintWriter writer, int i, String testName) {
324
            writer.println("<tr><td class='detail' align='right'>" + i + "</td>");
1✔
325
            writer.println("<td class='detail'>" + testName + "</td><td class='detail'>");
1✔
326
        }
1✔
327

328
        @Override
329
        protected void displayProblemDetailFooter(PrintWriter writer) {
330
            writer.println("</td></tr>");
1✔
331
        }
1✔
332

333
        @Override
334
        protected void displayProblemDetail(PrintWriter writer, String message) {
335
            writer.println(sgmlEscape(message));
1✔
336
        }
1✔
337

338
    }
339

340
    static class XMLResultsFormatter extends ResultsFormatter {
1✔
341

342
        @Override
343
        String getContentType() {
344
            return "text/xml;charset=UTF-8";
1✔
345
        }
346

347
        @Override
348
        protected void displayHeader(PrintWriter writer, String testClassName, TestResult testResult,
349
                String elapsedTimeString) {
350
            writer.println("<?xml version='1.0' encoding='UTF-8' ?>\n" + "<testsuite name=" + asAttribute(testClassName)
1✔
351
                    + " tests=" + asAttribute(testResult.runCount()) + " failures="
1✔
352
                    + asAttribute(testResult.failureCount()) + " errors=" + asAttribute(testResult.errorCount())
1✔
353
                    + " time=" + asAttribute(elapsedTimeString) + ">");
1✔
354
        }
1✔
355

356
        private String asAttribute(int value) {
357
            return '"' + Integer.toString(value) + '"';
1✔
358
        }
359

360
        private String asAttribute(String value) {
361
            return '"' + sgmlEscape(value) + '"';
1✔
362
        }
363

364
        @Override
365
        protected void displayFooter(PrintWriter writer) {
366
            writer.println("</testsuite>");
1✔
367
        }
1✔
368

369
        @Override
370
        protected void displayResults(PrintWriter writer, TestResult testResult) {
371
            displayResults(writer, "failure", testResult.failures());
1✔
372
            displayResults(writer, "error", testResult.errors());
1✔
373
        }
1✔
374

375
        private void displayResults(PrintWriter writer, String failureNodeName, Enumeration resultsEnumeration) {
376
            for (Enumeration e = resultsEnumeration; e.hasMoreElements();) {
1✔
377
                TestFailure failure = (TestFailure) e.nextElement();
1✔
378
                writer.println("  <testcase name=" + asAttribute(failure.failedTest().toString()) + ">");
1✔
379
                writer.print("    <" + failureNodeName + " type="
1✔
380
                        + asAttribute(failure.thrownException().getClass().getName()) + " message="
1✔
381
                        + asAttribute(failure.exceptionMessage()));
1✔
382
                if (!displayException()) {
1!
383
                    writer.println("/>");
×
384
                } else {
385
                    writer.println(">");
1✔
386
                    writer.print(sgmlEscape(BaseTestRunner.getFilteredTrace(failure.thrownException())));
1✔
387
                    writer.println("    </" + failureNodeName + ">");
1✔
388
                }
389
                writer.println("  </testcase>");
1✔
390
            }
1✔
391
        }
1✔
392

393
        private boolean displayException() {
394
            return true;
1✔
395
        }
396

397
        @Override
398
        protected String getLineBreak() {
399
            return "";
1✔
400
        }
401
    }
402

403
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc