Compare commits

..

30 commits

Author SHA1 Message Date
3e9c9eb106
Bump PMD extension to version 1.2.3 2025-04-25 09:30:50 -07:00
018ccd86b4
Update extensions
Bump JaCoCo Report to version 0.9.10
Bump PMD to version 1.2.2
2025-04-13 13:36:12 -07:00
312e396052
Bump JUnit to version 5.12.2 2025-04-13 13:35:33 -07:00
ac1209abec
Add OS matrix for Ubuntu, Windows and macOS 2025-03-26 13:27:12 -07:00
4b82d03234
JDK 24 2025-03-18 23:58:13 -07:00
08d006af82
Update dependencies & copyright
Bump bld to version 2.2.1
Bump AssertJ to version 3.27.3
Bump JUnit to version 5.12.1
Bump Jacoco Report extension to version 0.9.9
Bump PMD exception to version 1.2.1
2025-03-16 13:10:19 -07:00
f596469b5b
Cleaned up tests and added soft assertions 2024-10-26 21:16:18 -07:00
7ee45b34a4
Improved JavaDocs 2024-10-26 20:36:13 -07:00
96497f7f27
Updated dependencies
Bumped JUnit to version 5.11.3
Bumped PMD extension to version 1.1.7
Bumped JDK to version 23 (GitHub CI Workflow)
2024-10-26 20:35:43 -07:00
ec75fc4690
Fixed snapshot badge 2024-09-21 12:59:35 -07:00
1bb7167aba
Bumped bld to version 2.1.0 2024-09-21 12:44:55 -07:00
71467db442
Version 1.1.1 2024-06-07 17:41:41 -07:00
1c4b20e11c
Bumped PMD extension to version 1.0.1 2024-06-07 16:15:44 -07:00
053dcba26b
Sort command line output. Closes #10
Updated copyright

Code cleanup
2024-06-07 15:39:49 -07:00
8c79c0e17a
Added more status codes from Wikipedia, etc. Closes #9 2024-06-07 12:46:26 -07:00
91e19d325e
Changed rootPom() to pomRoot() 2024-06-07 12:16:10 -07:00
2d0167e5e9
Bumped AssertJ to version 3.26.0 2024-06-07 12:15:55 -07:00
780a5c30c4
Bumped PMD extension to version 1.0.0 2024-06-07 12:14:59 -07:00
96565dbfe7
Minor cleanup 2024-05-09 23:04:53 -07:00
1a0d4eb958
Updated copyright 2024-05-09 23:02:39 -07:00
774eadaac2
Bumped dependencies versions 2024-05-09 23:02:10 -07:00
6af9b46df9
Bumped JaCoCo extension to version 0.9.5 2024-05-09 22:58:06 -07:00
18f5e92261
Bumped PMD extension to version 0.9.9 2024-05-09 22:57:32 -07:00
d6f6c40d77
Bumped bld to version 1.9.1 2024-05-09 22:56:47 -07:00
cd68004962
Bumped workflow actions to lastest versions 2024-05-09 22:47:23 -07:00
59c775e33a Changed sh format to console 2024-01-31 17:31:49 -08:00
e784b5a8f0 Added contributing section 2024-01-31 17:26:09 -08:00
1d6a7824fe Bumped bld to 1.8.0 2024-01-31 15:42:25 -08:00
4011fe8024 Upgraded bld 2023-10-20 16:10:25 -07:00
477ef6237c Fixed bld badge 2023-09-29 05:13:36 -07:00
34 changed files with 413 additions and 282 deletions

View file

@ -1,41 +1,42 @@
inversion: 2
defaults: &defaults
working_directory: ~/repo
environment:
JVM_OPTS: -Xmx3200m
TERM: dumb
CI_NAME: "CircleCI"
defaults_gradle: &defaults_bld
steps:
- checkout
- run:
name: Download the dependencies
command: ./bld download
- run:
name: Run tests with bld
command: ./bld compile test
version: 2.1
commands:
build_and_test:
parameters:
reports-dir:
type: string
default: "build/reports/test_results"
steps:
- checkout
- run:
name: Download dependencies
command: ./bld download
- run:
name: Compile source
command: ./bld compile
- run:
name: Run tests
command: ./bld jacoco -reports-dir=<< parameters.reports-dir >>
- store_test_results:
path: << parameters.reports-dir >>
- store_artifacts:
path: build/reports/jacoco/test/html
jobs:
bld_jdk20:
<<: *defaults
docker:
- image: cimg/openjdk:20.0
<<: *defaults_bld
bld_jdk17:
<<: *defaults
docker:
- image: cimg/openjdk:17.0
steps:
- build_and_test
<<: *defaults_bld
bld_jdk21:
docker:
- image: cimg/openjdk:21.0
steps:
- build_and_test
workflows:
version: 2
bld:
jobs:
- bld_jdk17
- bld_jdk20
- bld_jdk21

View file

@ -4,50 +4,50 @@ on: [ push, pull_request, workflow_dispatch ]
jobs:
build-bld-project:
runs-on: ubuntu-latest
env:
COVERAGE_SDK: "17"
COVERAGE_JDK: "17"
strategy:
matrix:
java-version: [ 17, 20 ]
java-version: [ 17, 21, 24 ]
os: [ ubuntu-latest, windows-latest, macos-latest ]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout source repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK ${{ matrix.java-version }}
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'zulu'
distribution: "zulu"
java-version: ${{ matrix.java-version }}
- name: Grant execute permission for bld
run: chmod +x bld
- name: Download the dependencies
- name: Download dependencies
run: ./bld download
- name: Run tests with bld
run: ./bld compile jacoco
- name: Compile source
run: ./bld compile
- name: Run tests
run: ./bld jacoco
- name: Remove pom.xml
if: success() && matrix.java-version == env.COVERAGE_SDK
if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.os == 'ubuntu-latest'
run: rm -rf pom.xml
- name: SonarCloud Scan
uses: sonarsource/sonarcloud-github-action@master
if: success() && matrix.java-version == env.COVERAGE_SDK
if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.os == 'ubuntu-latest'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
if: success() && matrix.java-version == env.COVERAGE_SDK
if: success() && matrix.java-version == env.COVERAGE_JDK && matrix.os == 'ubuntu-latest'
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

View file

@ -1 +1 @@
future-release=1.1.0
future-release=1.1.2

6
.idea/bld.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="BldConfiguration">
<events />
</component>
</project>

View file

@ -2,11 +2,12 @@
<library name="bld">
<CLASSES>
<root url="file://$PROJECT_DIR$/lib/bld" />
<root url="jar://$USER_HOME$/.bld/dist/bld-1.7.2.jar!/" />
<root url="jar://$USER_HOME$/.bld/dist/bld-2.2.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.bld/dist/bld-1.7.2-sources.jar!/" />
<root url="file://$PROJECT_DIR$/lib/bld" />
<root url="jar://$USER_HOME$/.bld/dist/bld-2.2.1-sources.jar!/" />
</SOURCES>
<excluded>
<root url="jar://$PROJECT_DIR$/lib/bld/bld-wrapper.jar!/" />

View file

@ -7,7 +7,7 @@
<SOURCES>
<root url="file://$PROJECT_DIR$/lib/compile" />
</SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="false" type="SOURCES" />
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/compile" recursive="true" type="SOURCES" />
</library>
</component>

View file

@ -8,7 +8,7 @@
<SOURCES>
<root url="file://$PROJECT_DIR$/lib/runtime" />
</SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="false" type="SOURCES" />
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/runtime" recursive="true" type="SOURCES" />
</library>
</component>

View file

@ -8,7 +8,7 @@
<SOURCES>
<root url="file://$PROJECT_DIR$/lib/test" />
</SOURCES>
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" />
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="false" type="SOURCES" />
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="true" />
<jarDirectory url="file://$PROJECT_DIR$/lib/test" recursive="true" type="SOURCES" />
</library>
</component>

7
.idea/misc.xml generated
View file

@ -1,15 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<pattern value="net.thauvin.erik.httpstatus.HttpStatusBuild" />
<pattern value="net.thauvin.erik.httpstatus.HttpStatusBuild" method="pmd" />
<pattern value="net.thauvin.erik.httpstatus.HttpStatusBuild" method="jacoco" />
<pattern value="net.thauvin.erik.httpstatus.taglibs.ReasonTag" method="setCode" />
<pattern value="net.thauvin.erik.httpstatus.HttpStatusBuild" method="pmdCli" />
</component>
<component name="PDMPlugin">
<option name="customRuleSets">
<list>
<option value="K:\java\semver\config\pmd.xml" />
<option value="$PROJECT_DIR$/../bld-pitest/config/pmd.xml" />
<option value="$PROJECT_DIR$/../bld-jacoco-report/config/pmd.xml" />
<option value="$PROJECT_DIR$/../bld-checkstyle/config/pmd.xml" />
<option value="$PROJECT_DIR$/../bld-exec/config/pmd.xml" />
<option value="$PROJECT_DIR$/../bld-testng/config/pmd.xml" />
</list>
</option>
<option name="skipTestSources" value="false" />

18
.vscode/launch.json vendored
View file

@ -1,11 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Run Tests",
"request": "launch",
"mainClass": "net.thauvin.erik.httpstatus.HttpStatusTest"
}
]
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Run Tests",
"request": "launch",
"mainClass": "net.thauvin.erik.httpstatus.HttpStatusTest"
}
]
}

View file

@ -3,13 +3,12 @@
"src/main/java",
"src/main/resources",
"src/test/java",
"src/bld/java"
"src/bld/java",
"src/bld/resources"
],
"java.configuration.updateBuildConfiguration": "automatic",
"java.project.referencedLibraries": [
"${HOME}bld-1.7.0.jar",
"lib/compile/*.jar",
"lib/runtime/*.jar",
"lib/test/*.jar"
"${HOME}/.bld/dist/bld-2.2.1.jar",
"lib/**/*.jar",
]
}

View file

@ -1,5 +1,14 @@
# Changelog
## [1.1.1](https://github.com/ethauvin/httpstatus/tree/1.1.1) (2024-06-07)
[Full Changelog](https://github.com/ethauvin/httpstatus/compare/1.1.0...1.1.1)
**Implemented enhancements:**
- Sort command line output [\#10](https://github.com/ethauvin/HttpStatus/issues/10)
- Update reasons properties status codes [\#9](https://github.com/ethauvin/HttpStatus/issues/9)
## [1.1.0](https://github.com/ethauvin/httpstatus/tree/1.1.0) (2023-09-29)
[Full Changelog](https://github.com/ethauvin/httpstatus/compare/1.0.5...1.1.0)

View file

@ -1,4 +1,4 @@
Copyright (c) 2015-2023, Erik C. Thauvin (erik@thauvin.net)
Copyright (c) 2015-2025, Erik C. Thauvin (erik@thauvin.net)
All rights reserved.
Redistribution and use in source and binary forms, with or without

View file

@ -2,9 +2,9 @@
[![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](http://opensource.org/licenses/BSD-3-Clause)
[![Java](https://img.shields.io/badge/java-17%2B-blue)](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html)
[![bld](https://img.shields.io/badge/1.7.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld)
[![bld](https://img.shields.io/badge/2.2.1-FA9052?label=bld&labelColor=2392FF)](https://rife2.com/bld)
[![Release](https://img.shields.io/github/release/ethauvin/httpstatus.svg)](https://github.com/ethauvin/httpstatus/releases/latest)
[![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/net.thauvin.erik.httpstatus/httpstatus?label=sanpshot&server=https%3A%2F%2Foss.sonatype.org)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/httpstatus/httpstatus/)
[![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/net.thauvin.erik.httpstatus/httpstatus.svg?label=sanpshot&server=https%3A%2F%2Foss.sonatype.org)](https://oss.sonatype.org/content/repositories/snapshots/net/thauvin/erik/httpstatus/httpstatus/)
[![Maven Central](https://img.shields.io/maven-central/v/net.thauvin.erik.httpstatus/httpstatus.svg?color=blue)](https://central.sonatype.com/artifact/net.thauvin.erik.httpstatus/httpstatus)
[![Known Vulnerabilities](https://snyk.io/test/github/ethauvin/httpstatus/badge.svg?targetFile=pom.xml)](https://snyk.io/test/github/ethauvin/httpstatus?targetFile=pom.xml)
@ -17,11 +17,11 @@ A simple [JSP](http://www.oracle.com/technetwork/java/javaee/jsp/index.html) Tag
## Table of Contents
- [Examples](#examples)
- Usage
- [Usage](#usage)
- [Gradle](#gradle)
- [bld](#bld)
- [Maven](#maven)
- JSP Tags
- [JSP Tags](#jsp-tags)
- [hs:cause](#hscause)
- [hs:code](#hscode)
- [hs:message](#hsmessage)
@ -29,6 +29,7 @@ A simple [JSP](http://www.oracle.com/technetwork/java/javaee/jsp/index.html) Tag
- [StatusCode Bean](#statuscode-bean)
- [Reasons](#reasons)
- [Command Line Usage](#command-line-usage)
- [Contributing](#contributing)
## Examples
@ -55,7 +56,7 @@ or
would display on a [501 status code](https://www.rfc-editor.org/rfc/rfc9110.html#name-501-not-implemented):
```plain
```console
Not Implemented
```
@ -71,7 +72,7 @@ repositories {
}
dependencies {
implementation 'net.thauvin.erik.httpstatus:httpstatus:1.1.0'
implementation 'net.thauvin.erik.httpstatus:httpstatus:1.1.1'
}
```
@ -93,7 +94,7 @@ As a `Maven` artifact:
<dependency>
<groupId>net.thauvin.erik.httpstatus</groupId>
<artifactId>httpstatus</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
</dependency>
```
@ -110,7 +111,7 @@ The `<hs:cause/>` tag displays the cause of current HTTP status code, if any. A
Optional attributes are:
| Attribute | Description |
|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `default` | The fallback value to output, if no cause is |
| `escapeXml` | Converts &lt;, &gt;, &amp;, ', " to their corresponding [entity codes](http://dev.w3.org/html5/html-author/charref). Value is `true` by default. |
@ -133,7 +134,7 @@ The `<hs:message/>` tag displays the current error message, if any. A shorthand
Optional attributes are:
| Attribute | Description |
|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `default` | The fallback value to output, if no error message is available. |
| `escapeXml` | Converts &lt;, &gt;, &amp;, ', " to their corresponding [entity codes](http://dev.w3.org/html5/html-author/charref). Value is `true` by default. |
@ -142,7 +143,7 @@ Optional attributes are:
The `<hs:reason/>` tag displays the reason for an HTTP status code, if any. Optional attributes are:
| Attribute | Description |
|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `default` | The fallback value to output, if no reason is available. |
| `code` | The HTTP status error code. If not specified the current status code is used. |
| `escapeXml` | Converts &lt;, &gt;, &amp;, ', " to their corresponding [entity codes](http://dev.w3.org/html5/html-author/charref). Value is `true` by default. |
@ -190,7 +191,7 @@ public class ExampleServlet extends HttpServlet {
The `StatusCode` bean methods are:
| Method | Description |
|-----------------|----------------------------------------------------------------------|
| --------------- | -------------------------------------------------------------------- |
| `getReason` | Returns the reason for the status code (eg: `Internal Server Error`) |
| `isClientError` | Checks if the status code is a client error. |
| `isError` | Checks if the status code is a server or client error. |
@ -205,11 +206,16 @@ The `StatusCode` bean methods are:
The reasons are defined in a [ResourceBundle](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/ResourceBundle.html) properties as follows:
| Status Code | Reason |
|-------------|------------------------------------------------------------|
| ----------- | ---------------------------------------------------------- |
| `100` | Continue |
| `101` | Switching Protocols |
| `102` | Processing |
| `103` | Early Hints |
| `110` | Response is Stale |
| `111` | Revalidation Failed |
| `112` | Disconnected Operation |
| `113` | Heuristic Expiration |
| `199` | Miscellaneous Warning |
| `200` | OK |
| `201` | Created |
| `202` | Accepted |
@ -219,15 +225,17 @@ The reasons are defined in a [ResourceBundle](https://docs.oracle.com/en/java/ja
| `206` | Partial Content |
| `207` | Multi-Status |
| `208` | Already Reported |
| `214` | Transformation Applied |
| `218` | This is fine |
| `226` | IM Used |
| `299` | Miscellaneous Persistent Warning |
| `300` | Multiple Choices |
| `301` | Moved Permanently |
| `302` | Found/Moved Temporarily |
| `303` | See Other |
| `304` | Not Modified |
| `305` | Use Proxy |
| `306` | Switch Proxy |
| `306` | Unused |
| `307` | Temporary Redirect |
| `308` | Permanent Redirect |
| `400` | Bad Request |
@ -243,18 +251,19 @@ The reasons are defined in a [ResourceBundle](https://docs.oracle.com/en/java/ja
| `410` | Gone |
| `411` | Length Required |
| `412` | Precondition Failed |
| `413` | Request Entity/Payload Too Large |
| `414` | Request-URI Too Long |
| `413` | Payload Too Large |
| `414` | URI Too Long |
| `415` | Unsupported Media Type |
| `416` | Requested Range Not Satisfiable |
| `416` | Range Not Satisfiable |
| `417` | Expectation Failed |
| `418` | I'm A Teapot |
| `419` | Insufficient Space on Resource |
| `420` | Method Failure |
| `421` | Misdirected Request |
| `422` | Unprocessable Entity |
| `422` | Unprocessable Content |
| `423` | Locked |
| `424` | Failed Dependency |
| `425` | Too Early |
| `426` | Upgrade Required |
| `428` | Precondition Required |
| `429` | Too Many Requests |
@ -269,7 +278,7 @@ The reasons are defined in a [ResourceBundle](https://docs.oracle.com/en/java/ja
| `463` | X-Forwarded-For Header with More than 30 IP Addresses |
| `494` | Request Header Too Large |
| `495` | SSL Certificate Error |
| `496` | No SSL Certificate |
| `496` | SSL Certificate Required |
| `497` | HTTP Request Sent to HTTPS Port |
| `498` | Token Expired/Invalid |
| `499` | Client Closed Request |
@ -287,7 +296,7 @@ The reasons are defined in a [ResourceBundle](https://docs.oracle.com/en/java/ja
| `511` | Network Authentication Required |
| `520` | Unknown Error |
| `521` | Web Server Is Down |
| `522` | Origin Connection Time-out |
| `522` | Connection Timed Out |
| `523` | Origin Is Unreachable |
| `524` | A Timeout Occurred |
| `525` | SSL Handshake Failed |
@ -295,27 +304,35 @@ The reasons are defined in a [ResourceBundle](https://docs.oracle.com/en/java/ja
| `527` | Railgun Error |
| `529` | Site is overloaded |
| `530` | Site is frozen |
| `540` | Temporarily Disabled |
| `561` | Unauthorized |
| `598` | Network Read Timeout Error |
| `599` | Network Connect Timeout Error |
| `783` | Unexpected Token |
## Command Line Usage
You can query the reason phrase for status codes as follows:
```sh
$ java -jar httpstatus-1.1.0.jar 404 500
```console
$ java -jar httpstatus-1.1.1.jar 404 500
404: Not Found
500: Internal Server Error
```
If no status code is specified, all will be printed:
```sh
$ java -jar httpstatus-1.1.0.jar
```console
$ java -jar httpstatus-1.1.1.jar
100: Continue
101: Switching Protocols
102: Processing
103: Early Hints
110: Response is Stale
111: Revalidation Failed
112: Disconnected Operation
113: Heuristic Expiration
199: Miscellaneous Warning
200: OK
201: Created
202: Accepted
@ -325,11 +342,30 @@ $ java -jar httpstatus-1.1.0.jar
You can also print status codes by [response classes](https://www.rfc-editor.org/rfc/rfc9110.html#name-status-codes):
```sh
$ java -jar httpstatus-1.1.0.jar 2xx
```console
$ java -jar httpstatus-1.1.1.jar 2xx
200: OK
201: Created
202: Accepted
203: Non-Authoritative Information
...
```
## Contributing
If you want to contribute to this project, all you have to do is clone the GitHub
repository:
```console
git clone git@github.com:ethauvin/HttpStatus.git
```
Then use [bld](https://rife2.com/bld) to build:
```console
cd HttpStatus
./bld compile
```
The project has an [IntelliJ IDEA](https://www.jetbrains.com/idea/) project structure. You can just open it after all
the dependencies were downloaded and peruse the code.

View file

@ -7,9 +7,9 @@
<!-- BEST PRACTICES -->
<rule ref="category/java/bestpractices.xml">
<exclude name="AvoidPrintStackTrace"/>
<exclude name="JUnit4TestShouldUseTestAnnotation"/>
<exclude name="JUnitTestContainsTooManyAsserts"/>
<exclude name="GuardLogStatement"/>
<exclude name="UnitTestContainsTooManyAsserts"/>
<exclude name="UnitTestShouldUseTestAnnotation"/>
</rule>
<rule ref="category/java/bestpractices.xml/MissingOverride">
@ -24,8 +24,8 @@
<rule ref="category/java/codestyle.xml">
<exclude name="AtLeastOneConstructor"/>
<exclude name="ClassNamingConventions"/>
<exclude name="ConfusingTernary"/>
<exclude name="CommentDefaultAccessModifier"/>
<exclude name="ConfusingTernary"/>
<exclude name="FieldNamingConventions"/>
<exclude name="LocalVariableCouldBeFinal"/>
<exclude name="LongVariable"/>
@ -35,8 +35,9 @@
<exclude name="ShortClassName"/>
<exclude name="ShortMethodName"/>
<exclude name="ShortVariable"/>
<exclude name="UselessParentheses"/>
<exclude name="UseExplicitTypes"/>
<exclude name="UseUnderscoresInNumericLiterals"/>
<exclude name="UselessParentheses"/>
</rule>
<rule ref="category/java/codestyle.xml/UnnecessaryImport">
@ -52,8 +53,6 @@
<exclude name="AvoidUncheckedExceptionsInSignatures"/>
<exclude name="CognitiveComplexity"/>
<exclude name="CyclomaticComplexity"/>
<exclude name="ExcessiveClassLength"/>
<exclude name="ExcessiveMethodLength"/>
<exclude name="ExcessiveParameterList"/>
<exclude name="ExcessivePublicCount"/>
<exclude name="GodClass"/>

Binary file not shown.

View file

@ -1,7 +1,7 @@
bld.downloadExtensionJavadoc=false
bld.downloadExtensionSources=true
bld.extension-pmd=com.uwyn.rife2:bld-pmd:0.9.2
bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.1-SNAPSHOT
bld.repositories=MAVEN_LOCAL,RIFE2_SNAPSHOTS,RIFE2_RELEASES,MAVEN_CENTRAL
bld.downloadLocation=
bld.version=1.7.2
bld.extension-jacoco=com.uwyn.rife2:bld-jacoco-report:0.9.10
bld.extension-pmd=com.uwyn.rife2:bld-pmd:1.2.3
bld.repositories=MAVEN_CENTRAL,RIFE2_RELEASES,MAVEN_LOCAL,RIFE2_SNAPSHOTS
bld.version=2.2.1

10
pom.xml
View file

@ -4,33 +4,33 @@
<modelVersion>4.0.0</modelVersion>
<groupId>net.thauvin.erik.httpstatus</groupId>
<artifactId>httpstatus</artifactId>
<version>1.1.0</version>
<version>1.1.2-SNAPSHOT</version>
<name>HttpStatus</name>
<description>Tag library to display the code, reason, cause and/or message for HTTP status codes in JSP error pages</description>
<url>https://github.com/ethauvin/HttpStatus</url>
<licenses>
<license>
<name>The BSD 3-Clause License</name>
<url>http://opensource.org/licenses/BSD-3-Clause</url>
<url>https://opensource.org/licenses/BSD-3-Clause</url>
</license>
</licenses>
<dependencies>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<version>6.1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>jakarta.servlet.jsp</groupId>
<artifactId>jakarta.servlet.jsp-api</artifactId>
<version>3.1.1</version>
<version>4.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>jakarta.el</groupId>
<artifactId>jakarta.el-api</artifactId>
<version>5.0.1</version>
<version>6.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>

View file

@ -1,7 +1,7 @@
/*
* HttpStatusBuild.java
*
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net)
* Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -39,8 +39,7 @@ import rife.bld.extension.PmdOperation;
import rife.bld.publish.*;
import rife.tools.exceptions.FileUtilsErrorException;
import java.io.IOException;
import java.nio.file.Path;
import java.io.File;
import java.util.List;
import java.util.jar.Attributes;
@ -50,10 +49,15 @@ import static rife.bld.dependencies.Scope.test;
import static rife.bld.operations.JavadocOptions.DocLinkOption.NO_MISSING;
public class HttpStatusBuild extends Project {
final PmdOperation pmdOp = new PmdOperation()
.fromProject(this)
.failOnViolation(true)
.ruleSets("config/pmd.xml");
public HttpStatusBuild() {
pkg = "net.thauvin.erik.httpstatus";
name = "HttpStatus";
version = version(1, 1, 0);
version = version(1, 1, 2, "SNAPSHOT");
var description = "Tag library to display the code, reason, cause and/or message for HTTP status codes in JSP error pages";
var url = "https://github.com/ethauvin/HttpStatus";
@ -63,16 +67,17 @@ public class HttpStatusBuild extends Project {
javaRelease = 17;
downloadSources = true;
autoDownloadPurge = true;
repositories = List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS);
scope(compile)
.include(dependency("jakarta.servlet", "jakarta.servlet-api", version(6, 0, 0)))
.include(dependency("jakarta.servlet.jsp", "jakarta.servlet.jsp-api", version(3, 1, 1)))
.include(dependency("jakarta.el", "jakarta.el-api", version(5, 0, 1)));
.include(dependency("jakarta.servlet", "jakarta.servlet-api", version(6, 1, 0)))
.include(dependency("jakarta.servlet.jsp", "jakarta.servlet.jsp-api", version(4, 0, 0)))
.include(dependency("jakarta.el", "jakarta.el-api", version(6, 0, 1)));
scope(test)
.include(dependency("org.assertj", "assertj-core", version(3, 24, 2)))
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 10, 0)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 10, 0)));
.include(dependency("org.assertj", "assertj-core", version(3, 27, 3)))
.include(dependency("org.junit.jupiter", "junit-jupiter", version(5, 12, 2)))
.include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1, 12, 2)));
jarOperation().manifestAttribute(Attributes.Name.MAIN_CLASS, pkg + '.' + "Reasons");
@ -84,8 +89,9 @@ public class HttpStatusBuild extends Project {
publishOperation()
.repository(version.isSnapshot() ? repository(SONATYPE_SNAPSHOTS_LEGACY.location())
.withCredentials(property("sonatype.user"), property("sonatype.password"))
: repository("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
: repository(SONATYPE_RELEASES_LEGACY.location())
.withCredentials(property("sonatype.user"), property("sonatype.password")))
.repository(repository("github"))
.info(new PublishInfo()
.groupId(pkg)
.artifactId(name.toLowerCase())
@ -93,11 +99,18 @@ public class HttpStatusBuild extends Project {
.version(version)
.description(description)
.url(url)
.developer(new PublishDeveloper().id("ethauvin").name("Erik C. Thauvin").email("erik@thauvin.net")
.url("https://erik.thauvin.net/"))
.license(new PublishLicense().name("The BSD 3-Clause License")
.url("http://opensource.org/licenses/BSD-3-Clause"))
.scm(new PublishScm().connection("scm:git:" + url + ".git")
.developer(new PublishDeveloper()
.id("ethauvin")
.name("Erik C. Thauvin")
.email("erik@thauvin.net")
.url("https://erik.thauvin.net/")
)
.license(new PublishLicense()
.name("The BSD 3-Clause License")
.url("https://opensource.org/licenses/BSD-3-Clause")
)
.scm(new PublishScm()
.connection("scm:git:" + url + ".git")
.developerConnection("scm:git:git@github.com:ethauvin/" + name + ".git")
.url(url))
.signKey(property("sign.key"))
@ -109,35 +122,36 @@ public class HttpStatusBuild extends Project {
}
@BuildCommand(summary = "Generates JaCoCo Reports")
public void jacoco() throws IOException {
public void jacoco() throws Exception {
new JacocoReportOperation()
.fromProject(this)
.execute();
}
@BuildCommand(summary = "Runs PMD analysis")
public void pmd() {
new PmdOperation()
.fromProject(this)
.failOnViolation(true)
.ruleSets("config/pmd.xml")
.execute();
public void pmd() throws Exception {
pmdOp.execute();
}
@BuildCommand(value = "pmd-cli", summary = "Runs PMD analysis (CLI)")
public void pmdCli() throws Exception {
pmdOp.includeLineNumber(false).execute();
}
private void pomRoot() throws FileUtilsErrorException {
PomBuilder.generateInto(publishOperation().fromProject(this).info(), dependencies(),
new File(workDirectory, "pom.xml"));
}
@Override
public void publish() throws Exception {
super.publish();
rootPom();
pomRoot();
}
@Override
public void publishLocal() throws Exception {
super.publishLocal();
rootPom();
}
private void rootPom() throws FileUtilsErrorException {
PomBuilder.generateInto(publishOperation().info(), publishOperation().dependencies(),
Path.of(workDirectory.getPath(), "pom.xml").toFile());
pomRoot();
}
}

View file

@ -1,7 +1,7 @@
/*
* Reasons.java
*
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net)
* Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -34,6 +34,7 @@ package net.thauvin.erik.httpstatus;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
/**
@ -56,8 +57,8 @@ public final class Reasons {
// Initializes the reason phrases map.
static {
final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_BASENAME);
for (final String key : bundle.keySet()) {
var bundle = ResourceBundle.getBundle(BUNDLE_BASENAME);
for (var key : bundle.keySet()) {
REASON_PHRASES.put(key, bundle.getString(key));
}
}
@ -75,7 +76,7 @@ public final class Reasons {
* @param statusCode The status code.
* @return The reason phrase, or <code>null</code>.
*/
public static String getReasonPhrase(final int statusCode) {
public static String getReasonPhrase(int statusCode) {
return getReasonPhrase(Integer.toString(statusCode));
}
@ -85,7 +86,7 @@ public final class Reasons {
* @param statusCode The status code.
* @return The reason phrase, or <code>null</code>.
*/
public static String getReasonPhrase(final String statusCode) {
public static String getReasonPhrase(String statusCode) {
return REASON_PHRASES.get(statusCode);
}
@ -95,29 +96,26 @@ public final class Reasons {
* @param args The status code(s) or response class(es), prints all if none.
*/
@SuppressWarnings("PMD.SystemPrintln")
public static void main(final String... args) {
public static void main(String... args) {
var keys = new TreeSet<>(REASON_PHRASES.keySet());
if (args.length >= 1) {
for (final String key : args) {
if (key.endsWith("xx")) {
var responseClass = key.charAt(0);
REASON_PHRASES.forEach((k, v) -> {
for (var arg : args) {
if (arg.endsWith("xx")) { // e.g.: 2xx
var responseClass = arg.charAt(0);
keys.forEach(k -> {
if (k.charAt(0) == responseClass) {
System.out.println(k + ": " + v);
System.out.println(k + ": " + REASON_PHRASES.get(k));
}
});
} else {
final String value = REASON_PHRASES.get(key);
} else { // e.g.: 404
var value = REASON_PHRASES.get(arg);
if (value != null) {
System.out.println(key + ": " + value);
System.out.println(arg + ": " + value);
}
}
}
} else {
REASON_PHRASES.forEach((k, v) -> {
if (v != null) {
System.out.println(k + ": " + v);
}
});
} else { // Print all
keys.forEach(k -> System.out.println(k + ": " + REASON_PHRASES.get(k)));
System.out.println("Total: " + REASON_PHRASES.size());
}
}

View file

@ -1,7 +1,7 @@
/*
* StatusCode.java
*
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net)
* Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -58,7 +58,7 @@ public class StatusCode implements Serializable {
*
* @param code The status code.
*/
public StatusCode(final int code) {
public StatusCode(int code) {
this.code = code;
}
@ -139,7 +139,7 @@ public class StatusCode implements Serializable {
* @return <code>true</code> if the status code is valid, <code>false</code> otherwise.
*/
public boolean isValid() {
return code >= 100 && code < 600;
return code == 783 || (code >= 100 && code < 600);
}
/**
@ -147,7 +147,7 @@ public class StatusCode implements Serializable {
*
* @param code The HTTP status code.
*/
public void setCode(final int code) {
public void setCode(int code) {
this.code = code;
}
}

View file

@ -1,7 +1,7 @@
/*
* Utils.java
*
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net)
* Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -59,11 +59,11 @@ public final class Utils {
* @param value The string value to convert.
* @return The converted string value.
*/
public static String escapeXml(final String value) {
final StringBuilder escaped = new StringBuilder();
public static String escapeXml(String value) {
var escaped = new StringBuilder();
for (int i = 0; i < value.length(); i++) {
final char c = value.charAt(i);
for (var i = 0; i < value.length(); i++) {
var c = value.charAt(i);
switch (c) {
case '<' -> escaped.append("&lt;");
case '>' -> escaped.append("&gt;");
@ -86,7 +86,7 @@ public final class Utils {
* @param xml The {@link #escapeXml(String) xml} flag.
* @throws IOException If an I/O error occurs.
*/
public static void outWrite(final Writer out, final String value, final String defaultValue, final boolean xml)
public static void outWrite(Writer out, String value, String defaultValue, boolean xml)
throws IOException {
if (value != null) {
out.write(xml ? escapeXml(value) : value);

View file

@ -1,7 +1,7 @@
/*
* CauseTag.java
*
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net)
* Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -38,6 +38,7 @@ import net.thauvin.erik.httpstatus.Utils;
import java.io.IOException;
/**
* The <code>&lt;hs:cause&gt;</code> tag returns the cause (if any) for the current HTTP Status Error Code.
*
@ -47,14 +48,16 @@ import java.io.IOException;
*/
public class CauseTag extends XmlSupport {
/**
* {@inheritDoc}
* Prints the cause (if any) for the current HTTP Status Error Code.
*
* @throws IOException If an error occurs while writing the output.
*/
@Override
public void doTag() throws IOException {
final PageContext pageContext = (PageContext) getJspContext();
final JspWriter out = pageContext.getOut();
PageContext pageContext = (PageContext) getJspContext();
JspWriter out = pageContext.getOut();
final Throwable cause = pageContext.getErrorData().getThrowable().getCause();
Throwable cause = pageContext.getErrorData().getThrowable().getCause();
Utils.outWrite(out, getCause(cause), defaultValue, escapeXml);
}

View file

@ -1,7 +1,7 @@
/*
* CodeTag.java
*
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net)
* Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -47,12 +47,14 @@ import java.io.IOException;
*/
public class CodeTag extends SimpleTagSupport {
/**
* {@inheritDoc}
* Writes the HTTP Status Error Code to the current JspWriter.
*
* @throws IOException If an I/O error occurs.
*/
@Override
public void doTag() throws IOException {
final PageContext pageContext = (PageContext) getJspContext();
final JspWriter out = pageContext.getOut();
PageContext pageContext = (PageContext) getJspContext();
JspWriter out = pageContext.getOut();
out.write(String.valueOf(pageContext.getErrorData().getStatusCode()));
}

View file

@ -1,7 +1,7 @@
/*
* MessageTag.java
*
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net)
* Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -47,14 +47,16 @@ import java.io.IOException;
*/
public class MessageTag extends XmlSupport {
/**
* {@inheritDoc}
* Writes the error message associated with the current HTTP Status Error Code.
*
* @throws IOException If an I/O error occurs.
*/
@Override
public void doTag() throws IOException {
final PageContext pageContext = (PageContext) getJspContext();
final JspWriter out = pageContext.getOut();
PageContext pageContext = (PageContext) getJspContext();
JspWriter out = pageContext.getOut();
final String message = (String) pageContext.getRequest().getAttribute(
String message = (String) pageContext.getRequest().getAttribute(
jakarta.servlet.RequestDispatcher.ERROR_MESSAGE);
Utils.outWrite(out, message, defaultValue, escapeXml);

View file

@ -1,7 +1,7 @@
/*
* ReasonTag.java
*
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net)
* Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -51,12 +51,12 @@ public class ReasonTag extends XmlSupport {
private int statusCode = -1;
/**
* {@inheritDoc}
* Writes the Reason Phrase for the current (or specified) HTTP Status Error Code.
*/
@Override
public void doTag() {
final PageContext pageContext = (PageContext) getJspContext();
final JspWriter out = pageContext.getOut();
PageContext pageContext = (PageContext) getJspContext();
JspWriter out = pageContext.getOut();
try {
if (statusCode > -1) {
@ -75,7 +75,7 @@ public class ReasonTag extends XmlSupport {
*
* @param statusCode The status code.
*/
public void setCode(final int statusCode) {
public void setCode(int statusCode) {
this.statusCode = statusCode;
}
}

View file

@ -1,7 +1,7 @@
/*
* XmlSupport.java
*
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net)
* Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -58,7 +58,7 @@ public abstract class XmlSupport extends SimpleTagSupport {
* @param defaultValue The default value.
*/
@SuppressWarnings("unused")
public void setDefault(final String defaultValue) {
public void setDefault(String defaultValue) {
this.defaultValue = defaultValue;
}
@ -68,7 +68,7 @@ public abstract class XmlSupport extends SimpleTagSupport {
* @param escapeXml <code>true</code> or <code>false</code>
*/
@SuppressWarnings("unused")
public void setEscapeXml(final boolean escapeXml) {
public void setEscapeXml(boolean escapeXml) {
this.escapeXml = escapeXml;
}
}

View file

@ -2,7 +2,7 @@
<!--
~ httpstatus.tld
~
~ Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net)
~ Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
~ All rights reserved.
~
~ Redistribution and use in source and binary forms, with or without
@ -37,7 +37,7 @@
<description>HttpStatus JSP Tag Library</description>
<display-name>HttpStatus JSP Tags</display-name>
<tlib-version>1.1.0</tlib-version>
<tlib-version>1.1.1</tlib-version>
<short-name>hs</short-name>
<uri>http://erik.thauvin.net/taglibs/httpstatus</uri>

View file

@ -1,7 +1,44 @@
#
# reasons.properties
#
# Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of this project nor the names of its contributors may be
# used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
100=Continue
101=Switching Protocols
102=Processing
103=Early Hints
110=Response is Stale
111=Revalidation Failed
112=Disconnected Operation
113=Heuristic Expiration
199=Miscellaneous Warning
200=OK
201=Created
202=Accepted
@ -11,15 +48,17 @@
206=Partial Content
207=Multi-Status
208=Already Reported
214=Transformation Applied
218=This is fine
226=IM Used
299=Miscellaneous Persistent Warning
300=Multiple Choices
301=Moved Permanently
302=Found/Moved Temporarily
303=See Other
304=Not Modified
305=Use Proxy
306=Switch Proxy
306=Unused
307=Temporary Redirect
308=Permanent Redirect
400=Bad Request
@ -35,18 +74,19 @@
410=Gone
411=Length Required
412=Precondition Failed
413=Request Entity/Payload Too Large
414=Request-URI Too Long
413=Payload Too Large
414=URI Too Long
415=Unsupported Media Type
416=Requested Range Not Satisfiable
416=Range Not Satisfiable
417=Expectation Failed
418=I'm A Teapot
419=Insufficient Space on Resource
420=Method Failure
421=Misdirected Request
422=Unprocessable Entity
422=Unprocessable Content
423=Locked
424=Failed Dependency
425=Too Early
426=Upgrade Required
428=Precondition Required
429=Too Many Requests
@ -61,7 +101,7 @@
463=X-Forwarded-For Header with More than 30 IP Addresses
494=Request Header Too Large
495=SSL Certificate Error
496=No SSL Certificate
496=SSL Certificate Required
497=HTTP Request Sent to HTTPS Port
498=Token Expired/Invalid
499=Client Closed Request
@ -79,7 +119,7 @@
511=Network Authentication Required
520=Unknown Error
521=Web Server Is Down
522=Origin Connection Time-out
522=Connection Timed Out
523=Origin Is Unreachable
524=A Timeout Occurred
525=SSL Handshake Failed
@ -87,5 +127,8 @@
527=Railgun Error
529=Site is overloaded
530=Site is frozen
540=Temporarily Disabled
561=Unauthorized
598=Network Read Timeout Error
599=Network Connect Timeout Error
783=Unexpected Token

View file

@ -1,7 +1,7 @@
/*
* CauseTagTest.java
*
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net)
* Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -33,10 +33,9 @@
package net.thauvin.erik.httpstatus;
import net.thauvin.erik.httpstatus.taglibs.CauseTag;
import org.assertj.core.api.AutoCloseableSoftAssertions;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Implements the CauseTagTest class.
*
@ -49,9 +48,11 @@ class CauseTagTest {
var message = "This is the cause";
var tag = new CauseTag();
assertThat(tag.getCause(new Exception(message))).as("has cause").isEqualTo(message);
assertThat(tag.getCause(new Exception())).as("no cause").isNull();
assertThat(tag.getCause(null)).as("null").isNull();
assertThat(tag.getCause(new Exception(""))).as("empty").isEmpty();
try (var softly = new AutoCloseableSoftAssertions()) {
softly.assertThat(tag.getCause(new Exception(message))).as("has cause").isEqualTo(message);
softly.assertThat(tag.getCause(new Exception())).as("no cause").isNull();
softly.assertThat(tag.getCause(null)).as("null").isNull();
softly.assertThat(tag.getCause(new Exception(""))).as("empty").isEmpty();
}
}
}

View file

@ -1,7 +1,7 @@
/*
* ReasonsMainTest.java
*
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net)
* Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -50,55 +50,55 @@ import static org.assertj.core.api.Assertions.assertThat;
* @since 1.0
*/
class ReasonsMainTest {
private final static PrintStream originalOut = System.out;
private final static ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private static final ByteArrayOutputStream OUTPUT_STREAM = new ByteArrayOutputStream();
private static final PrintStream SYSTEM_OUT = System.out;
@AfterAll
public static void restoreStreams() {
System.setOut(originalOut);
System.setOut(SYSTEM_OUT);
}
@BeforeAll
public static void setUpStreams() {
System.setOut(new PrintStream(outContent));
System.setOut(new PrintStream(OUTPUT_STREAM));
}
@BeforeEach
public void resetStreams() {
outContent.reset();
OUTPUT_STREAM.reset();
}
@Test
void testMain() {
Reasons.main("401");
assertThat(outContent.toString()).contains(Reasons.getReasonPhrase("401")).as("401");
assertThat(outContent.toString()).doesNotContain("500").as("401 no 500");
assertThat(OUTPUT_STREAM.toString()).contains(Reasons.getReasonPhrase("401")).as("401");
assertThat(OUTPUT_STREAM.toString()).doesNotContain("500").as("401 no 500");
}
@Test
void testMainAll() {
Reasons.main();
assertThat(outContent.toString()).contains(Reasons.getReasonPhrase(301)).as("301");
assertThat(outContent.toString()).contains(Reasons.getReasonPhrase(404)).as("404");
assertThat(OUTPUT_STREAM.toString()).contains(Reasons.getReasonPhrase(301)).as("301");
assertThat(OUTPUT_STREAM.toString()).contains(Reasons.getReasonPhrase(404)).as("404");
}
@Test
void testMainArgs() {
Reasons.main("500", "302");
assertThat(outContent.toString()).contains(Reasons.getReasonPhrase("500")).as("500 (302)");
assertThat(outContent.toString()).contains(Reasons.getReasonPhrase("302")).as("(500) 302");
assertThat(outContent.toString()).doesNotContain("404").as("500/302 not 404");
assertThat(OUTPUT_STREAM.toString()).contains(Reasons.getReasonPhrase("500")).as("500 (302)");
assertThat(OUTPUT_STREAM.toString()).contains(Reasons.getReasonPhrase("302")).as("(500) 302");
assertThat(OUTPUT_STREAM.toString()).doesNotContain("404").as("500/302 not 404");
}
@Test
void testMainArgsClass() {
Reasons.main("2xx");
assertThat(outContent.toString()).contains(Reasons.getReasonPhrase("200")).as("2xx");
assertThat(OUTPUT_STREAM.toString()).contains(Reasons.getReasonPhrase("200")).as("2xx");
}
@Test
void testMainInvalid() {
Reasons.main("aaa");
assertThat(outContent.toString()).as("invalid argument: aaa").isEmpty();
assertThat(OUTPUT_STREAM.toString()).as("invalid argument: aaa").isEmpty();
}
}

View file

@ -1,7 +1,7 @@
/*
* ReasonsTest.java
*
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net)
* Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -48,11 +48,11 @@ import static org.assertj.core.api.Assertions.assertThat;
class ReasonsTest {
@Test
void testGetReasonPhrase() {
final ResourceBundle bundle = ResourceBundle.getBundle(Reasons.BUNDLE_BASENAME);
for (final String key : bundle.keySet()) {
assertThat(Reasons.getReasonPhrase(key)).as("getReasonPhrase(" + key + ')').isEqualTo(bundle.getString(key));
assertThat(Reasons.getReasonPhrase(Integer.parseInt(key)))
.as("getReasonPhrase(int: " + key + ')').isEqualTo(bundle.getString(key));
var bundle = ResourceBundle.getBundle(Reasons.BUNDLE_BASENAME);
for (var key : bundle.keySet()) {
assertThat(Reasons.getReasonPhrase(key)).as("getReasonPhrase(%s)", key).isEqualTo(bundle.getString(key));
assertThat(Reasons.getReasonPhrase(Integer.parseInt(key))).as("getReasonPhrase(%s)", key)
.isEqualTo(bundle.getString(key));
}
}

View file

@ -1,7 +1,7 @@
/*
* StatusCodeTest.java
*
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net)
* Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,6 +32,7 @@
package net.thauvin.erik.httpstatus;
import org.assertj.core.api.AutoCloseableSoftAssertions;
import org.junit.jupiter.api.Test;
import java.util.ResourceBundle;
@ -47,39 +48,49 @@ import static org.assertj.core.api.Assertions.assertThat;
class StatusCodeTest {
@Test
void testStatusCode() {
final ResourceBundle bundle = ResourceBundle.getBundle(Reasons.BUNDLE_BASENAME);
StatusCode statusCode = new StatusCode();
for (final String key : bundle.keySet()) {
final int code = Integer.parseInt(key);
statusCode.setCode(code);
assertThat(statusCode.getCode()).as("is not " + code).isEqualTo(code);
assertThat(statusCode.isInfo()).as(code + " is info").isEqualTo(code >= 100 && code < 200);
assertThat(statusCode.isSuccess()).as(code + " is ok").isEqualTo(code >= 200 && code < 300);
assertThat(statusCode.isRedirect()).as(code + " is redirect").isEqualTo(code >= 300 && code < 400);
assertThat(statusCode.isClientError()).as(code + " is client error").isEqualTo(code >= 400 && code < 500);
assertThat(statusCode.isServerError()).as(code + " is server error").isEqualTo(code >= 500 && code < 600);
assertThat(statusCode.isError()).as(code + " is error").isEqualTo(code >= 400 && code < 600);
assertThat(statusCode.isValid()).as(code + "is valid").isTrue();
var bundle = ResourceBundle.getBundle(Reasons.BUNDLE_BASENAME);
var statusCode = new StatusCode();
assertThat(statusCode.getReason()).as(code + "reason phrase is not valid")
.isEqualTo(Reasons.getReasonPhrase(code));
try (var softly = new AutoCloseableSoftAssertions()) {
for (var key : bundle.keySet()) {
int code = Integer.parseInt(key);
statusCode.setCode(code);
softly.assertThat(statusCode.getCode()).as("is not %s", code).isEqualTo(code);
softly.assertThat(statusCode.isInfo()).as("%s is info", code).isEqualTo(code >= 100 && code < 200);
softly.assertThat(statusCode.isSuccess()).as("%s is ok", code).isEqualTo(code >= 200 && code < 300);
softly.assertThat(statusCode.isRedirect()).as("%s is redirect", code)
.isEqualTo(code >= 300 && code < 400);
softly.assertThat(statusCode.isClientError()).as("%s is client error", code)
.isEqualTo(code >= 400 && code < 500);
softly.assertThat(statusCode.isServerError()).as("%s is server error", code)
.isEqualTo(code >= 500 && code < 600);
softly.assertThat(statusCode.isError()).as("%s is error", code).isEqualTo(code >= 400 && code < 600);
softly.assertThat(statusCode.isValid()).as("%s is valid", code).isTrue();
softly.assertThat(statusCode.getReason()).as("%s reason phrase is not valid", code)
.isEqualTo(Reasons.getReasonPhrase(code));
}
}
final int[] unknowns = {0, 99, 600};
for (final int code : unknowns) {
statusCode.setCode(code);
assertThat(statusCode.getCode()).as("is not " + code).isEqualTo(code);
assertThat(statusCode.isInfo()).as(code + " is info").isFalse();
assertThat(statusCode.isSuccess()).as(code + " is ok").isFalse();
assertThat(statusCode.isRedirect()).as(code + " is redirect").isFalse();
assertThat(statusCode.isClientError()).as(code + " is client error").isFalse();
assertThat(statusCode.isServerError()).as(code + " is server error").isFalse();
assertThat(statusCode.isError()).as(code + " is error").isFalse();
assertThat(statusCode.isValid()).as("600 is invalid").isFalse();
assertThat(statusCode.getReason()).as(code + "reason phrase is not null.").isNull();
try (var softly = new AutoCloseableSoftAssertions()) {
int[] unknowns = {0, 99, 600};
for (var code : unknowns) {
statusCode.setCode(code);
softly.assertThat(statusCode.getCode()).as("is not %s", code).isEqualTo(code);
softly.assertThat(statusCode.isInfo()).as("%s is info", code).isFalse();
softly.assertThat(statusCode.isSuccess()).as("%s is ok", code).isFalse();
softly.assertThat(statusCode.isRedirect()).as("%s is redirect", code).isFalse();
softly.assertThat(statusCode.isClientError()).as("%s is client error", code).isFalse();
softly.assertThat(statusCode.isServerError()).as("%s is server error", code).isFalse();
softly.assertThat(statusCode.isError()).as("%s is error", code).isFalse();
softly.assertThat(statusCode.isValid()).as("%s is invalid", code).isFalse();
softly.assertThat(statusCode.getReason()).as("%s reason phrase is not null.", code).isNull();
}
}
statusCode = new StatusCode(900);
assertThat(statusCode.getCode()).as("is not 900").isEqualTo(900);
assertThat(statusCode.getCode()).as("is not %s", statusCode.getCode()).isEqualTo(900);
}
}

View file

@ -1,7 +1,7 @@
/*
* UtilsTest.java
*
* Copyright 2015-2023 Erik C. Thauvin (erik@thauvin.net)
* Copyright 2015-2025 Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,6 +32,7 @@
package net.thauvin.erik.httpstatus;
import org.assertj.core.api.AutoCloseableSoftAssertions;
import org.junit.jupiter.api.Test;
import java.io.IOException;
@ -56,44 +57,44 @@ class UtilsTest {
"according the &quot;encoding&quot; parameter &amp; value.");
}
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
@Test
void testOutWrite() throws IOException {
try (StringWriter sw = new StringWriter()) {
Utils.outWrite(sw, null, "default", false);
assertThat(sw.toString()).isEqualTo("default").as("outWrite(default)");
try (var sw = new StringWriter(); var softly = new AutoCloseableSoftAssertions()) {
var defaultValue = "default";
Utils.outWrite(sw, null, defaultValue, false);
softly.assertThat(sw.toString()).as("outWrite(default)").isEqualTo(defaultValue);
sw.getBuffer().setLength(0);
Utils.outWrite(sw, "", "default", false);
assertThat(sw.toString()).isEqualTo("").as("outWrite(value empty)");
Utils.outWrite(sw, "", defaultValue, false);
softly.assertThat(sw.toString()).as("outWrite(value empty)").isEmpty();
sw.getBuffer().setLength(0);
Utils.outWrite(sw, null, null, true);
assertThat(sw.toString()).isEqualTo("").as("outWrite(null)");
softly.assertThat(sw.toString()).as("outWrite(null)").isEmpty();
sw.getBuffer().setLength(0);
Utils.outWrite(sw, "value", "default", false);
assertThat(sw.toString()).isEqualTo("value").as("outWrite(value)");
Utils.outWrite(sw, "value", defaultValue, false);
softly.assertThat(sw.toString()).as("outWrite(value)").isEqualTo("value");
sw.getBuffer().setLength(0);
Utils.outWrite(sw, "wan't", "default", true);
assertThat(sw.toString()).isEqualTo("wan&apos;t").as("outWrite(wan't)");
Utils.outWrite(sw, "wan't", defaultValue, true);
softly.assertThat(sw.toString()).as("outWrite(wan't)").isEqualTo("wan&apos;t");
sw.getBuffer().setLength(0);
Utils.outWrite(sw, null, "1 & 1", true);
assertThat(sw.toString()).isEqualTo("1 &amp; 1").as("outWrite(1 & 1)");
softly.assertThat(sw.toString()).as("outWrite(1 & 1)").isEqualTo("1 &amp; 1");
sw.getBuffer().setLength(0);
Utils.outWrite(sw, "", "default", true);
assertThat(sw.toString()).isEqualTo("").as("outWrite(value empty).as(xml)");
Utils.outWrite(sw, "", defaultValue, true);
softly.assertThat(sw.toString()).as("outWrite(value empty).as(xml)").isEmpty();
sw.getBuffer().setLength(0);
Utils.outWrite(sw, null, "", true);
assertThat(sw.toString()).isEqualTo("").as("outWrite(default empty)");
softly.assertThat(sw.toString()).as("outWrite(default empty)").isEmpty();
sw.getBuffer().setLength(0);
Utils.outWrite(sw, null, null, true);
assertThat(sw.toString()).isEqualTo("").as("outWrite(null).as(xml)");
softly.assertThat(sw.toString()).as("outWrite(null).as(xml)").isEmpty();
}
}
}