├── .editorconfig ├── .github ├── dependabot.yml ├── release-drafter.yml └── workflows │ ├── sast.yml │ └── test.yml ├── .gitignore ├── CHANGELOG ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle ├── compilation.gradle ├── dependencies.gradle ├── publish.gradle ├── tests.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── src ├── main │ └── java │ │ └── com │ │ └── codeborne │ │ └── xlstest │ │ ├── IO.java │ │ ├── XLS.java │ │ └── matchers │ │ ├── ContainsRow.java │ │ ├── ContainsText.java │ │ ├── DoesNotContainText.java │ │ └── XLSMatcher.java └── test │ ├── java │ └── com │ │ └── codeborne │ │ └── xlstest │ │ ├── CreateXLSXTest.java │ │ ├── CreateXlsTest.java │ │ ├── InvalidXlsTest.java │ │ ├── RealWorldExamplesTest.java │ │ ├── XLSInformationTest.java │ │ ├── formats │ │ └── numbers │ │ │ └── AutomaticAndPlainTextTests.java │ │ └── matchers │ │ ├── ContainsRowTest.java │ │ └── ContainsTextTest.java │ └── resources │ ├── acquiring.xls │ ├── formats.xlsx │ ├── small.xls │ ├── statement.xls │ └── statement.xlsx └── xls-test.iml /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gradle 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: daily 12 | open-pull-requests-limit: 10 13 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: 'v$NEXT_PATCH_VERSION' 2 | tag-template: 'v$NEXT_PATCH_VERSION' 3 | template: | 4 | ## Changes 5 | $CHANGES 6 | 7 | categories: 8 | - title: '🚀 Features' 9 | labels: 10 | - 'feature' 11 | - 'refactoring' 12 | - title: '🐛 Bug Fixes' 13 | label: 'bug' 14 | - title: 📦 Dependency updates 15 | label: 'dependencies' 16 | - title: 📖 Documentation 17 | label: 'documentation' 18 | -------------------------------------------------------------------------------- /.github/workflows/sast.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL security static code analysis" 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | schedule: 9 | - cron: '0 0 * * 6' 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | analyze: 16 | permissions: 17 | actions: read # for github/codeql-action/init to get workflow details 18 | contents: read # for actions/checkout to fetch code 19 | security-events: write # for github/codeql-action/autobuild to send a status report 20 | name: Analyze 21 | runs-on: ubuntu-latest 22 | strategy: 23 | fail-fast: false 24 | steps: 25 | - name: Checkout repository 26 | uses: actions/checkout@v4 27 | with: 28 | # We must fetch at least the immediate parents so that if this is 29 | # a pull request then we can checkout the head. 30 | fetch-depth: 2 31 | - name: Setup java 32 | uses: actions/setup-java@v4 33 | with: 34 | distribution: 'temurin' 35 | cache: 'gradle' 36 | java-version: 17 37 | # If this run was triggered by a pull request event, then checkout 38 | # the head of the pull request instead of the merge commit. 39 | - run: git checkout HEAD^2 40 | if: ${{ github.event_name == 'pull_request' }} 41 | - name: Initialize CodeQL 42 | uses: github/codeql-action/init@v3 43 | with: 44 | languages: java 45 | - name: Autobuild 46 | uses: github/codeql-action/autobuild@v3 47 | - name: Perform CodeQL Analysis 48 | uses: github/codeql-action/analyze@v3 49 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Run tests 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | 8 | jobs: 9 | run-tests: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v4 14 | - name: Set up JDK 15 | uses: actions/setup-java@v4 16 | with: 17 | distribution: 'temurin' 18 | cache: 'gradle' 19 | java-version: '11' 20 | - name: Run tests in Gradle 21 | run: ./gradlew clean test --info --rerun-tasks 22 | - uses: actions/upload-artifact@v4 23 | if: failure() 24 | with: 25 | name: test-report 26 | path: build/reports/ 27 | auto-merge-dependabot: 28 | name: 🤖 Auto merge dependabot PR 29 | timeout-minutes: 10 30 | needs: run-tests 31 | if: ${{ github.actor == 'dependabot[bot]' }} 32 | runs-on: ubuntu-latest 33 | permissions: 34 | pull-requests: write 35 | contents: write 36 | steps: 37 | - name: 🤖 Merge PR from dependabot 38 | uses: fastify/github-action-merge-dependabot@v3.11.1 39 | with: 40 | github-token: ${{secrets.GITHUB_TOKEN}} 41 | target: minor 42 | merge-method: rebase 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .idea 3 | out 4 | *.ipr 5 | *.iws 6 | .gradle 7 | .project 8 | .classpath 9 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | == Changelog 2 | 3 | === 1.7.2 (released 26.09.2024) 4 | * bump POI from 5.2.5 to 5.3.0 5 | * bump Hamcrest from 2.2 to 3.0 6 | 7 | === 1.7.1 (released 09.02.2024) 8 | * bump POI from 5.2.3 to 5.2.5 9 | * upgrade Gradle from 7.x 8.5 10 | 11 | === 1.7.0 (released 22.12.2022) 12 | * bump POI from 5.2.2 to 5.2.3 13 | 14 | === 1.6.0 (released 05.09.2022) 15 | * #4 add matcher doesNotContainText - thanks to Vitali Plagov for PR #4 16 | * upgrade POI 4.1.2 -> 5.2.2 17 | * upgrade from hamcrest-core:1.3 to hamcrest 2.2 18 | 19 | === 1.5.0 (released 03.12.2021) 20 | * #2 fix assertions for floating point numbers -- thanks to Dmitry Romashov for PR #3 21 | 22 | === 1.4.3 (released 15.06.2020) 23 | * upgrade to POI 4.1.2 and JUnit 4.13 24 | 25 | === 1.4.2 (released 16.08.2019) 26 | * upgrade to POI 4.1.0 27 | 28 | === 1.4.1 (released 27.11.2018) 29 | * upgrade to POI 4.0.0 30 | 31 | === 1.4.0 (released 04.06.2018) 32 | * upgrade to Java 8 33 | 34 | === 1.3 (released 19.02.2018) 35 | * Add XLSX support 36 | * upgrade to POI 3.17 37 | * now all constructors with File, URL or InputStream parameter do throw IOException (instead of wrapping it into IllegalArgumentException) 38 | 39 | === 1.2 (released 12.02.2016) 40 | * add method `assertThat(xls, containsRow("cell 1 text", "cell 2 text", "cell 3 text"));` 41 | * change license to less restrictive MIT 42 | 43 | === 1.1 (released 12.08.2015) 44 | * simplify API: all public methods are in class XLS 45 | 46 | === 1.0 (released 28.06.2015) 47 | * created `xls-test` library with the only function `assertThat(xls, containsText("Some cell text"));` 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) [2015] [Andrei Solntsev] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.codeborne/xls-test/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.codeborne/xls-test) 2 | [![Coverage Status](https://coveralls.io/repos/github/codeborne/xls-test/badge.svg?branch=main)](https://coveralls.io/github/codeborne/xls-test?branch=main) 3 | 4 | # XLS Test 5 | Excel testing library 6 | 7 | Be sure that your code generates correct Excel! 8 | 9 | ## How to use 10 | 11 | ```java 12 | import com.codeborne.xlstest.XLS; 13 | import static com.codeborne.xlstest.XLS.*; 14 | import static org.hamcrest.MatcherAssert.assertThat; 15 | 16 | public class ExcelContainsTextTest { 17 | @Test 18 | public void canAssertThatXlsContainsText() { 19 | XLS spreadsheet = new XLS(getClass().getClassLoader().getResource("statement.xls")); 20 | assertThat(spreadsheet, containsText("Statement")); 21 | } 22 | } 23 | ``` 24 | 25 | ## How to start 26 | 27 | If you use **Maven**, add the following dependency to pom.xml: 28 | 29 | ```xml 30 | 31 | com.codeborne 32 | xls-test 33 | 1.7.2 34 | 35 | ``` 36 | 37 | If you use **Gradle**, add the following dependency to build.gradle: 38 | 39 | ```groovy 40 | testCompile 'com.codeborne:xls-test:1.7.2' 41 | ``` 42 | 43 | ## How to contribute 44 | 45 | You are welcome to suggest your features and fixes! 46 | 47 | Just fork the [xls-test](https://github.com/codeborne/xls-test) and create pull request. 48 | Any contribution is important! 49 | 50 | **Become part of open-source community!** 51 | 52 | # Thanks 53 | 54 | Many thanks to these incredible tools that help us to create open-source software: 55 | 56 | ![Intellij IDEA](https://cloud.google.com/tools/images/icon_IntelliJIDEA.png) 57 | 58 | ![YourKit Java profiler](http://selenide.org/images/yourkit.png) 59 | 60 | # License 61 | xls-test is open-source project and distributed under [MIT](http://choosealicense.com/licenses/mit/) license 62 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | maven { url 'https://plugins.gradle.org/m2' } 5 | } 6 | } 7 | 8 | plugins { 9 | id 'java' 10 | id 'jacoco' 11 | id 'com.github.kt3k.coveralls' version '2.12.2' 12 | } 13 | 14 | group='com.codeborne' 15 | archivesBaseName = 'xls-test' 16 | version='1.7.2' 17 | 18 | defaultTasks 'test', 'publishToMavenLocal' 19 | 20 | apply from: file('gradle/compilation.gradle') 21 | apply from: file('gradle/dependencies.gradle') 22 | apply from: file('gradle/tests.gradle') 23 | apply from: file('gradle/publish.gradle') 24 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Dfile.encoding=UTF-8 2 | -------------------------------------------------------------------------------- /gradle/compilation.gradle: -------------------------------------------------------------------------------- 1 | [compileJava, compileTestJava]*.options.collect {options -> options.encoding = 'UTF-8'} 2 | [compileJava, compileTestJava]*.options.collect {options -> options.debug = true} 3 | compileJava.options.debugOptions.debugLevel = "source,lines,vars" 4 | 5 | sourceCompatibility = 1.8 6 | targetCompatibility = 1.8 7 | -------------------------------------------------------------------------------- /gradle/dependencies.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | implementation group: 'net.sf.jxls', name: 'jxls-core', version: '1.0.6', transitive: true 3 | implementation group: 'net.sf.jxls', name: 'jxls-reader', version: '1.0.6', transitive: true 4 | implementation group: 'org.apache.commons', name: 'commons-jexl', version: '2.1.1', transitive: true 5 | implementation group: 'org.apache.poi', name: 'poi', version: '5.3.0', transitive: true 6 | implementation group: 'org.apache.poi', name: 'poi-ooxml', version: '5.3.0', transitive: true 7 | 8 | implementation group: 'org.hamcrest', name: 'hamcrest', version: '3.0', transitive: false 9 | testImplementation group: 'junit', name: 'junit', version: '4.13.2', transitive: false 10 | } 11 | 12 | repositories { 13 | mavenCentral() 14 | } 15 | -------------------------------------------------------------------------------- /gradle/publish.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'maven-publish' 2 | 3 | jar { 4 | manifest { 5 | attributes( 6 | "Implementation-Title": project.group + '.' + project.name, 7 | "Implementation-Version": version, 8 | "Implementation-Vendor": "Codeborne" 9 | ) 10 | } 11 | } 12 | 13 | tasks.register('sourcesJar', Jar) { 14 | dependsOn classes 15 | archiveClassifier = 'sources' 16 | from sourceSets.main.allSource 17 | } 18 | 19 | tasks.withType(Javadoc).configureEach { 20 | failOnError = false 21 | options.encoding = 'UTF-8' 22 | source = sourceSets.main.allJava 23 | } 24 | 25 | tasks.register('javadocJar', Jar) { 26 | dependsOn javadoc 27 | archiveClassifier = 'javadoc' 28 | from javadoc.destinationDir 29 | } 30 | 31 | if (project.hasProperty("signing.keyId")) { 32 | apply plugin: 'signing' 33 | 34 | signing { 35 | afterEvaluate { 36 | sign publishing.publications.mavenJava 37 | } 38 | } 39 | } 40 | 41 | artifacts { 42 | archives jar 43 | archives sourcesJar 44 | archives javadocJar 45 | } 46 | 47 | publishing { 48 | if (project.hasProperty("sonatypeUsername")) { 49 | repositories { 50 | maven { 51 | name 'Maven' 52 | url project.version.endsWith("-SNAPSHOT") ? 53 | 'https://oss.sonatype.org/content/repositories/snapshots/' : 54 | 'https://oss.sonatype.org/service/local/staging/deploy/maven2/' 55 | credentials { 56 | username "$sonatypeUsername" 57 | password "$sonatypePassword" 58 | } 59 | } 60 | } 61 | } 62 | 63 | publications { 64 | mavenJava(MavenPublication) { 65 | groupId "${project.group}" 66 | artifactId "${project.name}" 67 | 68 | from components.java 69 | artifact(sourcesJar) 70 | artifact(javadocJar) 71 | 72 | pom { 73 | name = archivesBaseName 74 | description = 'XLS Test: Excel testing library, created by Codeborne.' 75 | url = 'https://github.com/codeborne/xls-test' 76 | licenses { 77 | license { 78 | name = 'MIT' 79 | url = 'https://opensource.org/licenses/MIT' 80 | } 81 | } 82 | developers { 83 | developer { 84 | id = 'asolntsev' 85 | name = 'Andrei Solntsev' 86 | } 87 | } 88 | scm { 89 | connection = 'scm:git@github.com:codeborne/xls-test.git' 90 | developerConnection = 'scm:git@github.com:codeborne/xls-test.git' 91 | url = 'https://github.com/codeborne/xls-test' 92 | } 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /gradle/tests.gradle: -------------------------------------------------------------------------------- 1 | test { 2 | include 'com/codeborne/xlstest/**/*' 3 | systemProperties['file.encoding'] = 'UTF-8' 4 | testLogging.showStandardStreams = true 5 | jacoco { 6 | enabled = true 7 | } 8 | } 9 | 10 | tasks.withType(JacocoReport).configureEach { 11 | reports { 12 | xml.required = true 13 | csv.required = false 14 | html.required = true 15 | } 16 | } 17 | 18 | tasks.coveralls { 19 | onlyIf { System.env.'CI' } 20 | } 21 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeborne/xls-test/b5a35e247a5094666e6c24a964019fd1eb907005/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | if ! command -v java >/dev/null 2>&1 137 | then 138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 139 | 140 | Please set the JAVA_HOME variable in your environment to match the 141 | location of your Java installation." 142 | fi 143 | fi 144 | 145 | # Increase the maximum file descriptors if we can. 146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 147 | case $MAX_FD in #( 148 | max*) 149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 150 | # shellcheck disable=SC2039,SC3045 151 | MAX_FD=$( ulimit -H -n ) || 152 | warn "Could not query maximum file descriptor limit" 153 | esac 154 | case $MAX_FD in #( 155 | '' | soft) :;; #( 156 | *) 157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 158 | # shellcheck disable=SC2039,SC3045 159 | ulimit -n "$MAX_FD" || 160 | warn "Could not set maximum file descriptor limit to $MAX_FD" 161 | esac 162 | fi 163 | 164 | # Collect all arguments for the java command, stacking in reverse order: 165 | # * args from the command line 166 | # * the main class name 167 | # * -classpath 168 | # * -D...appname settings 169 | # * --module-path (only if needed) 170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 171 | 172 | # For Cygwin or MSYS, switch paths to Windows format before running java 173 | if "$cygwin" || "$msys" ; then 174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 176 | 177 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 178 | 179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 180 | for arg do 181 | if 182 | case $arg in #( 183 | -*) false ;; # don't mess with options #( 184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 185 | [ -e "$t" ] ;; #( 186 | *) false ;; 187 | esac 188 | then 189 | arg=$( cygpath --path --ignore --mixed "$arg" ) 190 | fi 191 | # Roll the args list around exactly as many times as the number of 192 | # args, so each arg winds up back in the position where it started, but 193 | # possibly modified. 194 | # 195 | # NB: a `for` loop captures its iteration list before it begins, so 196 | # changing the positional parameters here affects neither the number of 197 | # iterations, nor the values presented in `arg`. 198 | shift # remove old arg 199 | set -- "$@" "$arg" # push replacement arg 200 | done 201 | fi 202 | 203 | 204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 206 | 207 | # Collect all arguments for the java command: 208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 209 | # and any embedded shellness will be escaped. 210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 211 | # treated as '${Hostname}' itself on the command line. 212 | 213 | set -- \ 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 215 | -classpath "$CLASSPATH" \ 216 | org.gradle.wrapper.GradleWrapperMain \ 217 | "$@" 218 | 219 | # Stop when "xargs" is not available. 220 | if ! command -v xargs >/dev/null 2>&1 221 | then 222 | die "xargs is not available" 223 | fi 224 | 225 | # Use "xargs" to parse quoted args. 226 | # 227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 228 | # 229 | # In Bash we could simply go: 230 | # 231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 232 | # set -- "${ARGS[@]}" "$@" 233 | # 234 | # but POSIX shell has neither arrays nor command substitution, so instead we 235 | # post-process each arg (as a line of input to sed) to backslash-escape any 236 | # character that might be a shell metacharacter, then use eval to reverse 237 | # that process (while maintaining the separation between arguments), and wrap 238 | # the whole thing up as a single "set" statement. 239 | # 240 | # This will of course break if any of these variables contains a newline or 241 | # an unmatched quote. 242 | # 243 | 244 | eval "set -- $( 245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 246 | xargs -n1 | 247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 248 | tr '\n' ' ' 249 | )" '"$@"' 250 | 251 | exec "$JAVACMD" "$@" 252 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /src/main/java/com/codeborne/xlstest/IO.java: -------------------------------------------------------------------------------- 1 | package com.codeborne.xlstest; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.File; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.net.URL; 8 | import java.nio.file.Files; 9 | import java.nio.file.Paths; 10 | 11 | class IO { 12 | static byte[] readBytes(URL url) throws IOException { 13 | try (InputStream inputStream = url.openStream()) { 14 | return readBytes(inputStream); 15 | } 16 | } 17 | 18 | static byte[] readBytes(InputStream inputStream) throws IOException { 19 | ByteArrayOutputStream result = new ByteArrayOutputStream(); 20 | byte[] buffer = new byte[2048]; 21 | 22 | int nRead; 23 | while ((nRead = inputStream.read(buffer, 0, buffer.length)) != -1) { 24 | result.write(buffer, 0, nRead); 25 | } 26 | 27 | return result.toByteArray(); 28 | } 29 | 30 | static byte[] readFile(File xlsFile) { 31 | try { 32 | return Files.readAllBytes(Paths.get(xlsFile.getAbsolutePath())); 33 | } 34 | catch (IOException e) { 35 | throw new IllegalArgumentException("Failed to read file " + xlsFile, e); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/codeborne/xlstest/XLS.java: -------------------------------------------------------------------------------- 1 | package com.codeborne.xlstest; 2 | 3 | import com.codeborne.xlstest.matchers.ContainsRow; 4 | import com.codeborne.xlstest.matchers.ContainsText; 5 | import com.codeborne.xlstest.matchers.DoesNotContainText; 6 | import org.apache.poi.ss.usermodel.Workbook; 7 | import org.apache.poi.ss.usermodel.WorkbookFactory; 8 | import org.hamcrest.Matcher; 9 | 10 | import java.io.ByteArrayInputStream; 11 | import java.io.File; 12 | import java.io.IOException; 13 | import java.io.InputStream; 14 | import java.net.URI; 15 | import java.net.URL; 16 | 17 | import static com.codeborne.xlstest.IO.readBytes; 18 | import static com.codeborne.xlstest.IO.readFile; 19 | 20 | public class XLS { 21 | public final String name; 22 | public final Workbook excel; 23 | 24 | private XLS(String name, byte[] content) { 25 | this.name = name; 26 | try (InputStream inputStream = new ByteArrayInputStream(content)) { 27 | excel = WorkbookFactory.create(inputStream); 28 | } 29 | catch (Exception e) { 30 | throw new IllegalArgumentException("Invalid XLS " + name, e); 31 | } 32 | } 33 | 34 | public XLS(File xlsFile) { 35 | this(xlsFile.getAbsolutePath(), readFile(xlsFile)); 36 | } 37 | 38 | public XLS(URL url) throws IOException { 39 | this(url.toString(), readBytes(url)); 40 | } 41 | 42 | public XLS(URI uri) throws IOException { 43 | this(uri.toURL()); 44 | } 45 | 46 | public XLS(byte[] content) { 47 | this("", content); 48 | } 49 | 50 | public XLS(InputStream inputStream) throws IOException { 51 | this(readBytes(inputStream)); 52 | } 53 | 54 | public static Matcher containsText(String text) { 55 | return new ContainsText(text); 56 | } 57 | 58 | public static Matcher containsRow(String... cellTexts) { 59 | return new ContainsRow(cellTexts); 60 | } 61 | 62 | public static Matcher doesNotContainText(String text) { 63 | return new DoesNotContainText(text); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/codeborne/xlstest/matchers/ContainsRow.java: -------------------------------------------------------------------------------- 1 | package com.codeborne.xlstest.matchers; 2 | 3 | import com.codeborne.xlstest.XLS; 4 | import org.apache.poi.ss.usermodel.Cell; 5 | import org.apache.poi.ss.usermodel.Row; 6 | import org.apache.poi.ss.usermodel.Sheet; 7 | import org.hamcrest.Description; 8 | 9 | import java.util.Arrays; 10 | import java.util.LinkedList; 11 | import java.util.Queue; 12 | 13 | import static java.util.Arrays.asList; 14 | 15 | public class ContainsRow extends XLSMatcher { 16 | private final String[] cellTexts; 17 | 18 | public ContainsRow(String... cellTexts) { 19 | this.cellTexts = cellTexts; 20 | } 21 | 22 | @Override 23 | protected boolean matchesSafely(XLS item) { 24 | for (int i = 0; i < item.excel.getNumberOfSheets(); i++) { 25 | Sheet sheet = item.excel.getSheetAt(i); 26 | for (Row row : sheet) { 27 | Queue expectedTexts = new LinkedList<>(asList(cellTexts)); 28 | for (Cell cell : row) { 29 | String expectedText = expectedTexts.peek(); 30 | if (getFormattedCellValue(cell).contains(expectedText)) { 31 | expectedTexts.remove(); 32 | } 33 | if (expectedTexts.isEmpty()) return true; 34 | } 35 | } 36 | } 37 | return false; 38 | } 39 | 40 | @Override 41 | public void describeTo(Description description) { 42 | description.appendText("a XLS containing row ").appendValue(Arrays.toString(cellTexts)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/codeborne/xlstest/matchers/ContainsText.java: -------------------------------------------------------------------------------- 1 | package com.codeborne.xlstest.matchers; 2 | 3 | import com.codeborne.xlstest.XLS; 4 | import org.apache.poi.ss.usermodel.Cell; 5 | import org.apache.poi.ss.usermodel.Row; 6 | import org.apache.poi.ss.usermodel.Sheet; 7 | import org.hamcrest.Description; 8 | 9 | public class ContainsText extends XLSMatcher { 10 | private final String substring; 11 | 12 | public ContainsText(String substring) { 13 | this.substring = reduceSpaces(substring); 14 | } 15 | 16 | @Override 17 | protected boolean matchesSafely(XLS item) { 18 | for (int i = 0; i < item.excel.getNumberOfSheets(); i++) { 19 | Sheet sheet = item.excel.getSheetAt(i); 20 | for (Row row : sheet) { 21 | for (Cell cell : row) { 22 | String cellValue = reduceSpaces(getFormattedCellValue(cell)); 23 | if (cellValue.contains(substring)) 24 | return true; 25 | } 26 | } 27 | } 28 | return false; 29 | } 30 | 31 | @Override 32 | public void describeTo(Description description) { 33 | description.appendText("a XLS containing text ").appendValue(reduceSpaces(substring)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/codeborne/xlstest/matchers/DoesNotContainText.java: -------------------------------------------------------------------------------- 1 | package com.codeborne.xlstest.matchers; 2 | 3 | import com.codeborne.xlstest.XLS; 4 | import org.hamcrest.Description; 5 | 6 | public class DoesNotContainText extends XLSMatcher { 7 | 8 | private final String substring; 9 | 10 | public DoesNotContainText(String substring) { 11 | this.substring = reduceSpaces(substring); 12 | } 13 | 14 | @Override 15 | protected boolean matchesSafely(XLS item) { 16 | boolean contains = new ContainsText(substring).matchesSafely(item); 17 | return !contains; 18 | } 19 | 20 | @Override 21 | public void describeTo(Description description) { 22 | description.appendText("a XLS not containing text ").appendValue(reduceSpaces(substring)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/codeborne/xlstest/matchers/XLSMatcher.java: -------------------------------------------------------------------------------- 1 | package com.codeborne.xlstest.matchers; 2 | 3 | import com.codeborne.xlstest.XLS; 4 | import org.apache.poi.ss.usermodel.BuiltinFormats; 5 | import org.apache.poi.ss.usermodel.Cell; 6 | import org.apache.poi.ss.usermodel.Row; 7 | import org.apache.poi.ss.usermodel.Sheet; 8 | import org.hamcrest.Description; 9 | import org.hamcrest.SelfDescribing; 10 | import org.hamcrest.TypeSafeMatcher; 11 | 12 | import java.text.DecimalFormat; 13 | import java.util.Arrays; 14 | import java.util.List; 15 | 16 | abstract class XLSMatcher extends TypeSafeMatcher implements SelfDescribing { 17 | private List legalNumericFormats = Arrays.asList( 18 | BuiltinFormats.getBuiltinFormat(1), 19 | BuiltinFormats.getBuiltinFormat(2), 20 | BuiltinFormats.getBuiltinFormat(3), 21 | BuiltinFormats.getBuiltinFormat(4), 22 | BuiltinFormats.getBuiltinFormat(9), 23 | BuiltinFormats.getBuiltinFormat(10) 24 | ); 25 | 26 | protected String reduceSpaces(String text) { 27 | return text.replaceAll("[\\s\\n\\r\u00a0]+", " ").trim(); 28 | } 29 | 30 | protected String getFormattedCellValue(Cell cell) { 31 | switch (cell.getCellType()) { 32 | case NUMERIC: 33 | DecimalFormat formatter; 34 | if (legalNumericFormats.contains(cell.getCellStyle().getDataFormatString())) { 35 | formatter = new DecimalFormat(cell.getCellStyle().getDataFormatString()); 36 | } else { 37 | formatter = new DecimalFormat(); 38 | } 39 | return formatter.format(cell.getNumericCellValue()); 40 | case STRING: 41 | case BLANK: 42 | default: 43 | return cell.toString(); 44 | } 45 | } 46 | 47 | @Override 48 | protected void describeMismatchSafely(XLS item, Description mismatchDescription) { 49 | mismatchDescription.appendText("was \"").appendText(item.name).appendText("\"\n"); 50 | 51 | for (int i = 0; i < item.excel.getNumberOfSheets(); i++) { 52 | Sheet sheet = item.excel.getSheetAt(i); 53 | for (Row row : sheet) { 54 | for (Cell cell : row) { 55 | mismatchDescription.appendText(getFormattedCellValue(cell)).appendText("\t"); 56 | } 57 | mismatchDescription.appendText("\n"); 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/com/codeborne/xlstest/CreateXLSXTest.java: -------------------------------------------------------------------------------- 1 | package com.codeborne.xlstest; 2 | 3 | import org.junit.Test; 4 | 5 | import java.io.File; 6 | import java.io.InputStream; 7 | import java.net.URI; 8 | import java.net.URL; 9 | import java.nio.file.Files; 10 | import java.nio.file.Paths; 11 | 12 | import static com.codeborne.xlstest.XLS.containsText; 13 | import static org.hamcrest.MatcherAssert.assertThat; 14 | 15 | public class CreateXLSXTest { 16 | @Test 17 | public void fromFile() throws Exception { 18 | File file = new File(getClass().getClassLoader().getResource("statement.xlsx").toURI()); 19 | assertThat(new XLS(file), containsText("Выписка")); 20 | } 21 | 22 | @Test 23 | public void fromUrl() throws Exception { 24 | URL url = getClass().getClassLoader().getResource("statement.xlsx"); 25 | assertThat(new XLS(url), containsText("Выписка")); 26 | } 27 | 28 | @Test 29 | public void fromUri() throws Exception { 30 | URI uri = getClass().getClassLoader().getResource("statement.xlsx").toURI(); 31 | assertThat(new XLS(uri), containsText("Выписка")); 32 | } 33 | 34 | @Test 35 | public void fromInputStream() throws Exception { 36 | InputStream inputStream = getClass().getClassLoader().getResourceAsStream("statement.xlsx"); 37 | assertThat(new XLS(inputStream), containsText("Выписка")); 38 | } 39 | 40 | @Test 41 | public void fromBytes() throws Exception { 42 | byte[] bytes = Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("statement.xlsx").toURI())); 43 | assertThat(new XLS(bytes), containsText("Выписка")); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/com/codeborne/xlstest/CreateXlsTest.java: -------------------------------------------------------------------------------- 1 | package com.codeborne.xlstest; 2 | 3 | import org.junit.Test; 4 | 5 | import java.io.File; 6 | import java.io.InputStream; 7 | import java.net.URI; 8 | import java.net.URL; 9 | import java.nio.file.Files; 10 | import java.nio.file.Paths; 11 | 12 | import static com.codeborne.xlstest.XLS.containsText; 13 | import static org.hamcrest.MatcherAssert.assertThat; 14 | 15 | public class CreateXlsTest { 16 | @Test 17 | public void fromFile() throws Exception { 18 | File file = new File(getClass().getClassLoader().getResource("statement.xls").toURI()); 19 | assertThat(new XLS(file), containsText("Выписка")); 20 | } 21 | 22 | @Test 23 | public void fromUrl() throws Exception { 24 | URL url = getClass().getClassLoader().getResource("statement.xls"); 25 | assertThat(new XLS(url), containsText("Выписка")); 26 | } 27 | 28 | @Test 29 | public void fromUri() throws Exception { 30 | URI uri = getClass().getClassLoader().getResource("statement.xls").toURI(); 31 | assertThat(new XLS(uri), containsText("Выписка")); 32 | } 33 | 34 | @Test 35 | public void fromInputStream() throws Exception { 36 | InputStream inputStream = getClass().getClassLoader().getResourceAsStream("statement.xls"); 37 | assertThat(new XLS(inputStream), containsText("Выписка")); 38 | } 39 | 40 | @Test 41 | public void fromBytes() throws Exception { 42 | byte[] bytes = Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("statement.xls").toURI())); 43 | assertThat(new XLS(bytes), containsText("Выписка")); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/com/codeborne/xlstest/InvalidXlsTest.java: -------------------------------------------------------------------------------- 1 | package com.codeborne.xlstest; 2 | 3 | import org.junit.Test; 4 | 5 | import java.io.File; 6 | 7 | import static org.hamcrest.Matchers.is; 8 | import static org.hamcrest.Matchers.notNullValue; 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | import static org.junit.Assert.fail; 11 | 12 | public class InvalidXlsTest { 13 | @Test 14 | public void throws_IllegalArgumentException_ifFailedToParseXlsFromBytes() { 15 | try { 16 | new XLS("This is not Excel file".getBytes()); 17 | fail("expected IllegalArgumentException"); 18 | } 19 | catch (IllegalArgumentException expected) { 20 | assertThat(expected.getMessage(), is("Invalid XLS ")); 21 | assertThat(expected.getCause(), is(notNullValue())); 22 | } 23 | } 24 | 25 | @Test 26 | public void throws_IllegalArgumentException_ifFailedToReadXlsFile() { 27 | try { 28 | new XLS(new File("missing-file.xls")); 29 | fail("expected IllegalArgumentException"); 30 | } 31 | catch (IllegalArgumentException expected) { 32 | assertThat(expected.getMessage(), is("Failed to read file missing-file.xls")); 33 | assertThat(expected.getCause(), is(notNullValue())); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/codeborne/xlstest/RealWorldExamplesTest.java: -------------------------------------------------------------------------------- 1 | package com.codeborne.xlstest; 2 | 3 | import org.junit.Test; 4 | 5 | import static com.codeborne.xlstest.XLS.containsText; 6 | import static org.hamcrest.MatcherAssert.assertThat; 7 | 8 | public class RealWorldExamplesTest { 9 | @Test 10 | public void bankStatement() throws Exception { 11 | XLS xls = new XLS(getClass().getClassLoader().getResource("statement.xls")); 12 | assertThat(xls, containsText("Выписка")); 13 | assertThat(xls, containsText("Период")); 14 | assertThat(xls, containsText("18.06.2015 - 18.06.2015")); 15 | } 16 | 17 | @Test 18 | public void acquiringReport() throws Exception { 19 | XLS xls = new XLS(getClass().getClassLoader().getResource("acquiring.xls")); 20 | assertThat(xls, containsText("Отчёт об операциях по пластиковым картам - 27.06.2015")); 21 | assertThat(xls, containsText("с 27.05.2015 по 27.06.2015")); 22 | assertThat(xls, containsText("ООО \"Джапан Мотор Сервис\", ИНН 7830002292, Номер договора 08-1-1-04-2437")); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/codeborne/xlstest/XLSInformationTest.java: -------------------------------------------------------------------------------- 1 | package com.codeborne.xlstest; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.hamcrest.CoreMatchers.endsWith; 6 | import static org.hamcrest.CoreMatchers.equalTo; 7 | import static org.hamcrest.MatcherAssert.assertThat; 8 | 9 | public class XLSInformationTest { 10 | @Test 11 | public void canGetInformationFromXls() throws Exception { 12 | XLS XLS = new XLS(getClass().getClassLoader().getResource("statement.xls")); 13 | assertThat(XLS.name, endsWith("statement.xls")); 14 | assertThat(XLS.excel.getNumberOfSheets(), equalTo(3)); 15 | assertThat(XLS.excel.getActiveSheetIndex(), equalTo(0)); 16 | assertThat(XLS.excel.getSheetName(0), equalTo("Sheet1")); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/codeborne/xlstest/formats/numbers/AutomaticAndPlainTextTests.java: -------------------------------------------------------------------------------- 1 | package com.codeborne.xlstest.formats.numbers; 2 | 3 | import com.codeborne.xlstest.XLS; 4 | import org.junit.Test; 5 | 6 | import java.io.File; 7 | 8 | import static com.codeborne.xlstest.XLS.containsText; 9 | import static org.hamcrest.MatcherAssert.assertThat; 10 | 11 | public class AutomaticAndPlainTextTests { 12 | @Test 13 | public void automaticStyle_valueInCell1_displayedValue1_parsedAs1() throws Exception { 14 | File file = new File(getClass().getClassLoader().getResource("formats.xlsx").toURI()); 15 | assertThat(new XLS(file), containsText("1")); 16 | } 17 | 18 | @Test 19 | public void automaticStyle_valueInCell1comma2_displayedValue1comma2_parsedAs1point2() throws Exception { 20 | File file = new File(getClass().getClassLoader().getResource("formats.xlsx").toURI()); 21 | assertThat(new XLS(file), containsText("1.2")); 22 | } 23 | 24 | @Test 25 | public void plainText_valueInCell2_displayedValue2_parsedAs2() throws Exception { 26 | File file = new File(getClass().getClassLoader().getResource("formats.xlsx").toURI()); 27 | assertThat(new XLS(file), containsText("2")); 28 | } 29 | 30 | @Test 31 | public void plainText_valueInCell2point1_displayedValue2point1_parsedAs2point1() throws Exception { 32 | File file = new File(getClass().getClassLoader().getResource("formats.xlsx").toURI()); 33 | assertThat(new XLS(file), containsText("2.1")); 34 | } 35 | 36 | @Test 37 | public void plainText_valueInCell2comma2_displayedValue2comma2_parsedAs2comma2() throws Exception { 38 | File file = new File(getClass().getClassLoader().getResource("formats.xlsx").toURI()); 39 | assertThat(new XLS(file), containsText("2,2")); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/com/codeborne/xlstest/matchers/ContainsRowTest.java: -------------------------------------------------------------------------------- 1 | package com.codeborne.xlstest.matchers; 2 | 3 | import com.codeborne.xlstest.XLS; 4 | import org.junit.Test; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | 9 | import static com.codeborne.xlstest.XLS.containsRow; 10 | import static org.hamcrest.CoreMatchers.not; 11 | import static org.hamcrest.Matchers.is; 12 | import static org.hamcrest.MatcherAssert.assertThat; 13 | import static org.junit.Assert.fail; 14 | 15 | public class ContainsRowTest { 16 | @Test 17 | public void rowContainsCells_all() throws IOException { 18 | XLS xls = new XLS(getClass().getClassLoader().getResource("acquiring.xls")); 19 | assertThat(xls, containsRow("PP028000", "дом 261Б, ул Семафорная, г Красноярск, 197372, РОССИЯ", "Оплата", "1,021.00", "10.21", "1,010.79", "27.05.2015 00:00:00", "415039******2364", "476956", "281814930")); 20 | } 21 | 22 | @Test 23 | public void rowContainsCells_withGaps() throws Exception { 24 | XLS xls = new XLS(getClass().getClassLoader().getResource("acquiring.xls")); 25 | assertThat(xls, containsRow("PP028000")); 26 | assertThat(xls, containsRow("PP028000", "281814930")); 27 | assertThat(xls, containsRow("281814930")); 28 | assertThat(xls, containsRow("Итого по терминалу", "48,271.00")); 29 | } 30 | 31 | @Test 32 | public void rowContainsCells_noMatch() throws IOException { 33 | XLS xls = new XLS(getClass().getClassLoader().getResource("acquiring.xls")); 34 | assertThat(xls, not(containsRow("foobar"))); 35 | assertThat(xls, not(containsRow("foobar", "PP028000", "281814930"))); 36 | assertThat(xls, not(containsRow("PP028000", "281814930", "foobar"))); 37 | assertThat(xls, not(containsRow("PP028000", "foobar", "281814930"))); 38 | } 39 | 40 | @Test 41 | public void errorDescription() throws IOException { 42 | XLS xls = new XLS(new File("src/test/resources/small.xls")); 43 | try { 44 | assertThat(xls, containsRow("wrong data")); 45 | fail("expected AssertionError"); 46 | } 47 | catch (AssertionError expected) { 48 | assertThat(expected.getMessage(), is( 49 | "\nExpected: a XLS containing row \"[wrong data]\"" + 50 | "\n but: was \"" + System.getProperty("user.dir") + "/src/test/resources/small.xls\"" + 51 | "\nВыписка\t\t\nСчёт\t40820810590480000591\t\n")); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/com/codeborne/xlstest/matchers/ContainsTextTest.java: -------------------------------------------------------------------------------- 1 | package com.codeborne.xlstest.matchers; 2 | 3 | import com.codeborne.xlstest.XLS; 4 | import org.junit.Test; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | import java.util.Objects; 9 | 10 | import static com.codeborne.xlstest.XLS.containsText; 11 | import static com.codeborne.xlstest.XLS.doesNotContainText; 12 | import static org.hamcrest.MatcherAssert.assertThat; 13 | import static org.hamcrest.Matchers.is; 14 | import static org.junit.Assert.fail; 15 | 16 | public class ContainsTextTest { 17 | @Test 18 | public void canAssertThatXlsContainsText() throws IOException { 19 | XLS XLS = new XLS(Objects.requireNonNull(getClass().getClassLoader().getResource("statement.xls"))); 20 | assertThat(XLS, containsText("Выписка")); 21 | assertThat(XLS, containsText("Solntsev Andrei")); 22 | assertThat(XLS, containsText("25.06.2015 23:09:32")); 23 | 24 | assertThat(XLS, containsText("Счёт")); 25 | assertThat(XLS, containsText("40820810590480000591")); 26 | assertThat(XLS, containsText("Период")); 27 | assertThat(XLS, containsText("18.06.2015 - 18.06.2015")); 28 | assertThat(XLS, containsText("Входящий остаток на 18.06.2015")); 29 | assertThat(XLS, containsText("6.40")); 30 | 31 | assertThat(XLS, containsText("Дата")); 32 | assertThat(XLS, containsText("Счёт\nплательщика/получателя")); 33 | assertThat(XLS, containsText("Плательщик / Получатель")); 34 | assertThat(XLS, containsText("Операция")); 35 | assertThat(XLS, containsText("Сумма (RUB)")); 36 | 37 | assertThat(XLS, containsText("18.06.2015")); 38 | assertThat(XLS, containsText("40820810590550000146")); 39 | assertThat(XLS, containsText("Solntsev Andrei")); 40 | assertThat(XLS, containsText("сюда. Интернет-банк")); 41 | assertThat(XLS, containsText("-1.00")); 42 | 43 | assertThat(XLS, containsText("туда. Интернет-банк")); 44 | assertThat(XLS, containsText("1.00")); 45 | 46 | assertThat(XLS, containsText("Исходящий остаток на 18.06.2015")); 47 | assertThat(XLS, containsText("6.40")); 48 | 49 | assertThat(XLS, containsText("Поступление")); 50 | assertThat(XLS, containsText("Списание")); 51 | assertThat(XLS, containsText("Зарезервировано")); 52 | assertThat(XLS, containsText("349,928.00")); 53 | } 54 | 55 | @Test 56 | public void canAssertXlsDoesNotContainText() throws IOException { 57 | XLS xls = new XLS(Objects.requireNonNull(getClass().getClassLoader().getResource("statement.xls"))); 58 | assertThat(xls, doesNotContainText("null")); 59 | } 60 | 61 | @Test 62 | public void errorDescriptionForDoesNotContainTextMatcher() { 63 | XLS xls = new XLS(new File("src/test/resources/small.xls")); 64 | try { 65 | assertThat(xls, doesNotContainText("Выписка")); 66 | fail("expected AssertionError"); 67 | } 68 | catch (AssertionError expected) { 69 | assertThat(expected.getMessage(), is( 70 | "\nExpected: a XLS not containing text \"Выписка\"" + 71 | "\n but: was \"" + System.getProperty("user.dir") + "/src/test/resources/small.xls\"" + 72 | "\nВыписка\t\t\nСчёт\t40820810590480000591\t\n")); 73 | } 74 | } 75 | 76 | @Test 77 | public void errorDescriptionForContainsTextMatcher() { 78 | XLS xls = new XLS(new File("src/test/resources/small.xls")); 79 | try { 80 | assertThat(xls, containsText("wrong text")); 81 | fail("expected AssertionError"); 82 | } 83 | catch (AssertionError expected) { 84 | assertThat(expected.getMessage(), is( 85 | "\nExpected: a XLS containing text \"wrong text\"" + 86 | "\n but: was \"" + System.getProperty("user.dir") + "/src/test/resources/small.xls\"" + 87 | "\nВыписка\t\t\nСчёт\t40820810590480000591\t\n")); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/test/resources/acquiring.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeborne/xls-test/b5a35e247a5094666e6c24a964019fd1eb907005/src/test/resources/acquiring.xls -------------------------------------------------------------------------------- /src/test/resources/formats.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeborne/xls-test/b5a35e247a5094666e6c24a964019fd1eb907005/src/test/resources/formats.xlsx -------------------------------------------------------------------------------- /src/test/resources/small.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeborne/xls-test/b5a35e247a5094666e6c24a964019fd1eb907005/src/test/resources/small.xls -------------------------------------------------------------------------------- /src/test/resources/statement.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeborne/xls-test/b5a35e247a5094666e6c24a964019fd1eb907005/src/test/resources/statement.xls -------------------------------------------------------------------------------- /src/test/resources/statement.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeborne/xls-test/b5a35e247a5094666e6c24a964019fd1eb907005/src/test/resources/statement.xlsx -------------------------------------------------------------------------------- /xls-test.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | --------------------------------------------------------------------------------