diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-11-04 03:04:02 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-11-04 03:04:02 +0000 |
commit | 9b6d0b5639882de2aa5624f174e87cb28717d9e7 (patch) | |
tree | b9d08e0241a6b4395446f0d76f19c07f37874827 | |
parent | 8305e91863d11c7ccec698de0cbc0078e5199927 (diff) | |
parent | 0c4d7b72e49a04598d65c566f44504b95342d75a (diff) | |
download | apache-commons-io-android14-qpr2-s3-release.tar.gz |
Snap for 11051137 from 0c4d7b72e49a04598d65c566f44504b95342d75a to 24Q1-releaseandroid-14.0.0_r37android-14.0.0_r36android-14.0.0_r35android-14.0.0_r34android-14.0.0_r33android-14.0.0_r32android-14.0.0_r31android-14.0.0_r30android-14.0.0_r29android14-qpr2-s5-releaseandroid14-qpr2-s4-releaseandroid14-qpr2-s3-releaseandroid14-qpr2-s2-releaseandroid14-qpr2-s1-releaseandroid14-qpr2-release
Change-Id: I714f4fd5addf48715cac4ccd95aee0668d6a2507
90 files changed, 1760 insertions, 666 deletions
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 14204217..120d34f3 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -45,7 +45,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 @@ -57,7 +57,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # v2.21.7 + uses: github/codeql-action/init@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -68,7 +68,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # v2.21.7 + uses: github/codeql-action/autobuild@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3 # âšī¸ Command-line programs to run using the OS shell. # đ https://git.io/JvXDl @@ -82,4 +82,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # v2.21.7 + uses: github/codeql-action/analyze@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index f100bf3f..5c778d55 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -29,7 +29,7 @@ jobs: java: [ 8 ] steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 @@ -44,7 +44,7 @@ jobs: distribution: 'temurin' java-version: ${{ matrix.java }} - name: Build with Maven - run: mvn -V test jacoco:report --file pom.xml --no-transfer-progress + run: mvn --show-version --batch-mode --no-transfer-progress test jacoco:report - name: Upload coverage to Codecov uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4 diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 6bd303e9..3ed497d6 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -28,22 +28,22 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] - java: [ 8, 11, 17 ] + java: [ 8, 11, 17, 21 ] experimental: [false] # include: -# - java: 18-ea +# - java: 22-ea # os: ubuntu-latest # experimental: true -# - java: 18-ea +# - java: 22-ea # os: windows-latest # experimental: true -# - java: 18-ea +# - java: 22-ea # os: macos-latest # experimental: true fail-fast: false steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 @@ -58,4 +58,4 @@ jobs: distribution: 'temurin' java-version: ${{ matrix.java }} - name: Build with Maven - run: mvn -V --file pom.xml --no-transfer-progress -DtrimStackTrace=false + run: mvn --show-version --batch-mode --no-transfer-progress -DtrimStackTrace=false diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index 3f533c0e..890f0498 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -40,12 +40,12 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@08b4669551908b1024bb425080c797723083c031 # 2.2.0 + uses: ossf/scorecard-action@483ef80eb98fb506c348f7d62e28055e49fe2398 # 2.3.0 with: results_file: results.sarif results_format: sarif @@ -64,6 +64,6 @@ jobs: retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # 2.21.7 + uses: github/codeql-action/upload-sarif@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # 2.22.3 with: sarif_file: results.sarif @@ -13,11 +13,11 @@ third_party { type: GIT value: "https://github.com/apache/commons-io.git" } - version: "rel/commons-io-2.14.0" + version: "rel/commons-io-2.15.0" license_type: NOTICE last_upgrade_date { year: 2023 - month: 10 - day: 11 + month: 11 + day: 1 } } @@ -46,7 +46,7 @@ Apache Commons IO [![GitHub Actions Status](https://github.com/apache/commons-io/workflows/Java%20CI/badge.svg)](https://github.com/apache/commons-io/actions) [![Coverage Status](https://codecov.io/gh/apache/commons-io/branch/master/graph/badge.svg)](https://app.codecov.io/gh/apache/commons-io) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/commons-io/commons-io/badge.svg?gav=true)](https://maven-badges.herokuapp.com/maven-central/commons-io/commons-io/?gav=true) -[![Javadocs](https://javadoc.io/badge/commons-io/commons-io/2.14.0.svg)](https://javadoc.io/doc/commons-io/commons-io/2.14.0) +[![Javadocs](https://javadoc.io/badge/commons-io/commons-io/2.15.0.svg)](https://javadoc.io/doc/commons-io/commons-io/2.15.0) [![CodeQL](https://github.com/apache/commons-io/workflows/CodeQL/badge.svg)](https://github.com/apache/commons-io/actions/workflows/codeql-analysis.yml?query=workflow%3ACodeQL) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/apache/commons-io/badge)](https://api.securityscorecards.dev/projects/github.com/apache/commons-io) @@ -60,8 +60,8 @@ More information can be found on the [Apache Commons IO homepage](https://common The [Javadoc](https://commons.apache.org/proper/commons-io/apidocs) can be browsed. Questions related to the usage of Apache Commons IO should be posted to the [user mailing list][ml]. -Where can I get the latest release? ------------------------------------ +Getting the latest release +-------------------------- You can download source and binaries from our [download page](https://commons.apache.org/proper/commons-io/download_io.cgi). Alternatively, you can pull it from the central Maven repositories: @@ -70,17 +70,25 @@ Alternatively, you can pull it from the central Maven repositories: <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> - <version>2.14.0</version> + <version>2.15.0</version> </dependency> ``` +Building +-------- + +Building requires a Java JDK and [Apache Maven](https://maven.apache.org/). +The required Java version is found in the `pom.xml` as the `maven.compiler.source` property. + +From a command shell, run `mvn` without arguments to invoke the default Maven goal to run all tests and checks. + Contributing ------------ We accept Pull Requests via GitHub. The [developer mailing list](https://commons.apache.org/mail-lists.html) is the main channel of communication for contributors. There are some guidelines which will make applying PRs easier for us: + No tabs! Please use spaces for indentation. -+ Respect the code style. ++ Respect the existing code style for each file. + Create minimal diffs - disable on save actions like reformat source code or organize imports. If you feel the source code should be reformatted create a separate PR for this change. + Provide JUnit tests for your changes and make sure your changes don't break any existing tests by running ```mvn```. @@ -89,13 +97,13 @@ You can learn more about contributing via GitHub in our [contribution guidelines License ------- -This code is under the [Apache License v2](https://www.apache.org/licenses/LICENSE-2.0). +This code is licensed under the [Apache License v2](https://www.apache.org/licenses/LICENSE-2.0). See the `NOTICE.txt` file for required notices and attributions. -Donations ---------- -You like Apache Commons IO? Then [donate back to the ASF](https://www.apache.org/foundation/contributing.html) to support the development. +Donating +-------- +You like Apache Commons IO? Then [donate back to the ASF](https://www.apache.org/foundation/contributing.html) to support development. Additional Resources -------------------- @@ -109,54 +117,4 @@ Additional Resources Apache Commons Components ------------------------- -| Component | GitHub Repository | Apache Homepage | -| --------- | ----------------- | ----------------| -| Apache Commons BCEL | [commons-bcel](https://github.com/apache/commons-bcel) | [commons-bcel](https://commons.apache.org/proper/commons-bcel) | -| Apache Commons Beanutils | [commons-beanutils](https://github.com/apache/commons-beanutils) | [commons-beanutils](https://commons.apache.org/proper/commons-beanutils) | -| Apache Commons BSF | [commons-bsf](https://github.com/apache/commons-bsf) | [commons-bsf](https://commons.apache.org/proper/commons-bsf) | -| Apache Commons Build-plugin | [commons-build-plugin](https://github.com/apache/commons-build-plugin) | [commons-build-plugin](https://commons.apache.org/proper/commons-build-plugin) | -| Apache Commons Chain | [commons-chain](https://github.com/apache/commons-chain) | [commons-chain](https://commons.apache.org/proper/commons-chain) | -| Apache Commons CLI | [commons-cli](https://github.com/apache/commons-cli) | [commons-cli](https://commons.apache.org/proper/commons-cli) | -| Apache Commons Codec | [commons-codec](https://github.com/apache/commons-codec) | [commons-codec](https://commons.apache.org/proper/commons-codec) | -| Apache Commons Collections | [commons-collections](https://github.com/apache/commons-collections) | [commons-collections](https://commons.apache.org/proper/commons-collections) | -| Apache Commons Compress | [commons-compress](https://github.com/apache/commons-compress) | [commons-compress](https://commons.apache.org/proper/commons-compress) | -| Apache Commons Configuration | [commons-configuration](https://github.com/apache/commons-configuration) | [commons-configuration](https://commons.apache.org/proper/commons-configuration) | -| Apache Commons Crypto | [commons-crypto](https://github.com/apache/commons-crypto) | [commons-crypto](https://commons.apache.org/proper/commons-crypto) | -| Apache Commons CSV | [commons-csv](https://github.com/apache/commons-csv) | [commons-csv](https://commons.apache.org/proper/commons-csv) | -| Apache Commons Daemon | [commons-daemon](https://github.com/apache/commons-daemon) | [commons-daemon](https://commons.apache.org/proper/commons-daemon) | -| Apache Commons DBCP | [commons-dbcp](https://github.com/apache/commons-dbcp) | [commons-dbcp](https://commons.apache.org/proper/commons-dbcp) | -| Apache Commons Dbutils | [commons-dbutils](https://github.com/apache/commons-dbutils) | [commons-dbutils](https://commons.apache.org/proper/commons-dbutils) | -| Apache Commons Digester | [commons-digester](https://github.com/apache/commons-digester) | [commons-digester](https://commons.apache.org/proper/commons-digester) | -| Apache Commons Email | [commons-email](https://github.com/apache/commons-email) | [commons-email](https://commons.apache.org/proper/commons-email) | -| Apache Commons Exec | [commons-exec](https://github.com/apache/commons-exec) | [commons-exec](https://commons.apache.org/proper/commons-exec) | -| Apache Commons Fileupload | [commons-fileupload](https://github.com/apache/commons-fileupload) | [commons-fileupload](https://commons.apache.org/proper/commons-fileupload) | -| Apache Commons Functor | [commons-functor](https://github.com/apache/commons-functor) | [commons-functor](https://commons.apache.org/proper/commons-functor) | -| Apache Commons Geometry | [commons-geometry](https://github.com/apache/commons-geometry) | [commons-geometry](https://commons.apache.org/proper/commons-geometry) | -| Apache Commons Graph | [commons-graph](https://github.com/apache/commons-graph) | [commons-graph](https://commons.apache.org/proper/commons-graph) | -| Apache Commons Imaging | [commons-imaging](https://github.com/apache/commons-imaging) | [commons-imaging](https://commons.apache.org/proper/commons-imaging) | -| Apache Commons IO | [commons-io](https://github.com/apache/commons-io) | [commons-io](https://commons.apache.org/proper/commons-io) | -| Apache Commons JCI | [commons-jci](https://github.com/apache/commons-jci) | [commons-jci](https://commons.apache.org/proper/commons-jci) | -| Apache Commons JCS | [commons-jcs](https://github.com/apache/commons-jcs) | [commons-jcs](https://commons.apache.org/proper/commons-jcs) | -| Apache Commons Jelly | [commons-jelly](https://github.com/apache/commons-jelly) | [commons-jelly](https://commons.apache.org/proper/commons-jelly) | -| Apache Commons Jexl | [commons-jexl](https://github.com/apache/commons-jexl) | [commons-jexl](https://commons.apache.org/proper/commons-jexl) | -| Apache Commons Jxpath | [commons-jxpath](https://github.com/apache/commons-jxpath) | [commons-jxpath](https://commons.apache.org/proper/commons-jxpath) | -| Apache Commons Lang | [commons-lang](https://github.com/apache/commons-lang) | [commons-lang](https://commons.apache.org/proper/commons-lang) | -| Apache Commons Logging | [commons-logging](https://github.com/apache/commons-logging) | [commons-logging](https://commons.apache.org/proper/commons-logging) | -| Apache Commons Math | [commons-math](https://github.com/apache/commons-math) | [commons-math](https://commons.apache.org/proper/commons-math) | -| Apache Commons Net | [commons-net](https://github.com/apache/commons-net) | [commons-net](https://commons.apache.org/proper/commons-net) | -| Apache Commons Numbers | [commons-numbers](https://github.com/apache/commons-numbers) | [commons-numbers](https://commons.apache.org/proper/commons-numbers) | -| Apache Commons Parent | [commons-parent](https://github.com/apache/commons-parent) | [commons-parent](https://commons.apache.org/proper/commons-parent) | -| Apache Commons Pool | [commons-pool](https://github.com/apache/commons-pool) | [commons-pool](https://commons.apache.org/proper/commons-pool) | -| Apache Commons Proxy | [commons-proxy](https://github.com/apache/commons-proxy) | [commons-proxy](https://commons.apache.org/proper/commons-proxy) | -| Apache Commons RDF | [commons-rdf](https://github.com/apache/commons-rdf) | [commons-rdf](https://commons.apache.org/proper/commons-rdf) | -| Apache Commons Release-plugin | [commons-release-plugin](https://github.com/apache/commons-release-plugin) | [commons-release-plugin](https://commons.apache.org/proper/commons-release-plugin) | -| Apache Commons Rng | [commons-rng](https://github.com/apache/commons-rng) | [commons-rng](https://commons.apache.org/proper/commons-rng) | -| Apache Commons Scxml | [commons-scxml](https://github.com/apache/commons-scxml) | [commons-scxml](https://commons.apache.org/proper/commons-scxml) | -| Apache Commons Signing | [commons-signing](https://github.com/apache/commons-signing) | [commons-signing](https://commons.apache.org/proper/commons-signing) | -| Apache Commons Skin | [commons-skin](https://github.com/apache/commons-skin) | [commons-skin](https://commons.apache.org/proper/commons-skin) | -| Apache Commons Statistics | [commons-statistics](https://github.com/apache/commons-statistics) | [commons-statistics](https://commons.apache.org/proper/commons-statistics) | -| Apache Commons Testing | [commons-testing](https://github.com/apache/commons-testing) | [commons-testing](https://commons.apache.org/proper/commons-testing) | -| Apache Commons Text | [commons-text](https://github.com/apache/commons-text) | [commons-text](https://commons.apache.org/proper/commons-text) | -| Apache Commons Validator | [commons-validator](https://github.com/apache/commons-validator) | [commons-validator](https://commons.apache.org/proper/commons-validator) | -| Apache Commons VFS | [commons-vfs](https://github.com/apache/commons-vfs) | [commons-vfs](https://commons.apache.org/proper/commons-vfs) | -| Apache Commons Weaver | [commons-weaver](https://github.com/apache/commons-weaver) | [commons-weaver](https://commons.apache.org/proper/commons-weaver) | +Please see the [list of components](https://commons.apache.org/components.html) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 8300ad4f..7eb52960 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,3 +1,82 @@ +Apache Commons IO +Version 2.15.0 +Release Notes + +INTRODUCTION: + +Commons IO is a package of Java utility classes like java.io. +Classes in this package are considered to be so standard and of such high +reuse as to justify existence in java.io. + +The Apache Commons IO library contains utility classes, stream implementations, file filters, +file comparators, endian transformation classes, and much more. + +Java 8 is required. + +Changes in this version include: + +New features: +o Add org.apache.commons.io.channels.FileChannels. Thanks to Gary Gregory. +o Add RandomAccessFiles#contentEquals(RandomAccessFile, RandomAccessFile). Thanks to Gary Gregory. +o Add RandomAccessFiles#reset(RandomAccessFile). Thanks to Gary Gregory. +o Add PathUtilsContentEqualsBenchmark. Thanks to Gary Gregory. +o Add org.apache.commons.io.StreamIterator. Thanks to Gary Gregory. +o Add MessageDigestInputStream and deprecate MessageDigestCalculatingInputStream. Thanks to Gary Gregory. + +Fixed Bugs: +o IO-810: XmlStreamReader encoding match RE is too strict. Thanks to Laurence Gonsalves. +o IO-810: Javadoc in FileUtils does not reflect code for thrown exceptions. Thanks to Gregor Dschung, Gary Gregory. +o IO-812: Javadoc should mention closing Streams based on file resources. Thanks to Adam Rauch, Gary Gregory. +o IO-811: In tests, Files.walk() direct and indirect callers fail to close the returned Stream. Thanks to Adam Rauch, Gary Gregory. +o IO-811: FileUtils.listFiles(File, String[], boolean) fails to close its internal Stream. Thanks to Adam Rauch, Gary Gregory. +o IO-811: FileUtils.iterateFiles(File, String[], boolean) fails to close its internal Stream. Thanks to Adam Rauch, Gary Gregory. +o IO-811: StreamIterator fails to close its internal Stream. Thanks to Adam Rauch, Gary Gregory. +o IO-814: Don't throw UncheckedIOException #491. Thanks to Elliotte Rusty Harold, Gary Gregory. +o IO-414: Don't write a BOM on every (or any) line #492. Thanks to Elliotte Rusty Harold, Gary Gregory. +o IO-814: RandomAccessFileMode.create(Path) provides a better NullPointerException message. Thanks to Gary Gregory. +o Improve performance of PathUtils.fileContentEquals(Path, Path, LinkOption[], OpenOption[]) by about 60%, see PathUtilsContentEqualsBenchmark. Thanks to Gary Gregory. +o Improve performance of PathUtils.fileContentEquals(Path, Path) by about 60%, see PathUtilsContentEqualsBenchmark. Thanks to Gary Gregory. +o Improve performance of FileUtils.contentEquals(File, File) by about 60%, see PathUtilsContentEqualsBenchmark. Thanks to Gary Gregory. +o Remove unused test code #494. Thanks to Elliotte Rusty Harold. +o [Javadoc] IOUtils#contentEquals does not throw NullPointerException #496. Thanks to sebbASF. +o Fix CodeQL warnings in UnsynchronizedBufferedInputStream: Implicit narrowing conversion in compound assignment. Thanks to Gary Gregory. +o MessageDigestCalculatingInputStream.MessageDigestMaintainingObserver.MessageDigestMaintainingObserver(MessageDigest) now throws a NullPointerException + if the MessageDigest is null. Thanks to Gary Gregory. +o MessageDigestCalculatingInputStream.MessageDigestCalculatingInputStream(InputStream, MessageDigest) now throws a NullPointerException + if the MessageDigest is null. Thanks to Gary Gregory. +o IO-816: UnsynchronizedBufferedInputStream.read(byte[], int, int) does not use buffer. Thanks to Andreas Loth, Gary Gregory. + +Changes: +o Bump org.apache.commons:commons-parent from 62 to 64. Thanks to Gary Gregory. + +Compatibility with 2.6: +Binary compatible: Yes. +Source compatible: Yes. +Semantic compatible: Yes. + +Commons IO 2.9.0 requires Java 8. +Commons IO 2.8.0 requires Java 8. +Commons IO 2.7 requires Java 8. +Commons IO 2.6 requires Java 7. +Commons IO 2.5 requires Java 6. +Commons IO 2.4 requires Java 6. +Commons IO 2.3 requires Java 6. +Commons IO 2.2 requires Java 5. +Commons IO 1.4 requires Java 1.3. + +Historical list of changes: https://commons.apache.org/proper/commons-io/changes-report.html + +For complete information on Apache Commons IO, including instructions on how to submit bug reports, +patches, or suggestions for improvement, see the Apache Commons IO website: + +https://commons.apache.org/proper/commons-io/ + +Download page: https://commons.apache.org/proper/commons-io/download_io.cgi + +Have fun! +-Apache Commons Team + +============================================================================== Apache Commons IO Version 2.14.0 @@ -1,4 +1,4 @@ -<?xml version="1.0"?> +<?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with @@ -19,12 +19,12 @@ <parent> <groupId>org.apache.commons</groupId> <artifactId>commons-parent</artifactId> - <version>62</version> + <version>64</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> - <version>2.14.0</version> + <version>2.15.0</version> <name>Apache Commons IO</name> <inceptionYear>2002</inceptionYear> @@ -52,7 +52,7 @@ file comparators, endian transformation classes, and much more. <connection>scm:git:https://gitbox.apache.org/repos/asf/commons-io.git</connection> <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/commons-io.git</developerConnection> <url>https://gitbox.apache.org/repos/asf?p=commons-io.git</url> - <tag>rel/commons-io-2.13.0</tag> + <tag>rel/commons-io-2.15.0</tag> </scm> <developers> @@ -257,6 +257,20 @@ file comparators, endian transformation classes, and much more. <scope>test</scope> </dependency> <dependency> + <!-- Java 21 support, revisit for Mockito 5 --> + <groupId>net.bytebuddy</groupId> + <artifactId>byte-buddy</artifactId> + <version>${commons.bytebuddy.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <!-- Java 21 support, revisit for Mockito 5 --> + <groupId>net.bytebuddy</groupId> + <artifactId>byte-buddy-agent</artifactId> + <version>${commons.bytebuddy.version}</version> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-inline</artifactId> <version>4.11.0</version> @@ -275,6 +289,12 @@ file comparators, endian transformation classes, and much more. <scope>test</scope> </dependency> <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + <version>1.16.0</version> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-core</artifactId> <version>${jmh.version}</version> @@ -294,8 +314,9 @@ file comparators, endian transformation classes, and much more. <commons.componentid>io</commons.componentid> <commons.module.name>org.apache.commons.io</commons.module.name> <commons.rc.version>RC1</commons.rc.version> - <commons.bc.version>2.13.0</commons.bc.version> - <commons.release.version>2.14.0</commons.release.version> + <commons.bc.version>2.14.0</commons.bc.version> + <commons.release.version>2.15.0</commons.release.version> + <commons.release.next>2.15.1</commons.release.next> <commons.release.desc>(requires Java 8)</commons.release.desc> <commons.jira.id>IO</commons.jira.id> <commons.jira.pid>12310477</commons.jira.pid> @@ -325,11 +346,10 @@ file comparators, endian transformation classes, and much more. <commons.javadoc.java.link>${commons.javadoc8.java.link}</commons.javadoc.java.link> <commons.moditect.version>1.0.0.Final</commons.moditect.version> <jmh.version>1.37</jmh.version> + <commons.bytebuddy.version>1.14.9</commons.bytebuddy.version> <japicmp.skip>false</japicmp.skip> <jacoco.skip>${env.JACOCO_SKIP}</jacoco.skip> <commons.release.isDistModule>true</commons.release.isDistModule> - <commons.releaseManagerName>Gary Gregory</commons.releaseManagerName> - <commons.releaseManagerKey>86fdc7e2a11262cb</commons.releaseManagerKey> </properties> <build> @@ -389,7 +409,8 @@ file comparators, endian transformation classes, and much more. </classpathDependencyExcludes> <forkCount>1</forkCount> <reuseForks>false</reuseForks> - <!-- limit memory size see IO-161 --> + <!-- Limit memory size see IO-161 --> + <!-- Mockito inline may need -XX:+EnableDynamicAgentLoading --> <argLine>${argLine} -Xmx25M</argLine> <includes> <!-- Only include test classes, not test data --> @@ -436,6 +457,14 @@ file comparators, endian transformation classes, and much more. <plugin> <groupId>com.github.siom79.japicmp</groupId> <artifactId>japicmp-maven-plugin</artifactId> + <configuration> + <parameter> + <excludes> + <!-- False positive: https://github.com/siom79/japicmp/issues/365 --> + <exclude>org.apache.commons.io.StreamIterator</exclude> + </excludes> + </parameter> + </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -465,7 +494,15 @@ file comparators, endian transformation classes, and much more. <plugin> <groupId>com.github.siom79.japicmp</groupId> <artifactId>japicmp-maven-plugin</artifactId> - </plugin> + <configuration> + <parameter> + <excludes> + <!-- False positive: https://github.com/siom79/japicmp/issues/365 --> + <exclude>org.apache.commons.io.StreamIterator</exclude> + </excludes> + </parameter> + </configuration> + </plugin> </plugins> </reporting> <profiles> diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 28efbb7d..d8665e8f 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -47,7 +47,92 @@ The <action> type attribute can be add,update,fix,remove. </properties> <body> - <release version="2.14.0" date="2023-09-24" description="Java 8 required."> + <release version="2.15.0" date="2023-10-21" description="Java 8 is required."> + <!-- FIX --> + <action dev="sebb" type="fix" issue="IO-810" due-to="Laurence Gonsalves"> + XmlStreamReader encoding match RE is too strict. + </action> + <action dev="ggregory" type="fix" issue="IO-810" due-to="Gregor Dschung, Gary Gregory"> + Javadoc in FileUtils does not reflect code for thrown exceptions. + </action> + <action dev="ggregory" type="fix" issue="IO-812" due-to="Adam Rauch, Gary Gregory"> + Javadoc should mention closing Streams based on file resources. + </action> + <action dev="ggregory" type="fix" issue="IO-811" due-to="Adam Rauch, Gary Gregory"> + In tests, Files.walk() direct and indirect callers fail to close the returned Stream. + </action> + <action dev="ggregory" type="fix" issue="IO-811" due-to="Adam Rauch, Gary Gregory"> + FileUtils.listFiles(File, String[], boolean) fails to close its internal Stream. + </action> + <action dev="ggregory" type="fix" issue="IO-811" due-to="Adam Rauch, Gary Gregory"> + FileUtils.iterateFiles(File, String[], boolean) fails to close its internal Stream. + </action> + <action dev="ggregory" type="fix" issue="IO-811" due-to="Adam Rauch, Gary Gregory"> + StreamIterator fails to close its internal Stream. + </action> + <action dev="ggregory" type="fix" issue="IO-814" due-to="Elliotte Rusty Harold, Gary Gregory"> + Don't throw UncheckedIOException #491. + </action> + <action dev="ggregory" type="fix" issue="IO-414" due-to="Elliotte Rusty Harold, Gary Gregory"> + Don't write a BOM on every (or any) line #492. + </action> + <action dev="ggregory" type="fix" issue="IO-814" due-to="Gary Gregory"> + RandomAccessFileMode.create(Path) provides a better NullPointerException message. + </action> + <action dev="ggregory" type="fix" due-to="Gary Gregory"> + Improve performance of PathUtils.fileContentEquals(Path, Path, LinkOption[], OpenOption[]) by about 60%, see PathUtilsContentEqualsBenchmark. + </action> + <action dev="ggregory" type="fix" due-to="Gary Gregory"> + Improve performance of PathUtils.fileContentEquals(Path, Path) by about 60%, see PathUtilsContentEqualsBenchmark. + </action> + <action dev="ggregory" type="fix" due-to="Gary Gregory"> + Improve performance of FileUtils.contentEquals(File, File) by about 60%, see PathUtilsContentEqualsBenchmark. + </action> + <action dev="ggregory" type="fix" due-to="Elliotte Rusty Harold"> + Remove unused test code #494. + </action> + <action dev="ggregory" type="fix" due-to="sebbASF"> + [Javadoc] IOUtils#contentEquals does not throw NullPointerException #496. + </action> + <action dev="ggregory" type="fix" due-to="Gary Gregory"> + Fix CodeQL warnings in UnsynchronizedBufferedInputStream: Implicit narrowing conversion in compound assignment. + </action> + <action dev="ggregory" type="fix" due-to="Gary Gregory"> + MessageDigestCalculatingInputStream.MessageDigestMaintainingObserver.MessageDigestMaintainingObserver(MessageDigest) now throws a NullPointerException + if the MessageDigest is null. + </action> + <action dev="ggregory" type="fix" due-to="Gary Gregory"> + MessageDigestCalculatingInputStream.MessageDigestCalculatingInputStream(InputStream, MessageDigest) now throws a NullPointerException + if the MessageDigest is null. + </action> + <action issue="IO-816" dev="ggregory" type="fix" due-to="Andreas Loth, Gary Gregory"> + UnsynchronizedBufferedInputStream.read(byte[], int, int) does not use buffer. + </action> + <!-- ADD --> + <action dev="ggregory" type="add" due-to="Gary Gregory"> + Add org.apache.commons.io.channels.FileChannels. + </action> + <action dev="ggregory" type="add" due-to="Gary Gregory"> + Add RandomAccessFiles#contentEquals(RandomAccessFile, RandomAccessFile). + </action> + <action dev="ggregory" type="add" due-to="Gary Gregory"> + Add RandomAccessFiles#reset(RandomAccessFile). + </action> + <action dev="ggregory" type="add" due-to="Gary Gregory"> + Add PathUtilsContentEqualsBenchmark. + </action> + <action dev="ggregory" type="add" due-to="Gary Gregory"> + Add org.apache.commons.io.StreamIterator. + </action> + <action dev="ggregory" type="add" due-to="Gary Gregory"> + Add MessageDigestInputStream and deprecate MessageDigestCalculatingInputStream. + </action> + <!-- UPDATE --> + <action dev="ggregory" type="update" due-to="Gary Gregory"> + Bump org.apache.commons:commons-parent from 62 to 64. + </action> + </release> + <release version="2.14.0" date="2023-09-24" description="Java 8 is required."> <!-- FIX --> <action dev="ggregory" type="fix" issue="IO-799" due-to="Jeroen van der Vegt, Gary Gregory"> ReaderInputStream.read() throws an exception instead of returning -1 when called again after returning -1. @@ -133,7 +218,7 @@ The <action> type attribute can be add,update,fix,remove. Bump commons-lang3 from 3.12 to 3.13.0. </action> </release> - <release version="2.13.0" date="2023-06-03" description="Java 8 required."> + <release version="2.13.0" date="2023-06-03" description="Java 8 is required."> <!-- FIX --> <action issue="IO-791" dev="ggregory" type="fix" due-to="Chad Wilson, Gary Gregory"> Regression in FileUtils.touch() - no longer creates parent directories. @@ -204,7 +289,7 @@ The <action> type attribute can be add,update,fix,remove. Bump commons-parent from 57 to 58. </action> </release> - <release version="2.12.0" date="2023-05-13" description="Java 8 required."> + <release version="2.12.0" date="2023-05-13" description="Java 8 is required."> <!-- FIX --> <action issue="IO-697" dev="kinow" type="fix" due-to="otter606"> IOUtils.toByteArray size validation does not match documentation. @@ -741,7 +826,7 @@ The <action> type attribute can be add,update,fix,remove. Bump default buffer size for WriterOutputStream to IOUtils#DEFAULT_BUFFER_SIZE. </action> </release> - <release version="2.11.0" date="2021-07-09" description="Java 8 required."> + <release version="2.11.0" date="2021-07-09" description="Java 8 is required."> <!-- FIX --> <action issue="IO-741" dev="ggregory" type="fix" due-to="Zach Sherman"> FileUtils.listFiles does not list matching files if File parameter is a symbolic link. @@ -793,7 +878,7 @@ The <action> type attribute can be add,update,fix,remove. </action> </release> <!-- The release date is the date RC is cut --> - <release version="2.10.0" date="2021-06-10" description="Java 8 required."> + <release version="2.10.0" date="2021-06-10" description="Java 8 is required."> <!-- FIX --> <action issue="IO-733" dev="ggregory" type="fix" due-to="Jim Sellers, Gary Gregory"> RegexFileFilter uses the path and file name instead of just the file name. @@ -828,7 +913,7 @@ The <action> type attribute can be add,update,fix,remove. Bump mockito-inline from 3.10.0 to 3.11.0 #242. </action> </release> - <release version="2.9.0" date="2021-05-22" description="Java 8 required."> + <release version="2.9.0" date="2021-05-22" description="Java 8 is required."> <!-- FIX --> <action issue="IO-686" dev="ggregory" type="fix" due-to="Alan Moffat, Gary Gregory"> IOUtils.toByteArray(InputStream) Javadoc does not match code. @@ -1073,7 +1158,7 @@ The <action> type attribute can be add,update,fix,remove. </action> </release> <!-- The release date is the date RC is cut --> - <release version="2.8.0" date="2020-09-05" description="Java 8 required."> + <release version="2.8.0" date="2020-09-05" description="Java 8 is required."> <action dev="ggregory" type="add" due-to="Gary Gregory"> Add org.apache.commons.io.input.CircularInputStream. </action> @@ -1199,7 +1284,7 @@ The <action> type attribute can be add,update,fix,remove. </action> </release> <!-- The release date is the date RC is cut --> - <release version="2.7" date="2020-05-24" description="Java 8 required."> + <release version="2.7" date="2020-05-24" description="Java 8 is required."> <action issue="IO-589" dev="sebb" type="fix"> Some tests fail if the base path contains a space. </action> diff --git a/src/conf/checkstyle.xml b/src/conf/checkstyle.xml index d2fc3923..4ff52333 100644 --- a/src/conf/checkstyle.xml +++ b/src/conf/checkstyle.xml @@ -34,6 +34,12 @@ limitations under the License. <module name="AvoidStarImport" /> <module name="RedundantImport" /> <module name="UnusedImports" /> + <module name="ImportOrder"> + <property name="option" value="top"/> + <property name="groups" value="java,javax,org"/> + <property name="ordered" value="true"/> + <property name="separated" value="true"/> + </module> <module name="NeedBraces" /> <module name="LeftCurly" /> <module name="JavadocMethod" /> diff --git a/src/main/java/org/apache/commons/io/ByteOrderMark.java b/src/main/java/org/apache/commons/io/ByteOrderMark.java index 2e4f0305..c5ab57b1 100644 --- a/src/main/java/org/apache/commons/io/ByteOrderMark.java +++ b/src/main/java/org/apache/commons/io/ByteOrderMark.java @@ -115,7 +115,14 @@ public class ByteOrderMark implements Serializable { */ public static final char UTF_BOM = '\uFEFF'; + /** + * Charset name. + */ private final String charsetName; + + /** + * Bytes. + */ private final int[] bytes; /** diff --git a/src/main/java/org/apache/commons/io/CopyUtils.java b/src/main/java/org/apache/commons/io/CopyUtils.java index b7e7829e..da01a987 100644 --- a/src/main/java/org/apache/commons/io/CopyUtils.java +++ b/src/main/java/org/apache/commons/io/CopyUtils.java @@ -103,7 +103,7 @@ import java.nio.charset.Charset; * method variants to specify the encoding, each row may * correspond to up to 2 methods. * <p> - * Origin of code: Excalibur. + * Provenance: Excalibur. * * @deprecated Use IOUtils. Will be removed in 3.0. * Methods renamed to IOUtils.write() or IOUtils.copy(). diff --git a/src/main/java/org/apache/commons/io/EndianUtils.java b/src/main/java/org/apache/commons/io/EndianUtils.java index acc95319..83c2ce25 100644 --- a/src/main/java/org/apache/commons/io/EndianUtils.java +++ b/src/main/java/org/apache/commons/io/EndianUtils.java @@ -34,7 +34,7 @@ import java.io.OutputStream; * This class helps you solve this incompatibility. * </p> * <p> - * Origin of code: Excalibur + * Provenance: Excalibur * </p> * * @see org.apache.commons.io.input.SwappedDataInputStream diff --git a/src/main/java/org/apache/commons/io/FileUtils.java b/src/main/java/org/apache/commons/io/FileUtils.java index 807dc37c..80d100f1 100644 --- a/src/main/java/org/apache/commons/io/FileUtils.java +++ b/src/main/java/org/apache/commons/io/FileUtils.java @@ -36,6 +36,7 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.charset.UnsupportedCharsetException; import java.nio.file.CopyOption; +import java.nio.file.DirectoryStream; import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; import java.nio.file.Files; @@ -108,7 +109,7 @@ import org.apache.commons.io.function.Uncheck; * {@link SecurityException} are not documented in the Javadoc. * </p> * <p> - * Origin of code: Excalibur, Alexandria, Commons-Utils + * Provenance: Excalibur, Alexandria, Commons-Utils * </p> */ public class FileUtils { @@ -352,16 +353,13 @@ public class FileUtils { * This method checks to see if the two files are different lengths or if they point to the same file, before * resorting to byte-by-byte comparison of the contents. * </p> - * <p> - * Code origin: Avalon - * </p> * * @param file1 the first file * @param file2 the second file * @return true if the content of the files are equal or they both don't exist, false otherwise * @throws IllegalArgumentException when an input is not a file. * @throws IOException If an I/O error occurs. - * @see org.apache.commons.io.file.PathUtils#fileContentEquals(Path,Path,java.nio.file.LinkOption[],java.nio.file.OpenOption...) + * @see PathUtils#fileContentEquals(Path,Path) */ public static boolean contentEquals(final File file1, final File file2) throws IOException { if (file1 == null && file2 == null) { @@ -393,9 +391,7 @@ public class FileUtils { return true; } - try (InputStream input1 = Files.newInputStream(file1.toPath()); InputStream input2 = Files.newInputStream(file2.toPath())) { - return IOUtils.contentEquals(input1, input2); - } + return PathUtils.fileContentEquals(file1.toPath(), file2.toPath()); } /** @@ -451,12 +447,12 @@ public class FileUtils { } /** - * Converts a Collection containing java.io.File instances into array + * Converts a Collection containing {@link File} instances into array * representation. This is to account for the difference between * File.listFiles() and FileUtils.listFiles(). * - * @param files a Collection containing java.io.File instances - * @return an array of java.io.File + * @param files a Collection containing {@link File} instances + * @return an array of {@link File} */ public static File[] convertFileCollectionToFileArray(final Collection<File> files) { return files.toArray(EMPTY_FILE_ARRAY); @@ -1449,7 +1445,7 @@ public class FileUtils { /** * Returns a {@link File} representing the system temporary directory. * - * @return the system temporary directory. + * @return the system temporary directory as a File * @since 2.0 */ public static File getTempDirectory() { @@ -1459,7 +1455,12 @@ public class FileUtils { /** * Returns the path to the system temporary directory. * - * @return the path to the system temporary directory. + * WARNING: this method relies on the Java system property 'java.io.tmpdir' + * which may or may not have a trailing file separator. + * This can affect code that uses String processing to manipulate pathnames rather + * than the standard libary methods in classes such as {@link java.io.File} + * + * @return the path to the system temporary directory as a String * @since 2.0 */ public static String getTempDirectoryPath() { @@ -1971,7 +1972,7 @@ public class FileUtils { * @param dirFilter optional filter to apply when finding subdirectories. * If this parameter is {@code null}, subdirectories will not be included in the * search. Use TrueFileFilter.INSTANCE to match all directories. - * @return an iterator of java.io.File for the matching files + * @return an iterator of {@link File} for the matching files * @see org.apache.commons.io.filefilter.FileFilterUtils * @see org.apache.commons.io.filefilter.NameFileFilter * @since 1.2 @@ -1988,14 +1989,14 @@ public class FileUtils { * </p> * * @param directory the directory to search in - * @param extensions an array of extensions, ex. {"java","xml"}. If this + * @param extensions an array of extensions, for example, {"java","xml"}. If this * parameter is {@code null}, all files are returned. * @param recursive if true all subdirectories are searched as well - * @return an iterator of java.io.File with the matching files + * @return an iterator of {@link File} with the matching files * @since 1.2 */ public static Iterator<File> iterateFiles(final File directory, final String[] extensions, final boolean recursive) { - return Uncheck.apply(d -> streamFiles(d, recursive, extensions).iterator(), directory); + return StreamIterator.iterator(Uncheck.get(() -> streamFiles(directory, recursive, extensions))); } /** @@ -2016,7 +2017,7 @@ public class FileUtils { * @param dirFilter optional filter to apply when finding subdirectories. * If this parameter is {@code null}, subdirectories will not be included in the * search. Use TrueFileFilter.INSTANCE to match all directories. - * @return an iterator of java.io.File for the matching files + * @return an iterator of {@link File} for the matching files * @see org.apache.commons.io.filefilter.FileFilterUtils * @see org.apache.commons.io.filefilter.NameFileFilter * @since 2.2 @@ -2216,28 +2217,30 @@ public class FileUtils { * @param dirFilter optional filter to apply when finding subdirectories. * If this parameter is {@code null}, subdirectories will not be included in the * search. Use {@link TrueFileFilter#INSTANCE} to match all directories. - * @return a collection of java.io.File with the matching files + * @return a collection of {@link File} with the matching files * @see org.apache.commons.io.filefilter.FileFilterUtils * @see org.apache.commons.io.filefilter.NameFileFilter */ public static Collection<File> listFiles(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) { final AccumulatorPathVisitor visitor = Uncheck .apply(d -> listAccumulate(d, FileFileFilter.INSTANCE.and(fileFilter), dirFilter, FileVisitOption.FOLLOW_LINKS), directory); - return visitor.getFileList().stream().map(Path::toFile).collect(Collectors.toList()); + return toList(visitor.getFileList().stream().map(Path::toFile)); } /** - * Finds files within a given directory (and optionally its subdirectories) + * Lists files within a given directory (and optionally its subdirectories) * which match an array of extensions. * * @param directory the directory to search in - * @param extensions an array of extensions, ex. {"java","xml"}. If this + * @param extensions an array of extensions, for example, {"java","xml"}. If this * parameter is {@code null}, all files are returned. * @param recursive if true all subdirectories are searched as well - * @return a collection of java.io.File with the matching files + * @return a collection of {@link File} with the matching files */ public static Collection<File> listFiles(final File directory, final String[] extensions, final boolean recursive) { - return Uncheck.apply(d -> toList(streamFiles(d, recursive, extensions)), directory); + try (Stream<File> fileStream = Uncheck.get(() -> streamFiles(directory, recursive, extensions))) { + return toList(fileStream); + } } /** @@ -2253,7 +2256,7 @@ public class FileUtils { * @param dirFilter optional filter to apply when finding subdirectories. * If this parameter is {@code null}, subdirectories will not be included in the * search. Use TrueFileFilter.INSTANCE to match all directories. - * @return a collection of java.io.File with the matching files + * @return a collection of {@link File} with the matching files * @see org.apache.commons.io.FileUtils#listFiles * @see org.apache.commons.io.filefilter.FileFilterUtils * @see org.apache.commons.io.filefilter.NameFileFilter @@ -2264,7 +2267,7 @@ public class FileUtils { directory); final List<Path> list = visitor.getFileList(); list.addAll(visitor.getDirList()); - return list.stream().map(Path::toFile).collect(Collectors.toList()); + return toList(list.stream().map(Path::toFile)); } /** @@ -2570,9 +2573,8 @@ public class FileUtils { * @param file the file to read, must not be {@code null} * @return the file contents, never {@code null} * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a + * regular file, or for some other reason why the file cannot be opened for reading. * @since 1.1 */ public static byte[] readFileToByteArray(final File file) throws IOException { @@ -2587,9 +2589,8 @@ public class FileUtils { * @param file the file to read, must not be {@code null} * @return the file contents, never {@code null} * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a + * regular file, or for some other reason why the file cannot be opened for reading. * @since 1.3.1 * @deprecated 2.5 use {@link #readFileToString(File, Charset)} instead (and specify the appropriate encoding) */ @@ -2606,9 +2607,8 @@ public class FileUtils { * @param charsetName the name of the requested charset, {@code null} means platform default * @return the file contents, never {@code null} * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a + * regular file, or for some other reason why the file cannot be opened for reading. * @since 2.3 */ public static String readFileToString(final File file, final Charset charsetName) throws IOException { @@ -2622,9 +2622,8 @@ public class FileUtils { * @param charsetName the name of the requested charset, {@code null} means platform default * @return the file contents, never {@code null} * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a + * regular file, or for some other reason why the file cannot be opened for reading. * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io * .UnsupportedEncodingException} in version 2.2 if the named charset is unavailable. * @since 2.3 @@ -2640,9 +2639,8 @@ public class FileUtils { * @param file the file to read, must not be {@code null} * @return the list of Strings representing each line in the file, never {@code null} * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a + * regular file, or for some other reason why the file cannot be opened for reading. * @since 1.3 * @deprecated 2.5 use {@link #readLines(File, Charset)} instead (and specify the appropriate encoding) */ @@ -2659,9 +2657,8 @@ public class FileUtils { * @param charset the charset to use, {@code null} means platform default * @return the list of Strings representing each line in the file, never {@code null} * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a + * regular file, or for some other reason why the file cannot be opened for reading. * @since 2.3 */ public static List<String> readLines(final File file, final Charset charset) throws IOException { @@ -2675,9 +2672,8 @@ public class FileUtils { * @param charsetName the name of the requested charset, {@code null} means platform default * @return the list of Strings representing each line in the file, never {@code null} * @throws NullPointerException if file is {@code null}. - * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some - * other reason cannot be opened for reading. - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a + * regular file, or for some other reason why the file cannot be opened for reading. * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io * .UnsupportedEncodingException} in version 2.2 if the named charset is unavailable. * @since 1.1 @@ -2861,9 +2857,8 @@ public class FileUtils { * {@code false} otherwise * @throws NullPointerException if sourceFile is {@code null}. * @throws NullPointerException if targetFile is {@code null}. - * @throws IOException if setting the last-modified time failed. */ - private static boolean setTimes(final File sourceFile, final File targetFile) throws IOException { + private static boolean setTimes(final File sourceFile, final File targetFile) { Objects.requireNonNull(sourceFile, "sourceFile"); Objects.requireNonNull(targetFile, "targetFile"); try { @@ -2967,14 +2962,17 @@ public class FileUtils { } /** - * Streams over the files in a given directory (and optionally - * its subdirectories) which match an array of extensions. + * Streams over the files in a given directory (and optionally its subdirectories) which match an array of extensions. + * <p> + * The returned {@link Stream} may wrap one or more {@link DirectoryStream}s. When you require timely disposal of file system resources, use a + * {@code try}-with-resources block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. Calling a + * closed stream causes a {@link IllegalStateException}. + * </p> * * @param directory the directory to search in * @param recursive if true all subdirectories are searched as well - * @param extensions an array of extensions, ex. {"java","xml"}. If this - * parameter is {@code null}, all files are returned. - * @return an iterator of java.io.File with the matching files + * @param extensions an array of extensions, for example, {"java","xml"}. If this parameter is {@code null}, all files are returned. + * @return a Stream of {@link File} for matching files. * @throws IOException if an I/O error is thrown when accessing the starting file. * @since 2.9.0 */ @@ -3006,8 +3004,8 @@ public class FileUtils { if (url == null || !"file".equalsIgnoreCase(url.getProtocol())) { return null; } - final String filename = url.getFile().replace('/', File.separatorChar); - return new File(decodeUrl(filename)); + final String fileName = url.getFile().replace('/', File.separatorChar); + return new File(decodeUrl(fileName)); } /** @@ -3048,6 +3046,15 @@ public class FileUtils { return files; } + /** + * Consumes all of the given stream. + * <p> + * When called from a FileTreeWalker, the walker <em>closes</em> the stream because {@link FileTreeWalker#next()} calls {@code top.stream().close()}. + * </p> + * + * @param stream The stream to consume. + * @return a new List. + */ private static List<File> toList(final Stream<File> stream) { return stream.collect(Collectors.toList()); } diff --git a/src/main/java/org/apache/commons/io/FilenameUtils.java b/src/main/java/org/apache/commons/io/FilenameUtils.java index 09c62f71..049c3a71 100644 --- a/src/main/java/org/apache/commons/io/FilenameUtils.java +++ b/src/main/java/org/apache/commons/io/FilenameUtils.java @@ -90,7 +90,7 @@ import java.util.stream.Stream; * currently running on. * </p> * <p> - * Origin of code: Excalibur, Alexandria, Tomcat, Commons-Utils. + * Provenance: Excalibur, Alexandria, Tomcat, Commons-Utils. * </p> * * @since 1.1 @@ -846,7 +846,7 @@ public class FilenameUtils { * ~user --> 6 --> named user (slash added) * //server/a/b/c.txt --> 9 * ///a/b/c.txt --> -1 --> error - * C: --> 0 --> valid filename as only null character and / are reserved characters + * C: --> 0 --> valid file name as only null character and / are reserved characters * </pre> * <p> * The output will be the same irrespective of the machine that the code is running on. diff --git a/src/main/java/org/apache/commons/io/HexDump.java b/src/main/java/org/apache/commons/io/HexDump.java index d7e5abdc..0a53e3d6 100644 --- a/src/main/java/org/apache/commons/io/HexDump.java +++ b/src/main/java/org/apache/commons/io/HexDump.java @@ -31,7 +31,7 @@ import org.apache.commons.io.output.CloseShieldOutputStream; * in hexadecimal form. * </p> * <p> - * Origin of code: POI. + * Provenance: POI. * </p> */ public class HexDump { diff --git a/src/main/java/org/apache/commons/io/IOIndexedException.java b/src/main/java/org/apache/commons/io/IOIndexedException.java index 9a85328e..1893509f 100644 --- a/src/main/java/org/apache/commons/io/IOIndexedException.java +++ b/src/main/java/org/apache/commons/io/IOIndexedException.java @@ -42,6 +42,9 @@ public class IOIndexedException extends IOException { return String.format("%s #%,d: %s", name, index, msg); } + /** + * Index. + */ private final int index; /** diff --git a/src/main/java/org/apache/commons/io/IOUtils.java b/src/main/java/org/apache/commons/io/IOUtils.java index b6b6f137..dfb4c19e 100644 --- a/src/main/java/org/apache/commons/io/IOUtils.java +++ b/src/main/java/org/apache/commons/io/IOUtils.java @@ -45,6 +45,7 @@ import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.channels.Selector; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.Arrays; import java.util.Collection; @@ -118,7 +119,7 @@ import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; * closing streams after use. * </p> * <p> - * Origin of code: Excalibur. + * Provenance: Excalibur. * </p> */ public class IOUtils { @@ -893,7 +894,6 @@ public class IOUtils { * @param input2 the second stream * @return true if the content of the streams are equal or they both don't * exist, false otherwise - * @throws NullPointerException if either input is null * @throws IOException if an I/O error occurs */ public static boolean contentEquals(final InputStream input1, final InputStream input2) throws IOException { @@ -3827,28 +3827,36 @@ public class IOUtils { * Writes the {@link #toString()} value of each item in a collection to * an {@link OutputStream} line by line, using the specified character * encoding and the specified line ending. + * <p> + * UTF-16 is written big-endian with no byte order mark. + * For little endian, use UTF-16LE. For a BOM, write it to the stream + * before calling this method. + * </p> * * @param lines the lines to write, null entries produce blank lines * @param lineEnding the line separator to use, null is system default * @param output the {@link OutputStream} to write to, not null, not closed * @param charset the charset to use, null means platform default - * @throws NullPointerException if the output is null + * @throws NullPointerException if output is null * @throws IOException if an I/O error occurs * @since 2.3 */ public static void writeLines(final Collection<?> lines, String lineEnding, final OutputStream output, - final Charset charset) throws IOException { + Charset charset) throws IOException { if (lines == null) { return; } if (lineEnding == null) { lineEnding = System.lineSeparator(); } - final Charset cs = Charsets.toCharset(charset); - final byte[] eolBytes = lineEnding.getBytes(cs); + if (StandardCharsets.UTF_16.equals(charset)) { + // don't write a BOM + charset = StandardCharsets.UTF_16BE; + } + final byte[] eolBytes = lineEnding.getBytes(charset); for (final Object line : lines) { if (line != null) { - write(line.toString(), output, cs); + write(line.toString(), output, charset); } output.write(eolBytes); } diff --git a/src/main/java/org/apache/commons/io/RandomAccessFileMode.java b/src/main/java/org/apache/commons/io/RandomAccessFileMode.java index 54061588..8b51e439 100644 --- a/src/main/java/org/apache/commons/io/RandomAccessFileMode.java +++ b/src/main/java/org/apache/commons/io/RandomAccessFileMode.java @@ -20,6 +20,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.RandomAccessFile; import java.nio.file.Path; +import java.util.Objects; /** * Access modes and factory methods for {@link RandomAccessFile}. @@ -77,7 +78,7 @@ public enum RandomAccessFileMode { * @throws FileNotFoundException See {@link RandomAccessFile#RandomAccessFile(File, String)}. */ public RandomAccessFile create(final Path file) throws FileNotFoundException { - return create(file.toFile()); + return create(Objects.requireNonNull(file.toFile(), "file")); } /** diff --git a/src/main/java/org/apache/commons/io/RandomAccessFiles.java b/src/main/java/org/apache/commons/io/RandomAccessFiles.java index 2fc071fc..0e0140b6 100644 --- a/src/main/java/org/apache/commons/io/RandomAccessFiles.java +++ b/src/main/java/org/apache/commons/io/RandomAccessFiles.java @@ -19,15 +19,55 @@ package org.apache.commons.io; import java.io.IOException; import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import java.util.Objects; + +import org.apache.commons.io.channels.FileChannels; /** - * Works on RandomAccessFile. + * Works with {@link RandomAccessFile}. * * @since 2.13.0 */ public class RandomAccessFiles { /** + * Tests if two RandomAccessFile contents are equal. + * + * @param raf1 A RandomAccessFile. + * @param raf2 Another RandomAccessFile. + * @return true if the contents of both RandomAccessFiles are equal, false otherwise. + * @throws IOException if an I/O error occurs. + * @since 2.15.0 + */ + @SuppressWarnings("resource") // See comments + public static boolean contentEquals(final RandomAccessFile raf1, final RandomAccessFile raf2) throws IOException { + // Short-circuit test + if (Objects.equals(raf1, raf2)) { + return true; + } + // Short-circuit test + final long length1 = length(raf1); + final long length2 = length(raf2); + if (length1 != length2) { + return false; + } + if (length1 == 0 && length2 == 0) { + return true; + } + // Dig in and to the work + // We do not close FileChannels because that closes the owning RandomAccessFile. + // Instead, the caller is assumed to manage the given RandomAccessFile objects. + final FileChannel channel1 = raf1.getChannel(); + final FileChannel channel2 = raf2.getChannel(); + return FileChannels.contentEquals(channel1, channel2, IOUtils.DEFAULT_BUFFER_SIZE); + } + + private static long length(final RandomAccessFile raf) throws IOException { + return raf != null ? raf.length() : 0; + } + + /** * Reads a byte array starting at "position" for "length" bytes. * * @param input The source RandomAccessFile. @@ -42,4 +82,17 @@ public class RandomAccessFiles { return IOUtils.toByteArray(input::read, length); } + /** + * Resets the given file to position 0. + * + * @param raf The RandomAccessFile to reset. + * @return The given RandomAccessFile. + * @throws IOException If {@code pos} is less than {@code 0} or if an I/O error occurs. + * @since 2.15.0 + */ + public static RandomAccessFile reset(final RandomAccessFile raf) throws IOException { + raf.seek(0); + return raf; + } + } diff --git a/src/main/java/org/apache/commons/io/StreamIterator.java b/src/main/java/org/apache/commons/io/StreamIterator.java index 3a321681..23465657 100644 --- a/src/main/java/org/apache/commons/io/StreamIterator.java +++ b/src/main/java/org/apache/commons/io/StreamIterator.java @@ -17,42 +17,55 @@ package org.apache.commons.io; -import java.io.Closeable; import java.util.Iterator; import java.util.Objects; import java.util.stream.Stream; /** - * Wraps and presents a stream as a closable iterator resource that automatically closes itself when reaching the end - * of stream. + * Wraps and presents a {@link Stream} as a {@link AutoCloseable} {@link Iterator} resource that automatically closes itself when reaching the end of stream. * - * @param <E> The stream and iterator type. - * @since 2.9.0 + * <h2>Warning</h2> + * <p> + * In order to close the stream, the call site MUST either close the stream it allocated OR call this iterator until the end. + * </p> + * + * @param <E> The {@link Stream} and {@link Iterator} type. + * @since 2.15.0 */ -final class StreamIterator<E> implements Iterator<E>, Closeable { +public final class StreamIterator<E> implements Iterator<E>, AutoCloseable { /** - * Wraps and presents a stream as a closable resource that automatically closes itself when reaching the end of - * stream. - * <h2>Warning</h2> + * Wraps and presents a stream as a closable resource that automatically closes itself when reaching the end of stream. + * <p> + * <b>Warning</b> + * </p> * <p> - * In order to close the stream, the call site MUST either close the stream it allocated OR call the iterator until - * the end. + * In order to close the stream, the call site MUST either close the stream it allocated OR call this iterator until the end. * </p> * - * @param <T> The stream and iterator type. + * @param <T> The stream and iterator type. * @param stream The stream iterate. * @return A new iterator. */ - @SuppressWarnings("resource") // Caller MUST close or iterate to the end. - public static <T> Iterator<T> iterator(final Stream<T> stream) { - return new StreamIterator<>(stream).iterator; + public static <T> StreamIterator<T> iterator(final Stream<T> stream) { + return new StreamIterator<>(stream); } + /** + * The given stream's Iterator. + */ private final Iterator<E> iterator; + /** + * The given stream. + */ private final Stream<E> stream; + /** + * Whether {@link #close()} has been called. + */ + private boolean closed; + private StreamIterator(final Stream<E> stream) { this.stream = Objects.requireNonNull(stream, "stream"); this.iterator = stream.iterator(); @@ -63,11 +76,16 @@ final class StreamIterator<E> implements Iterator<E>, Closeable { */ @Override public void close() { + closed = true; stream.close(); } @Override public boolean hasNext() { + if (closed) { + // Calling Iterator#hasNext() on a closed java.nio.file.FileTreeIterator causes an IllegalStateException. + return false; + } final boolean hasNext = iterator.hasNext(); if (!hasNext) { close(); diff --git a/src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java b/src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java index d94638ac..e0f9ba66 100644 --- a/src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java +++ b/src/main/java/org/apache/commons/io/build/AbstractStreamBuilder.java @@ -154,6 +154,11 @@ public abstract class AbstractStreamBuilder<T, B extends AbstractStreamBuilder<T return checkOrigin().getInputStream(getOpenOptions()); } + /** + * Gets the OpenOption. + * + * @return the OpenOption. + */ protected OpenOption[] getOpenOptions() { return openOptions; } diff --git a/src/main/java/org/apache/commons/io/channels/FileChannels.java b/src/main/java/org/apache/commons/io/channels/FileChannels.java new file mode 100644 index 00000000..468c85b4 --- /dev/null +++ b/src/main/java/org/apache/commons/io/channels/FileChannels.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.io.channels; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.util.Objects; + +import org.apache.commons.io.IOUtils; + +/** + * Works with {@link FileChannel}. + * + * @since 2.15.0 + */ +public final class FileChannels { + + /** + * Tests if two RandomAccessFiles contents are equal. + * + * @param channel1 A FileChannel. + * @param channel2 Another FileChannel. + * @param byteBufferSize The two internal buffer capacities, in bytes. + * @return true if the contents of both RandomAccessFiles are equal, false otherwise. + * @throws IOException if an I/O error occurs. + */ + public static boolean contentEquals(final FileChannel channel1, final FileChannel channel2, final int byteBufferSize) throws IOException { + // Short-circuit test + if (Objects.equals(channel1, channel2)) { + return true; + } + // Short-circuit test + final long size1 = size(channel1); + final long size2 = size(channel2); + if (size1 != size2) { + return false; + } + if (size1 == 0 && size2 == 0) { + return true; + } + // Dig in and do the work + final ByteBuffer byteBuffer1 = ByteBuffer.allocateDirect(byteBufferSize); + final ByteBuffer byteBuffer2 = ByteBuffer.allocateDirect(byteBufferSize); + while (true) { + final int read1 = channel1.read(byteBuffer1); + final int read2 = channel2.read(byteBuffer2); + if (read1 == IOUtils.EOF && read2 == IOUtils.EOF) { + return byteBuffer1.equals(byteBuffer2); + } + if (read1 != read2) { + return false; + } + if (!byteBuffer1.equals(byteBuffer2)) { + return false; + } + byteBuffer1.clear(); + byteBuffer2.clear(); + } + } + + private static long size(final FileChannel channel) throws IOException { + return channel != null ? channel.size() : 0; + } + + /** + * Don't instantiate. + */ + private FileChannels() { + // no-op + } +} diff --git a/src/main/java/org/apache/commons/io/channels/package-info.java b/src/main/java/org/apache/commons/io/channels/package-info.java new file mode 100644 index 00000000..51a7ca28 --- /dev/null +++ b/src/main/java/org/apache/commons/io/channels/package-info.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Provides classes to work with {@link java.nio.channels}. + * + * @since 2.15.0 + */ +package org.apache.commons.io.channels; diff --git a/src/main/java/org/apache/commons/io/comparator/CompositeFileComparator.java b/src/main/java/org/apache/commons/io/comparator/CompositeFileComparator.java index 0f57a833..d50f3252 100644 --- a/src/main/java/org/apache/commons/io/comparator/CompositeFileComparator.java +++ b/src/main/java/org/apache/commons/io/comparator/CompositeFileComparator.java @@ -19,6 +19,7 @@ package org.apache.commons.io.comparator; import java.io.File; import java.io.Serializable; import java.util.Comparator; +import java.util.function.IntFunction; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -48,6 +49,9 @@ public class CompositeFileComparator extends AbstractFileComparator implements S private static final Comparator<?>[] EMPTY_COMPARATOR_ARRAY = {}; private static final long serialVersionUID = -2224170307287243428L; + /** + * Delegates. + */ private final Comparator<File>[] delegates; /** @@ -65,7 +69,8 @@ public class CompositeFileComparator extends AbstractFileComparator implements S * @param delegates The delegate file comparators */ public CompositeFileComparator(final Iterable<Comparator<File>> delegates) { - this.delegates = delegates == null ? emptyArray() : StreamSupport.stream(delegates.spliterator(), false).toArray(Comparator[]::new); + this.delegates = delegates == null ? emptyArray() + : StreamSupport.stream(delegates.spliterator(), false).toArray((IntFunction<Comparator<File>[]>) Comparator[]::new); } /** diff --git a/src/main/java/org/apache/commons/io/file/FilesUncheck.java b/src/main/java/org/apache/commons/io/file/FilesUncheck.java index 02a1febb..02688cac 100644 --- a/src/main/java/org/apache/commons/io/file/FilesUncheck.java +++ b/src/main/java/org/apache/commons/io/file/FilesUncheck.java @@ -22,6 +22,7 @@ import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.Reader; import java.io.UncheckedIOException; import java.nio.channels.SeekableByteChannel; import java.nio.charset.Charset; @@ -244,6 +245,10 @@ public final class FilesUncheck { /** * Delegates to {@link Files#find(Path, int, BiPredicate, FileVisitOption...)} throwing {@link UncheckedIOException} instead of {@link IOException}. + * <p> + * The returned {@link Stream} wraps a {@link DirectoryStream}. When you require timely disposal of file system resources, use a {@code try}-with-resources + * block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. + * </p> * * @param start See delegate. * @param maxDepth See delegate. @@ -348,6 +353,10 @@ public final class FilesUncheck { /** * Delegates to {@link Files#lines(Path)} throwing {@link UncheckedIOException} instead of {@link IOException}. + * <p> + * The returned {@link Stream} wraps a {@link Reader}. When you require timely disposal of file system resources, use a {@code try}-with-resources block to + * ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. + * </p> * * @param path See delegate. * @return See delegate. @@ -359,6 +368,10 @@ public final class FilesUncheck { /** * Delegates to {@link Files#lines(Path, Charset)} throwing {@link UncheckedIOException} instead of {@link IOException}. + * <p> + * The returned {@link Stream} wraps a {@link Reader}. When you require timely disposal of file system resources, use a {@code try}-with-resources block to + * ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. + * </p> * * @param path See delegate. * @param cs See delegate. @@ -371,6 +384,10 @@ public final class FilesUncheck { /** * Delegates to {@link Files#list(Path)} throwing {@link UncheckedIOException} instead of {@link IOException}. + * <p> + * The returned {@link Stream} wraps a {@link DirectoryStream}. When you require timely disposal of file system resources, use a {@code try}-with-resources + * block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. + * </p> * * @param dir See delegate. * @return See delegate. @@ -474,8 +491,11 @@ public final class FilesUncheck { } /** - * Delegates to {@link Files#newDirectoryStream(Path)} throwing {@link UncheckedIOException} instead of - * {@link IOException}. + * Delegates to {@link Files#newDirectoryStream(Path)} throwing {@link UncheckedIOException} instead of {@link IOException}. + * <p> + * If you don't use the try-with-resources construct, then you must call the stream's {@link Stream#close()} method after iteration is complete to free any + * resources held for the open directory. + * </p> * * @param dir See delegate. * @return See delegate. @@ -485,10 +505,14 @@ public final class FilesUncheck { } /** - * Delegates to {@link Files#newDirectoryStream(Path, java.nio.file.DirectoryStream.Filter)} throwing - * {@link UncheckedIOException} instead of {@link IOException}. + * Delegates to {@link Files#newDirectoryStream(Path, java.nio.file.DirectoryStream.Filter)} throwing {@link UncheckedIOException} instead of + * {@link IOException}. + * <p> + * If you don't use the try-with-resources construct, then you must call the stream's {@link Stream#close()} method after iteration is complete to free any + * resources held for the open directory. + * </p> * - * @param dir See delegate. + * @param dir See delegate. * @param filter See delegate. * @return See delegate. */ @@ -499,6 +523,10 @@ public final class FilesUncheck { /** * Delegates to {@link Files#newDirectoryStream(Path, String)} throwing {@link UncheckedIOException} instead of * {@link IOException}. + * <p> + * The returned {@link Stream} wraps a {@link DirectoryStream}. When you require timely disposal of file system resources, use a {@code try}-with-resources + * block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. + * </p> * * @param dir See delegate. * @param glob See delegate. @@ -674,10 +702,14 @@ public final class FilesUncheck { } /** - * Delegates to {@link Files#walk(Path, FileVisitOption...)} throwing {@link UncheckedIOException} instead of - * {@link IOException}. + * Delegates to {@link Files#walk(Path, FileVisitOption...)} throwing {@link UncheckedIOException} instead of {@link IOException}. + * <p> + * The returned {@link Stream} may wrap one or more {@link DirectoryStream}s. When you require timely disposal of file system resources, use a + * {@code try}-with-resources block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. Calling a + * closed stream causes a {@link IllegalStateException}. + * </p> * - * @param start See delegate. + * @param start See delegate. * @param options See delegate. * @return See delegate. */ @@ -686,12 +718,16 @@ public final class FilesUncheck { } /** - * Delegates to {@link Files#walk(Path, int, FileVisitOption...)} throwing {@link UncheckedIOException} instead of - * {@link IOException}. + * Delegates to {@link Files#walk(Path, int, FileVisitOption...)} throwing {@link UncheckedIOException} instead of {@link IOException}. + * <p> + * The returned {@link Stream} may wrap one or more {@link DirectoryStream}s. When you require timely disposal of file system resources, use a + * {@code try}-with-resources block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. Calling a + * closed stream causes a {@link IllegalStateException}. + * </p> * - * @param start See delegate. + * @param start See delegate. * @param maxDepth See delegate. - * @param options See delegate. + * @param options See delegate. * @return See delegate. */ public static Stream<Path> walk(final Path start, final int maxDepth, final FileVisitOption... options) { diff --git a/src/main/java/org/apache/commons/io/file/PathUtils.java b/src/main/java/org/apache/commons/io/file/PathUtils.java index 56b2a05c..d85fdb67 100644 --- a/src/main/java/org/apache/commons/io/file/PathUtils.java +++ b/src/main/java/org/apache/commons/io/file/PathUtils.java @@ -21,7 +21,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.UncheckedIOException; +import java.io.RandomAccessFile; import java.math.BigInteger; import java.net.URI; import java.net.URISyntaxException; @@ -70,14 +70,14 @@ import java.util.stream.Stream; import org.apache.commons.io.Charsets; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; +import org.apache.commons.io.RandomAccessFileMode; +import org.apache.commons.io.RandomAccessFiles; import org.apache.commons.io.ThreadUtils; import org.apache.commons.io.file.Counters.PathCounters; import org.apache.commons.io.file.attribute.FileTimes; import org.apache.commons.io.filefilter.IOFileFilter; import org.apache.commons.io.function.IOFunction; import org.apache.commons.io.function.IOSupplier; -import org.apache.commons.io.function.Uncheck; /** * NIO Path utilities. @@ -90,7 +90,7 @@ public final class PathUtils { * Private worker/holder that computes and tracks relative path names and their equality. We reuse the sorted relative * lists when comparing directories. */ - private static class RelativeSortedPaths { + private static final class RelativeSortedPaths { final boolean equals; // final List<Path> relativeDirList1; // might need later? @@ -365,7 +365,7 @@ public final class PathUtils { * Creates the parent directories for the given {@code path}. * <p> * If the parent directory already exists, then return it. - * <p> + * </p> * * @param path The path to a file (or directory). * @param attrs An optional list of file attributes to set atomically when creating the directories. @@ -381,7 +381,7 @@ public final class PathUtils { * Creates the parent directories for the given {@code path}. * <p> * If the parent directory already exists, then return it. - * <p> + * </p> * * @param path The path to a file (or directory). * @param linkOption A {@link LinkOption} or null. @@ -719,20 +719,20 @@ public final class PathUtils { /** * Compares the file contents of two Paths to determine if they are equal or not. * <p> - * File content is accessed through {@link Files#newInputStream(Path,OpenOption...)}. + * File content is accessed through {@link RandomAccessFileMode#create(Path)}. * </p> * * @param path1 the first stream. * @param path2 the second stream. * @param linkOptions options specifying how files are followed. - * @param openOptions options specifying how files are opened. + * @param openOptions ignored. * @return true if the content of the streams are equal or they both don't exist, false otherwise. * @throws NullPointerException if openOptions is null. * @throws IOException if an I/O error occurs. * @see org.apache.commons.io.FileUtils#contentEquals(java.io.File, java.io.File) */ public static boolean fileContentEquals(final Path path1, final Path path2, final LinkOption[] linkOptions, final OpenOption[] openOptions) - throws IOException { + throws IOException { if (path1 == null && path2 == null) { return true; } @@ -766,9 +766,9 @@ public final class PathUtils { // same file return true; } - try (InputStream inputStream1 = Files.newInputStream(nPath1, openOptions); - InputStream inputStream2 = Files.newInputStream(nPath2, openOptions)) { - return IOUtils.contentEquals(inputStream1, inputStream2); + try (RandomAccessFile raf1 = RandomAccessFileMode.READ_ONLY.create(path1.toRealPath(linkOptions)); + RandomAccessFile raf2 = RandomAccessFileMode.READ_ONLY.create(path2.toRealPath(linkOptions))) { + return RandomAccessFiles.contentEquals(raf1, raf2); } } @@ -1182,8 +1182,12 @@ public final class PathUtils { /** * Creates a new DirectoryStream for Paths rooted at the given directory. + * <p> + * If you don't use the try-with-resources construct, then you must call the stream's {@link Stream#close()} method after iteration is complete to free any + * resources held for the open directory. + * </p> * - * @param dir the path to the directory to stream. + * @param dir the path to the directory to stream. * @param pathFilter the directory stream filter. * @return a new instance. * @throws IOException if an I/O error occurs. @@ -1243,21 +1247,20 @@ public final class PathUtils { } /** - * Reads the BasicFileAttributes from the given path. Returns null instead of throwing - * {@link UnsupportedOperationException}. Throws {@link Uncheck} instead of {@link IOException}. + * Reads the BasicFileAttributes from the given path. Returns null if the attributes can't be read. * * @param <A> The {@link BasicFileAttributes} type * @param path The Path to test. * @param type the {@link Class} of the file attributes required to read. * @param options options indicating how to handle symbolic links. - * @return the file attributes. + * @return the file attributes or null if the attributes can't be read. * @see Files#readAttributes(Path, Class, LinkOption...) * @since 2.12.0 */ public static <A extends BasicFileAttributes> A readAttributes(final Path path, final Class<A> type, final LinkOption... options) { try { - return path == null ? null : Uncheck.apply(Files::readAttributes, path, type, options); - } catch (final UnsupportedOperationException e) { + return path == null ? null : Files.readAttributes(path, type, options); + } catch (final UnsupportedOperationException | IOException e) { // For example, on Windows. return null; } @@ -1270,16 +1273,14 @@ public final class PathUtils { * @return the path attributes. * @throws IOException if an I/O error occurs. * @since 2.9.0 - * @deprecated Will be removed in 3.0.0 in favor of {@link #readBasicFileAttributes(Path, LinkOption...)}. */ - @Deprecated public static BasicFileAttributes readBasicFileAttributes(final Path path) throws IOException { return Files.readAttributes(path, BasicFileAttributes.class); } /** - * Reads the BasicFileAttributes from the given path. Returns null instead of throwing - * {@link UnsupportedOperationException}. + * Reads the BasicFileAttributes from the given path. Returns null if the attributes + * can't be read. * * @param path the path to read. * @param options options indicating how to handle symbolic links. @@ -1291,12 +1292,11 @@ public final class PathUtils { } /** - * Reads the BasicFileAttributes from the given path. Returns null instead of throwing - * {@link UnsupportedOperationException}. + * Reads the BasicFileAttributes from the given path. Returns null if the attributes + * can't be read. * * @param path the path to read. * @return the path attributes. - * @throws UncheckedIOException if an I/O error occurs * @since 2.9.0 * @deprecated Use {@link #readBasicFileAttributes(Path, LinkOption...)}. */ @@ -1306,8 +1306,8 @@ public final class PathUtils { } /** - * Reads the DosFileAttributes from the given path. Returns null instead of throwing - * {@link UnsupportedOperationException}. + * Reads the DosFileAttributes from the given path. Returns null if the attributes + * can't be read. * * @param path the path to read. * @param options options indicating how to handle symbolic links. @@ -1323,8 +1323,8 @@ public final class PathUtils { } /** - * Reads the PosixFileAttributes or DosFileAttributes from the given path. Returns null instead of throwing - * {@link UnsupportedOperationException}. + * Reads the PosixFileAttributes or DosFileAttributes from the given path. Returns null if the attributes + * can't be read. * * @param path The Path to read. * @param options options indicating how to handle symbolic links. @@ -1751,6 +1751,11 @@ public final class PathUtils { /** * Returns a stream of filtered paths. + * <p> + * The returned {@link Stream} may wrap one or more {@link DirectoryStream}s. When you require timely disposal of file system resources, use a + * {@code try}-with-resources block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. Calling a + * closed stream causes a {@link IllegalStateException}. + * </p> * * @param start the start path * @param pathFilter the path filter @@ -1801,7 +1806,7 @@ public final class PathUtils { } /** - * Does allow to instantiate. + * Prevents instantiation. */ private PathUtils() { // do not instantiate. diff --git a/src/main/java/org/apache/commons/io/filefilter/DelegateFileFilter.java b/src/main/java/org/apache/commons/io/filefilter/DelegateFileFilter.java index 14c99566..ee2bb02b 100644 --- a/src/main/java/org/apache/commons/io/filefilter/DelegateFileFilter.java +++ b/src/main/java/org/apache/commons/io/filefilter/DelegateFileFilter.java @@ -39,7 +39,7 @@ public class DelegateFileFilter extends AbstractFileFilter implements Serializab /** The File filter */ private final FileFilter fileFilter; /** The Filename filter */ - private final FilenameFilter filenameFilter; + private final FilenameFilter fileNameFilter; /** * Constructs a delegate file filter around an existing FileFilter. @@ -49,17 +49,17 @@ public class DelegateFileFilter extends AbstractFileFilter implements Serializab public DelegateFileFilter(final FileFilter fileFilter) { Objects.requireNonNull(fileFilter, "filter"); this.fileFilter = fileFilter; - this.filenameFilter = null; + this.fileNameFilter = null; } /** * Constructs a delegate file filter around an existing FilenameFilter. * - * @param filenameFilter the filter to decorate + * @param fileNameFilter the filter to decorate */ - public DelegateFileFilter(final FilenameFilter filenameFilter) { - Objects.requireNonNull(filenameFilter, "filter"); - this.filenameFilter = filenameFilter; + public DelegateFileFilter(final FilenameFilter fileNameFilter) { + Objects.requireNonNull(fileNameFilter, "filter"); + this.fileNameFilter = fileNameFilter; this.fileFilter = null; } @@ -86,8 +86,8 @@ public class DelegateFileFilter extends AbstractFileFilter implements Serializab */ @Override public boolean accept(final File dir, final String name) { - if (filenameFilter != null) { - return filenameFilter.accept(dir, name); + if (fileNameFilter != null) { + return fileNameFilter.accept(dir, name); } return super.accept(dir, name); } @@ -99,7 +99,7 @@ public class DelegateFileFilter extends AbstractFileFilter implements Serializab */ @Override public String toString() { - final String delegate = fileFilter != null ? fileFilter.toString() : filenameFilter.toString(); + final String delegate = fileFilter != null ? fileFilter.toString() : fileNameFilter.toString(); return super.toString() + "(" + delegate + ")"; } diff --git a/src/main/java/org/apache/commons/io/filefilter/package-info.java b/src/main/java/org/apache/commons/io/filefilter/package-info.java index a374fb0d..3bf71238 100644 --- a/src/main/java/org/apache/commons/io/filefilter/package-info.java +++ b/src/main/java/org/apache/commons/io/filefilter/package-info.java @@ -40,7 +40,7 @@ * </tr> * <tr> * <td><a href="NameFileFilter.html">NameFileFilter</a></td> - * <td>Filter based on a filename</td> + * <td>Filter based on a file name</td> * </tr> * <tr> * <td><a href="WildcardFileFilter.html">WildcardFileFilter</a></td> diff --git a/src/main/java/org/apache/commons/io/input/ByteBufferCleaner.java b/src/main/java/org/apache/commons/io/input/ByteBufferCleaner.java index fc334e96..72b1b1e8 100644 --- a/src/main/java/org/apache/commons/io/input/ByteBufferCleaner.java +++ b/src/main/java/org/apache/commons/io/input/ByteBufferCleaner.java @@ -38,7 +38,7 @@ class ByteBufferCleaner { void clean(ByteBuffer buffer) throws ReflectiveOperationException; } - private static class Java8Cleaner implements Cleaner { + private static final class Java8Cleaner implements Cleaner { private final Method cleanerMethod; private final Method cleanMethod; @@ -57,7 +57,7 @@ class ByteBufferCleaner { } } - private static class Java9Cleaner implements Cleaner { + private static final class Java9Cleaner implements Cleaner { private final Object theUnsafe; private final Method invokeCleaner; diff --git a/src/main/java/org/apache/commons/io/input/MemoryMappedFileInputStream.java b/src/main/java/org/apache/commons/io/input/MemoryMappedFileInputStream.java index 89114be9..3d03f8ce 100644 --- a/src/main/java/org/apache/commons/io/input/MemoryMappedFileInputStream.java +++ b/src/main/java/org/apache/commons/io/input/MemoryMappedFileInputStream.java @@ -87,6 +87,9 @@ public final class MemoryMappedFileInputStream extends InputStream { */ public static class Builder extends AbstractStreamBuilder<MemoryMappedFileInputStream, Builder> { + /** + * Constructs a new Builder. + */ public Builder() { setBufferSizeDefault(DEFAULT_BUFFER_SIZE); setBufferSize(DEFAULT_BUFFER_SIZE); diff --git a/src/main/java/org/apache/commons/io/input/MessageDigestCalculatingInputStream.java b/src/main/java/org/apache/commons/io/input/MessageDigestCalculatingInputStream.java index 7aed4185..97d7ff59 100644 --- a/src/main/java/org/apache/commons/io/input/MessageDigestCalculatingInputStream.java +++ b/src/main/java/org/apache/commons/io/input/MessageDigestCalculatingInputStream.java @@ -21,12 +21,13 @@ import java.io.InputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Provider; +import java.util.Objects; import org.apache.commons.io.build.AbstractStreamBuilder; /** * This class is an example for using an {@link ObservableInputStream}. It creates its own {@link org.apache.commons.io.input.ObservableInputStream.Observer}, - * which calculates a checksum using a MessageDigest, for example an MD5 sum. + * which calculates a checksum using a {@link MessageDigest}, for example, a SHA-512 sum. * <p> * To build an instance, see {@link Builder}. * </p> @@ -35,12 +36,11 @@ import org.apache.commons.io.build.AbstractStreamBuilder; * Cryptography Architecture Standard Algorithm Name Documentation</a> for information about standard algorithm names. * </p> * <p> - * <em>Note</em>: Neither {@link ObservableInputStream}, nor {@link MessageDigest}, are thread safe. So is {@link MessageDigestCalculatingInputStream}. - * </p> - * <p> - * TODO Rename to MessageDigestInputStream in 3.0. + * <em>Note</em>: Neither {@link ObservableInputStream}, nor {@link MessageDigest}, are thread safe, so is {@link MessageDigestCalculatingInputStream}. * </p> + * @deprecated Use {@link MessageDigestInputStream}. */ +@Deprecated public class MessageDigestCalculatingInputStream extends ObservableInputStream { /** @@ -61,6 +61,9 @@ public class MessageDigestCalculatingInputStream extends ObservableInputStream { private MessageDigest messageDigest; + /** + * Constructs a new Builder. + */ public Builder() { try { this.messageDigest = getDefaultMessageDigest(); @@ -92,6 +95,9 @@ public class MessageDigestCalculatingInputStream extends ObservableInputStream { /** * Sets the message digest. + * <p> + * The MD5 cryptographic algorithm is weak and should not be used. + * </p> * * @param messageDigest the message digest. */ @@ -101,6 +107,9 @@ public class MessageDigestCalculatingInputStream extends ObservableInputStream { /** * Sets the name of the name of the message digest algorithm. + * <p> + * The MD5 cryptographic algorithm is weak and should not be used. + * </p> * * @param algorithm the name of the algorithm. See the MessageDigest section in the * <a href= "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest"> Java Cryptography @@ -123,9 +132,10 @@ public class MessageDigestCalculatingInputStream extends ObservableInputStream { * Constructs an MessageDigestMaintainingObserver for the given MessageDigest. * * @param messageDigest the message digest to use + * @throws NullPointerException if messageDigest is null. */ public MessageDigestMaintainingObserver(final MessageDigest messageDigest) { - this.messageDigest = messageDigest; + this.messageDigest = Objects.requireNonNull(messageDigest, "messageDigest"); } @Override @@ -187,9 +197,13 @@ public class MessageDigestCalculatingInputStream extends ObservableInputStream { /** * Constructs a new instance, which calculates a signature on the given stream, using the given {@link MessageDigest}. + * <p> + * The MD5 cryptographic algorithm is weak and should not be used. + * </p> * * @param inputStream the stream to calculate the message digest for * @param messageDigest the message digest to use + * @throws NullPointerException if messageDigest is null. * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}. */ @Deprecated @@ -200,6 +214,9 @@ public class MessageDigestCalculatingInputStream extends ObservableInputStream { /** * Constructs a new instance, which calculates a signature on the given stream, using a {@link MessageDigest} with the given algorithm. + * <p> + * The MD5 cryptographic algorithm is weak and should not be used. + * </p> * * @param inputStream the stream to calculate the message digest for * @param algorithm the name of the algorithm requested. See the MessageDigest section in the diff --git a/src/main/java/org/apache/commons/io/input/MessageDigestInputStream.java b/src/main/java/org/apache/commons/io/input/MessageDigestInputStream.java new file mode 100644 index 00000000..d822256b --- /dev/null +++ b/src/main/java/org/apache/commons/io/input/MessageDigestInputStream.java @@ -0,0 +1,193 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.io.input; + +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Objects; + +import org.apache.commons.io.build.AbstractStreamBuilder; + +/** + * This class is an example for using an {@link ObservableInputStream}. It creates its own {@link org.apache.commons.io.input.ObservableInputStream.Observer}, + * which calculates a checksum using a {@link MessageDigest}, for example, a SHA-512 sum. + * <p> + * To build an instance, see {@link Builder}. + * </p> + * <p> + * See the MessageDigest section in the <a href= "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest"> Java + * Cryptography Architecture Standard Algorithm Name Documentation</a> for information about standard algorithm names. + * </p> + * <p> + * You must specify a message digest algorithm name or instance. + * </p> + * <p> + * <em>Note</em>: Neither {@link ObservableInputStream}, nor {@link MessageDigest}, are thread safe, so is {@link MessageDigestInputStream}. + * </p> + * + * @since 2.15.0 + */ +public final class MessageDigestInputStream extends ObservableInputStream { + + /** + * Builds new {@link MessageDigestInputStream} instances. + * <p> + * For example: + * </p> + * <pre>{@code + * MessageDigestInputStream s = MessageDigestInputStream.builder() + * .setPath(path) + * .setMessageDigest("SHA-512") + * .get();} + * </pre> + * <p> + * You must specify a message digest algorithm name or instance. + * </p> + */ + public static class Builder extends AbstractStreamBuilder<MessageDigestInputStream, Builder> { + + private MessageDigest messageDigest; + + /** + * Constructs a new Builder. + */ + public Builder() { + // empty + } + + /** + * Constructs a new instance. + * <p> + * This builder use the aspects InputStream, OpenOption[], and MessageDigest. + * </p> + * <p> + * You must provide an origin that can be converted to an InputStream by this builder, otherwise, this call will throw an + * {@link UnsupportedOperationException}. + * </p> + * + * @return a new instance. + * @throws UnsupportedOperationException if the origin cannot provide an InputStream. + * @see #getInputStream() + */ + @SuppressWarnings("resource") + @Override + public MessageDigestInputStream get() throws IOException { + return new MessageDigestInputStream(getInputStream(), messageDigest); + } + + /** + * Sets the message digest. + * <p> + * The MD5 cryptographic algorithm is weak and should not be used. + * </p> + * + * @param messageDigest the message digest. + * @return this + */ + public Builder setMessageDigest(final MessageDigest messageDigest) { + this.messageDigest = messageDigest; + return this; + } + + /** + * Sets the name of the name of the message digest algorithm. + * <p> + * The MD5 cryptographic algorithm is weak and should not be used. + * </p> + * + * @param algorithm the name of the algorithm. See the MessageDigest section in the + * <a href= "https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#MessageDigest"> Java Cryptography + * Architecture Standard Algorithm Name Documentation</a> for information about standard algorithm names. + * @return this + * @throws NoSuchAlgorithmException if no Provider supports a MessageDigestSpi implementation for the specified algorithm. + */ + public Builder setMessageDigest(final String algorithm) throws NoSuchAlgorithmException { + this.messageDigest = MessageDigest.getInstance(algorithm); + return this; + } + + } + + /** + * Maintains the message digest. + */ + public static class MessageDigestMaintainingObserver extends Observer { + + private final MessageDigest messageDigest; + + /** + * Constructs an MessageDigestMaintainingObserver for the given MessageDigest. + * + * @param messageDigest the message digest to use + * @throws NullPointerException if messageDigest is null. + */ + public MessageDigestMaintainingObserver(final MessageDigest messageDigest) { + this.messageDigest = Objects.requireNonNull(messageDigest, "messageDigest"); + } + + @Override + public void data(final byte[] input, final int offset, final int length) throws IOException { + messageDigest.update(input, offset, length); + } + + @Override + public void data(final int input) throws IOException { + messageDigest.update((byte) input); + } + } + + /** + * Constructs a new {@link Builder}. + * + * @return a new {@link Builder}. + */ + public static Builder builder() { + return new Builder(); + } + + private final MessageDigest messageDigest; + + /** + * Constructs a new instance, which calculates a signature on the given stream, using the given {@link MessageDigest}. + * <p> + * The MD5 cryptographic algorithm is weak and should not be used. + * </p> + * + * @param inputStream the stream to calculate the message digest for + * @param messageDigest the message digest to use + * @throws NullPointerException if messageDigest is null. + */ + private MessageDigestInputStream(final InputStream inputStream, final MessageDigest messageDigest) { + super(inputStream, new MessageDigestMaintainingObserver(messageDigest)); + this.messageDigest = messageDigest; + } + + /** + * Gets the {@link MessageDigest}, which is being used for generating the checksum. + * <p> + * <em>Note</em>: The checksum will only reflect the data, which has been read so far. This is probably not, what you expect. Make sure, that the complete + * data has been read, if that is what you want. The easiest way to do so is by invoking {@link #consume()}. + * </p> + * + * @return the message digest used + */ + public MessageDigest getMessageDigest() { + return messageDigest; + } +} diff --git a/src/main/java/org/apache/commons/io/input/ObservableInputStream.java b/src/main/java/org/apache/commons/io/input/ObservableInputStream.java index ee080f06..a97702fb 100644 --- a/src/main/java/org/apache/commons/io/input/ObservableInputStream.java +++ b/src/main/java/org/apache/commons/io/input/ObservableInputStream.java @@ -39,7 +39,7 @@ import org.apache.commons.io.function.IOConsumer; * be used. * </p> * - * @see MessageDigestCalculatingInputStream + * @see MessageDigestInputStream */ public class ObservableInputStream extends ProxyInputStream { diff --git a/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java b/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java index 04c9cf91..7ef620fe 100644 --- a/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java +++ b/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java @@ -66,6 +66,9 @@ public class ReversedLinesFileReader implements Closeable { */ public static class Builder extends AbstractStreamBuilder<ReversedLinesFileReader, Builder> { + /** + * Constructs a new Builder. + */ public Builder() { setBufferSizeDefault(DEFAULT_BLOCK_SIZE); setBufferSize(DEFAULT_BLOCK_SIZE); diff --git a/src/main/java/org/apache/commons/io/input/SwappedDataInputStream.java b/src/main/java/org/apache/commons/io/input/SwappedDataInputStream.java index 31600f58..9239b520 100644 --- a/src/main/java/org/apache/commons/io/input/SwappedDataInputStream.java +++ b/src/main/java/org/apache/commons/io/input/SwappedDataInputStream.java @@ -29,7 +29,7 @@ import org.apache.commons.io.EndianUtils; * DataInput for systems relying on little endian data formats. When read, values will be changed from little endian to * big endian formats for internal usage. * <p> - * <b>Origin of code: </b>Avalon Excalibur (IO) + * Provenance: Avalon Excalibur (IO) * </p> */ public class SwappedDataInputStream extends ProxyInputStream implements DataInput { diff --git a/src/main/java/org/apache/commons/io/input/UnsynchronizedBufferedInputStream.java b/src/main/java/org/apache/commons/io/input/UnsynchronizedBufferedInputStream.java index ffd456df..b33a1187 100644 --- a/src/main/java/org/apache/commons/io/input/UnsynchronizedBufferedInputStream.java +++ b/src/main/java/org/apache/commons/io/input/UnsynchronizedBufferedInputStream.java @@ -105,7 +105,7 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte protected volatile byte[] buffer; /** - * The total number of bytes inside the byte array {@code buf}. + * The total number of bytes inside the byte array {@code buffer}. */ protected int count; @@ -120,7 +120,7 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte protected int markPos = IOUtils.EOF; /** - * The current position within the byte array {@code buf}. + * The current position within the byte array {@code buffer}. */ protected int pos; @@ -190,8 +190,8 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte } final byte[] newbuf = new byte[newLength]; System.arraycopy(localBuf, 0, newbuf, 0, localBuf.length); - // Reassign buf, which will invalidate any local references - // FIXME: what if buf was null? + // Reassign buffer, which will invalidate any local references + // FIXME: what if buffer was null? localBuf = buffer = newbuf; } else if (markPos > 0) { System.arraycopy(localBuf, markPos, localBuf, 0, localBuf.length - markPos); @@ -276,7 +276,7 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte * set and the requested number of bytes is larger than the receiver's buffer size, this implementation bypasses the buffer and simply places the results * directly into {@code buffer}. * - * @param buffer the byte array in which to store the bytes read. + * @param dest the byte array in which to store the bytes read. * @param offset the initial position in {@code buffer} to store the bytes read from this stream. * @param length the maximum number of bytes to store in {@code buffer}. * @return the number of bytes actually read or -1 if end of stream. @@ -284,7 +284,7 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte * @throws IOException if the stream is already closed or another IOException occurs. */ @Override - public int read(final byte[] buffer, int offset, final int length) throws IOException { + public int read(final byte[] dest, int offset, final int length) throws IOException { // Use local ref since buf may be invalidated by an unsynchronized // close() byte[] localBuf = buffer; @@ -292,7 +292,7 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte throw new IOException("Stream is closed"); } // avoid int overflow - if (offset > buffer.length - length || offset < 0 || length < 0) { + if (offset > dest.length - length || offset < 0 || length < 0) { throw new IndexOutOfBoundsException(); } if (length == 0) { @@ -307,7 +307,7 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte if (pos < count) { /* There are bytes available in the buffer. */ final int copylength = count - pos >= length ? length : count - pos; - System.arraycopy(localBuf, pos, buffer, offset, copylength); + System.arraycopy(localBuf, pos, dest, offset, copylength); pos += copylength; if (copylength == length || localIn.available() == 0) { return copylength; @@ -324,7 +324,7 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte * If we're not marked and the required size is greater than the buffer, simply read the bytes directly bypassing the buffer. */ if (markPos == IOUtils.EOF && required >= localBuf.length) { - read = localIn.read(buffer, offset, required); + read = localIn.read(dest, offset, required); if (read == IOUtils.EOF) { return required == length ? IOUtils.EOF : length - required; } @@ -341,7 +341,7 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte } read = count - pos >= required ? required : count - pos; - System.arraycopy(localBuf, pos, buffer, offset, read); + System.arraycopy(localBuf, pos, dest, offset, read); pos += read; } required -= read; @@ -397,10 +397,12 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte } if (count - pos >= amount) { - pos += amount; + // (int count - int pos) here is always an int so amount is also in the int range if the above test is true. + // We can safely cast to int and avoid static analysis warnings. + pos += (int) amount; return amount; } - long read = count - pos; + int read = count - pos; pos = count; if (markPos != IOUtils.EOF && amount <= markLimit) { @@ -408,7 +410,9 @@ public final class UnsynchronizedBufferedInputStream extends UnsynchronizedFilte return read; } if (count - pos >= amount - read) { - pos += amount - read; + // (int count - int pos) here is always an int so (amount - read) is also in the int range if the above test is true. + // We can safely cast to int and avoid static analysis warnings. + pos += (int) amount - read; return amount; } // Couldn't get all the bytes, skip what we read diff --git a/src/main/java/org/apache/commons/io/input/UnsynchronizedByteArrayInputStream.java b/src/main/java/org/apache/commons/io/input/UnsynchronizedByteArrayInputStream.java index a4fc696c..f10c1120 100644 --- a/src/main/java/org/apache/commons/io/input/UnsynchronizedByteArrayInputStream.java +++ b/src/main/java/org/apache/commons/io/input/UnsynchronizedByteArrayInputStream.java @@ -106,6 +106,12 @@ public class UnsynchronizedByteArrayInputStream extends InputStream { return super.setByteArray(origin); } + /** + * Sets the length. + * + * @param length Must be greater or equal to 0. + * @return this. + */ public Builder setLength(final int length) { if (length < 0) { throw new IllegalArgumentException("length cannot be negative"); @@ -114,6 +120,12 @@ public class UnsynchronizedByteArrayInputStream extends InputStream { return this; } + /** + * Sets the offset. + * + * @param offset Must be greater or equal to 0. + * @return this. + */ public Builder setOffset(final int offset) { if (offset < 0) { throw new IllegalArgumentException("offset cannot be negative"); diff --git a/src/main/java/org/apache/commons/io/input/XmlStreamReader.java b/src/main/java/org/apache/commons/io/input/XmlStreamReader.java index a38ef807..290e5360 100644 --- a/src/main/java/org/apache/commons/io/input/XmlStreamReader.java +++ b/src/main/java/org/apache/commons/io/input/XmlStreamReader.java @@ -157,11 +157,23 @@ public class XmlStreamReader extends Reader { return super.setCharset(Charsets.toCharset(charset, getCharsetDefault())); } + /** + * Sets the HTTP content type. + * + * @param httpContentType the HTTP content type. + * @return this. + */ public Builder setHttpContentType(final String httpContentType) { this.httpContentType = httpContentType; return this; } + /** + * Sets the lenient toggle. + * + * @param lenient the lenient toggle. + * @return this. + */ public Builder setLenient(final boolean lenient) { this.lenient = lenient; return this; @@ -209,8 +221,14 @@ public class XmlStreamReader extends Reader { // @formatter:off "^<\\?xml\\s+" + "version\\s*=\\s*(?:(?:\"1\\.[0-9]+\")|(?:'1.[0-9]+'))\\s+" - + "encoding\\s*=\\s*((?:\"[A-Za-z]([A-Za-z0-9\\._]|-)*\")|(?:'[A-Za-z]([A-Za-z0-9\\\\._]|-)*'))", + + "encoding\\s*=\\s*" + + "((?:\"[A-Za-z0-9][A-Za-z0-9._+:-]*\")" // double-quoted + + "|(?:'[A-Za-z0-9][A-Za-z0-9._+:-]*'))", // single-quoted Pattern.MULTILINE); + // N.B. the documented pattern is + // EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* + // However this does not match all the aliases that are supported by Java. + // e.g. '437', 'ISO_8859-1:1987' and 'ebcdic-de-273+euro' // @formatter:on private static final String RAW_EX_1 = "Illegal encoding, BOM [{0}] XML guess [{1}] XML prolog [{2}] encoding mismatch"; diff --git a/src/main/java/org/apache/commons/io/output/DeferredFileOutputStream.java b/src/main/java/org/apache/commons/io/output/DeferredFileOutputStream.java index d4dc19e9..3382bdcd 100644 --- a/src/main/java/org/apache/commons/io/output/DeferredFileOutputStream.java +++ b/src/main/java/org/apache/commons/io/output/DeferredFileOutputStream.java @@ -70,6 +70,9 @@ public class DeferredFileOutputStream extends ThresholdingOutputStream { private String suffix; private Path directory; + /** + * Constructs a new builder. + */ public Builder() { setBufferSizeDefault(AbstractByteArrayOutputStream.DEFAULT_SIZE); setBufferSize(AbstractByteArrayOutputStream.DEFAULT_SIZE); @@ -265,28 +268,6 @@ public class DeferredFileOutputStream extends ThresholdingOutputStream { } /** - * Constructs an instance of this class which will trigger an event at the specified threshold, and save data either to a file beyond that point. - * - * @param threshold The number of bytes at which to trigger an event. - * @param outputFile The file to which data is saved beyond the threshold. - * @param prefix Prefix to use for the temporary file. - * @param suffix Suffix to use for the temporary file. - * @param directory Temporary file directory. - * @param initialBufferSize The initial size of the in memory buffer. - * @throws IllegalArgumentException if initialBufferSize < 0. - */ - private DeferredFileOutputStream(final int threshold, final Path outputFile, final String prefix, final String suffix, final Path directory, - final int initialBufferSize) { - super(threshold); - this.outputPath = toPath(outputFile, null); - this.prefix = prefix; - this.suffix = suffix; - this.directory = toPath(directory, PathUtils::getTempDirectory); - this.memoryOutputStream = new ByteArrayOutputStream(checkBufferSize(initialBufferSize)); - this.currentOutputStream = memoryOutputStream; - } - - /** * Constructs an instance of this class which will trigger an event at the specified threshold, and save data to a file beyond that point. * * @param threshold The number of bytes at which to trigger an event. @@ -317,6 +298,28 @@ public class DeferredFileOutputStream extends ThresholdingOutputStream { } /** + * Constructs an instance of this class which will trigger an event at the specified threshold, and save data either to a file beyond that point. + * + * @param threshold The number of bytes at which to trigger an event. + * @param outputFile The file to which data is saved beyond the threshold. + * @param prefix Prefix to use for the temporary file. + * @param suffix Suffix to use for the temporary file. + * @param directory Temporary file directory. + * @param initialBufferSize The initial size of the in memory buffer. + * @throws IllegalArgumentException if initialBufferSize < 0. + */ + private DeferredFileOutputStream(final int threshold, final Path outputFile, final String prefix, final String suffix, final Path directory, + final int initialBufferSize) { + super(threshold); + this.outputPath = toPath(outputFile, null); + this.prefix = prefix; + this.suffix = suffix; + this.directory = toPath(directory, PathUtils::getTempDirectory); + this.memoryOutputStream = new ByteArrayOutputStream(checkBufferSize(initialBufferSize)); + this.currentOutputStream = memoryOutputStream; + } + + /** * Constructs an instance of this class which will trigger an event at the specified threshold, and save data to a temporary file beyond that point. The * initial buffer size will default to 32 bytes which is ByteArrayOutputStream's default buffer size. * diff --git a/src/main/java/org/apache/commons/io/output/LockableFileWriter.java b/src/main/java/org/apache/commons/io/output/LockableFileWriter.java index 064de220..b33abc81 100644 --- a/src/main/java/org/apache/commons/io/output/LockableFileWriter.java +++ b/src/main/java/org/apache/commons/io/output/LockableFileWriter.java @@ -70,6 +70,9 @@ public class LockableFileWriter extends Writer { private boolean append; private AbstractOrigin<?, ?> lockDirectory = AbstractOriginSupplier.newFileOrigin(FileUtils.getTempDirectoryPath()); + /** + * Constructs a new Builder. + */ public Builder() { setBufferSizeDefault(AbstractByteArrayOutputStream.DEFAULT_SIZE); setBufferSize(AbstractByteArrayOutputStream.DEFAULT_SIZE); diff --git a/src/main/java/org/apache/commons/io/output/ThresholdingOutputStream.java b/src/main/java/org/apache/commons/io/output/ThresholdingOutputStream.java index 1d8a3a03..8102eb58 100644 --- a/src/main/java/org/apache/commons/io/output/ThresholdingOutputStream.java +++ b/src/main/java/org/apache/commons/io/output/ThresholdingOutputStream.java @@ -149,11 +149,10 @@ public class ThresholdingOutputStream extends OutputStream { * * @return The underlying output stream. * @throws IOException if an error occurs. - * @deprecated Use {@link #getOutputStream()}. + * @since 2.14.0 */ - @Deprecated - protected OutputStream getStream() throws IOException { - return getOutputStream(); + protected OutputStream getOutputStream() throws IOException { + return outputStreamGetter.apply(this); } /** @@ -162,10 +161,11 @@ public class ThresholdingOutputStream extends OutputStream { * * @return The underlying output stream. * @throws IOException if an error occurs. - * @since 2.14.0 + * @deprecated Use {@link #getOutputStream()}. */ - protected OutputStream getOutputStream() throws IOException { - return outputStreamGetter.apply(this); + @Deprecated + protected OutputStream getStream() throws IOException { + return getOutputStream(); } /** diff --git a/src/main/java/org/apache/commons/io/output/WriterOutputStream.java b/src/main/java/org/apache/commons/io/output/WriterOutputStream.java index dc4cd6fd..bc2c5c21 100644 --- a/src/main/java/org/apache/commons/io/output/WriterOutputStream.java +++ b/src/main/java/org/apache/commons/io/output/WriterOutputStream.java @@ -99,6 +99,9 @@ public class WriterOutputStream extends OutputStream { private CharsetDecoder charsetDecoder; private boolean writeImmediately; + /** + * Constructs a new Builder. + */ public Builder() { this.charsetDecoder = getCharset().newDecoder(); } diff --git a/src/main/java/org/apache/commons/io/output/XmlStreamWriter.java b/src/main/java/org/apache/commons/io/output/XmlStreamWriter.java index b40a2aca..6f732a72 100644 --- a/src/main/java/org/apache/commons/io/output/XmlStreamWriter.java +++ b/src/main/java/org/apache/commons/io/output/XmlStreamWriter.java @@ -62,6 +62,9 @@ public class XmlStreamWriter extends Writer { */ public static class Builder extends AbstractStreamBuilder<XmlStreamWriter, Builder> { + /** + * Constructs a new Builder. + */ public Builder() { setCharsetDefault(StandardCharsets.UTF_8); setCharset(StandardCharsets.UTF_8); diff --git a/src/main/java/org/apache/commons/io/package-info.java b/src/main/java/org/apache/commons/io/package-info.java index 29464fe9..6633c106 100644 --- a/src/main/java/org/apache/commons/io/package-info.java +++ b/src/main/java/org/apache/commons/io/package-info.java @@ -24,7 +24,7 @@ * <b>FileUtils</b> provides operations based around the JDK File class. These include reading, writing, copying, comparing and deleting. * </p> * <p> - * <b>FilenameUtils</b> provides utilities based on filenames. This utility class manipulates filenames without using File objects. It aims to simplify the + * <b>FilenameUtils</b> provides utilities based on filenames. This utility class manipulates file names without using File objects. It aims to simplify the * transition between Windows and Unix. Before using this class however, you should consider whether you should be using File objects. * </p> * <p> diff --git a/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java b/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java index bde163c7..6e60f32e 100644 --- a/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java +++ b/src/main/java/org/apache/commons/io/serialization/ValidatingObjectInputStream.java @@ -110,6 +110,32 @@ public class ValidatingObjectInputStream extends ObjectInputStream { } /** + * Checks that the class name conforms to requirements. + * + * @param name The class name + * @throws InvalidClassException when a non-accepted class is encountered + */ + private void checkClassName(final String name) throws InvalidClassException { + // Reject has precedence over accept + for (final ClassNameMatcher m : rejectMatchers) { + if (m.matches(name)) { + invalidClassNameFound(name); + } + } + + boolean ok = false; + for (final ClassNameMatcher m : acceptMatchers) { + if (m.matches(name)) { + ok = true; + break; + } + } + if (!ok) { + invalidClassNameFound(name); + } + } + + /** * Called to throw {@link InvalidClassException} if an invalid * class name is found during deserialization. Can be overridden, for example * to log those class names. @@ -172,31 +198,7 @@ public class ValidatingObjectInputStream extends ObjectInputStream { @Override protected Class<?> resolveClass(final ObjectStreamClass osc) throws IOException, ClassNotFoundException { - validateClassName(osc.getName()); + checkClassName(osc.getName()); return super.resolveClass(osc); } - - /** Check that the classname conforms to requirements. - * @param name The class name - * @throws InvalidClassException when a non-accepted class is encountered - */ - private void validateClassName(final String name) throws InvalidClassException { - // Reject has precedence over accept - for (final ClassNameMatcher m : rejectMatchers) { - if (m.matches(name)) { - invalidClassNameFound(name); - } - } - - boolean ok = false; - for (final ClassNameMatcher m : acceptMatchers) { - if (m.matches(name)) { - ok = true; - break; - } - } - if (!ok) { - invalidClassNameFound(name); - } - } }
\ No newline at end of file diff --git a/src/site/xdoc/download_io.xml b/src/site/xdoc/download_io.xml index 1d7ef8ec..02445fe0 100644 --- a/src/site/xdoc/download_io.xml +++ b/src/site/xdoc/download_io.xml @@ -113,32 +113,32 @@ limitations under the License. </p> </subsection> </section> - <section name="Apache Commons IO 2.14.0 (requires Java 8)"> + <section name="Apache Commons IO 2.15.0 (requires Java 8)"> <subsection name="Binaries"> <table> <tr> - <td><a href="[preferred]/commons/io/binaries/commons-io-2.14.0-bin.tar.gz">commons-io-2.14.0-bin.tar.gz</a></td> - <td><a href="https://downloads.apache.org/commons/io/binaries/commons-io-2.14.0-bin.tar.gz.sha512">sha512</a></td> - <td><a href="https://downloads.apache.org/commons/io/binaries/commons-io-2.14.0-bin.tar.gz.asc">pgp</a></td> + <td><a href="[preferred]/commons/io/binaries/commons-io-2.15.0-bin.tar.gz">commons-io-2.15.0-bin.tar.gz</a></td> + <td><a href="https://downloads.apache.org/commons/io/binaries/commons-io-2.15.0-bin.tar.gz.sha512">sha512</a></td> + <td><a href="https://downloads.apache.org/commons/io/binaries/commons-io-2.15.0-bin.tar.gz.asc">pgp</a></td> </tr> <tr> - <td><a href="[preferred]/commons/io/binaries/commons-io-2.14.0-bin.zip">commons-io-2.14.0-bin.zip</a></td> - <td><a href="https://downloads.apache.org/commons/io/binaries/commons-io-2.14.0-bin.zip.sha512">sha512</a></td> - <td><a href="https://downloads.apache.org/commons/io/binaries/commons-io-2.14.0-bin.zip.asc">pgp</a></td> + <td><a href="[preferred]/commons/io/binaries/commons-io-2.15.0-bin.zip">commons-io-2.15.0-bin.zip</a></td> + <td><a href="https://downloads.apache.org/commons/io/binaries/commons-io-2.15.0-bin.zip.sha512">sha512</a></td> + <td><a href="https://downloads.apache.org/commons/io/binaries/commons-io-2.15.0-bin.zip.asc">pgp</a></td> </tr> </table> </subsection> <subsection name="Source"> <table> <tr> - <td><a href="[preferred]/commons/io/source/commons-io-2.14.0-src.tar.gz">commons-io-2.14.0-src.tar.gz</a></td> - <td><a href="https://downloads.apache.org/commons/io/source/commons-io-2.14.0-src.tar.gz.sha512">sha512</a></td> - <td><a href="https://downloads.apache.org/commons/io/source/commons-io-2.14.0-src.tar.gz.asc">pgp</a></td> + <td><a href="[preferred]/commons/io/source/commons-io-2.15.0-src.tar.gz">commons-io-2.15.0-src.tar.gz</a></td> + <td><a href="https://downloads.apache.org/commons/io/source/commons-io-2.15.0-src.tar.gz.sha512">sha512</a></td> + <td><a href="https://downloads.apache.org/commons/io/source/commons-io-2.15.0-src.tar.gz.asc">pgp</a></td> </tr> <tr> - <td><a href="[preferred]/commons/io/source/commons-io-2.14.0-src.zip">commons-io-2.14.0-src.zip</a></td> - <td><a href="https://downloads.apache.org/commons/io/source/commons-io-2.14.0-src.zip.sha512">sha512</a></td> - <td><a href="https://downloads.apache.org/commons/io/source/commons-io-2.14.0-src.zip.asc">pgp</a></td> + <td><a href="[preferred]/commons/io/source/commons-io-2.15.0-src.zip">commons-io-2.15.0-src.zip</a></td> + <td><a href="https://downloads.apache.org/commons/io/source/commons-io-2.15.0-src.zip.sha512">sha512</a></td> + <td><a href="https://downloads.apache.org/commons/io/source/commons-io-2.15.0-src.zip.asc">pgp</a></td> </tr> </table> </subsection> diff --git a/src/site/xdoc/index.xml b/src/site/xdoc/index.xml index 1723036e..faecfc29 100644 --- a/src/site/xdoc/index.xml +++ b/src/site/xdoc/index.xml @@ -118,18 +118,9 @@ limitations under the License. The Java platform requirements are: </p> <ul> - <li>Version 2.14.0 requires Java 8.</li> - <li>Version 2.13.0 requires Java 8.</li> - <li>Version 2.12.0 requires Java 8.</li> - <li>Version 2.11.0 requires Java 8.</li> - <li>Version 2.10.0 requires Java 8.</li> - <li>Version 2.9.0 requires Java 8.</li> - <li>Version 2.8.0 requires Java 8.</li> - <li>Version 2.7 requires Java 8.</li> + <li>Version 2.7 and up requires Java 8.</li> <li>Version 2.6 requires Java 7.</li> - <li>Version 2.5 requires Java 6.</li> - <li>Version 2.4 requires Java 6.</li> - <li>Version 2.3 requires Java 6.</li> + <li>Version 2.3 through 2.5 requires Java 6.</li> <li>Version 2.2 requires Java 5.</li> </ul> </subsection> diff --git a/src/site/xdoc/mail-lists.xml b/src/site/xdoc/mail-lists.xml index 36189d55..bb94ded2 100644 --- a/src/site/xdoc/mail-lists.xml +++ b/src/site/xdoc/mail-lists.xml @@ -59,9 +59,9 @@ limitations under the License. </p> <p> Questions related to the usage of Apache Commons IO should be posted to the - <a href="https://mail-archives.apache.org/mod_mbox/commons-user/">User List</a>. + <a href="https://lists.apache.org/list.html?user@commons.apache.org">User List</a>. <br /> - The <a href="https://mail-archives.apache.org/mod_mbox/commons-dev/">Developer List</a> + The <a href="https://lists.apache.org/list.html?dev@commons.apache.org">Developer List</a> is for questions and discussion related to the development of Apache Commons IO. <br /> Please do not cross-post; developers are also subscribed to the user list. @@ -70,8 +70,10 @@ limitations under the License. to subscribe. </p> <p> - <strong>Note:</strong> please don't send patches or attachments to any of the mailing lists. + <strong>Note:</strong> please don't send patches or attachments to any of the mailing lists; + most of the lists are set up to drop attachments. Patches are best handled via the <a href="issue-tracking.html">Issue Tracking</a> system. + If you have a GitHub account, most components also accept PRs (pull requests). Otherwise, please upload the file to a public server and include the URL in the mail. </p> </section> @@ -105,12 +107,11 @@ limitations under the License. <td><a href="mailto:user-subscribe@commons.apache.org">Subscribe</a></td> <td><a href="mailto:user-unsubscribe@commons.apache.org">Unsubscribe</a></td> <td><a href="mailto:user@commons.apache.org?subject=[io]">Post</a></td> - <td><a href="https://mail-archives.apache.org/mod_mbox/commons-user/">mail-archives.apache.org</a><br /> + <td> <a href="https://lists.apache.org/list.html?user@commons.apache.org">lists.apache.org</a> </td> - <td><a href="https://markmail.org/list/org.apache.commons.users/">markmail.org</a><br /> - <a href="https://www.mail-archive.com/user@commons.apache.org/">www.mail-archive.com</a><br /> - <a href="https://news.gmane.org/gmane.comp.jakarta.commons.devel">news.gmane.org</a> + <td> + <a href="https://www.mail-archive.com/user@commons.apache.org/">www.mail-archive.com</a> </td> </tr> @@ -125,12 +126,11 @@ limitations under the License. <td><a href="mailto:dev-subscribe@commons.apache.org">Subscribe</a></td> <td><a href="mailto:dev-unsubscribe@commons.apache.org">Unsubscribe</a></td> <td><a href="mailto:dev@commons.apache.org?subject=[io]">Post</a></td> - <td><a href="https://mail-archives.apache.org/mod_mbox/commons-dev/">mail-archives.apache.org</a><br /> + <td> <a href="https://lists.apache.org/list.html?dev@commons.apache.org">lists.apache.org</a> </td> - <td><a href="https://markmail.org/list/org.apache.commons.dev/">markmail.org</a><br /> - <a href="https://www.mail-archive.com/dev@commons.apache.org/">www.mail-archive.com</a><br /> - <a href="https://news.gmane.org/gmane.comp.jakarta.commons.devel">news.gmane.org</a> + <td> + <a href="https://www.mail-archive.com/dev@commons.apache.org/">www.mail-archive.com</a> </td> </tr> @@ -145,10 +145,10 @@ limitations under the License. <td><a href="mailto:issues-subscribe@commons.apache.org">Subscribe</a></td> <td><a href="mailto:issues-unsubscribe@commons.apache.org">Unsubscribe</a></td> <td><i>read only</i></td> - <td><a href="https://mail-archives.apache.org/mod_mbox/commons-issues/">mail-archives.apache.org</a><br /> + <td> <a href="https://lists.apache.org/list.html?issues@commons.apache.org">lists.apache.org</a> </td> - <td><a href="https://markmail.org/list/org.apache.commons.issues/">markmail.org</a><br /> + <td> <a href="https://www.mail-archive.com/issues@commons.apache.org/">www.mail-archive.com</a> </td> </tr> @@ -164,10 +164,10 @@ limitations under the License. <td><a href="mailto:commits-subscribe@commons.apache.org">Subscribe</a></td> <td><a href="mailto:commits-unsubscribe@commons.apache.org">Unsubscribe</a></td> <td><i>read only</i></td> - <td><a href="https://mail-archives.apache.org/mod_mbox/commons-commits/">mail-archives.apache.org</a><br /> + <td> <a href="https://lists.apache.org/list.html?commits@commons.apache.org">lists.apache.org</a> </td> - <td><a href="https://markmail.org/list/org.apache.commons.commits/">markmail.org</a><br /> + <td> <a href="https://www.mail-archive.com/commits@commons.apache.org/">www.mail-archive.com</a> </td> </tr> @@ -199,13 +199,11 @@ limitations under the License. <td><a class="externalLink" href="mailto:announce-subscribe@apache.org">Subscribe</a></td> <td><a class="externalLink" href="mailto:announce-unsubscribe@apache.org">Unsubscribe</a></td> <td><i>read only</i></td> - <td><a class="externalLink" href="https://mail-archives.apache.org/mod_mbox/www-announce/">mail-archives.apache.org</a><br /> + <td> <a class="externalLink" href="https://lists.apache.org/list.html?announce@apache.org">lists.apache.org</a> </td> - <td><a class="externalLink" href="https://markmail.org/list/org.apache.announce/">markmail.org</a><br /> - <a class="externalLink" href="https://old.nabble.com/Apache-News-and-Announce-f109.html">old.nabble.com</a><br /> - <a class="externalLink" href="https://www.mail-archive.com/announce@apache.org/">www.mail-archive.com</a><br /> - <a class="externalLink" href="https://news.gmane.org/gmane.comp.apache.announce">news.gmane.org</a> + <td> + <a class="externalLink" href="https://www.mail-archive.com/announce@apache.org/">www.mail-archive.com</a> </td> </tr> </table> diff --git a/src/test/java/org/apache/commons/io/CharsetsTest.java b/src/test/java/org/apache/commons/io/CharsetsTest.java index b68b90b6..7c988978 100644 --- a/src/test/java/org/apache/commons/io/CharsetsTest.java +++ b/src/test/java/org/apache/commons/io/CharsetsTest.java @@ -21,6 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.Set; import java.util.SortedMap; import org.junit.jupiter.api.Test; @@ -31,6 +32,20 @@ import org.junit.jupiter.api.Test; @SuppressWarnings("deprecation") // testing deprecated code public class CharsetsTest { + /** + * For parameterized tests. + */ + public static final String AVAIL_CHARSETS = "org.apache.commons.io.CharsetsTest#availableCharsetsKeySet"; + + /** + * For parameterized tests. + * + * @return {@code Charset.availableCharsets().keySet()}. + */ + public static Set<String> availableCharsetsKeySet() { + return Charset.availableCharsets().keySet(); + } + @Test public void testIso8859_1() { assertEquals("ISO-8859-1", Charsets.ISO_8859_1.name()); diff --git a/src/test/java/org/apache/commons/io/DemuxInputStreamTest.java b/src/test/java/org/apache/commons/io/DemuxInputStreamTest.java index 6872bc54..6b1a63b2 100644 --- a/src/test/java/org/apache/commons/io/DemuxInputStreamTest.java +++ b/src/test/java/org/apache/commons/io/DemuxInputStreamTest.java @@ -37,7 +37,7 @@ import org.junit.jupiter.api.Test; */ public class DemuxInputStreamTest { - private static class ReaderThread extends Thread { + private static final class ReaderThread extends Thread { private final DemuxInputStream demuxInputStream; private final InputStream inputStream; private final StringBuffer stringBuffer = new StringBuffer(); @@ -62,7 +62,7 @@ public class DemuxInputStreamTest { // System.out.println( "Reading: " + (char)ch ); stringBuffer.append((char) ch); - final int sleepMillis = Math.abs(c_random.nextInt() % 10); + final int sleepMillis = Math.abs(RANDOM.nextInt() % 10); TestUtils.sleep(sleepMillis); ch = demuxInputStream.read(); } @@ -72,7 +72,7 @@ public class DemuxInputStreamTest { } } - private static class WriterThread extends Thread { + private static final class WriterThread extends Thread { private final byte[] byteArray; private final DemuxOutputStream demuxOutputStream; private final OutputStream outputStream; @@ -91,7 +91,7 @@ public class DemuxInputStreamTest { try { // System.out.println( "Writing: " + (char)byteArray[ i ] ); demuxOutputStream.write(element); - final int sleepMillis = Math.abs(c_random.nextInt() % 10); + final int sleepMillis = Math.abs(RANDOM.nextInt() % 10); TestUtils.sleep(sleepMillis); } catch (final Exception e) { e.printStackTrace(); @@ -100,7 +100,7 @@ public class DemuxInputStreamTest { } } - private static final Random c_random = new Random(); + private static final Random RANDOM = new Random(); private static final String DATA1 = "Data for thread1"; private static final String DATA2 = "Data for thread2"; diff --git a/src/test/java/org/apache/commons/io/DirectoryWalkerTest.java b/src/test/java/org/apache/commons/io/DirectoryWalkerTest.java index 5ac3aa9c..ccb5c110 100644 --- a/src/test/java/org/apache/commons/io/DirectoryWalkerTest.java +++ b/src/test/java/org/apache/commons/io/DirectoryWalkerTest.java @@ -90,7 +90,7 @@ public class DirectoryWalkerTest { * Test DirectoryWalker implementation that always returns false * from handleDirectoryStart() */ - private static class TestFalseFileFinder extends TestFileFinder { + private static final class TestFalseFileFinder extends TestFileFinder { protected TestFalseFileFinder(final FileFilter filter, final int depthLimit) { super(filter, depthLimit); @@ -143,7 +143,7 @@ public class DirectoryWalkerTest { * Test DirectoryWalker implementation that finds files in a directory hierarchy * applying a file filter. */ - private static class TestFileFinderString extends DirectoryWalker<String> { + private static final class TestFileFinderString extends DirectoryWalker<String> { protected TestFileFinderString(final FileFilter filter, final int depthLimit) { super(filter, depthLimit); @@ -234,12 +234,12 @@ public class DirectoryWalkerTest { private static final File outputDir = new File(ioDir, "output"); private static final File[] dirs = {orgDir, apacheDir, commonsDir, ioDir, outputDir}; // Files - private static final File filenameUtils = new File(ioDir, "FilenameUtils.java"); + private static final File fileNameUtils = new File(ioDir, "FilenameUtils.java"); private static final File ioUtils = new File(ioDir, "IOUtils.java"); private static final File proxyWriter = new File(outputDir, "ProxyWriter.java"); private static final File nullStream = new File(outputDir, "NullOutputStream.java"); - private static final File[] ioFiles = {filenameUtils, ioUtils}; + private static final File[] ioFiles = {fileNameUtils, ioUtils}; private static final File[] outputFiles = {proxyWriter, nullStream}; // Filters diff --git a/src/test/java/org/apache/commons/io/DirectoryWalkerTestCaseJava4.java b/src/test/java/org/apache/commons/io/DirectoryWalkerTestCaseJava4.java index f55699ad..ad7337dd 100644 --- a/src/test/java/org/apache/commons/io/DirectoryWalkerTestCaseJava4.java +++ b/src/test/java/org/apache/commons/io/DirectoryWalkerTestCaseJava4.java @@ -102,7 +102,7 @@ public class DirectoryWalkerTestCaseJava4 { * Test DirectoryWalker implementation that always returns false * from handleDirectoryStart() */ - private static class TestFalseFileFinder extends TestFileFinder { + private static final class TestFalseFileFinder extends TestFileFinder { protected TestFalseFileFinder(final FileFilter filter, final int depthLimit) { super(filter, depthLimit); @@ -237,12 +237,12 @@ public class DirectoryWalkerTestCaseJava4 { private static final File outputDir = new File(ioDir, "output"); private static final File[] dirs = {orgDir, apacheDir, commonsDir, ioDir, outputDir}; // Files - private static final File filenameUtils = new File(ioDir, "FilenameUtils.java"); + private static final File fileNameUtils = new File(ioDir, "FilenameUtils.java"); private static final File ioUtils = new File(ioDir, "IOUtils.java"); private static final File proxyWriter = new File(outputDir, "ProxyWriter.java"); private static final File nullStream = new File(outputDir, "NullOutputStream.java"); - private static final File[] ioFiles = {filenameUtils, ioUtils}; + private static final File[] ioFiles = {fileNameUtils, ioUtils}; private static final File[] outputFiles = {proxyWriter, nullStream}; // Filters private static final IOFileFilter dirsFilter = createNameFilter(dirs); diff --git a/src/test/java/org/apache/commons/io/EndianUtilsTest.java b/src/test/java/org/apache/commons/io/EndianUtilsTest.java index 79df0c66..4247644d 100644 --- a/src/test/java/org/apache/commons/io/EndianUtilsTest.java +++ b/src/test/java/org/apache/commons/io/EndianUtilsTest.java @@ -38,7 +38,7 @@ public class EndianUtilsTest { } @Test - public void testEOFException() throws IOException { + public void testEOFException() { final ByteArrayInputStream input = new ByteArrayInputStream(new byte[] {}); assertThrows(EOFException.class, () -> EndianUtils.readSwappedDouble(input)); } diff --git a/src/test/java/org/apache/commons/io/FileUtilsDirectoryContainsTest.java b/src/test/java/org/apache/commons/io/FileUtilsDirectoryContainsTest.java index bba9f098..3e92fef6 100644 --- a/src/test/java/org/apache/commons/io/FileUtilsDirectoryContainsTest.java +++ b/src/test/java/org/apache/commons/io/FileUtilsDirectoryContainsTest.java @@ -112,7 +112,7 @@ public class FileUtilsDirectoryContainsTest { } @Test - public void testDirectoryDoesNotExist() throws IOException { + public void testDirectoryDoesNotExist() { final File dir = new File("DOESNOTEXIST"); assertFalse(dir.exists()); assertThrows(IllegalArgumentException.class, () -> FileUtils.directoryContains(dir, file1)); @@ -158,12 +158,12 @@ public class FileUtilsDirectoryContainsTest { } @Test - public void testSameFile() throws IOException { + public void testSameFile() { assertThrows(IllegalArgumentException.class, () -> FileUtils.directoryContains(file1, file1)); } @Test - public void testUnrealizedContainment() throws IOException { + public void testUnrealizedContainment() { final File dir = new File("DOESNOTEXIST"); final File file = new File(dir, "DOESNOTEXIST2"); assertFalse(dir.exists()); diff --git a/src/test/java/org/apache/commons/io/FileUtilsListFilesTest.java b/src/test/java/org/apache/commons/io/FileUtilsListFilesTest.java index 27a81c98..e65bc8de 100644 --- a/src/test/java/org/apache/commons/io/FileUtilsListFilesTest.java +++ b/src/test/java/org/apache/commons/io/FileUtilsListFilesTest.java @@ -29,6 +29,7 @@ import java.util.stream.Collectors; import org.apache.commons.io.filefilter.FileFilterUtils; import org.apache.commons.io.filefilter.IOFileFilter; +import org.apache.commons.lang3.function.Consumers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -45,8 +46,15 @@ public class FileUtilsListFilesTest { return files.stream().map(File::getName).collect(Collectors.toList()); } + /** + * Consumes and closes the underlying stream. + * + * @param files The iterator to consume. + * @return a new collection. + */ private Collection<String> filesToFilenames(final Iterator<File> files) { final Collection<String> fileNames = new ArrayList<>(); + // Iterator.forEachRemaining() closes the underlying stream. files.forEachRemaining(f -> fileNames.add(f.getName())); return fileNames; } @@ -88,68 +96,83 @@ public class FileUtilsListFilesTest { final String[] extensions = { "xml", "txt" }; Iterator<File> files = FileUtils.iterateFiles(temporaryFolder, extensions, false); - Collection<String> filenames = filesToFilenames(files); - assertEquals(1, filenames.size()); - assertTrue(filenames.contains("dummy-build.xml")); - assertFalse(filenames.contains("README")); - assertFalse(filenames.contains("dummy-file.txt")); - - files = FileUtils.iterateFiles(temporaryFolder, extensions, true); - filenames = filesToFilenames(files); - assertEquals(4, filenames.size()); - assertTrue(filenames.contains("dummy-file.txt")); - assertFalse(filenames.contains("dummy-index.html")); + try { + final Collection<String> fileNames = filesToFilenames(files); + assertEquals(1, fileNames.size()); + assertTrue(fileNames.contains("dummy-build.xml")); + assertFalse(fileNames.contains("README")); + assertFalse(fileNames.contains("dummy-file.txt")); + } finally { + // Backstop in case filesToFilenames() failure. + files.forEachRemaining(Consumers.nop()); + } + + try { + files = FileUtils.iterateFiles(temporaryFolder, extensions, true); + final Collection<String> fileNames = filesToFilenames(files); + assertEquals(4, fileNames.size()); + assertTrue(fileNames.contains("dummy-file.txt")); + assertFalse(fileNames.contains("dummy-index.html")); + } finally { + // Backstop in case filesToFilenames() failure. + files.forEachRemaining(Consumers.nop()); + } files = FileUtils.iterateFiles(temporaryFolder, null, false); - filenames = filesToFilenames(files); - assertEquals(2, filenames.size()); - assertTrue(filenames.contains("dummy-build.xml")); - assertTrue(filenames.contains("README")); - assertFalse(filenames.contains("dummy-file.txt")); + try { + final Collection<String> fileNames = filesToFilenames(files); + assertEquals(2, fileNames.size()); + assertTrue(fileNames.contains("dummy-build.xml")); + assertTrue(fileNames.contains("README")); + assertFalse(fileNames.contains("dummy-file.txt")); + } finally { + // Backstop in case filesToFilenames() failure. + files.forEachRemaining(Consumers.nop()); + } } @Test public void testListFiles() { Collection<File> files; - Collection<String> filenames; + Collection<String> fileNames; IOFileFilter fileFilter; IOFileFilter dirFilter; // First, find non-recursively fileFilter = FileFilterUtils.trueFileFilter(); files = FileUtils.listFiles(temporaryFolder, fileFilter, null); - filenames = filesToFilenames(files); - assertTrue(filenames.contains("dummy-build.xml"), "'dummy-build.xml' is missing"); - assertFalse(filenames.contains("dummy-index.html"), "'dummy-index.html' shouldn't be found"); - assertFalse(filenames.contains("Entries"), "'Entries' shouldn't be found"); + fileNames = filesToFilenames(files); + assertTrue(fileNames.contains("dummy-build.xml"), "'dummy-build.xml' is missing"); + assertFalse(fileNames.contains("dummy-index.html"), "'dummy-index.html' shouldn't be found"); + assertFalse(fileNames.contains("Entries"), "'Entries' shouldn't be found"); // Second, find recursively fileFilter = FileFilterUtils.trueFileFilter(); dirFilter = FileFilterUtils.notFileFilter(FileFilterUtils.nameFileFilter("CVS")); files = FileUtils.listFiles(temporaryFolder, fileFilter, dirFilter); - filenames = filesToFilenames(files); - assertTrue(filenames.contains("dummy-build.xml"), "'dummy-build.xml' is missing"); - assertTrue(filenames.contains("dummy-index.html"), "'dummy-index.html' is missing"); - assertFalse(filenames.contains("Entries"), "'Entries' shouldn't be found"); + fileNames = filesToFilenames(files); + assertTrue(fileNames.contains("dummy-build.xml"), "'dummy-build.xml' is missing"); + assertTrue(fileNames.contains("dummy-index.html"), "'dummy-index.html' is missing"); + assertFalse(fileNames.contains("Entries"), "'Entries' shouldn't be found"); // Do the same as above but now with the filter coming from FileFilterUtils fileFilter = FileFilterUtils.trueFileFilter(); dirFilter = FileFilterUtils.makeCVSAware(null); files = FileUtils.listFiles(temporaryFolder, fileFilter, dirFilter); - filenames = filesToFilenames(files); - assertTrue(filenames.contains("dummy-build.xml"), "'dummy-build.xml' is missing"); - assertTrue(filenames.contains("dummy-index.html"), "'dummy-index.html' is missing"); - assertFalse(filenames.contains("Entries"), "'Entries' shouldn't be found"); + fileNames = filesToFilenames(files); + assertTrue(fileNames.contains("dummy-build.xml"), "'dummy-build.xml' is missing"); + assertTrue(fileNames.contains("dummy-index.html"), "'dummy-index.html' is missing"); + assertFalse(fileNames.contains("Entries"), "'Entries' shouldn't be found"); // Again with the CVS filter but now with a non-null parameter fileFilter = FileFilterUtils.trueFileFilter(); dirFilter = FileFilterUtils.prefixFileFilter("sub"); dirFilter = FileFilterUtils.makeCVSAware(dirFilter); files = FileUtils.listFiles(temporaryFolder, fileFilter, dirFilter); - filenames = filesToFilenames(files); - assertTrue(filenames.contains("dummy-build.xml"), "'dummy-build.xml' is missing"); - assertTrue(filenames.contains("dummy-index.html"), "'dummy-index.html' is missing"); - assertFalse(filenames.contains("Entries"), "'Entries' shouldn't be found"); + fileNames = filesToFilenames(files); + assertTrue(fileNames.contains("dummy-build.xml"), "'dummy-build.xml' is missing"); + assertTrue(fileNames.contains("dummy-index.html"), "'dummy-index.html' is missing"); + assertFalse(fileNames.contains("Entries"), "'Entries' shouldn't be found"); assertThrows(NullPointerException.class, () -> FileUtils.listFiles(temporaryFolder, null, null)); } @@ -160,23 +183,23 @@ public class FileUtilsListFilesTest { Collection<File> files = FileUtils.listFiles(temporaryFolder, extensions, false); assertEquals(1, files.size()); - Collection<String> filenames = filesToFilenames(files); - assertTrue(filenames.contains("dummy-build.xml")); - assertFalse(filenames.contains("README")); - assertFalse(filenames.contains("dummy-file.txt")); + Collection<String> fileNames = filesToFilenames(files); + assertTrue(fileNames.contains("dummy-build.xml")); + assertFalse(fileNames.contains("README")); + assertFalse(fileNames.contains("dummy-file.txt")); files = FileUtils.listFiles(temporaryFolder, extensions, true); - filenames = filesToFilenames(files); - assertEquals(4, filenames.size()); - assertTrue(filenames.contains("dummy-file.txt")); - assertFalse(filenames.contains("dummy-index.html")); + fileNames = filesToFilenames(files); + assertEquals(4, fileNames.size()); + assertTrue(fileNames.contains("dummy-file.txt")); + assertFalse(fileNames.contains("dummy-index.html")); files = FileUtils.listFiles(temporaryFolder, null, false); assertEquals(2, files.size()); - filenames = filesToFilenames(files); - assertTrue(filenames.contains("dummy-build.xml")); - assertTrue(filenames.contains("README")); - assertFalse(filenames.contains("dummy-file.txt")); + fileNames = filesToFilenames(files); + assertTrue(fileNames.contains("dummy-build.xml")); + assertTrue(fileNames.contains("README")); + assertFalse(fileNames.contains("dummy-file.txt")); } diff --git a/src/test/java/org/apache/commons/io/FileUtilsTest.java b/src/test/java/org/apache/commons/io/FileUtilsTest.java index 4d976c4e..2c820c8d 100644 --- a/src/test/java/org/apache/commons/io/FileUtilsTest.java +++ b/src/test/java/org/apache/commons/io/FileUtilsTest.java @@ -40,6 +40,7 @@ import java.math.BigInteger; import java.net.URL; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.charset.UnsupportedCharsetException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -47,6 +48,7 @@ import java.nio.file.StandardCopyOption; import java.nio.file.attribute.AclFileAttributeView; import java.nio.file.attribute.FileTime; import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; @@ -86,6 +88,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIf; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -123,20 +126,6 @@ public class FileUtilsTest extends AbstractTempDirTest { } } - // Test helper class to pretend a file is shorter than it is - private static class ShorterFile extends File { - private static final long serialVersionUID = 1L; - - public ShorterFile(final String pathname) { - super(pathname); - } - - @Override - public long length() { - return super.length() - 1; - } - } - private static final String UTF_8 = StandardCharsets.UTF_8.name(); /** Test data. */ @@ -168,11 +157,6 @@ public class FileUtilsTest extends AbstractTempDirTest { */ private static final ListDirectoryWalker LIST_WALKER = new ListDirectoryWalker(); - /** - * Delay in milliseconds to make sure test for "last modified date" are accurate - */ - //private static final int LAST_MODIFIED_DELAY = 600; - private File testFile1; private File testFile2; @@ -1452,7 +1436,7 @@ public class FileUtilsTest extends AbstractTempDirTest { public void testFileUtils() throws Exception { // Loads file from classpath final File file1 = new File(tempDirFile, "test.txt"); - final String filename = file1.getAbsolutePath(); + final String fileName = file1.getAbsolutePath(); //Create test file on-the-fly (used to be in CVS) try (OutputStream out = Files.newOutputStream(file1.toPath())) { @@ -1461,16 +1445,16 @@ public class FileUtilsTest extends AbstractTempDirTest { final File file2 = new File(tempDirFile, "test2.txt"); - FileUtils.writeStringToFile(file2, filename, UTF_8); + FileUtils.writeStringToFile(file2, fileName, UTF_8); assertTrue(file2.exists()); assertTrue(file2.length() > 0); final String file2contents = FileUtils.readFileToString(file2, UTF_8); - assertEquals(filename, file2contents, "Second file's contents correct"); + assertEquals(fileName, file2contents, "Second file's contents correct"); assertTrue(file2.delete()); - final String contents = FileUtils.readFileToString(new File(filename), UTF_8); + final String contents = FileUtils.readFileToString(new File(fileName), UTF_8); assertEquals("This is a test", contents, "FileUtils.fileRead()"); } @@ -1645,8 +1629,8 @@ public class FileUtilsTest extends AbstractTempDirTest { @Test public void testIO575() throws IOException { final Path sourceDir = Files.createTempDirectory("source-dir"); - final String filename = "some-file"; - final Path sourceFile = Files.createFile(sourceDir.resolve(filename)); + final String fileName = "some-file"; + final Path sourceFile = Files.createFile(sourceDir.resolve(fileName)); assertEquals(SystemUtils.IS_OS_WINDOWS, sourceFile.toFile().canExecute()); @@ -1658,7 +1642,7 @@ public class FileUtilsTest extends AbstractTempDirTest { FileUtils.copyDirectory(sourceDir.toFile(), destDir.toFile()); - final Path destFile = destDir.resolve(filename); + final Path destFile = destDir.resolve(fileName); assertTrue(destFile.toFile().exists()); assertTrue(destFile.toFile().canExecute()); @@ -2445,6 +2429,41 @@ public class FileUtilsTest extends AbstractTempDirTest { } @Test + public void testReadFileToByteArray_Errors() { + assertThrows(NullPointerException.class, () -> FileUtils.readFileToByteArray(null)); + assertThrows(IOException.class, () -> FileUtils.readFileToByteArray(new File("non-exsistent"))); + assertThrows(IOException.class, () -> FileUtils.readFileToByteArray(tempDirFile)); + } + + @Test + @EnabledIf("isPosixFilePermissionsSupported") + public void testReadFileToByteArray_IOExceptionOnPosixFileSystem() throws Exception { + final File file = TestUtils.newFile(tempDirFile, "cant-read.txt"); + TestUtils.createFile(file, 100); + Files.setPosixFilePermissions(file.toPath(), PosixFilePermissions.fromString("---------")); + + assertThrows(IOException.class, () -> FileUtils.readFileToByteArray(file)); + } + + @Test + public void testReadFileToString_Errors() { + assertThrows(NullPointerException.class, () -> FileUtils.readFileToString(null)); + assertThrows(IOException.class, () -> FileUtils.readFileToString(new File("non-exsistent"))); + assertThrows(IOException.class, () -> FileUtils.readFileToString(tempDirFile)); + assertThrows(UnsupportedCharsetException.class, () -> FileUtils.readFileToString(tempDirFile, "unsupported-charset")); + } + + @Test + @EnabledIf("isPosixFilePermissionsSupported") + public void testReadFileToString_IOExceptionOnPosixFileSystem() throws Exception { + final File file = TestUtils.newFile(tempDirFile, "cant-read.txt"); + TestUtils.createFile(file, 100); + Files.setPosixFilePermissions(file.toPath(), PosixFilePermissions.fromString("---------")); + + assertThrows(IOException.class, () -> FileUtils.readFileToString(file)); + } + + @Test public void testReadFileToStringWithDefaultEncoding() throws Exception { final File file = new File(tempDirFile, "read.obj"); final String fixture = "Hello /u1234"; @@ -2478,6 +2497,24 @@ public class FileUtilsTest extends AbstractTempDirTest { } @Test + public void testReadLines_Errors() { + assertThrows(NullPointerException.class, () -> FileUtils.readLines(null)); + assertThrows(IOException.class, () -> FileUtils.readLines(new File("non-exsistent"))); + assertThrows(IOException.class, () -> FileUtils.readLines(tempDirFile)); + assertThrows(UnsupportedCharsetException.class, () -> FileUtils.readLines(tempDirFile, "unsupported-charset")); + } + + @Test + @EnabledIf("isPosixFilePermissionsSupported") + public void testReadLines_IOExceptionOnPosixFileSystem() throws Exception { + final File file = TestUtils.newFile(tempDirFile, "cant-read.txt"); + TestUtils.createFile(file, 100); + Files.setPosixFilePermissions(file.toPath(), PosixFilePermissions.fromString("---------")); + + assertThrows(IOException.class, () -> FileUtils.readLines(file)); + } + + @Test public void testSizeOf() throws Exception { final File file = new File(tempDirFile, getName()); diff --git a/src/test/java/org/apache/commons/io/IOUtilsMultithreadedSkipTest.java b/src/test/java/org/apache/commons/io/IOUtilsMultithreadedSkipTest.java index 9db0d67b..a492d397 100644 --- a/src/test/java/org/apache/commons/io/IOUtilsMultithreadedSkipTest.java +++ b/src/test/java/org/apache/commons/io/IOUtilsMultithreadedSkipTest.java @@ -87,7 +87,7 @@ public class IOUtilsMultithreadedSkipTest { try (final InputStream inputStream = getClass().getResourceAsStream(FIXTURE)) { bytes = IOUtils.toByteArray(inputStream); } - final int numSkips = (random.nextInt(bytes.length) / 100) + 1; + final int numSkips = random.nextInt(bytes.length) / 100 + 1; final int[] skips = generateSkips(bytes, numSkips, random); final int[] expected; diff --git a/src/test/java/org/apache/commons/io/IOUtilsTest.java b/src/test/java/org/apache/commons/io/IOUtilsTest.java index e361e885..c921abc1 100644 --- a/src/test/java/org/apache/commons/io/IOUtilsTest.java +++ b/src/test/java/org/apache/commons/io/IOUtilsTest.java @@ -1257,7 +1257,7 @@ public class IOUtilsTest { assertThrows(NullPointerException.class, () -> IOUtils.resourceToURL(null, ClassLoader.getSystemClassLoader())); } - public void testSingleEOL(final String s1, final String s2, final boolean ifEquals) throws IOException { + public void testSingleEOL(final String s1, final String s2, final boolean ifEquals) { assertEquals(ifEquals, IOUtils.contentEqualsIgnoreEOL( new CharArrayReader(s1.toCharArray()), new CharArrayReader(s2.toCharArray()) @@ -1750,6 +1750,15 @@ public class IOUtilsTest { } @Test + public void testWriteLines() throws IOException { + final String[] data = {"The", "quick"}; + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + IOUtils.writeLines(Arrays.asList(data), "\n", out, "UTF-16"); + final String result = new String(out.toByteArray(), StandardCharsets.UTF_16); + assertEquals("The\nquick\n", result); + } + + @Test public void testWriteLittleString() throws IOException { final String data = "\uD83D"; // White-box test to check that not closing the internal channel is not a problem. diff --git a/src/test/java/org/apache/commons/io/RandomAccessFilesTest.java b/src/test/java/org/apache/commons/io/RandomAccessFilesTest.java index d3873599..ce7fa8fd 100644 --- a/src/test/java/org/apache/commons/io/RandomAccessFilesTest.java +++ b/src/test/java/org/apache/commons/io/RandomAccessFilesTest.java @@ -19,10 +19,15 @@ package org.apache.commons.io; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.io.RandomAccessFile; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; import org.junit.jupiter.api.Test; @@ -31,32 +36,101 @@ import org.junit.jupiter.api.Test; */ public class RandomAccessFilesTest { - protected static final String FILE_RES_RO = "/org/apache/commons/io/test-file-20byteslength.bin"; - protected static final String FILE_NAME_RO = "src/test/resources" + FILE_RES_RO; + private static final String FILE_NAME_RO_20 = "src/test/resources/org/apache/commons/io/test-file-20byteslength.bin"; + private static final String FILE_NAME_RO_0 = "src/test/resources/org/apache/commons/io/test-file-empty.bin"; + private static final String FILE_NAME_RO_0_BIS = "src/test/resources/org/apache/commons/io/test-file-empty2.bin"; + + @Test + public void testContentEquals() throws IOException { + try (RandomAccessFile raf1 = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO_20)) { + assertEquals(raf1, raf1); + assertTrue(RandomAccessFiles.contentEquals(raf1, raf1)); + } + // as above, to make sure resources are OK + try (RandomAccessFile raf1 = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO_20)) { + assertEquals(raf1, raf1); + assertTrue(RandomAccessFiles.contentEquals(raf1, raf1)); + } + // same 20 bytes + try (RandomAccessFile raf1 = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO_20); + RandomAccessFile raf2 = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO_20)) { + assertTrue(RandomAccessFiles.contentEquals(raf1, raf2)); + } + // same empty file + try (RandomAccessFile raf1 = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO_0); + RandomAccessFile raf2 = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO_0)) { + assertTrue(RandomAccessFiles.contentEquals(raf1, raf2)); + assertTrue(RandomAccessFiles.contentEquals(RandomAccessFiles.reset(raf2), RandomAccessFiles.reset(raf1))); + } + // diff empty file + try (RandomAccessFile raf1 = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO_0); + RandomAccessFile raf2 = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO_0_BIS)) { + assertTrue(RandomAccessFiles.contentEquals(raf1, raf2)); + assertTrue(RandomAccessFiles.contentEquals(RandomAccessFiles.reset(raf2), RandomAccessFiles.reset(raf1))); + } + try (RandomAccessFile raf1 = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO_0); + RandomAccessFile raf2 = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO_20)) { + assertFalse(RandomAccessFiles.contentEquals(raf1, raf2)); + assertFalse(RandomAccessFiles.contentEquals(RandomAccessFiles.reset(raf2), RandomAccessFiles.reset(raf1))); + } + // + final Path bigFile1 = Files.createTempFile(getClass().getSimpleName(), "-1.bin"); + final Path bigFile2 = Files.createTempFile(getClass().getSimpleName(), "-2.bin"); + final Path bigFile3 = Files.createTempFile(getClass().getSimpleName(), "-3.bin"); + try { + final int newLength = 1_000_000; + final byte[] bytes1 = new byte[newLength]; + final byte[] bytes2 = new byte[newLength]; + Arrays.fill(bytes1, (byte) 1); + Arrays.fill(bytes2, (byte) 2); + Files.write(bigFile1, bytes1); + Files.write(bigFile2, bytes2); + try (RandomAccessFile raf1 = RandomAccessFileMode.READ_ONLY.create(bigFile1); + RandomAccessFile raf2 = RandomAccessFileMode.READ_ONLY.create(bigFile2)) { + assertFalse(RandomAccessFiles.contentEquals(raf1, raf2)); + assertFalse(RandomAccessFiles.contentEquals(RandomAccessFiles.reset(raf2), RandomAccessFiles.reset(raf1))); + assertTrue(RandomAccessFiles.contentEquals(RandomAccessFiles.reset(raf1), RandomAccessFiles.reset(raf1))); + } + // Make the last byte different + final byte[] bytes3 = bytes1.clone(); + bytes3[bytes3.length - 1] = 9; + Files.write(bigFile3, bytes3); + try (RandomAccessFile raf1 = RandomAccessFileMode.READ_ONLY.create(bigFile1); + RandomAccessFile raf3 = RandomAccessFileMode.READ_ONLY.create(bigFile3)) { + assertFalse(RandomAccessFiles.contentEquals(raf1, raf3)); + assertFalse(RandomAccessFiles.contentEquals(RandomAccessFiles.reset(raf3), RandomAccessFiles.reset(raf1))); + } + } finally { + // Delete ASAP + Files.deleteIfExists(bigFile1); + Files.deleteIfExists(bigFile2); + Files.deleteIfExists(bigFile3); + } + } @Test public void testRead() throws IOException { - try (final RandomAccessFile raf = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO)) { + try (final RandomAccessFile raf = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO_20)) { final byte[] buffer = RandomAccessFiles.read(raf, 0, 0); assertArrayEquals(new byte[] {}, buffer); } - try (final RandomAccessFile raf = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO)) { + try (final RandomAccessFile raf = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO_20)) { final byte[] buffer = RandomAccessFiles.read(raf, 1, 0); assertArrayEquals(new byte[] {}, buffer); } - try (final RandomAccessFile raf = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO)) { + try (final RandomAccessFile raf = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO_20)) { final byte[] buffer = RandomAccessFiles.read(raf, 0, 1); assertArrayEquals(new byte[] { '1' }, buffer); } - try (final RandomAccessFile raf = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO)) { + try (final RandomAccessFile raf = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO_20)) { final byte[] buffer = RandomAccessFiles.read(raf, 1, 1); assertArrayEquals(new byte[] { '2' }, buffer); } - try (final RandomAccessFile raf = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO)) { + try (final RandomAccessFile raf = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO_20)) { final byte[] buffer = RandomAccessFiles.read(raf, 0, 20); assertEquals(20, buffer.length); } - try (final RandomAccessFile raf = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO)) { + try (final RandomAccessFile raf = RandomAccessFileMode.READ_ONLY.create(FILE_NAME_RO_20)) { assertThrows(IOException.class, () -> RandomAccessFiles.read(raf, 0, 21)); } } diff --git a/src/test/java/org/apache/commons/io/StreamIteratorTest.java b/src/test/java/org/apache/commons/io/StreamIteratorTest.java new file mode 100644 index 00000000..7cfa9afb --- /dev/null +++ b/src/test/java/org/apache/commons/io/StreamIteratorTest.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.io; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Iterator; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +/** + * Tests {@link StreamIterator}. + */ +public class StreamIteratorTest { + + @Test + public void testForEachRemaining() { + final AtomicBoolean closed = new AtomicBoolean(); + final Iterator<Integer> iter = StreamIterator.iterator(Stream.of(1, 2, 3).onClose(() -> closed.set(true))); + final AtomicInteger sum = new AtomicInteger(); + + iter.forEachRemaining(sum::addAndGet); + + assertEquals(6, sum.get()); + assertTrue(closed.get()); + } + + @Test + public void testHasNext() { + final AtomicBoolean closed = new AtomicBoolean(); + final Iterator<Integer> iter = StreamIterator.iterator(Stream.of(1, 2, 3).onClose(() -> closed.set(true))); + int sum = 0; + + while (iter.hasNext()) { + sum += iter.next(); + } + + assertEquals(6, sum); + assertTrue(closed.get()); + } +} diff --git a/src/test/java/org/apache/commons/io/file/AbstractTempDirTest.java b/src/test/java/org/apache/commons/io/file/AbstractTempDirTest.java index a5ed616f..16bd66cc 100644 --- a/src/test/java/org/apache/commons/io/file/AbstractTempDirTest.java +++ b/src/test/java/org/apache/commons/io/file/AbstractTempDirTest.java @@ -19,6 +19,7 @@ package org.apache.commons.io.file; import java.io.File; import java.io.IOException; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; @@ -52,4 +53,8 @@ public abstract class AbstractTempDirTest { tempDirFile = tempDirPath.toFile(); } + + protected final boolean isPosixFilePermissionsSupported() { + return FileSystems.getDefault().supportedFileAttributeViews().contains("posix"); + } } diff --git a/src/test/java/org/apache/commons/io/file/FilesUncheckTest.java b/src/test/java/org/apache/commons/io/file/FilesUncheckTest.java index 4fa73681..80f4d37b 100644 --- a/src/test/java/org/apache/commons/io/file/FilesUncheckTest.java +++ b/src/test/java/org/apache/commons/io/file/FilesUncheckTest.java @@ -50,6 +50,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; +import java.util.stream.Stream; import org.apache.commons.io.IOUtils; import org.apache.commons.io.function.Uncheck; @@ -166,7 +167,9 @@ public class FilesUncheckTest { @Test public void testFind() { - assertNotNull(FilesUncheck.find(FILE_PATH_EMPTY, 0, (t, u) -> false)); + try (Stream<Path> find = FilesUncheck.find(FILE_PATH_EMPTY, 0, (t, u) -> false)) { + assertNotNull(find); + } } @Test @@ -207,17 +210,23 @@ public class FilesUncheckTest { @Test public void testLinesPath() { - assertEquals(0, FilesUncheck.lines(FILE_PATH_EMPTY).count()); + try (Stream<String> stream = FilesUncheck.lines(FILE_PATH_EMPTY)) { + assertEquals(0, stream.count()); + } } @Test public void testLinesPathCharset() { - assertEquals(0, FilesUncheck.lines(FILE_PATH_EMPTY, StandardCharsets.UTF_8).count()); + try (Stream<String> stream = FilesUncheck.lines(FILE_PATH_EMPTY, StandardCharsets.UTF_8)) { + assertEquals(0, stream.count()); + } } @Test public void testList() { - assertEquals(1, FilesUncheck.list(Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-0")).count()); + try (Stream<Path> stream = FilesUncheck.list(Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-0"))) { + assertEquals(1, stream.count()); + } } @Test @@ -426,12 +435,16 @@ public class FilesUncheckTest { @Test public void testWalkPathFileVisitOptionArray() { - assertTrue(0 < FilesUncheck.walk(TARGET_PATH, FileVisitOption.FOLLOW_LINKS).count()); + try (Stream<Path> stream = FilesUncheck.walk(TARGET_PATH, FileVisitOption.FOLLOW_LINKS)) { + assertTrue(0 < stream.count()); + } } @Test public void testWalkPathIntFileVisitOptionArray() { - assertEquals(1, FilesUncheck.walk(TARGET_PATH, 0, FileVisitOption.FOLLOW_LINKS).count()); + try (Stream<Path> stream = FilesUncheck.walk(TARGET_PATH, 0, FileVisitOption.FOLLOW_LINKS)) { + assertEquals(1, stream.count()); + } } @Test diff --git a/src/test/java/org/apache/commons/io/filefilter/AbstractConditionalFileFilterTest.java b/src/test/java/org/apache/commons/io/filefilter/AbstractConditionalFileFilterTest.java index 5a99d620..a663e5f6 100644 --- a/src/test/java/org/apache/commons/io/filefilter/AbstractConditionalFileFilterTest.java +++ b/src/test/java/org/apache/commons/io/filefilter/AbstractConditionalFileFilterTest.java @@ -104,7 +104,7 @@ public abstract class AbstractConditionalFileFilterTest extends AbstractIOFileFi final boolean[] trueResults = testTrueResults.get(i); final boolean[] falseResults = testFalseResults.get(i); final boolean fileResults = testFileResults.get(i); - final boolean filenameResults = testFilenameResults.get(i); + final boolean fileNameResults = testFilenameResults.get(i); // Test conditional AND filter created by passing filters to the constructor final IOFileFilter filter = this.buildFilterUsingAdd(filters); @@ -116,10 +116,10 @@ public abstract class AbstractConditionalFileFilterTest extends AbstractIOFileFi assertTrueFiltersInvoked(i, trueFilters, trueResults); assertFalseFiltersInvoked(i, falseFilters, falseResults); - // Test as a filename filter + // Test as a file name filter resetTrueFilters(this.trueFilters); resetFalseFilters(this.falseFilters); - assertFilenameFiltering(i, filter, this.file, filenameResults); + assertFilenameFiltering(i, filter, this.file, fileNameResults); assertTrueFiltersInvoked(i, trueFilters, trueResults); assertFalseFiltersInvoked(i, falseFilters, falseResults); } @@ -138,7 +138,7 @@ public abstract class AbstractConditionalFileFilterTest extends AbstractIOFileFi final boolean[] trueResults = testTrueResults.get(i); final boolean[] falseResults = testFalseResults.get(i); final boolean fileResults = testFileResults.get(i); - final boolean filenameResults = testFilenameResults.get(i); + final boolean fileNameResults = testFilenameResults.get(i); // Test conditional AND filter created by passing filters to the constructor final IOFileFilter filter = this.buildFilterUsingConstructor(filters); @@ -150,10 +150,10 @@ public abstract class AbstractConditionalFileFilterTest extends AbstractIOFileFi assertTrueFiltersInvoked(i, trueFilters, trueResults); assertFalseFiltersInvoked(i, falseFilters, falseResults); - // Test as a filename filter + // Test as a file name filter resetTrueFilters(this.trueFilters); resetFalseFilters(this.falseFilters); - assertFilenameFiltering(i, filter, this.file, filenameResults); + assertFilenameFiltering(i, filter, this.file, fileNameResults); assertTrueFiltersInvoked(i, trueFilters, trueResults); assertFalseFiltersInvoked(i, falseFilters, falseResults); } diff --git a/src/test/java/org/apache/commons/io/function/IOBaseStreamTest.java b/src/test/java/org/apache/commons/io/function/IOBaseStreamTest.java index 1c05418c..a0bd3e47 100644 --- a/src/test/java/org/apache/commons/io/function/IOBaseStreamTest.java +++ b/src/test/java/org/apache/commons/io/function/IOBaseStreamTest.java @@ -67,7 +67,7 @@ public class IOBaseStreamTest { /** * Implements IOBaseStream with a concrete type. */ - private static class IOBaseStreamPathFixture<B extends BaseStream<Path, B>> extends IOBaseStreamFixture<Path, IOBaseStreamPathFixture<B>, B> { + private static final class IOBaseStreamPathFixture<B extends BaseStream<Path, B>> extends IOBaseStreamFixture<Path, IOBaseStreamPathFixture<B>, B> { private IOBaseStreamPathFixture(final B baseStream) { super(baseStream); @@ -80,7 +80,7 @@ public class IOBaseStreamTest { } - private static class MyRuntimeException extends RuntimeException { + private static final class MyRuntimeException extends RuntimeException { private static final long serialVersionUID = 1L; diff --git a/src/test/java/org/apache/commons/io/function/IOBinaryOperatorStreamTest.java b/src/test/java/org/apache/commons/io/function/IOBinaryOperatorStreamTest.java index a591e780..501d75f8 100644 --- a/src/test/java/org/apache/commons/io/function/IOBinaryOperatorStreamTest.java +++ b/src/test/java/org/apache/commons/io/function/IOBinaryOperatorStreamTest.java @@ -88,14 +88,19 @@ public class IOBinaryOperatorStreamTest { public void testReduce() throws IOException { // A silly example to pass in a IOBinaryOperator. final Path current = PathUtils.current(); - final Path expected = Files.list(current).reduce((t, u) -> { - try { - return t.toRealPath(); - } catch (final IOException e) { - return fail(e); - } - }).get(); - assertEquals(expected, Files.list(current).reduce(REAL_PATH_BO).get()); + final Path expected; + try (Stream<Path> stream = Files.list(current)) { + expected = stream.reduce((t, u) -> { + try { + return t.toRealPath(); + } catch (final IOException e) { + return fail(e); + } + }).get(); + } + try (Stream<Path> stream = Files.list(current)) { + assertEquals(expected, stream.reduce(REAL_PATH_BO).get()); + } } } diff --git a/src/test/java/org/apache/commons/io/function/IOConsumerTest.java b/src/test/java/org/apache/commons/io/function/IOConsumerTest.java index 5bfeb401..1871be48 100644 --- a/src/test/java/org/apache/commons/io/function/IOConsumerTest.java +++ b/src/test/java/org/apache/commons/io/function/IOConsumerTest.java @@ -76,11 +76,11 @@ public class IOConsumerTest { public void testForAllArrayOf1() throws IOException { IOConsumer.forAll(TestUtils.throwingIOConsumer(), (String[]) null); IOConsumer.forAll(null, (String[]) null); - assertThrows(IOExceptionList.class, () -> IOConsumer.forAll(TestUtils.throwingIOConsumer(), new String[] {"1"})); + assertThrows(IOExceptionList.class, () -> IOConsumer.forAll(TestUtils.throwingIOConsumer(), "1")); // final AtomicReference<String> ref = new AtomicReference<>("0"); final IOConsumer<String> consumer1 = s -> ref.set(ref.get() + s); - IOConsumer.forAll(consumer1, new String[] {"1"}); + IOConsumer.forAll(consumer1, "1"); assertEquals("01", ref.get()); } @@ -88,11 +88,11 @@ public class IOConsumerTest { public void testForAllArrayOf2() throws IOException { IOConsumer.forAll(TestUtils.throwingIOConsumer(), (String[]) null); IOConsumer.forAll(null, (String[]) null); - assertThrows(IOExceptionList.class, () -> IOConsumer.forAll(TestUtils.throwingIOConsumer(), new String[] {"1", "2"})); + assertThrows(IOExceptionList.class, () -> IOConsumer.forAll(TestUtils.throwingIOConsumer(), "1", "2")); // final AtomicReference<String> ref = new AtomicReference<>("0"); final IOConsumer<String> consumer1 = s -> ref.set(ref.get() + s); - IOConsumer.forAll(consumer1, new String[] {"1", "2"}); + IOConsumer.forAll(consumer1, "1", "2"); assertEquals("012", ref.get()); } diff --git a/src/test/java/org/apache/commons/io/function/IOFunctionTest.java b/src/test/java/org/apache/commons/io/function/IOFunctionTest.java index 1032aeee..af859aba 100644 --- a/src/test/java/org/apache/commons/io/function/IOFunctionTest.java +++ b/src/test/java/org/apache/commons/io/function/IOFunctionTest.java @@ -38,7 +38,7 @@ import org.junit.jupiter.api.Test; */ public class IOFunctionTest { - private static class Holder<T> { + private static final class Holder<T> { T value; } @@ -168,7 +168,7 @@ public class IOFunctionTest { public void testIdentity() throws IOException { assertEquals(IOFunction.identity(), IOFunction.identity()); final IOFunction<byte[], byte[]> identityFunction = IOFunction.identity(); - final byte[] buf = new byte[] {(byte) 0xa, (byte) 0xb, (byte) 0xc}; + final byte[] buf = {(byte) 0xa, (byte) 0xb, (byte) 0xc}; assertEquals(buf, identityFunction.apply(buf)); assertArrayEquals(buf, identityFunction.apply(buf)); } diff --git a/src/test/java/org/apache/commons/io/function/IOLongSupplierTest.java b/src/test/java/org/apache/commons/io/function/IOLongSupplierTest.java index 07748ded..dce0a426 100644 --- a/src/test/java/org/apache/commons/io/function/IOLongSupplierTest.java +++ b/src/test/java/org/apache/commons/io/function/IOLongSupplierTest.java @@ -49,7 +49,7 @@ public class IOLongSupplierTest { } @Test - public void testAsSupplier() throws IOException { + public void testAsSupplier() { assertThrows(UncheckedIOException.class, () -> TestConstants.THROWING_IO_LONG_SUPPLIER.asSupplier().getAsLong()); assertEquals(1L, getThrowsNone(() -> TestUtils.compareAndSetThrowsIO(atomicLong, 1L))); assertEquals(1L, atomicLong.get()); diff --git a/src/test/java/org/apache/commons/io/function/IOStreamTest.java b/src/test/java/org/apache/commons/io/function/IOStreamTest.java index 198a361c..3e2ef9c5 100644 --- a/src/test/java/org/apache/commons/io/function/IOStreamTest.java +++ b/src/test/java/org/apache/commons/io/function/IOStreamTest.java @@ -402,7 +402,7 @@ public class IOStreamTest { @SuppressWarnings("resource") // custom stream not recognized by compiler warning machinery @Test - public void testOnCloseMultipleHandlers() throws IOException { + public void testOnCloseMultipleHandlers() { // final AtomicReference<String> ref = new AtomicReference<>(); // Sanity check @@ -511,13 +511,14 @@ public class IOStreamTest { assertEquals(1, IOStream.of("C", "D").skip(1).peek(e -> compareAndSetRE(ref, null, e)).count()); assertEquals(1, IOStream.of("C", "D").skip(1).peek(e -> compareAndSetIO(ref, null, e)).count()); assertNull(ref.get()); - } else if (AT_LEAST_JAVA_11) { - assertThrows(RuntimeException.class, () -> IOStream.of("C", "D").skip(1).peek(e -> compareAndSetRE(ref, null, e)).count()); - assertThrows(IOException.class, () -> IOStream.of("C", "D").skip(1).peek(e -> compareAndSetIO(ref, null, e)).count()); - assertEquals("B", ref.get()); } else { - assertThrows(RuntimeException.class, () -> IOStream.of("C", "D").skip(1).peek(e -> compareAndSetRE(ref, null, e)).count()); - assertThrows(IOException.class, () -> IOStream.of("C", "D").skip(1).peek(e -> compareAndSetIO(ref, null, e)).count()); + if (AT_LEAST_JAVA_11) { + assertThrows(RuntimeException.class, () -> IOStream.of("C", "D").skip(1).peek(e -> compareAndSetRE(ref, null, e)).count()); + assertThrows(IOException.class, () -> IOStream.of("C", "D").skip(1).peek(e -> compareAndSetIO(ref, null, e)).count()); + } else { + assertThrows(RuntimeException.class, () -> IOStream.of("C", "D").skip(1).peek(e -> compareAndSetRE(ref, null, e)).count()); + assertThrows(IOException.class, () -> IOStream.of("C", "D").skip(1).peek(e -> compareAndSetIO(ref, null, e)).count()); + } assertEquals("B", ref.get()); } } diff --git a/src/test/java/org/apache/commons/io/function/TestConstants.java b/src/test/java/org/apache/commons/io/function/TestConstants.java index bafe7ef0..dfea176a 100644 --- a/src/test/java/org/apache/commons/io/function/TestConstants.java +++ b/src/test/java/org/apache/commons/io/function/TestConstants.java @@ -44,17 +44,17 @@ class TestConstants { static IOFunction<Object, Object> THROWING_IO_FUNCTION = t -> throwIOException(); - static IOIntSupplier THROWING_IO_INT_SUPPLIER = () -> throwIOException(); + static IOIntSupplier THROWING_IO_INT_SUPPLIER = TestConstants::throwIOException; - static IOLongSupplier THROWING_IO_LONG_SUPPLIER = () -> throwIOException(); + static IOLongSupplier THROWING_IO_LONG_SUPPLIER = TestConstants::throwIOException; static IOPredicate<Object> THROWING_IO_PREDICATE = t -> throwIOException(); static IOQuadFunction<Object, Object, Object, Object, Object> THROWING_IO_QUAD_FUNCTION = (t, u, v, w) -> throwIOException(); - static IORunnable THROWING_IO_RUNNABLE = () -> throwIOException(); + static IORunnable THROWING_IO_RUNNABLE = TestConstants::throwIOException; - static IOSupplier<Object> THROWING_IO_SUPPLIER = () -> throwIOException(); + static IOSupplier<Object> THROWING_IO_SUPPLIER = TestConstants::throwIOException; static IOTriConsumer<Object, Object, Object> THROWING_IO_TRI_CONSUMER = (t, u, v) -> throwIOException(); diff --git a/src/test/java/org/apache/commons/io/input/BOMInputStreamTest.java b/src/test/java/org/apache/commons/io/input/BOMInputStreamTest.java index a79cb1c9..9ce5d54e 100644 --- a/src/test/java/org/apache/commons/io/input/BOMInputStreamTest.java +++ b/src/test/java/org/apache/commons/io/input/BOMInputStreamTest.java @@ -52,7 +52,7 @@ public class BOMInputStreamTest { /** * A mock InputStream that expects {@code close()} to be called. */ - private static class ExpectCloseInputStream extends InputStream { + private static final class ExpectCloseInputStream extends InputStream { private boolean _closeCalled; public void assertCloseCalled() { @@ -415,7 +415,7 @@ public class BOMInputStreamTest { assertThrows(IllegalArgumentException.class, () -> BOMInputStream.builder() .setInputStream(createUtf8Input(data, true)) .setInclude(true) - .setByteOrderMarks(new ByteOrderMark[0]) + .setByteOrderMarks() .get() .close()); } diff --git a/src/test/java/org/apache/commons/io/input/CharSequenceInputStreamTest.java b/src/test/java/org/apache/commons/io/input/CharSequenceInputStreamTest.java index 7bc997e0..a8e06b81 100644 --- a/src/test/java/org/apache/commons/io/input/CharSequenceInputStreamTest.java +++ b/src/test/java/org/apache/commons/io/input/CharSequenceInputStreamTest.java @@ -32,9 +32,12 @@ import java.util.Random; import java.util.Set; import org.apache.commons.io.Charsets; +import org.apache.commons.io.CharsetsTest; import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class CharSequenceInputStreamTest { @@ -78,11 +81,11 @@ public class CharSequenceInputStreamTest { "Shift_JIS".equalsIgnoreCase(csName); } - @Test - public void testAvailable() throws Exception { - for (final String csName : Charset.availableCharsets().keySet()) { - // prevent java.lang.UnsupportedOperationException at sun.nio.cs.ext.ISO2022_CN.newEncoder. - // also try and avoid the following exception + @ParameterizedTest(name = "{0}") + @MethodSource(CharsetsTest.AVAIL_CHARSETS) + public void testAvailable(final String csName) throws Exception { + // prevent java.lang.UnsupportedOperationException at sun.nio.cs.ext.ISO2022_CN.newEncoder. + // also try and avoid the following exception // java.lang.UnsupportedOperationException: null // at java.nio.CharBuffer.array(CharBuffer.java:940) // at sun.nio.cs.ext.COMPOUND_TEXT_Encoder.encodeLoop(COMPOUND_TEXT_Encoder.java:75) @@ -92,14 +95,13 @@ public class CharSequenceInputStreamTest { // at org.apache.commons.io.input.CharSequenceInputStreamTest.testAvailableRead(CharSequenceInputStreamTest.java:412) // at org.apache.commons.io.input.CharSequenceInputStreamTest.testAvailable(CharSequenceInputStreamTest.java:424) - try { - if (isAvailabilityTestableForCharset(csName)) { - testAvailableSkip(csName); - testAvailableRead(csName); - } - } catch (final UnsupportedOperationException e){ - fail("Operation not supported for " + csName); + try { + if (isAvailabilityTestableForCharset(csName)) { + testAvailableSkip(csName); + testAvailableRead(csName); } + } catch (final UnsupportedOperationException e) { + fail("Operation not supported for " + csName); } } @@ -157,13 +159,12 @@ public class CharSequenceInputStreamTest { // at sun.nio.cs.ext.COMPOUND_TEXT_Encoder.encodeLoop(COMPOUND_TEXT_Encoder.java:75) // at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:544) // at org.apache.commons.io.input.CharSequenceInputStream.fillBuffer(CharSequenceInputStream.java:111) - @Test - public void testBufferedRead_AvailableCharset() throws IOException { - for (final String csName : Charset.availableCharsets().keySet()) { - // prevent java.lang.UnsupportedOperationException at sun.nio.cs.ext.ISO2022_CN.newEncoder. - if (isAvailabilityTestableForCharset(csName)) { - testBufferedRead(TEST_STRING, csName); - } + @ParameterizedTest(name = "{0}") + @MethodSource(CharsetsTest.AVAIL_CHARSETS) + public void testBufferedRead_AvailableCharset(final String csName) throws IOException { + // prevent java.lang.UnsupportedOperationException at sun.nio.cs.ext.ISO2022_CN.newEncoder. + if (isAvailabilityTestableForCharset(csName)) { + testBufferedRead(TEST_STRING, csName); } } diff --git a/src/test/java/org/apache/commons/io/input/ClassLoaderObjectInputStreamTest.java b/src/test/java/org/apache/commons/io/input/ClassLoaderObjectInputStreamTest.java index 2e8d0f53..3b341ba0 100644 --- a/src/test/java/org/apache/commons/io/input/ClassLoaderObjectInputStreamTest.java +++ b/src/test/java/org/apache/commons/io/input/ClassLoaderObjectInputStreamTest.java @@ -43,7 +43,7 @@ public class ClassLoaderObjectInputStreamTest { A, B, C } - private static class Test implements Serializable { + private static final class Test implements Serializable { private static final long serialVersionUID = 1L; private final int i; diff --git a/src/test/java/org/apache/commons/io/input/MarkShieldInputStreamTest.java b/src/test/java/org/apache/commons/io/input/MarkShieldInputStreamTest.java index a72e0f3c..ba0944ef 100644 --- a/src/test/java/org/apache/commons/io/input/MarkShieldInputStreamTest.java +++ b/src/test/java/org/apache/commons/io/input/MarkShieldInputStreamTest.java @@ -28,7 +28,7 @@ import org.junit.jupiter.api.Test; public class MarkShieldInputStreamTest { - private static class MarkTestableInputStream extends ProxyInputStream { + private static final class MarkTestableInputStream extends ProxyInputStream { int markcount; int readlimit; diff --git a/src/test/java/org/apache/commons/io/input/MessageDigestCalculatingInputStreamTest.java b/src/test/java/org/apache/commons/io/input/MessageDigestCalculatingInputStreamTest.java index 517a014e..9123c41f 100644 --- a/src/test/java/org/apache/commons/io/input/MessageDigestCalculatingInputStreamTest.java +++ b/src/test/java/org/apache/commons/io/input/MessageDigestCalculatingInputStreamTest.java @@ -20,40 +20,57 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import java.io.ByteArrayInputStream; import java.security.MessageDigest; -import java.util.Random; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.codec.digest.MessageDigestAlgorithms; +import org.apache.commons.io.input.MessageDigestCalculatingInputStream.Builder; import org.junit.jupiter.api.Test; /** * Tests {@link MessageDigestCalculatingInputStream}. */ +@SuppressWarnings("deprecation") public class MessageDigestCalculatingInputStreamTest { - public static byte[] generateRandomByteStream(final int pSize) { - final byte[] buffer = new byte[pSize]; - final Random rnd = new Random(); - rnd.nextBytes(buffer); - return buffer; - } - @Test - public void test() throws Exception { + public void testNormalUse() throws Exception { for (int i = 256; i < 8192; i = i * 2) { - final byte[] buffer = generateRandomByteStream(i); - final MessageDigest messageDigest = MessageDigestCalculatingInputStream.getDefaultMessageDigest(); - final byte[] expect = messageDigest.digest(buffer); + final byte[] buffer = MessageDigestInputStreamTest.generateRandomByteStream(i); + final MessageDigest defaultMessageDigest = MessageDigestCalculatingInputStream.getDefaultMessageDigest(); + final byte[] defaultExpect = defaultMessageDigest.digest(buffer); + // Defaults try (MessageDigestCalculatingInputStream messageDigestInputStream = new MessageDigestCalculatingInputStream(new ByteArrayInputStream(buffer))) { messageDigestInputStream.consume(); - assertArrayEquals(expect, messageDigestInputStream.getMessageDigest().digest()); + assertArrayEquals(defaultExpect, messageDigestInputStream.getMessageDigest().digest()); } try (MessageDigestCalculatingInputStream messageDigestInputStream = MessageDigestCalculatingInputStream.builder() .setInputStream(new ByteArrayInputStream(buffer)).get()) { messageDigestInputStream.consume(); - assertArrayEquals(expect, messageDigestInputStream.getMessageDigest().digest()); + assertArrayEquals(defaultExpect, messageDigestInputStream.getMessageDigest().digest()); } try (MessageDigestCalculatingInputStream messageDigestInputStream = MessageDigestCalculatingInputStream.builder().setByteArray(buffer).get()) { messageDigestInputStream.consume(); - assertArrayEquals(expect, messageDigestInputStream.getMessageDigest().digest()); + assertArrayEquals(defaultExpect, messageDigestInputStream.getMessageDigest().digest()); + } + // SHA-512 + final byte[] sha512Expect = DigestUtils.sha512(buffer); + { + final Builder builder = MessageDigestCalculatingInputStream.builder(); + builder.setMessageDigest(MessageDigestAlgorithms.SHA_512); + builder.setInputStream(new ByteArrayInputStream(buffer)); + try (MessageDigestCalculatingInputStream messageDigestInputStream = builder.get()) { + messageDigestInputStream.consume(); + assertArrayEquals(sha512Expect, messageDigestInputStream.getMessageDigest().digest()); + } + } + { + final Builder builder = MessageDigestCalculatingInputStream.builder(); + builder.setMessageDigest(MessageDigestAlgorithms.SHA_512); + builder.setInputStream(new ByteArrayInputStream(buffer)); + try (MessageDigestCalculatingInputStream messageDigestInputStream = builder.get()) { + messageDigestInputStream.consume(); + assertArrayEquals(sha512Expect, messageDigestInputStream.getMessageDigest().digest()); + } } } } diff --git a/src/test/java/org/apache/commons/io/input/MessageDigestInputStreamTest.java b/src/test/java/org/apache/commons/io/input/MessageDigestInputStreamTest.java new file mode 100644 index 00000000..d41da0b7 --- /dev/null +++ b/src/test/java/org/apache/commons/io/input/MessageDigestInputStreamTest.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.io.input; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.ByteArrayInputStream; +import java.util.Random; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.codec.digest.MessageDigestAlgorithms; +import org.junit.jupiter.api.Test; + +/** + * Tests {@link MessageDigestInputStream}. + */ +public class MessageDigestInputStreamTest { + + static byte[] generateRandomByteStream(final int pSize) { + final byte[] buffer = new byte[pSize]; + final Random rnd = new Random(); + rnd.nextBytes(buffer); + return buffer; + } + + @Test + public void testNoDefault() throws Exception { + assertThrows(IllegalStateException.class, () -> MessageDigestInputStream.builder().get()); + assertThrows(NullPointerException.class, () -> MessageDigestInputStream.builder().setInputStream(new ByteArrayInputStream(new byte[] { 1 })).get()); + } + + @Test + public void testNormalUse() throws Exception { + for (int i = 256; i < 8192; i = i * 2) { + final byte[] buffer = generateRandomByteStream(i); + final byte[] expect = DigestUtils.sha512(buffer); + try (MessageDigestInputStream messageDigestInputStream = MessageDigestInputStream.builder().setMessageDigest(MessageDigestAlgorithms.SHA_512) + .setInputStream(new ByteArrayInputStream(buffer)).get()) { + messageDigestInputStream.consume(); + assertArrayEquals(expect, messageDigestInputStream.getMessageDigest().digest()); + } + try (MessageDigestInputStream messageDigestInputStream = MessageDigestInputStream.builder().setByteArray(buffer) + .setMessageDigest(DigestUtils.getSha512Digest()).get()) { + messageDigestInputStream.consume(); + assertArrayEquals(expect, messageDigestInputStream.getMessageDigest().digest()); + } + } + } + +} diff --git a/src/test/java/org/apache/commons/io/input/ObservableInputStreamTest.java b/src/test/java/org/apache/commons/io/input/ObservableInputStreamTest.java index 0a0e9150..8c099ade 100644 --- a/src/test/java/org/apache/commons/io/input/ObservableInputStreamTest.java +++ b/src/test/java/org/apache/commons/io/input/ObservableInputStreamTest.java @@ -35,7 +35,7 @@ import org.junit.jupiter.api.Test; */ public class ObservableInputStreamTest { - private static class DataViewObserver extends MethodCountObserver { + private static final class DataViewObserver extends MethodCountObserver { private byte[] buffer; private int lastValue = -1; private int length = -1; @@ -55,7 +55,7 @@ public class ObservableInputStreamTest { } } - private static class LengthObserver extends Observer { + private static final class LengthObserver extends Observer { private long total; @Override @@ -153,8 +153,7 @@ public class ObservableInputStreamTest { */ @Test public void testDataByteCalled_add() throws Exception { - final byte[] buffer = MessageDigestCalculatingInputStreamTest - .generateRandomByteStream(IOUtils.DEFAULT_BUFFER_SIZE); + final byte[] buffer = MessageDigestInputStreamTest.generateRandomByteStream(IOUtils.DEFAULT_BUFFER_SIZE); final DataViewObserver lko = new DataViewObserver(); try (ObservableInputStream ois = new ObservableInputStream(new ByteArrayInputStream(buffer))) { assertEquals(-1, lko.lastValue); @@ -185,8 +184,7 @@ public class ObservableInputStreamTest { */ @Test public void testDataByteCalled_ctor() throws Exception { - final byte[] buffer = MessageDigestCalculatingInputStreamTest - .generateRandomByteStream(IOUtils.DEFAULT_BUFFER_SIZE); + final byte[] buffer = MessageDigestInputStreamTest.generateRandomByteStream(IOUtils.DEFAULT_BUFFER_SIZE); final DataViewObserver lko = new DataViewObserver(); try (ObservableInputStream ois = new ObservableInputStream(new ByteArrayInputStream(buffer), lko)) { assertEquals(-1, lko.lastValue); @@ -216,10 +214,9 @@ public class ObservableInputStreamTest { */ @Test public void testDataBytesCalled() throws Exception { - final byte[] buffer = MessageDigestCalculatingInputStreamTest - .generateRandomByteStream(IOUtils.DEFAULT_BUFFER_SIZE); + final byte[] buffer = MessageDigestInputStreamTest.generateRandomByteStream(IOUtils.DEFAULT_BUFFER_SIZE); try (ByteArrayInputStream bais = new ByteArrayInputStream(buffer); - final ObservableInputStream ois = new ObservableInputStream(bais)) { + final ObservableInputStream ois = new ObservableInputStream(bais)) { final DataViewObserver observer = new DataViewObserver(); final byte[] readBuffer = new byte[23]; assertNull(observer.buffer); diff --git a/src/test/java/org/apache/commons/io/input/ProxyReaderTest.java b/src/test/java/org/apache/commons/io/input/ProxyReaderTest.java index b176d480..110d11d2 100644 --- a/src/test/java/org/apache/commons/io/input/ProxyReaderTest.java +++ b/src/test/java/org/apache/commons/io/input/ProxyReaderTest.java @@ -28,7 +28,7 @@ import org.junit.jupiter.api.Test; public class ProxyReaderTest { /** Custom NullReader implementation. */ - private static class CustomNullReader extends NullReader { + private static final class CustomNullReader extends NullReader { CustomNullReader(final int len) { super(len); } @@ -45,7 +45,7 @@ public class ProxyReaderTest { } /** ProxyReader implementation. */ - private static class ProxyReaderImpl extends ProxyReader { + private static final class ProxyReaderImpl extends ProxyReader { ProxyReaderImpl(final Reader proxy) { super(proxy); } diff --git a/src/test/java/org/apache/commons/io/input/TailerTest.java b/src/test/java/org/apache/commons/io/input/TailerTest.java index f0e1f340..783e1718 100644 --- a/src/test/java/org/apache/commons/io/input/TailerTest.java +++ b/src/test/java/org/apache/commons/io/input/TailerTest.java @@ -60,7 +60,7 @@ import org.junit.jupiter.api.io.TempDir; */ public class TailerTest { - private static class NonStandardTailable implements Tailer.Tailable { + private static final class NonStandardTailable implements Tailer.Tailable { private final File file; @@ -115,7 +115,7 @@ public class TailerTest { /** * Test {@link TailerListener} implementation. */ - private static class TestTailerListener extends TailerListenerAdapter { + private static final class TestTailerListener extends TailerListenerAdapter { // Must be synchronized because it is written by one thread and read by another private final List<String> lines = Collections.synchronizedList(new ArrayList<>()); @@ -266,16 +266,6 @@ public class TailerTest { } @Test - public void testCreatorWithDelayAndFromStartWithReopen() throws Exception { - final File file = new File(temporaryFolder, "tailer-create-with-delay-and-from-start-with-reopen.txt"); - createFile(file, 0); - final TestTailerListener listener = new TestTailerListener(1); - try (Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS, false, false)) { - validateTailer(listener, file); - } - } - - @Test public void testCreateWithDelay() throws Exception { final File file = new File(temporaryFolder, "tailer-create-with-delay.txt"); createFile(file, 0); @@ -325,6 +315,16 @@ public class TailerTest { } } + @Test + public void testCreatorWithDelayAndFromStartWithReopen() throws Exception { + final File file = new File(temporaryFolder, "tailer-create-with-delay-and-from-start-with-reopen.txt"); + createFile(file, 0); + final TestTailerListener listener = new TestTailerListener(1); + try (Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS, false, false)) { + validateTailer(listener, file); + } + } + /* * Tests [IO-357][Tailer] InterruptedException while the thread is sleeping is silently ignored. */ diff --git a/src/test/java/org/apache/commons/io/input/TimestampedObserverTest.java b/src/test/java/org/apache/commons/io/input/TimestampedObserverTest.java index 54922005..ea37b381 100644 --- a/src/test/java/org/apache/commons/io/input/TimestampedObserverTest.java +++ b/src/test/java/org/apache/commons/io/input/TimestampedObserverTest.java @@ -51,7 +51,7 @@ public class TimestampedObserverTest { assertTrue(timestampedObserver.getOpenToNowDuration().toNanos() > 0); assertNull(timestampedObserver.getCloseInstant()); assertFalse(timestampedObserver.isClosed()); - final byte[] buffer = MessageDigestCalculatingInputStreamTest.generateRandomByteStream(IOUtils.DEFAULT_BUFFER_SIZE); + final byte[] buffer = MessageDigestInputStreamTest.generateRandomByteStream(IOUtils.DEFAULT_BUFFER_SIZE); try (ObservableInputStream ois = new ObservableInputStream(new ByteArrayInputStream(buffer), timestampedObserver)) { assertTrue(timestampedObserver.getOpenInstant().isAfter(before)); assertTrue(timestampedObserver.getOpenToNowDuration().toNanos() > 0); @@ -68,7 +68,7 @@ public class TimestampedObserverTest { @Test public void testExample() throws IOException { final TimestampedObserver timestampedObserver = new TimestampedObserver(); - final byte[] buffer = MessageDigestCalculatingInputStreamTest + final byte[] buffer = MessageDigestInputStreamTest .generateRandomByteStream(IOUtils.DEFAULT_BUFFER_SIZE); try (ObservableInputStream ois = new ObservableInputStream(new ByteArrayInputStream(buffer), timestampedObserver)) { diff --git a/src/test/java/org/apache/commons/io/input/UnsynchronizedBufferedInputStreamTest.java b/src/test/java/org/apache/commons/io/input/UnsynchronizedBufferedInputStreamTest.java index f7fcba81..d2e969ca 100644 --- a/src/test/java/org/apache/commons/io/input/UnsynchronizedBufferedInputStreamTest.java +++ b/src/test/java/org/apache/commons/io/input/UnsynchronizedBufferedInputStreamTest.java @@ -21,7 +21,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -31,6 +30,7 @@ import java.nio.file.Files; import java.nio.file.Path; import org.apache.commons.io.IOUtils; +import org.apache.commons.io.input.UnsynchronizedBufferedInputStream.Builder; import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -50,12 +50,16 @@ public class UnsynchronizedBufferedInputStreamTest { Path fileName; - private BufferedInputStream is; + private UnsynchronizedBufferedInputStream is; private InputStream isFile; byte[] ibuf = new byte[BUFFER_SIZE]; + private Builder builder() { + return new UnsynchronizedBufferedInputStream.Builder(); + } + /** * Sets up the fixture, for example, open a network connection. This method is called before a test is executed. * @@ -67,7 +71,7 @@ public class UnsynchronizedBufferedInputStreamTest { Files.write(fileName, DATA.getBytes(StandardCharsets.UTF_8)); isFile = Files.newInputStream(fileName); - is = new BufferedInputStream(isFile); + is = builder().setInputStream(isFile).get(); } /** @@ -82,7 +86,7 @@ public class UnsynchronizedBufferedInputStreamTest { } /** - * Tests java.io.BufferedInputStream#available() + * Tests {@link UnsynchronizedBufferedInputStream#available()}. * * @throws IOException Thrown on test failure. */ @@ -91,7 +95,8 @@ public class UnsynchronizedBufferedInputStreamTest { assertEquals(DATA.length(), is.available(), "Returned incorrect number of available bytes"); // Test that a closed stream throws an IOE for available() - final BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(new byte[] { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' })); + final UnsynchronizedBufferedInputStream bis = builder() + .setInputStream(new ByteArrayInputStream(new byte[] { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' })).get(); final int available = bis.available(); bis.close(); assertTrue(available != 0); @@ -100,18 +105,13 @@ public class UnsynchronizedBufferedInputStreamTest { } /** - * Tests java.io.BufferedInputStream#close() + * Tests {@link UnsynchronizedBufferedInputStream#close()}. * * @throws IOException Thrown on test failure. */ @Test public void test_close() throws IOException { - new BufferedInputStream(isFile).close(); - - // regression for HARMONY-667 - try (BufferedInputStream buf = new BufferedInputStream(null, 5)) { - // closes - } + builder().setInputStream(isFile).get().close(); try (InputStream in = new InputStream() { Object lock = new Object(); @@ -140,7 +140,7 @@ public class UnsynchronizedBufferedInputStreamTest { return 1; } }) { - final BufferedInputStream bufin = new BufferedInputStream(in); + final UnsynchronizedBufferedInputStream bufin = builder().setInputStream(in).get(); final Thread thread = new Thread(() -> { try { Thread.sleep(1000); @@ -155,28 +155,24 @@ public class UnsynchronizedBufferedInputStreamTest { } /* - * Tests java.io.BufferedInputStream(InputStream) + * Tests {@link UnsynchronizedBufferedInputStream#Builder()}. */ @Test - public void test_ConstructorLjava_io_InputStream() throws IOException { - try (BufferedInputStream str = new BufferedInputStream(null)) { - assertThrows(IOException.class, () -> str.read(), "Expected an IOException"); - } + public void test_ConstructorLjava_io_InputStream() { + assertThrows(NullPointerException.class, () -> builder().setInputStream(null).get()); } /* - * Tests java.io.BufferedInputStream(InputStream) + * Tests {@link UnsynchronizedBufferedInputStream#Builder()}. */ @Test public void test_ConstructorLjava_io_InputStreamI() throws IOException { - try (BufferedInputStream str = new BufferedInputStream(null, 1)) { - assertThrows(IOException.class, () -> str.read(), "Expected an IOException"); - } + assertThrows(NullPointerException.class, () -> builder().setInputStream(null).setBufferSize(1).get()); - // Test for method java.io.BufferedInputStream(java.io.InputStream, int) + // Test for method UnsynchronizedBufferedInputStream(InputStream, int) // Create buffer with exact size of file - is = new BufferedInputStream(isFile, this.DATA.length()); + is = builder().setInputStream(isFile).setBufferSize(DATA.length()).get(); // Ensure buffer gets filled by evaluating one read is.read(); // Close underlying FileInputStream, all but 1 buffered bytes should @@ -184,16 +180,17 @@ public class UnsynchronizedBufferedInputStreamTest { isFile.close(); // Read the remaining buffered characters, no IOException should // occur. - is.skip(this.DATA.length() - 2); + is.skip(DATA.length() - 2); is.read(); // is.read should now throw an exception because it will have to be filled. assertThrows(IOException.class, () -> is.read()); - assertThrows(NullPointerException.class, () -> UnsynchronizedBufferedInputStream.builder().setInputStream(null).setBufferSize(100).get()); + assertThrows(NullPointerException.class, () -> builder().setInputStream(null).setBufferSize(100).get()); + assertThrows(NullPointerException.class, () -> builder().setInputStream(null)); } /** - * Tests java.io.BufferedInputStream#mark(int) + * Tests {@link UnsynchronizedBufferedInputStream#mark(int)}. * * @throws IOException Thrown on test failure. */ @@ -213,21 +210,21 @@ public class UnsynchronizedBufferedInputStreamTest { for (int i = 0; i < 256; i++) { bytes[i] = (byte) i; } - InputStream in = new BufferedInputStream(new ByteArrayInputStream(bytes), 12); + InputStream in = builder().setInputStream(new ByteArrayInputStream(bytes)).setBufferSize(12).get(); in.skip(6); in.mark(14); in.read(new byte[14], 0, 14); in.reset(); assertTrue(in.read() == 6 && in.read() == 7, "Wrong bytes"); - in = new BufferedInputStream(new ByteArrayInputStream(bytes), 12); + in = builder().setInputStream(new ByteArrayInputStream(bytes)).setBufferSize(12).get(); in.skip(6); in.mark(8); in.skip(7); in.reset(); assertTrue(in.read() == 6 && in.read() == 7, "Wrong bytes 2"); - BufferedInputStream buf = new BufferedInputStream(new ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4 }), 2); + UnsynchronizedBufferedInputStream buf = builder().setInputStream(new ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4 })).setBufferSize(2).get(); buf.mark(3); bytes = new byte[3]; int result = buf.read(bytes); @@ -237,7 +234,7 @@ public class UnsynchronizedBufferedInputStreamTest { assertEquals(2, bytes[2], "Assert 2:"); assertEquals(3, buf.read(), "Assert 3:"); - buf = new BufferedInputStream(new ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4 }), 2); + buf = builder().setInputStream(new ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4 })).setBufferSize(2).get(); buf.mark(3); bytes = new byte[4]; result = buf.read(bytes); @@ -249,14 +246,14 @@ public class UnsynchronizedBufferedInputStreamTest { assertEquals(4, buf.read(), "Assert 8:"); assertEquals(-1, buf.read(), "Assert 9:"); - buf = new BufferedInputStream(new ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4 }), 2); + buf = builder().setInputStream(new ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4 })).setBufferSize(2).get(); buf.mark(Integer.MAX_VALUE); buf.read(); buf.close(); } /** - * Tests java.io.BufferedInputStream#markSupported() + * Tests {@link UnsynchronizedBufferedInputStream#markSupported()}. */ @Test public void test_markSupported() { @@ -264,7 +261,7 @@ public class UnsynchronizedBufferedInputStreamTest { } /** - * Tests java.io.BufferedInputStream#read() + * Tests {@link UnsynchronizedBufferedInputStream#read()}. * * @throws IOException Thrown on test failure. */ @@ -278,7 +275,7 @@ public class UnsynchronizedBufferedInputStreamTest { for (int i = 0; i < 256; i++) { bytes[i] = (byte) i; } - final InputStream in = new BufferedInputStream(new ByteArrayInputStream(bytes), 12); + final InputStream in = builder().setInputStream(new ByteArrayInputStream(bytes)).setBufferSize(12).get(); assertEquals(0, in.read(), "Wrong initial byte"); // Fill the buffer final byte[] buf = new byte[14]; in.read(buf, 0, 14); // Read greater than the buffer @@ -287,7 +284,7 @@ public class UnsynchronizedBufferedInputStreamTest { } /** - * Tests java.io.BufferedInputStream#read(byte[], int, int) + * Tests {@link UnsynchronizedBufferedInputStream#read(byte[], int, int)}. * * @throws IOException Thrown on test failure. */ @@ -299,7 +296,7 @@ public class UnsynchronizedBufferedInputStreamTest { is.read(buf1, 0, buf1.length); assertTrue(new String(buf1, 0, buf1.length).equals(DATA.substring(3000, 3100)), "Failed to read correct data"); - try (BufferedInputStream bufin = new BufferedInputStream(new InputStream() { + try (UnsynchronizedBufferedInputStream bufin = builder().setInputStream(new InputStream() { int size = 2, pos = 0; byte[] contents = new byte[size]; @@ -330,7 +327,7 @@ public class UnsynchronizedBufferedInputStreamTest { pos += toRead; return toRead; } - })) { + }).get()) { bufin.read(); final int result = bufin.read(new byte[2], 0, 2); assertEquals(1, result, () -> "Incorrect result: " + result); @@ -338,26 +335,7 @@ public class UnsynchronizedBufferedInputStreamTest { } /** - * Tests java.io.BufferedInputStream#read(byte[], int, int) - * - * @throws IOException Thrown on test failure. - */ - @Test - public void test_read$BII_Exception() throws IOException { - final BufferedInputStream bis = new BufferedInputStream(null); - assertThrows(NullPointerException.class, () -> bis.read(null, -1, -1)); - - assertThrows(IndexOutOfBoundsException.class, () -> bis.read(new byte[0], -1, -1)); - assertThrows(IndexOutOfBoundsException.class, () -> bis.read(new byte[0], 1, -1)); - assertThrows(IndexOutOfBoundsException.class, () -> bis.read(new byte[0], 1, 1)); - - bis.close(); - - assertThrows(IOException.class, () -> bis.read(null, -1, -1)); - } - - /** - * Tests java.io.BufferedInputStream#reset() + * Tests {@link UnsynchronizedBufferedInputStream#reset()}. * * @throws IOException Thrown on test failure. */ @@ -372,7 +350,7 @@ public class UnsynchronizedBufferedInputStreamTest { is.reset(); assertTrue(new String(buf1, 0, buf1.length).equals(new String(buf2, 0, buf2.length)), "Reset failed"); - final BufferedInputStream bIn = new BufferedInputStream(new ByteArrayInputStream("1234567890".getBytes())); + final UnsynchronizedBufferedInputStream bIn = builder().setInputStream(new ByteArrayInputStream("1234567890".getBytes())).get(); bIn.mark(10); for (int i = 0; i < 11; i++) { bIn.read(); @@ -381,36 +359,14 @@ public class UnsynchronizedBufferedInputStreamTest { } /** - * Tests java.io.BufferedInputStream#reset() - * - * @throws IOException Thrown on test failure. - */ - @Test - public void test_reset_Exception() throws IOException { - final BufferedInputStream bis = new BufferedInputStream(null); - - // throws IOException with message "Mark has been invalidated" - assertThrows(IOException.class, () -> bis.reset()); - - // does not throw IOException - bis.mark(1); - bis.reset(); - - bis.close(); - - // throws IOException with message "stream is closed" - assertThrows(IOException.class, () -> bis.reset()); - } - - /** - * Tests java.io.BufferedInputStream#reset() + * Tests {@link UnsynchronizedBufferedInputStream#reset()}. * * @throws IOException Thrown on test failure. */ @Test public void test_reset_scenario1() throws IOException { final byte[] input = "12345678900".getBytes(); - final BufferedInputStream bufin = new BufferedInputStream(new ByteArrayInputStream(input)); + final UnsynchronizedBufferedInputStream bufin = builder().setInputStream(new ByteArrayInputStream(input)).get(); bufin.read(); bufin.mark(5); bufin.skip(5); @@ -418,33 +374,31 @@ public class UnsynchronizedBufferedInputStreamTest { } /** - * Tests java.io.BufferedInputStream#reset() + * Tests {@link UnsynchronizedBufferedInputStream#reset()}. * * @throws IOException Thrown on test failure. */ @Test public void test_reset_scenario2() throws IOException { final byte[] input = "12345678900".getBytes(); - final BufferedInputStream bufin = new BufferedInputStream(new ByteArrayInputStream(input)); + final UnsynchronizedBufferedInputStream bufin = builder().setInputStream(new ByteArrayInputStream(input)).get(); bufin.mark(5); bufin.skip(6); bufin.reset(); } /** - * Tests java.io.BufferedInputStream#skip(long) + * Tests {@link UnsynchronizedBufferedInputStream#skip(long)}. * * @throws IOException Thrown on test failure. */ @Test public void test_skip_NullInputStream() throws IOException { - try (BufferedInputStream buf = new BufferedInputStream(null, 5)) { - assertEquals(0, buf.skip(0)); - } + assertThrows(NullPointerException.class, () -> builder().setInputStream(null).setBufferSize(5).get()); } /** - * Tests java.io.BufferedInputStream#skip(long) + * Tests {@link UnsynchronizedBufferedInputStream#skip(long)}. * * @throws IOException Thrown on test failure. */ @@ -456,10 +410,5 @@ public class UnsynchronizedBufferedInputStreamTest { is.read(buf1, 0, buf1.length); is.reset(); assertTrue(new String(buf1, 0, buf1.length).equals(DATA.substring(1000, 1010)), "Failed to skip to correct position"); - - // regression for HARMONY-667 - try (BufferedInputStream buf = new BufferedInputStream(null, 5)) { - assertThrows(IOException.class, () -> buf.skip(10)); - } } } diff --git a/src/test/java/org/apache/commons/io/input/XmlStreamReaderTest.java b/src/test/java/org/apache/commons/io/input/XmlStreamReaderTest.java index 555cf7ca..63d587a8 100644 --- a/src/test/java/org/apache/commons/io/input/XmlStreamReaderTest.java +++ b/src/test/java/org/apache/commons/io/input/XmlStreamReaderTest.java @@ -30,6 +30,7 @@ import java.io.OutputStreamWriter; import java.io.Writer; import java.net.URL; import java.net.URLConnection; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -37,10 +38,15 @@ import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.text.MessageFormat; import java.util.HashMap; +import java.util.Locale; import java.util.Map; +import org.apache.commons.io.CharsetsTest; import org.apache.commons.io.IOUtils; +import org.apache.commons.io.function.IOFunction; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.junitpioneer.jupiter.DefaultLocale; public class XmlStreamReaderTest { @@ -162,6 +168,14 @@ public class XmlStreamReaderTest { return new ByteArrayInputStream(baos.toByteArray()); } + private void parseCharset(final String hdr, final String enc, final IOFunction<InputStream, XmlStreamReader> factory) throws Exception { + try (final InputStream stream = new ByteArrayInputStream(hdr.getBytes(StandardCharsets.UTF_8))) { + try (final XmlStreamReader xml = factory.apply(stream)) { + assertEquals(enc.toUpperCase(Locale.ROOT), xml.getEncoding(), enc); + } + } + } + public void testAlternateDefaultEncoding(final String contentType, final String bomEnc, final String streamEnc, final String prologEnc, final String alternateEnc) throws Exception { try (InputStream is = getXmlInputStream(bomEnc, prologEnc == null ? XML1 : XML3, streamEnc, prologEnc); @@ -276,6 +290,8 @@ public class XmlStreamReaderTest { assertThrows(NullPointerException.class, () -> new XmlStreamReader((URL) null)); } + // XML Stream generator + @Test public void testEncodingAttributeXML() throws Exception { try (InputStream is = new ByteArrayInputStream(ENCODING_ATTRIBUTE_XML.getBytes(StandardCharsets.UTF_8)); @@ -294,8 +310,6 @@ public class XmlStreamReaderTest { } } - // XML Stream generator - @Test public void testHttp() throws Exception { // niallp 2010-10-06 - remove following 2 tests - I reinstated @@ -431,6 +445,20 @@ public class XmlStreamReaderTest { } } + @ParameterizedTest(name = "{0}") + @MethodSource(CharsetsTest.AVAIL_CHARSETS) + public void testIO_815(final String csName) throws Exception { + final MessageFormat fmt = new MessageFormat("<?xml version=\"1.0\" encoding=''{0}''?>\n<root>text</root>"); + final IOFunction<InputStream, XmlStreamReader> factoryCtor = XmlStreamReader::new; + final IOFunction<InputStream, XmlStreamReader> factoryBuilder = stream -> XmlStreamReader.builder().setInputStream(stream).get(); + parseCharset(fmt.format(new Object[] { csName }), csName, factoryCtor); + parseCharset(fmt.format(new Object[] { csName }), csName, factoryBuilder); + for (final String alias : Charset.forName(csName).aliases()) { + parseCharset(fmt.format(new Object[] { alias }), alias, factoryCtor); + parseCharset(fmt.format(new Object[] { alias }), alias, factoryBuilder); + } + } + // Turkish language has specific rules to convert dotted and dotless i character. @Test @DefaultLocale(language = "tr") diff --git a/src/test/java/org/apache/commons/io/input/XmlStreamReaderUtilitiesTest.java b/src/test/java/org/apache/commons/io/input/XmlStreamReaderUtilitiesTest.java index e2cd2e68..821df8a6 100644 --- a/src/test/java/org/apache/commons/io/input/XmlStreamReaderUtilitiesTest.java +++ b/src/test/java/org/apache/commons/io/input/XmlStreamReaderUtilitiesTest.java @@ -31,7 +31,7 @@ import org.junit.jupiter.api.Test; public class XmlStreamReaderUtilitiesTest { /** Mock {@link XmlStreamReader} implementation */ - private static class MockXmlStreamReader extends XmlStreamReader { + private static final class MockXmlStreamReader extends XmlStreamReader { MockXmlStreamReader(final String defaultEncoding) throws IOException { super(CharSequenceInputStream.builder().setCharSequence("").get(), null, true, defaultEncoding); } diff --git a/src/test/java/org/apache/commons/io/input/compatibility/XmlStreamReaderUtilitiesCompatibilityTest.java b/src/test/java/org/apache/commons/io/input/compatibility/XmlStreamReaderUtilitiesCompatibilityTest.java index ee4310a8..acfeb742 100644 --- a/src/test/java/org/apache/commons/io/input/compatibility/XmlStreamReaderUtilitiesCompatibilityTest.java +++ b/src/test/java/org/apache/commons/io/input/compatibility/XmlStreamReaderUtilitiesCompatibilityTest.java @@ -27,7 +27,7 @@ import org.apache.commons.io.input.XmlStreamReaderUtilitiesTest; public class XmlStreamReaderUtilitiesCompatibilityTest extends XmlStreamReaderUtilitiesTest { /** Mock {@link XmlStreamReader} implementation */ - private static class MockXmlStreamReader extends XmlStreamReader { + private static final class MockXmlStreamReader extends XmlStreamReader { MockXmlStreamReader(final String defaultEncoding) throws IOException { super(CharSequenceInputStream.builder().setCharSequence("").get(), null, true, defaultEncoding); } diff --git a/src/test/java/org/apache/commons/io/jmh/PathUtilsContentEqualsBenchmark.java b/src/test/java/org/apache/commons/io/jmh/PathUtilsContentEqualsBenchmark.java new file mode 100644 index 00000000..20e49e71 --- /dev/null +++ b/src/test/java/org/apache/commons/io/jmh/PathUtilsContentEqualsBenchmark.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.io.jmh; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.RandomAccessFileMode; +import org.apache.commons.io.RandomAccessFiles; +import org.apache.commons.io.file.PathUtils; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +/** + * Test different implementations of {@link PathUtils#fileContentEquals(Path, Path)}. + * + * <pre> + * Benchmark Mode Cnt Score Error Units + * PathUtilsContentEqualsBenchmark.testCurrent_fileContentEquals avgt 5 4.538 â 1.010 ms/op + * PathUtilsContentEqualsBenchmark.testCurrent_fileContentEquals_Blackhole avgt 5 110.627 â 30.317 ms/op + * PathUtilsContentEqualsBenchmark.testProposal_contentEquals avgt 5 1.812 â 0.634 ms/op + * PathUtilsContentEqualsBenchmark.testProposal_contentEquals_Blackhole avgt 5 43.521 â 6.762 ms/op + * </pre> + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 10, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 10, timeUnit = TimeUnit.SECONDS) +@Fork(value = 1, jvmArgs = { "-server" }) +public class PathUtilsContentEqualsBenchmark { + + private static final Path bigFile1; + private static final Path bigFile2; + + static { + // Set up test fixtures + try { + bigFile1 = Files.createTempFile(PathUtilsContentEqualsBenchmark.class.getSimpleName(), "-1.bin"); + bigFile2 = Files.createTempFile(PathUtilsContentEqualsBenchmark.class.getSimpleName(), "-2.bin"); + final int newLength = 1_000_000; + final byte[] bytes1 = new byte[newLength]; + Arrays.fill(bytes1, (byte) 1); + Files.write(bigFile1, bytes1); + Files.copy(bigFile1, bigFile2, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public static boolean newFileContentEquals(final Path path1, final Path path2) throws IOException { + try (RandomAccessFile raf1 = RandomAccessFileMode.READ_ONLY.create(path1); + RandomAccessFile raf2 = RandomAccessFileMode.READ_ONLY.create(path2)) { + return RandomAccessFiles.contentEquals(raf1, raf2); + } + } + + @Benchmark + public boolean[] testCurrent_fileContentEquals() throws IOException { + final boolean[] res = new boolean[1]; + res[0] = PathUtils.fileContentEquals(bigFile1, bigFile2); + return res; + } + + @Benchmark + public void testCurrent_fileContentEquals_Blackhole(final Blackhole blackhole) throws IOException { + for (int i = 0; i < 5; i++) { + for (int j = 0; j < 5; j++) { + blackhole.consume(PathUtils.fileContentEquals(bigFile1, bigFile2)); + } + } + } + + @Benchmark + public boolean[] testProposal_contentEquals() throws IOException { + final boolean[] res = new boolean[1]; + res[0] = newFileContentEquals(bigFile1, bigFile2); + return res; + } + + @Benchmark + public void testProposal_contentEquals_Blackhole(final Blackhole blackhole) throws IOException { + for (int i = 0; i < 5; i++) { + for (int j = 0; j < 5; j++) { + blackhole.consume(newFileContentEquals(bigFile1, bigFile2)); + } + } + } + +} diff --git a/src/test/java/org/apache/commons/io/output/ByteArrayOutputStreamTest.java b/src/test/java/org/apache/commons/io/output/ByteArrayOutputStreamTest.java index 2d11e58c..a65961d0 100644 --- a/src/test/java/org/apache/commons/io/output/ByteArrayOutputStreamTest.java +++ b/src/test/java/org/apache/commons/io/output/ByteArrayOutputStreamTest.java @@ -46,7 +46,7 @@ public class ByteArrayOutputStreamTest { T newInstance(final int size); } - private static class ByteArrayOutputStreamFactory implements BAOSFactory<ByteArrayOutputStream> { + private static final class ByteArrayOutputStreamFactory implements BAOSFactory<ByteArrayOutputStream> { @Override public ByteArrayOutputStream newInstance() { return new ByteArrayOutputStream(); @@ -58,7 +58,7 @@ public class ByteArrayOutputStreamTest { } } - private static class UnsynchronizedByteArrayOutputStreamFactory implements BAOSFactory<UnsynchronizedByteArrayOutputStream> { + private static final class UnsynchronizedByteArrayOutputStreamFactory implements BAOSFactory<UnsynchronizedByteArrayOutputStream> { @Override public UnsynchronizedByteArrayOutputStream newInstance() { return new UnsynchronizedByteArrayOutputStream(); diff --git a/src/test/java/org/apache/commons/io/output/ThresholdingOutputStreamTest.java b/src/test/java/org/apache/commons/io/output/ThresholdingOutputStreamTest.java index dd1299e0..080a4927 100644 --- a/src/test/java/org/apache/commons/io/output/ThresholdingOutputStreamTest.java +++ b/src/test/java/org/apache/commons/io/output/ThresholdingOutputStreamTest.java @@ -33,7 +33,7 @@ import org.junit.jupiter.api.Test; public class ThresholdingOutputStreamTest { @Test - public void testSetByteCount_Stream() throws Exception { + public void testSetByteCount_OutputStream() throws Exception { final AtomicBoolean reached = new AtomicBoolean(false); try (ThresholdingOutputStream tos = new ThresholdingOutputStream(3) { { @@ -41,7 +41,7 @@ public class ThresholdingOutputStreamTest { } @Override - protected OutputStream getStream() throws IOException { + protected OutputStream getOutputStream() throws IOException { return new ByteArrayOutputStream(4); } @@ -58,7 +58,7 @@ public class ThresholdingOutputStreamTest { } @Test - public void testSetByteCount_OutputStream() throws Exception { + public void testSetByteCount_Stream() throws Exception { final AtomicBoolean reached = new AtomicBoolean(false); try (ThresholdingOutputStream tos = new ThresholdingOutputStream(3) { { @@ -66,7 +66,7 @@ public class ThresholdingOutputStreamTest { } @Override - protected OutputStream getOutputStream() throws IOException { + protected OutputStream getStream() throws IOException { return new ByteArrayOutputStream(4); } diff --git a/src/test/java/org/apache/commons/io/test/TestUtils.java b/src/test/java/org/apache/commons/io/test/TestUtils.java index 0620603d..3a01f702 100644 --- a/src/test/java/org/apache/commons/io/test/TestUtils.java +++ b/src/test/java/org/apache/commons/io/test/TestUtils.java @@ -224,11 +224,11 @@ public abstract class TestUtils { } } - public static File newFile(final File testDirectory, final String filename) throws IOException { - final File destination = new File(testDirectory, filename); + public static File newFile(final File testDirectory, final String fileName) throws IOException { + final File destination = new File(testDirectory, fileName); /* - assertTrue( filename + "Test output data file shouldn't previously exist", - !destination.exists() ); + assertTrue(fileName + "Test output data file shouldn't previously exist", + !destination.exists()); */ if (destination.exists()) { FileUtils.forceDelete(destination); diff --git a/src/test/resources/org/apache/commons/io/test-file-empty2.bin b/src/test/resources/org/apache/commons/io/test-file-empty2.bin new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/test/resources/org/apache/commons/io/test-file-empty2.bin |