pax_global_header00006660000000000000000000000064125026144170014514gustar00rootroot0000000000000052 comment=1f4996ea3dab06193c378fd66fd4f8fdc8334cc6 jsemver-0.9.0/000077500000000000000000000000001250261441700131755ustar00rootroot00000000000000jsemver-0.9.0/.gitignore000066400000000000000000000000101250261441700151540ustar00rootroot00000000000000/target/jsemver-0.9.0/.travis.yml000066400000000000000000000000171250261441700153040ustar00rootroot00000000000000language: java jsemver-0.9.0/CHANGELOG.md000066400000000000000000000057641250261441700150220ustar00rootroot00000000000000Java SemVer Changelog ===================== ### 0.9.0 (Mar 19, 2015) ### * [[#7](https://github.com/zafarkhaja/jsemver/issues/6)] Implemented internal DSL for the SemVer Expressions and Ranges * [[PR#18](https://github.com/zafarkhaja/jsemver/pull/18)] Introduced partial compatibility with `node-semver` ranges * Reworked the BNF grammar of the SemVer Expressions * Made some enhancements and improvements * Updated project dependencies and Maven plugins ### 0.8.0 (Aug 18, 2014) ### * Rearranged exceptions hierarchy * Refactored `VersionParser` and `ExpressionParser` * [[#7](https://github.com/zafarkhaja/jsemver/issues/7)] Improved error handling and error reporting in the Parsers * Made some minor improvements and bug fixes * Updated the `README` file with the "Exception Handling" section ### 0.7.2 (Dec 30, 2013) ### * [[#8](https://github.com/zafarkhaja/jsemver/issues/8)] Fixed `Version.hashCode()` to comply with `Version.equals()` ### 0.7.1 (Dec 01, 2013) ### * [[#5](https://github.com/zafarkhaja/jsemver/issues/5)] Got rid of 'unchecked' warnings * Made minor Javadoc corrections * Made small code improvements * Configured `maven-compiler-plugin` to show all warnings * Updated the `CHANGELOG.md` and `README.md` files ### 0.7.0 (Nov 16, 2013) ### * Adapted the library to the SemVer 2.0.0 * [[#1](https://github.com/zafarkhaja/jsemver/issues/1)] Created the SemVer Expressions Parser * [[#2](https://github.com/zafarkhaja/jsemver/issues/2)] Added Javadoc to the source code * [[#4](https://github.com/zafarkhaja/jsemver/issues/4)] Deployed to the Maven Central Repository * Implemented a parser instead of RegExps for the version parsing * Created the `MetadataVersion.NULL` object, refactored * Made some refactoring and minor improvements to the code * Updated and reformated the `README.md` file * Renamed the `artifactId` and changed the `name` in the `pom.xml` file * Updated the JUnit dependency to 4.11 * Prepared the `pom.xml` file for the repository * Created the `CHANGELOG.md` file ### 0.6.0 (Mar 31, 2013) ### * Adapted the library to the SemVer 2.0.0-rc.2 * Added setters for the pre-release version and the build metadata * Added the incrementors for the pre-release version and the build metadata * Created the `Version.Builder` class * Created the `Version.BUILD_AWARE_ORDER` comparator * Added support for the Travis CI * Made minor refactoring * Updated the `README.md` file ### 0.5.0 (Mar 8, 2013) ### * Updated the `README.md` file * Made minor refactoring ### 0.4.2 (Mar 6, 2013) ### * Renamed the `README` file to `README.md` ### 0.4.1 (Mar 6, 2013) ### * Bumped the version for the previous release ### 0.4.0 (Mar 6, 2013) ### * Made the version classes immutable * Made minor imrovements to the code ### 0.3.0 (Mar 4, 2013) ### * Added incrementor methods for the `NormalVersion` ### 0.2.1 (Mar 3, 2013) ### * Made minor imrovements to the code ### 0.2.0 (Mar 3, 2013) ### * Separated the logic into different classes ### 0.1.0 (Jan 27, 2013) ### * Implemented basic functionality, single `Version` class jsemver-0.9.0/LICENSE000066400000000000000000000021111250261441700141750ustar00rootroot00000000000000The MIT License Copyright 2012-2014 Zafar Khaja . Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. jsemver-0.9.0/README.md000066400000000000000000000240441250261441700144600ustar00rootroot00000000000000Java SemVer v0.9.0 (SemVer 2) [![Build Status](https://travis-ci.org/zafarkhaja/jsemver.png)](https://travis-ci.org/zafarkhaja/jsemver) ============================ Java SemVer is a Java implementation of the Semantic Versioning Specification (http://semver.org/). ### Versioning ### Java SemVer is versioned according to the SemVer Specification. **NOTE**: The current release of the Java SemVer library has a major version of zero which according to the SemVer p.4 means that the library is under initial development and its public API should not be considered stable. ### Table of Contents ### * [Installation](#installation) * [Usage](#usage) * [Creating Versions](#creating-versions) * [Incrementing Versions](#incrementing-versions) * [Comparing Versions](#comparing-versions) * [SemVer Expressions API (Ranges)](#semver-expressions-api-ranges) * [Exception Handling](#exception-handling) * [Bugs and Features](#bugs-and-features) * [License](#license) Installation ------------ To install the Java SemVer libary add the following dependency to your Maven project. **Current stable version** ~~~ xml com.github.zafarkhaja java-semver 0.9.0 ~~~ **Development version** ~~~ xml com.github.zafarkhaja java-semver 0.10.0-SNAPSHOT ~~~ **NOTE**: To use the development version you need to add the SNAPSHOT repository to your `pom.xml` file: http://oss.sonatype.org/content/repositories/snapshots/. Usage ----- Below are some common use cases for the Java SemVer library. ### Creating Versions ### The main class of the Java SemVer library is `Version` which implements the Facade design pattern. By design, the `Version` class is made immutable by making its constructors package-private, so that it can not be subclassed or directly instantiated. Instead of public constructors, the `Version` class provides few _static factory methods_. One of the methods is the `Version.valueOf` method. ~~~ java import com.github.zafarkhaja.semver.Version; Version v = Version.valueOf("1.0.0-rc.1+build.1"); int major = v.getMajorVersion(); // 1 int minor = v.getMinorVersion(); // 0 int patch = v.getPatchVersion(); // 0 String normal = v.getNormalVersion(); // "1.0.0" String preRelease = v.getPreReleaseVersion(); // "rc.1" String build = v.getBuildMetadata(); // "build.1" String str = v.toString(); // "1.0.0-rc.1+build.1" ~~~ The other static factory method is `Version.forIntegers` which is also overloaded to allow fewer arguments. ~~~ java import com.github.zafarkhaja.semver.Version; Version v1 = Version.forIntegers(1); Version v2 = Version.forIntegers(1, 2); Version v3 = Version.forIntegers(1, 2, 3); ~~~ Another way to create a `Version` is to use a _builder_ class `Version.Builder`. ~~~ java import com.github.zafarkhaja.semver.Version; Version.Builder builder = new Version.Builder("1.0.0"); builder.setPreReleaseVersion("rc.1"); builder.setBuildMetadata("build.1"); Version v = builder.build(); int major = v.getMajorVersion(); // 1 int minor = v.getMinorVersion(); // 0 int patch = v.getPatchVersion(); // 0 String normal = v.getNormalVersion(); // "1.0.0" String preRelease = v.getPreReleaseVersion(); // "rc.1" String build = v.getBuildMetadata(); // "build.1" String str = v.toString(); // "1.0.0-rc.1+build.1" ~~~ ### Incrementing Versions ### Because the `Version` class is immutable, the _incrementors_ return a new instance of `Version` rather than modifying the given one. Each of the normal version incrementors has an overloaded method that takes a pre-release version as an argument. ~~~ java import com.github.zafarkhaja.semver.Version; Version v1 = Version.valueOf("1.2.3"); // Incrementing the major version Version v2 = v1.incrementMajorVersion(); // "2.0.0" Version v2 = v1.incrementMajorVersion("alpha"); // "2.0.0-alpha" // Incrementing the minor version Version v3 = v1.incrementMinorVersion(); // "1.3.0" Version v3 = v1.incrementMinorVersion("alpha"); // "1.3.0-alpha" // Incrementing the patch version Version v4 = v1.incrementPatchVersion(); // "1.2.4" Version v4 = v1.incrementPatchVersion("alpha"); // "1.2.4-alpha" // Original Version is still the same String str = v1.toString(); // "1.2.3" ~~~ There are also incrementor methods for the pre-release version and the build metadata. ~~~ java import com.github.zafarkhaja.semver.Version; // Incrementing the pre-release version Version v1 = Version.valueOf("1.2.3-rc"); // considered as "rc.0" Version v2 = v1.incrementPreReleaseVersion(); // "1.2.3-rc.1" Version v3 = v2.incrementPreReleaseVersion(); // "1.2.3-rc.2" // Incrementing the build metadata Version v1 = Version.valueOf("1.2.3-rc+build"); // considered as "build.0" Version v2 = v1.incrementBuildMetadata(); // "1.2.3-rc+build.1" Version v3 = v2.incrementBuildMetadata(); // "1.2.3-rc+build.2" ~~~ When incrementing the normal or pre-release versions the build metadata is always dropped. ~~~ java import com.github.zafarkhaja.semver.Version; Version v1 = Version.valueOf("1.2.3-beta+build"); // Incrementing the normal version Version v2 = v1.incrementMajorVersion(); // "2.0.0" Version v2 = v1.incrementMajorVersion("alpha"); // "2.0.0-alpha" Version v3 = v1.incrementMinorVersion(); // "1.3.0" Version v3 = v1.incrementMinorVersion("alpha"); // "1.3.0-alpha" Version v4 = v1.incrementPatchVersion(); // "1.2.4" Version v4 = v1.incrementPatchVersion("alpha"); // "1.2.4-alpha" // Incrementing the pre-release version Version v2 = v1.incrementPreReleaseVersion(); // "1.2.3-beta.1" ~~~ **NOTE**: The discussion page https://github.com/mojombo/semver/issues/60 might be of good use in better understanding some of the decisions made regarding the incrementor methods. ### Comparing Versions ### Comparing versions with Java SemVer is easy. The `Version` class implements the `Comparable` interface, it also overrides the `Object.equals` method and provides some more methods for convenient comparing. ~~~ java import com.github.zafarkhaja.semver.Version; Version v1 = Version.valueOf("1.0.0-rc.1+build.1"); Version v2 = Version.valueOf("1.3.7+build.2.b8f12d7"); int result = v1.compareTo(v2); // < 0 boolean result = v1.equals(v2); // false boolean result = v1.greaterThan(v2); // false boolean result = v1.greaterThanOrEqualTo(v2); // false boolean result = v1.lessThan(v2); // true boolean result = v1.lessThanOrEqualTo(v2); // true ~~~ When determining version precedence the build metadata is ignored (SemVer p.10). ~~~ java import com.github.zafarkhaja.semver.Version; Version v1 = Version.valueOf("1.0.0+build.1"); Version v2 = Version.valueOf("1.0.0+build.2"); int result = v1.compareTo(v2); // = 0 boolean result = v1.equals(v2); // true ~~~ Sometimes, however, you might want to compare versions with the build metadata in mind. For such cases Java SemVer provides a _comparator_ `Version.BUILD_AWARE_ORDER` and a convenience method `Version.compareWithBuildsTo`. ~~~ java import com.github.zafarkhaja.semver.Version; Version v1 = Version.valueOf("1.0.0+build.1"); Version v2 = Version.valueOf("1.0.0+build.2"); int result = Version.BUILD_AWARE_ORDER.compare(v1, v2); // < 0 int result = v1.compareTo(v2); // = 0 boolean result = v1.equals(v2); // true int result = v1.compareWithBuildsTo(v2); // < 0 ~~~ SemVer Expressions API (Ranges) ---------------------- Java SemVer supports the SemVer Expressions API which is implemented as both internal DSL and external DSL. The entry point for the API are the `Version.satisfies` methods. ### Internal DSL ### The internal DSL is implemented by the `CompositeExpression` class using fluent interface. For convenience, it also provides the `Helper` class with static helper methods. ~~~ java import com.github.zafarkhaja.semver.Version; import static com.github.zafarkhaja.semver.expr.CompositeExpression.Helper.*; Version v = Version.valueOf("1.0.0-beta"); boolean result = v.satisfies(gte("1.0.0").and(lt("2.0.0"))); // false ~~~ ### External DSL ### The BNF grammar for the external DSL can be found in the corresponding [issue](https://github.com/zafarkhaja/jsemver/issues/1). ~~~ java import com.github.zafarkhaja.semver.Version; Version v = Version.valueOf("1.0.0-beta"); boolean result = v.satisfies(">=1.0.0 & <2.0.0"); // false ~~~ Below are examples of some common use cases, as well as syntactic sugar and some other interesting capabilities of the SemVer Expressions external DSL. * Wildcard Ranges (`*`|`X`|`x`) - `1.*` which is equivalent to `>=1.0.0 & <2.0.0` * Tilde Ranges (`~`) - `~1.5` which is equivalent to `>=1.5.0 & <1.6.0` * Hyphen Ranges (`-`) - `1.0-2.0` which is equivalent to `>=1.0.0 & <=2.0.0` * Caret Ranges (`^`) - `^0.2.3` which is equivalent to `>=0.2.3 & <0.3.0` * Partial Version Ranges - `1` which is equivalent to `1.X` or `>=1.0.0 & <2.0.0` * Negation operator - `!(1.x)` which is equivalent to `<1.0.0 & >=2.0.0` * Parenthesized expressions - `~1.3 | (1.4.* & !=1.4.5) | ~2` Exception Handling ------------------ There are two types of errors that may arrise while using Java SemVer * `IllegalArgumentException` is thrown when the passed value is `NULL` or empty if a method accepts `string` argument or a negative integer if a method accepts `int` arguments. * `ParseException` is thrown by methods that perform parsing of SemVer version strings or SemVer Expressions. There are few subtypes of the `ParseException` error - `UnexpectedCharacterException` is thrown when a SemVer version string contains an unexpected or illegal character - `LexerException` is thrown when a SemVer Expression contains an illegal character - `UnexpectedTokenException` is thrown when an unexpected token is encountered during the SemVer Expression parsing Bugs and Features ----------------- Bug reports and feature requests can be submitted at https://github.com/zafarkhaja/jsemver/issues. License ------- Java SemVer is licensed under the MIT License - see the `LICENSE` file for details. jsemver-0.9.0/pom.xml000066400000000000000000000042551250261441700145200ustar00rootroot00000000000000 4.0.0 org.sonatype.oss oss-parent 9 com.github.zafarkhaja java-semver 0.9.0 jar Java SemVer Java implementation of the SemVer Specification https://github.com/zafarkhaja/jsemver The MIT License http://www.opensource.org/licenses/mit-license.php repo zafarkhaja Zafar Khaja zafarkhaja@gmail.com +3 https://github.com/zafarkhaja/jsemver scm:git:git://github.com/zafarkhaja/jsemver.git scm:git:ssh://git@github.com/zafarkhaja/jsemver.git junit junit 4.12 test org.apache.maven.plugins maven-compiler-plugin 3.2 1.6 1.6 UTF-8 -Xlint:all org.apache.maven.plugins maven-javadoc-plugin 2.10.2 -Xdoclint:none jsemver-0.9.0/src/000077500000000000000000000000001250261441700137645ustar00rootroot00000000000000jsemver-0.9.0/src/main/000077500000000000000000000000001250261441700147105ustar00rootroot00000000000000jsemver-0.9.0/src/main/java/000077500000000000000000000000001250261441700156315ustar00rootroot00000000000000jsemver-0.9.0/src/main/java/com/000077500000000000000000000000001250261441700164075ustar00rootroot00000000000000jsemver-0.9.0/src/main/java/com/github/000077500000000000000000000000001250261441700176715ustar00rootroot00000000000000jsemver-0.9.0/src/main/java/com/github/zafarkhaja/000077500000000000000000000000001250261441700217735ustar00rootroot00000000000000jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/000077500000000000000000000000001250261441700232745ustar00rootroot00000000000000jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/MetadataVersion.java000066400000000000000000000161711250261441700272330ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver; import java.util.Arrays; /** * The {@code MetadataVersion} class is used to represent * the pre-release version and the build metadata. * * @author Zafar Khaja * @since 0.2.0 */ class MetadataVersion implements Comparable { /** * Null metadata, the implementation of the Null Object design pattern. */ static final MetadataVersion NULL = new NullMetadataVersion(); /** * The implementation of the Null Object design pattern. */ private static class NullMetadataVersion extends MetadataVersion { /** * Constructs a {@code NullMetadataVersion} instance. */ public NullMetadataVersion() { super(null); } /** * @throws NullPointerException as Null metadata cannot be incremented */ @Override MetadataVersion increment() { throw new NullPointerException("Metadata version is NULL"); } /** * {@inheritDoc} */ @Override public String toString() { return ""; } /** * {@inheritDoc} */ @Override public int hashCode() { return 0; } /** * {@inheritDoc} */ @Override public boolean equals(Object other) { return other instanceof NullMetadataVersion; } /** * {@inheritDoc} */ @Override public int compareTo(MetadataVersion other) { if (!equals(other)) { /** * Pre-release versions have a lower precedence than * the associated normal version. (SemVer p.9) */ return 1; } return 0; } } /** * The array containing the version's identifiers. */ private final String[] idents; /** * Constructs a {@code MetadataVersion} instance with identifiers. * @param identifiers the version's identifiers */ MetadataVersion(String[] identifiers) { idents = identifiers; } /** * Increments the metadata version. * * @return a new instance of the {@code MetadataVersion} class */ MetadataVersion increment() { String[] ids = idents; String lastId = ids[ids.length - 1]; if (isInt(lastId)) { int intId = Integer.parseInt(lastId); ids[ids.length - 1] = String.valueOf(++intId); } else { ids = Arrays.copyOf(ids, ids.length + 1); ids[ids.length - 1] = String.valueOf(1); } return new MetadataVersion(ids); } /** * {@inheritDoc} */ @Override public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof MetadataVersion)) { return false; } return compareTo((MetadataVersion) other) == 0; } /** * {@inheritDoc} */ @Override public int hashCode() { return Arrays.hashCode(idents); } /** * {@inheritDoc} */ @Override public String toString() { StringBuilder sb = new StringBuilder(); for (String ident : idents) { sb.append(ident).append("."); } return sb.deleteCharAt(sb.lastIndexOf(".")).toString(); } /** * {@inheritDoc} */ @Override public int compareTo(MetadataVersion other) { if (other == MetadataVersion.NULL) { /** * Pre-release versions have a lower precedence than * the associated normal version. (SemVer p.9) */ return -1; } int result = compareIdentifierArrays(other.idents); if (result == 0) { /** * A larger set of pre-release fields has a higher * precedence than a smaller set, if all of the * preceding identifiers are equal. (SemVer p.11) */ result = idents.length - other.idents.length; } return result; } /** * Compares two arrays of identifiers. * * @param otherIdents the identifiers of the other version * @return integer result of comparison compatible with * the {@code Comparable.compareTo} method */ private int compareIdentifierArrays(String[] otherIdents) { int result = 0; int length = getLeastCommonArrayLength(idents, otherIdents); for (int i = 0; i < length; i++) { result = compareIdentifiers(idents[i], otherIdents[i]); if (result != 0) { break; } } return result; } /** * Returns the size of the smallest array. * * @param arr1 the first array * @param arr2 the second array * @return the size of the smallest array */ private int getLeastCommonArrayLength(String[] arr1, String[] arr2) { return arr1.length <= arr2.length ? arr1.length : arr2.length; } /** * Compares two identifiers. * * @param ident1 the first identifier * @param ident2 the second identifier * @return integer result of comparison compatible with * the {@code Comparable.compareTo} method */ private int compareIdentifiers(String ident1, String ident2) { if (isInt(ident1) && isInt(ident2)) { return Integer.parseInt(ident1) - Integer.parseInt(ident2); } else { return ident1.compareTo(ident2); } } /** * Checks if the specified string is an integer. * * @param str the string to check * @return {@code true} if the specified string is an integer * or {@code false} otherwise */ private boolean isInt(String str) { try { Integer.parseInt(str); } catch (NumberFormatException e) { return false; } return true; } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/NormalVersion.java000066400000000000000000000114401250261441700267350ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver; /** * The {@code NormalVersion} class represents the version core. * * This class is immutable and hence thread-safe. * * @author Zafar Khaja * @since 0.2.0 */ class NormalVersion implements Comparable { /** * The major version number. */ private final int major; /** * The minor version number. */ private final int minor; /** * The patch version number. */ private final int patch; /** * Constructs a {@code NormalVersion} with the * major, minor and patch version numbers. * * @param major the major version number * @param minor the minor version number * @param patch the patch version number * @throws IllegalArgumentException if one of the version numbers is a negative integer */ NormalVersion(int major, int minor, int patch) { if (major < 0 || minor < 0 || patch < 0) { throw new IllegalArgumentException( "Major, minor and patch versions MUST be non-negative integers." ); } this.major = major; this.minor = minor; this.patch = patch; } /** * Returns the major version number. * * @return the major version number */ int getMajor() { return major; } /** * Returns the minor version number. * * @return the minor version number */ int getMinor() { return minor; } /** * Returns the patch version number. * * @return the patch version number */ int getPatch() { return patch; } /** * Increments the major version number. * * @return a new instance of the {@code NormalVersion} class */ NormalVersion incrementMajor() { return new NormalVersion(major + 1, 0, 0); } /** * Increments the minor version number. * * @return a new instance of the {@code NormalVersion} class */ NormalVersion incrementMinor() { return new NormalVersion(major, minor + 1, 0); } /** * Increments the patch version number. * * @return a new instance of the {@code NormalVersion} class */ NormalVersion incrementPatch() { return new NormalVersion(major, minor, patch + 1); } /** * {@inheritDoc} */ @Override public int compareTo(NormalVersion other) { int result = major - other.major; if (result == 0) { result = minor - other.minor; if (result == 0) { result = patch - other.patch; } } return result; } /** * {@inheritDoc} */ @Override public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof NormalVersion)) { return false; } return compareTo((NormalVersion) other) == 0; } /** * {@inheritDoc} */ @Override public int hashCode() { int hash = 17; hash = 31 * hash + major; hash = 31 * hash + minor; hash = 31 * hash + patch; return hash; } /** * Returns the string representation of this normal version. * * A normal version number MUST take the form X.Y.Z where X, Y, and Z are * non-negative integers. X is the major version, Y is the minor version, * and Z is the patch version. (SemVer p.2) * * @return the string representation of this normal version */ @Override public String toString() { return String.format("%d.%d.%d", major, minor, patch); } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/ParseException.java000066400000000000000000000050101250261441700270640ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver; /** * Thrown to indicate an error during the parsing. * * @author Zafar Khaja * @since 0.7.0 */ public class ParseException extends RuntimeException { /** * Constructs a {@code ParseException} instance with no error message. */ public ParseException() { super(); } /** * Constructs a {@code ParseException} instance with an error message. * * @param message the error message */ public ParseException(String message) { super(message); } /** * Constructs a {@code ParseException} instance with an error message * and the cause exception. * * @param message the error message * @param cause an exception that caused this exception */ public ParseException(String message, UnexpectedCharacterException cause) { super(message); initCause(cause); } /** * Returns the string representation of this exception. * * @return the string representation of this exception */ @Override public String toString() { Throwable cause = getCause(); String msg = getMessage(); if (msg != null) { msg += ((cause != null) ? " (" + cause.toString() + ")" : ""); return msg; } return ((cause != null) ? cause.toString() : ""); } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/Parser.java000066400000000000000000000030011250261441700253650ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver; /** * A parser interface. * * @param the type of parser's output * * @author Zafar Khaja * @since 0.7.0 */ public interface Parser { /** * Parses the input string. * * @param input the string to parse * @return the Abstract Syntax Tree */ T parse(String input); } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/UnexpectedCharacterException.java000066400000000000000000000102131250261441700317340ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver; import com.github.zafarkhaja.semver.VersionParser.CharType; import com.github.zafarkhaja.semver.util.UnexpectedElementException; import java.util.Arrays; /** * Thrown when attempting to consume a character of unexpected types. * * This exception is a wrapper exception extending {@code ParseException}. * * @author Zafar Khaja * @since 0.8.0 */ public class UnexpectedCharacterException extends ParseException { /** * The unexpected character. */ private final Character unexpected; /** * The position of the unexpected character. */ private final int position; /** * The array of expected character types. */ private final CharType[] expected; /** * Constructs a {@code UnexpectedCharacterException} instance with * the wrapped {@code UnexpectedElementException} exception. * * @param cause the wrapped exception */ UnexpectedCharacterException(UnexpectedElementException cause) { position = cause.getPosition(); unexpected = (Character) cause.getUnexpectedElement(); expected = (CharType[]) cause.getExpectedElementTypes(); } /** * Constructs a {@code UnexpectedCharacterException} instance * with the unexpected character, its position and the expected types. * * @param unexpected the unexpected character * @param position the position of the unexpected character * @param expected an array of the expected character types */ UnexpectedCharacterException( Character unexpected, int position, CharType... expected ) { this.unexpected = unexpected; this.position = position; this.expected = expected; } /** * Gets the unexpected character. * * @return the unexpected character */ Character getUnexpectedCharacter() { return unexpected; } /** * Gets the position of the unexpected character. * * @return the position of the unexpected character */ int getPosition() { return position; } /** * Gets the expected character types. * * @return an array of expected character types */ CharType[] getExpectedCharTypes() { return expected; } /** * Returns the string representation of this exception * containing the information about the unexpected * element and, if available, about the expected types. * * @return the string representation of this exception */ @Override public String toString() { String message = String.format( "Unexpected character '%s(%s)' at position '%d'", CharType.forCharacter(unexpected), unexpected, position ); if (expected.length > 0) { message += String.format( ", expecting '%s'", Arrays.toString(expected) ); } return message; } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/Version.java000066400000000000000000000507271250261441700255770ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver; import com.github.zafarkhaja.semver.expr.Expression; import com.github.zafarkhaja.semver.expr.ExpressionParser; import com.github.zafarkhaja.semver.expr.LexerException; import com.github.zafarkhaja.semver.expr.UnexpectedTokenException; import java.util.Comparator; /** * The {@code Version} class is the main class of the Java SemVer library. * * This class implements the Facade design pattern. * It is also immutable, which makes the class thread-safe. * * @author Zafar Khaja * @since 0.1.0 */ public class Version implements Comparable { /** * The normal version. */ private final NormalVersion normal; /** * The pre-release version. */ private final MetadataVersion preRelease; /** * The build metadata. */ private final MetadataVersion build; /** * A separator that separates the pre-release * version from the normal version. */ private static final String PRE_RELEASE_PREFIX = "-"; /** * A separator that separates the build metadata from * the normal version or the pre-release version. */ private static final String BUILD_PREFIX = "+"; /** * A mutable builder for the immutable {@code Version} class. */ public static class Builder { /** * The normal version string. */ private String normal; /** * The pre-release version string. */ private String preRelease; /** * The build metadata string. */ private String build; /** * Constructs a {@code Builder} instance. */ public Builder() { } /** * Constructs a {@code Builder} instance with the * string representation of the normal version. * * @param normal the string representation of the normal version */ public Builder(String normal) { this.normal = normal; } /** * Sets the normal version. * * @param normal the string representation of the normal version * @return this builder instance */ public Builder setNormalVersion(String normal) { this.normal = normal; return this; } /** * Sets the pre-release version. * * @param preRelease the string representation of the pre-release version * @return this builder instance */ public Builder setPreReleaseVersion(String preRelease) { this.preRelease = preRelease; return this; } /** * Sets the build metadata. * * @param build the string representation of the build metadata * @return this builder instance */ public Builder setBuildMetadata(String build) { this.build = build; return this; } /** * Builds a {@code Version} object. * * @return a newly built {@code Version} instance * @throws ParseException when invalid version string is provided * @throws UnexpectedCharacterException is a special case of {@code ParseException} */ public Version build() { StringBuilder sb = new StringBuilder(); if (isFilled(normal)) { sb.append(normal); } if (isFilled(preRelease)) { sb.append(PRE_RELEASE_PREFIX).append(preRelease); } if (isFilled(build)) { sb.append(BUILD_PREFIX).append(build); } return VersionParser.parseValidSemVer(sb.toString()); } /** * Checks if a string has a usable value. * * @param str the string to check * @return {@code true} if the string is filled or {@code false} otherwise */ private boolean isFilled(String str) { return str != null && !str.isEmpty(); } } /** * A comparator that respects the build metadata when comparing versions. */ public static final Comparator BUILD_AWARE_ORDER = new BuildAwareOrder(); /** * A build-aware comparator. */ private static class BuildAwareOrder implements Comparator { /** * Compares two {@code Version} instances taking * into account their build metadata. * * When compared build metadata is divided into identifiers. The * numeric identifiers are compared numerically, and the alphanumeric * identifiers are compared in the ASCII sort order. * * If one of the compared versions has no defined build * metadata, this version is considered to have a lower * precedence than that of the other. * * @return {@inheritDoc} */ @Override public int compare(Version v1, Version v2) { int result = v1.compareTo(v2); if (result == 0) { result = v1.build.compareTo(v2.build); if (v1.build == MetadataVersion.NULL || v2.build == MetadataVersion.NULL ) { /** * Build metadata should have a higher precedence * than the associated normal version which is the * opposite compared to pre-release versions. */ result = -1 * result; } } return result; } } /** * Constructs a {@code Version} instance with the normal version. * * @param normal the normal version */ Version(NormalVersion normal) { this(normal, MetadataVersion.NULL, MetadataVersion.NULL); } /** * Constructs a {@code Version} instance with the * normal version and the pre-release version. * * @param normal the normal version * @param preRelease the pre-release version */ Version(NormalVersion normal, MetadataVersion preRelease) { this(normal, preRelease, MetadataVersion.NULL); } /** * Constructs a {@code Version} instance with the normal * version, the pre-release version and the build metadata. * * @param normal the normal version * @param preRelease the pre-release version * @param build the build metadata */ Version( NormalVersion normal, MetadataVersion preRelease, MetadataVersion build ) { this.normal = normal; this.preRelease = preRelease; this.build = build; } /** * Creates a new instance of {@code Version} as a * result of parsing the specified version string. * * @param version the version string to parse * @return a new instance of the {@code Version} class * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when invalid version string is provided * @throws UnexpectedCharacterException is a special case of {@code ParseException} */ public static Version valueOf(String version) { return VersionParser.parseValidSemVer(version); } /** * Creates a new instance of {@code Version} * for the specified version numbers. * * @param major the major version number * @return a new instance of the {@code Version} class * @throws IllegalArgumentException if a negative integer is passed * @since 0.7.0 */ public static Version forIntegers(int major) { return new Version(new NormalVersion(major, 0, 0)); } /** * Creates a new instance of {@code Version} * for the specified version numbers. * * @param major the major version number * @param minor the minor version number * @return a new instance of the {@code Version} class * @throws IllegalArgumentException if a negative integer is passed * @since 0.7.0 */ public static Version forIntegers(int major, int minor) { return new Version(new NormalVersion(major, minor, 0)); } /** * Creates a new instance of {@code Version} * for the specified version numbers. * * @param major the major version number * @param minor the minor version number * @param patch the patch version number * @return a new instance of the {@code Version} class * @throws IllegalArgumentException if a negative integer is passed * @since 0.7.0 */ public static Version forIntegers(int major, int minor, int patch) { return new Version(new NormalVersion(major, minor, patch)); } /** * Checks if this version satisfies the specified SemVer Expression string. * * This method is a part of the SemVer Expressions API. * * @param expr the SemVer Expression string * @return {@code true} if this version satisfies the specified * SemVer Expression or {@code false} otherwise * @throws ParseException in case of a general parse error * @throws LexerException when encounters an illegal character * @throws UnexpectedTokenException when comes across an unexpected token * @since 0.7.0 */ public boolean satisfies(String expr) { Parser parser = ExpressionParser.newInstance(); return satisfies(parser.parse(expr)); } /** * Checks if this version satisfies the specified SemVer Expression. * * This method is a part of the SemVer Expressions API. * * @param expr the SemVer Expression * @return {@code true} if this version satisfies the specified * SemVer Expression or {@code false} otherwise * @since 0.9.0 */ public boolean satisfies(Expression expr) { return expr.interpret(this); } /** * Increments the major version. * * @return a new instance of the {@code Version} class */ public Version incrementMajorVersion() { return new Version(normal.incrementMajor()); } /** * Increments the major version and appends the pre-release version. * * @param preRelease the pre-release version to append * @return a new instance of the {@code Version} class * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when invalid version string is provided * @throws UnexpectedCharacterException is a special case of {@code ParseException} */ public Version incrementMajorVersion(String preRelease) { return new Version( normal.incrementMajor(), VersionParser.parsePreRelease(preRelease) ); } /** * Increments the minor version. * * @return a new instance of the {@code Version} class */ public Version incrementMinorVersion() { return new Version(normal.incrementMinor()); } /** * Increments the minor version and appends the pre-release version. * * @param preRelease the pre-release version to append * @return a new instance of the {@code Version} class * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when invalid version string is provided * @throws UnexpectedCharacterException is a special case of {@code ParseException} */ public Version incrementMinorVersion(String preRelease) { return new Version( normal.incrementMinor(), VersionParser.parsePreRelease(preRelease) ); } /** * Increments the patch version. * * @return a new instance of the {@code Version} class */ public Version incrementPatchVersion() { return new Version(normal.incrementPatch()); } /** * Increments the patch version and appends the pre-release version. * * @param preRelease the pre-release version to append * @return a new instance of the {@code Version} class * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when invalid version string is provided * @throws UnexpectedCharacterException is a special case of {@code ParseException} */ public Version incrementPatchVersion(String preRelease) { return new Version( normal.incrementPatch(), VersionParser.parsePreRelease(preRelease) ); } /** * Increments the pre-release version. * * @return a new instance of the {@code Version} class */ public Version incrementPreReleaseVersion() { return new Version(normal, preRelease.increment()); } /** * Increments the build metadata. * * @return a new instance of the {@code Version} class */ public Version incrementBuildMetadata() { return new Version(normal, preRelease, build.increment()); } /** * Sets the pre-release version. * * @param preRelease the pre-release version to set * @return a new instance of the {@code Version} class * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when invalid version string is provided * @throws UnexpectedCharacterException is a special case of {@code ParseException} */ public Version setPreReleaseVersion(String preRelease) { return new Version(normal, VersionParser.parsePreRelease(preRelease)); } /** * Sets the build metadata. * * @param build the build metadata to set * @return a new instance of the {@code Version} class * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when invalid version string is provided * @throws UnexpectedCharacterException is a special case of {@code ParseException} */ public Version setBuildMetadata(String build) { return new Version(normal, preRelease, VersionParser.parseBuild(build)); } /** * Returns the major version number. * * @return the major version number */ public int getMajorVersion() { return normal.getMajor(); } /** * Returns the minor version number. * * @return the minor version number */ public int getMinorVersion() { return normal.getMinor(); } /** * Returns the patch version number. * * @return the patch version number */ public int getPatchVersion() { return normal.getPatch(); } /** * Returns the string representation of the normal version. * * @return the string representation of the normal version */ public String getNormalVersion() { return normal.toString(); } /** * Returns the string representation of the pre-release version. * * @return the string representation of the pre-release version */ public String getPreReleaseVersion() { return preRelease.toString(); } /** * Returns the string representation of the build metadata. * * @return the string representation of the build metadata */ public String getBuildMetadata() { return build.toString(); } /** * Checks if this version is greater than the other version. * * @param other the other version to compare to * @return {@code true} if this version is greater than the other version * or {@code false} otherwise * @see #compareTo(Version other) */ public boolean greaterThan(Version other) { return compareTo(other) > 0; } /** * Checks if this version is greater than or equal to the other version. * * @param other the other version to compare to * @return {@code true} if this version is greater than or equal * to the other version or {@code false} otherwise * @see #compareTo(Version other) */ public boolean greaterThanOrEqualTo(Version other) { return compareTo(other) >= 0; } /** * Checks if this version is less than the other version. * * @param other the other version to compare to * @return {@code true} if this version is less than the other version * or {@code false} otherwise * @see #compareTo(Version other) */ public boolean lessThan(Version other) { return compareTo(other) < 0; } /** * Checks if this version is less than or equal to the other version. * * @param other the other version to compare to * @return {@code true} if this version is less than or equal * to the other version or {@code false} otherwise * @see #compareTo(Version other) */ public boolean lessThanOrEqualTo(Version other) { return compareTo(other) <= 0; } /** * Checks if this version equals the other version. * * The comparison is done by the {@code Version.compareTo} method. * * @param other the other version to compare to * @return {@code true} if this version equals the other version * or {@code false} otherwise * @see #compareTo(Version other) */ @Override public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof Version)) { return false; } return compareTo((Version) other) == 0; } /** * {@inheritDoc} */ @Override public int hashCode() { int hash = 5; hash = 97 * hash + normal.hashCode(); hash = 97 * hash + preRelease.hashCode(); return hash; } /** * {@inheritDoc} */ @Override public String toString() { StringBuilder sb = new StringBuilder(getNormalVersion()); if (!getPreReleaseVersion().isEmpty()) { sb.append(PRE_RELEASE_PREFIX).append(getPreReleaseVersion()); } if (!getBuildMetadata().isEmpty()) { sb.append(BUILD_PREFIX).append(getBuildMetadata()); } return sb.toString(); } /** * Compares this version to the other version. * * This method does not take into account the versions' build * metadata. If you want to compare the versions' build metadata * use the {@code Version.compareWithBuildsTo} method or the * {@code Version.BUILD_AWARE_ORDER} comparator. * * @param other the other version to compare to * @return a negative integer, zero or a positive integer if this version * is less than, equal to or greater the the specified version * @see #BUILD_AWARE_ORDER * @see #compareWithBuildsTo(Version other) */ @Override public int compareTo(Version other) { int result = normal.compareTo(other.normal); if (result == 0) { result = preRelease.compareTo(other.preRelease); } return result; } /** * Compare this version to the other version * taking into account the build metadata. * * The method makes use of the {@code Version.BUILD_AWARE_ORDER} comparator. * * @param other the other version to compare to * @return integer result of comparison compatible with * that of the {@code Comparable.compareTo} method * @see #BUILD_AWARE_ORDER */ public int compareWithBuildsTo(Version other) { return BUILD_AWARE_ORDER.compare(this, other); } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/VersionParser.java000066400000000000000000000410321250261441700267410ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver; import com.github.zafarkhaja.semver.util.Stream; import com.github.zafarkhaja.semver.util.UnexpectedElementException; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import static com.github.zafarkhaja.semver.VersionParser.CharType.*; /** * A parser for the SemVer Version. * * @author Zafar Khaja * @since 0.7.0 */ class VersionParser implements Parser { /** * Valid character types. */ static enum CharType implements Stream.ElementType { DIGIT { /** * {@inheritDoc} */ @Override public boolean isMatchedBy(Character chr) { if (chr == null) { return false; } return chr >= '0' && chr <= '9'; } }, LETTER { /** * {@inheritDoc} */ @Override public boolean isMatchedBy(Character chr) { if (chr == null) { return false; } return (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z'); } }, DOT { /** * {@inheritDoc} */ @Override public boolean isMatchedBy(Character chr) { if (chr == null) { return false; } return chr == '.'; } }, HYPHEN { /** * {@inheritDoc} */ @Override public boolean isMatchedBy(Character chr) { if (chr == null) { return false; } return chr == '-'; } }, PLUS { /** * {@inheritDoc} */ @Override public boolean isMatchedBy(Character chr) { if (chr == null) { return false; } return chr == '+'; } }, EOI { /** * {@inheritDoc} */ @Override public boolean isMatchedBy(Character chr) { return chr == null; } }, ILLEGAL { /** * {@inheritDoc} */ @Override public boolean isMatchedBy(Character chr) { EnumSet itself = EnumSet.of(ILLEGAL); for (CharType type : EnumSet.complementOf(itself)) { if (type.isMatchedBy(chr)) { return false; } } return true; } }; /** * Gets the type for a given character. * * @param chr the character to get the type for * @return the type of the specified character */ static CharType forCharacter(Character chr) { for (CharType type : values()) { if (type.isMatchedBy(chr)) { return type; } } return null; } } /** * The stream of characters. */ private final Stream chars; /** * Constructs a {@code VersionParser} instance * with the input string to parse. * * @param input the input string to parse * @throws IllegalArgumentException if the input string is {@code NULL} or empty */ VersionParser(String input) { if (input == null || input.isEmpty()) { throw new IllegalArgumentException("Input string is NULL or empty"); } Character[] elements = new Character[input.length()]; for (int i = 0; i < input.length(); i++) { elements[i] = input.charAt(i); } chars = new Stream(elements); } /** * Parses the input string. * * @param input the input string to parse * @return a valid version object * @throws ParseException when there is a grammar error * @throws UnexpectedCharacterException when encounters an unexpected character type */ @Override public Version parse(String input) { return parseValidSemVer(); } /** * Parses the whole version including pre-release version and build metadata. * * @param version the version string to parse * @return a valid version object * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when there is a grammar error * @throws UnexpectedCharacterException when encounters an unexpected character type */ static Version parseValidSemVer(String version) { VersionParser parser = new VersionParser(version); return parser.parseValidSemVer(); } /** * Parses the version core. * * @param versionCore the version core string to parse * @return a valid normal version object * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when there is a grammar error * @throws UnexpectedCharacterException when encounters an unexpected character type */ static NormalVersion parseVersionCore(String versionCore) { VersionParser parser = new VersionParser(versionCore); return parser.parseVersionCore(); } /** * Parses the pre-release version. * * @param preRelease the pre-release version string to parse * @return a valid pre-release version object * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when there is a grammar error * @throws UnexpectedCharacterException when encounters an unexpected character type */ static MetadataVersion parsePreRelease(String preRelease) { VersionParser parser = new VersionParser(preRelease); return parser.parsePreRelease(); } /** * Parses the build metadata. * * @param build the build metadata string to parse * @return a valid build metadata object * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when there is a grammar error * @throws UnexpectedCharacterException when encounters an unexpected character type */ static MetadataVersion parseBuild(String build) { VersionParser parser = new VersionParser(build); return parser.parseBuild(); } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::= 
     *                  |  "-" 
     *                  |  "+" 
     *                  |  "-"  "+" 
     * }
     * 
* * @return a valid version object */ private Version parseValidSemVer() { NormalVersion normal = parseVersionCore(); MetadataVersion preRelease = MetadataVersion.NULL; MetadataVersion build = MetadataVersion.NULL; Character next = consumeNextCharacter(HYPHEN, PLUS, EOI); if (HYPHEN.isMatchedBy(next)) { preRelease = parsePreRelease(); next = consumeNextCharacter(PLUS, EOI); if (PLUS.isMatchedBy(next)) { build = parseBuild(); } } else if (PLUS.isMatchedBy(next)) { build = parseBuild(); } consumeNextCharacter(EOI); return new Version(normal, preRelease, build); } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::=  "."  "." 
     * }
     * 
* * @return a valid normal version object */ private NormalVersion parseVersionCore() { int major = Integer.parseInt(numericIdentifier()); consumeNextCharacter(DOT); int minor = Integer.parseInt(numericIdentifier()); consumeNextCharacter(DOT); int patch = Integer.parseInt(numericIdentifier()); return new NormalVersion(major, minor, patch); } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::= 
     *
     *  ::= 
     *    |  "." 
     * }
     * 
* * @return a valid pre-release version object */ private MetadataVersion parsePreRelease() { ensureValidLookahead(DIGIT, LETTER, HYPHEN); List idents = new ArrayList(); do { idents.add(preReleaseIdentifier()); if (chars.positiveLookahead(DOT)) { consumeNextCharacter(DOT); continue; } break; } while (true); return new MetadataVersion(idents.toArray(new String[idents.size()])); } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::= 
     *                            | 
     * }
     * 
* * @return a single pre-release identifier */ private String preReleaseIdentifier() { checkForEmptyIdentifier(); CharType boundary = nearestCharType(DOT, PLUS, EOI); if (chars.positiveLookaheadBefore(boundary, LETTER, HYPHEN)) { return alphanumericIdentifier(); } else { return numericIdentifier(); } } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::= 
     *
     *  ::= 
     *                |  "." 
     * }
     * 
* * @return a valid build metadata object */ private MetadataVersion parseBuild() { ensureValidLookahead(DIGIT, LETTER, HYPHEN); List idents = new ArrayList(); do { idents.add(buildIdentifier()); if (chars.positiveLookahead(DOT)) { consumeNextCharacter(DOT); continue; } break; } while (true); return new MetadataVersion(idents.toArray(new String[idents.size()])); } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::= 
     *                      | 
     * }
     * 
* * @return a single build identifier */ private String buildIdentifier() { checkForEmptyIdentifier(); CharType boundary = nearestCharType(DOT, EOI); if (chars.positiveLookaheadBefore(boundary, LETTER, HYPHEN)) { return alphanumericIdentifier(); } else { return digits(); } } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::= "0"
     *                        | 
     *                        |  
     * }
     * 
* * @return a string representing the numeric identifier */ private String numericIdentifier() { checkForLeadingZeroes(); return digits(); } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::= 
     *             |  
     *             |  
     *             |   
     * }
     * 
* * @return a string representing the alphanumeric identifier */ private String alphanumericIdentifier() { StringBuilder sb = new StringBuilder(); do { sb.append(consumeNextCharacter(DIGIT, LETTER, HYPHEN)); } while (chars.positiveLookahead(DIGIT, LETTER, HYPHEN)); return sb.toString(); } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::= 
     *            |  
     * }
     * 
* * @return a string representing the digits */ private String digits() { StringBuilder sb = new StringBuilder(); do { sb.append(consumeNextCharacter(DIGIT)); } while (chars.positiveLookahead(DIGIT)); return sb.toString(); } /** * Finds the nearest character type. * * @param types the character types to choose from * @return the nearest character type or {@code EOI} */ private CharType nearestCharType(CharType... types) { for (Character chr : chars) { for (CharType type : types) { if (type.isMatchedBy(chr)) { return type; } } } return EOI; } /** * Checks for leading zeroes in the numeric identifiers. * * @throws ParseException if a numeric identifier has leading zero(es) */ private void checkForLeadingZeroes() { Character la1 = chars.lookahead(1); Character la2 = chars.lookahead(2); if (la1 != null && la1 == '0' && DIGIT.isMatchedBy(la2)) { throw new ParseException( "Numeric identifier MUST NOT contain leading zeroes" ); } } /** * Checks for empty identifiers in the pre-release version or build metadata. * * @throws ParseException if the pre-release version or build * metadata have empty identifier(s) */ private void checkForEmptyIdentifier() { Character la = chars.lookahead(1); if (DOT.isMatchedBy(la) || PLUS.isMatchedBy(la) || EOI.isMatchedBy(la)) { throw new ParseException( "Identifiers MUST NOT be empty", new UnexpectedCharacterException( la, chars.currentOffset(), DIGIT, LETTER, HYPHEN ) ); } } /** * Tries to consume the next character in the stream. * * @param expected the expected types of the next character * @return the next character in the stream * @throws UnexpectedCharacterException when encounters an unexpected character type */ private Character consumeNextCharacter(CharType... expected) { try { return chars.consume(expected); } catch (UnexpectedElementException e) { throw new UnexpectedCharacterException(e); } } /** * Checks if the next character in the stream is valid. * * @param expected the expected types of the next character * @throws UnexpectedCharacterException if the next character is not valid */ private void ensureValidLookahead(CharType... expected) { if (!chars.positiveLookahead(expected)) { throw new UnexpectedCharacterException( chars.lookahead(1), chars.currentOffset(), expected ); } } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/000077500000000000000000000000001250261441700242525ustar00rootroot00000000000000jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/And.java000066400000000000000000000044211250261441700256200ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** * Expression for the logical "and" operator. * * @author Zafar Khaja * @since 0.7.0 */ class And implements Expression { /** * The left-hand operand of expression. */ private final Expression left; /** * The right-hand operand of expression. */ private final Expression right; /** * Constructs a {@code And} expression with * the left-hand and right-hand operands. * * @param left the left-hand operand of expression * @param right the right-hand operand of expression */ And(Expression left, Expression right) { this.left = left; this.right = right; } /** * Checks if both operands evaluate to {@code true}. * * @param version the version to interpret against * @return {@code true} if both operands evaluate to {@code true} * or {@code false} otherwise */ @Override public boolean interpret(Version version) { return left.interpret(version) && right.interpret(version); } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/CompositeExpression.java000066400000000000000000000237311250261441700311450ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.ParseException; import com.github.zafarkhaja.semver.UnexpectedCharacterException; import com.github.zafarkhaja.semver.Version; /** * This class implements internal DSL for the * SemVer Expressions using fluent interface. * * @author Zafar Khaja * @since 0.9.0 */ public class CompositeExpression implements Expression { /** * A class with static helper methods. */ public static class Helper { /** * Creates a {@code CompositeExpression} with * an underlying {@code Not} expression. * * @param expr an {@code Expression} to negate * @return a newly created {@code CompositeExpression} */ public static CompositeExpression not(Expression expr) { return new CompositeExpression(new Not(expr)); } /** * Creates a {@code CompositeExpression} with * an underlying {@code Equal} expression. * * @param version a {@code Version} to check for equality * @return a newly created {@code CompositeExpression} */ public static CompositeExpression eq(Version version) { return new CompositeExpression(new Equal(version)); } /** * Creates a {@code CompositeExpression} with * an underlying {@code Equal} expression. * * @param version a {@code Version} string to check for equality * @return a newly created {@code CompositeExpression} * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when invalid version string is provided * @throws UnexpectedCharacterException is a special case of {@code ParseException} */ public static CompositeExpression eq(String version) { return eq(Version.valueOf(version)); } /** * Creates a {@code CompositeExpression} with * an underlying {@code NotEqual} expression. * * @param version a {@code Version} to check for non-equality * @return a newly created {@code CompositeExpression} */ public static CompositeExpression neq(Version version) { return new CompositeExpression(new NotEqual(version)); } /** * Creates a {@code CompositeExpression} with * an underlying {@code NotEqual} expression. * * @param version a {@code Version} string to check for non-equality * @return a newly created {@code CompositeExpression} * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when invalid version string is provided * @throws UnexpectedCharacterException is a special case of {@code ParseException} */ public static CompositeExpression neq(String version) { return neq(Version.valueOf(version)); } /** * Creates a {@code CompositeExpression} with * an underlying {@code Greater} expression. * * @param version a {@code Version} to compare with * @return a newly created {@code CompositeExpression} */ public static CompositeExpression gt(Version version) { return new CompositeExpression(new Greater(version)); } /** * Creates a {@code CompositeExpression} with * an underlying {@code Greater} expression. * * @param version a {@code Version} string to compare with * @return a newly created {@code CompositeExpression} * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when invalid version string is provided * @throws UnexpectedCharacterException is a special case of {@code ParseException} */ public static CompositeExpression gt(String version) { return gt(Version.valueOf(version)); } /** * Creates a {@code CompositeExpression} with an * underlying {@code GreaterOrEqual} expression. * * @param version a {@code Version} to compare with * @return a newly created {@code CompositeExpression} */ public static CompositeExpression gte(Version version) { return new CompositeExpression(new GreaterOrEqual(version)); } /** * Creates a {@code CompositeExpression} with an * underlying {@code GreaterOrEqual} expression. * * @param version a {@code Version} string to compare with * @return a newly created {@code CompositeExpression} * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when invalid version string is provided * @throws UnexpectedCharacterException is a special case of {@code ParseException} */ public static CompositeExpression gte(String version) { return gte(Version.valueOf(version)); } /** * Creates a {@code CompositeExpression} with * an underlying {@code Less} expression. * * @param version a {@code Version} to compare with * @return a newly created {@code CompositeExpression} */ public static CompositeExpression lt(Version version) { return new CompositeExpression(new Less(version)); } /** * Creates a {@code CompositeExpression} with * an underlying {@code Less} expression. * * @param version a {@code Version} string to compare with * @return a newly created {@code CompositeExpression} * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when invalid version string is provided * @throws UnexpectedCharacterException is a special case of {@code ParseException} */ public static CompositeExpression lt(String version) { return lt(Version.valueOf(version)); } /** * Creates a {@code CompositeExpression} with an * underlying {@code LessOrEqual} expression. * * @param version a {@code Version} to compare with * @return a newly created {@code CompositeExpression} */ public static CompositeExpression lte(Version version) { return new CompositeExpression(new LessOrEqual(version)); } /** * Creates a {@code CompositeExpression} with an * underlying {@code LessOrEqual} expression. * * @param version a {@code Version} string to compare with * @return a newly created {@code CompositeExpression} * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when invalid version string is provided * @throws UnexpectedCharacterException is a special case of {@code ParseException} */ public static CompositeExpression lte(String version) { return lte(Version.valueOf(version)); } } /** * The underlying expression tree. */ private Expression exprTree; /** * Constructs a {@code CompositeExpression} * with an underlying {@code Expression}. * * @param expr the underlying expression */ public CompositeExpression(Expression expr) { exprTree = expr; } /** * Adds another {@code Expression} to {@code CompositeExpression} * using {@code And} logical expression. * * @param expr an expression to add * @return this {@code CompositeExpression} */ public CompositeExpression and(Expression expr) { exprTree = new And(exprTree, expr); return this; } /** * Adds another {@code Expression} to {@code CompositeExpression} * using {@code Or} logical expression. * * @param expr an expression to add * @return this {@code CompositeExpression} */ public CompositeExpression or(Expression expr) { exprTree = new Or(exprTree, expr); return this; } /** * Interprets the expression. * * @param version a {@code Version} string to interpret against * @return the result of the expression interpretation * @throws IllegalArgumentException if the input string is {@code NULL} or empty * @throws ParseException when invalid version string is provided * @throws UnexpectedCharacterException is a special case of {@code ParseException} */ public boolean interpret(String version) { return interpret(Version.valueOf(version)); } /** * {@inheritDoc} */ @Override public boolean interpret(Version version) { return exprTree.interpret(version); } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/Equal.java000066400000000000000000000042341250261441700261670ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** * Expression for the comparison "equal" operator. * * @author Zafar Khaja * @since 0.7.0 */ class Equal implements Expression { /** * The parsed version, the right-hand operand of the "equal" operator. */ private final Version parsedVersion; /** * Constructs a {@code Equal} expression with the parsed version. * * @param parsedVersion the parsed version */ Equal(Version parsedVersion) { this.parsedVersion = parsedVersion; } /** * Checks if the current version equals the parsed version. * * @param version the version to compare to, the left-hand * operand of the "equal" operator * @return {@code true} if the version equals the * parsed version or {@code false} otherwise */ @Override public boolean interpret(Version version) { return version.equals(parsedVersion); } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/Expression.java000066400000000000000000000032721250261441700272600ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** * The {@code Expression} interface is to be implemented * by the nodes of the Abstract Syntax Tree produced by * the {@code ExpressionParser} class. * * @author Zafar Khaja * @since 0.7.0 */ public interface Expression { /** * Interprets the expression. * * @param version the version to interpret against * @return the result of the expression interpretation */ boolean interpret(Version version); } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/ExpressionParser.java000066400000000000000000000402601250261441700304330ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Parser; import com.github.zafarkhaja.semver.Version; import com.github.zafarkhaja.semver.expr.Lexer.Token; import com.github.zafarkhaja.semver.util.Stream; import com.github.zafarkhaja.semver.util.Stream.ElementType; import com.github.zafarkhaja.semver.util.UnexpectedElementException; import java.util.EnumSet; import java.util.Iterator; import static com.github.zafarkhaja.semver.expr.CompositeExpression.Helper.*; import static com.github.zafarkhaja.semver.expr.Lexer.Token.Type.*; /** * A parser for the SemVer Expressions. * * @author Zafar Khaja * @since 0.7.0 */ public class ExpressionParser implements Parser { /** * The lexer instance used for tokenization of the input string. */ private final Lexer lexer; /** * The stream of tokens produced by the lexer. */ private Stream tokens; /** * Constructs a {@code ExpressionParser} instance * with the corresponding lexer. * * @param lexer the lexer to use for tokenization of the input string */ ExpressionParser(Lexer lexer) { this.lexer = lexer; } /** * Creates and returns new instance of the {@code ExpressionParser} class. * * This method implements the Static Factory Method pattern. * * @return a new instance of the {@code ExpressionParser} class */ public static Parser newInstance() { return new ExpressionParser(new Lexer()); } /** * Parses the SemVer Expressions. * * @param input a string representing the SemVer Expression * @return the AST for the SemVer Expressions * @throws LexerException when encounters an illegal character * @throws UnexpectedTokenException when consumes a token of an unexpected type */ @Override public Expression parse(String input) { tokens = lexer.tokenize(input); Expression expr = parseSemVerExpression(); consumeNextToken(EOI); return expr; } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::= "("  ")"
     *                 | "!" "("  ")"
     *                 |  
     *                 | 
     * }
     * 
* * @return the expression AST */ private CompositeExpression parseSemVerExpression() { CompositeExpression expr; if (tokens.positiveLookahead(NOT)) { tokens.consume(); consumeNextToken(LEFT_PAREN); expr = not(parseSemVerExpression()); consumeNextToken(RIGHT_PAREN); } else if (tokens.positiveLookahead(LEFT_PAREN)) { consumeNextToken(LEFT_PAREN); expr = parseSemVerExpression(); consumeNextToken(RIGHT_PAREN); } else { expr = parseRange(); } return parseMoreExpressions(expr); } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::=   | epsilon
     * }
     * 
* * @param expr the left-hand expression of the logical operators * @return the expression AST */ private CompositeExpression parseMoreExpressions(CompositeExpression expr) { if (tokens.positiveLookahead(AND)) { tokens.consume(); expr = expr.and(parseSemVerExpression()); } else if (tokens.positiveLookahead(OR)) { tokens.consume(); expr = expr.or(parseSemVerExpression()); } return expr; } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::= 
     *          | 
     *          | 
     *          | 
     *          | 
     *          | 
     * }
     * 
* * @return the expression AST */ private CompositeExpression parseRange() { if (tokens.positiveLookahead(TILDE)) { return parseTildeRange(); } else if (tokens.positiveLookahead(CARET)) { return parseCaretRange(); } else if (isWildcardRange()) { return parseWildcardRange(); } else if (isHyphenRange()) { return parseHyphenRange(); } else if (isPartialVersionRange()) { return parsePartialVersionRange(); } return parseComparisonRange(); } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::=   | 
     * }
     * 
* * @return the expression AST */ private CompositeExpression parseComparisonRange() { Token token = tokens.lookahead(); CompositeExpression expr; switch (token.type) { case EQUAL: tokens.consume(); expr = eq(parseVersion()); break; case NOT_EQUAL: tokens.consume(); expr = neq(parseVersion()); break; case GREATER: tokens.consume(); expr = gt(parseVersion()); break; case GREATER_EQUAL: tokens.consume(); expr = gte(parseVersion()); break; case LESS: tokens.consume(); expr = lt(parseVersion()); break; case LESS_EQUAL: tokens.consume(); expr = lte(parseVersion()); break; default: expr = eq(parseVersion()); } return expr; } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::= "~" 
     * }
     * 
* * @return the expression AST */ private CompositeExpression parseTildeRange() { consumeNextToken(TILDE); int major = intOf(consumeNextToken(NUMERIC).lexeme); if (!tokens.positiveLookahead(DOT)) { return gte(versionFor(major)).and(lt(versionFor(major + 1))); } consumeNextToken(DOT); int minor = intOf(consumeNextToken(NUMERIC).lexeme); if (!tokens.positiveLookahead(DOT)) { return gte(versionFor(major, minor)).and(lt(versionFor(major, minor + 1))); } consumeNextToken(DOT); int patch = intOf(consumeNextToken(NUMERIC).lexeme); return gte(versionFor(major, minor, patch)).and(lt(versionFor(major, minor + 1))); } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::= "^" 
     * }
     * 
* * @return the expression AST */ private CompositeExpression parseCaretRange() { consumeNextToken(CARET); int major = intOf(consumeNextToken(NUMERIC).lexeme); if (!tokens.positiveLookahead(DOT)) { return gte(versionFor(major)).and(lt(versionFor(major + 1))); } consumeNextToken(DOT); int minor = intOf(consumeNextToken(NUMERIC).lexeme); if (!tokens.positiveLookahead(DOT)) { Version lower = versionFor(major, minor); Version upper = major > 0 ? lower.incrementMajorVersion() : lower.incrementMinorVersion(); return gte(lower).and(lt(upper)); } consumeNextToken(DOT); int patch = intOf(consumeNextToken(NUMERIC).lexeme); Version version = versionFor(major, minor, patch); CompositeExpression gte = gte(version); if (major > 0) { return gte.and(lt(version.incrementMajorVersion())); } else if (minor > 0) { return gte.and(lt(version.incrementMinorVersion())); } else if (patch > 0) { return gte.and(lt(version.incrementPatchVersion())); } return eq(version); } /** * Determines if the following version terminals are part * of the {@literal } non-terminal. * * @return {@code true} if the following version terminals are * part of the {@literal } non-terminal or * {@code false} otherwise */ private boolean isWildcardRange() { return isVersionFollowedBy(WILDCARD); } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::= 
     *                    |  "." 
     *                    |  "."  "." 
     *
     *  ::= "*" | "x" | "X"
     * }
     * 
* * @return the expression AST */ private CompositeExpression parseWildcardRange() { if (tokens.positiveLookahead(WILDCARD)) { tokens.consume(); return gte(versionFor(0, 0, 0)); } int major = intOf(consumeNextToken(NUMERIC).lexeme); consumeNextToken(DOT); if (tokens.positiveLookahead(WILDCARD)) { tokens.consume(); return gte(versionFor(major)).and(lt(versionFor(major + 1))); } int minor = intOf(consumeNextToken(NUMERIC).lexeme); consumeNextToken(DOT); consumeNextToken(WILDCARD); return gte(versionFor(major, minor)).and(lt(versionFor(major, minor + 1))); } /** * Determines if the following version terminals are * part of the {@literal } non-terminal. * * @return {@code true} if the following version terminals are * part of the {@literal } non-terminal or * {@code false} otherwise */ private boolean isHyphenRange() { return isVersionFollowedBy(HYPHEN); } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::=  "-" 
     * }
     * 
* * @return the expression AST */ private CompositeExpression parseHyphenRange() { CompositeExpression gte = gte(parseVersion()); consumeNextToken(HYPHEN); return gte.and(lte(parseVersion())); } /** * Determines if the following version terminals are part * of the {@literal } non-terminal. * * @return {@code true} if the following version terminals are part * of the {@literal } non-terminal or * {@code false} otherwise */ private boolean isPartialVersionRange() { if (!tokens.positiveLookahead(NUMERIC)) { return false; } EnumSet expected = EnumSet.complementOf(EnumSet.of(NUMERIC, DOT)); return tokens.positiveLookaheadUntil(5, expected.toArray(new Token.Type[expected.size()])); } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::=  |  "." 
     * }
     * 
* * @return the expression AST */ private CompositeExpression parsePartialVersionRange() { int major = intOf(consumeNextToken(NUMERIC).lexeme); if (!tokens.positiveLookahead(DOT)) { return gte(versionFor(major)).and(lt(versionFor(major + 1))); } consumeNextToken(DOT); int minor = intOf(consumeNextToken(NUMERIC).lexeme); return gte(versionFor(major, minor)).and(lt(versionFor(major, minor + 1))); } /** * Parses the {@literal } non-terminal. * *
     * {@literal
     *  ::= 
     *             |  "." 
     *             |  "."  "." 
     * }
     * 
* * @return the parsed version */ private Version parseVersion() { int major = intOf(consumeNextToken(NUMERIC).lexeme); int minor = 0; if (tokens.positiveLookahead(DOT)) { tokens.consume(); minor = intOf(consumeNextToken(NUMERIC).lexeme); } int patch = 0; if (tokens.positiveLookahead(DOT)) { tokens.consume(); patch = intOf(consumeNextToken(NUMERIC).lexeme); } return versionFor(major, minor, patch); } /** * Determines if the version terminals are * followed by the specified token type. * * This method is essentially a {@code lookahead(k)} method * which allows to solve the grammar's ambiguities. * * @param type the token type to check * @return {@code true} if the version terminals are followed by * the specified token type or {@code false} otherwise */ private boolean isVersionFollowedBy(ElementType type) { EnumSet expected = EnumSet.of(NUMERIC, DOT); Iterator it = tokens.iterator(); Token lookahead = null; while (it.hasNext()) { lookahead = it.next(); if (!expected.contains(lookahead.type)) { break; } } return type.isMatchedBy(lookahead); } /** * Creates a {@code Version} instance for the specified major version. * * @param major the major version number * @return the version for the specified major version */ private Version versionFor(int major) { return versionFor(major, 0, 0); } /** * Creates a {@code Version} instance for * the specified major and minor versions. * * @param major the major version number * @param minor the minor version number * @return the version for the specified major and minor versions */ private Version versionFor(int major, int minor) { return versionFor(major, minor, 0); } /** * Creates a {@code Version} instance for the * specified major, minor and patch versions. * * @param major the major version number * @param minor the minor version number * @param patch the patch version number * @return the version for the specified major, minor and patch versions */ private Version versionFor(int major, int minor, int patch) { return Version.forIntegers(major, minor, patch); } /** * Returns a {@code int} representation of the specified string. * * @param value the string to convert into an integer * @return the integer value of the specified string */ private int intOf(String value) { return Integer.parseInt(value); } /** * Tries to consume the next token in the stream. * * @param expected the expected types of the next token * @return the next token in the stream * @throws UnexpectedTokenException when encounters an unexpected token type */ private Token consumeNextToken(Token.Type... expected) { try { return tokens.consume(expected); } catch (UnexpectedElementException e) { throw new UnexpectedTokenException(e); } } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/Greater.java000066400000000000000000000043251250261441700265120ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** * Expression for the comparison "greater than" operator. * * @author Zafar Khaja * @since 0.7.0 */ class Greater implements Expression { /** * The parsed version, the right-hand * operand of the "greater than" operator. */ private final Version parsedVersion; /** * Constructs a {@code Greater} expression with the parsed version. * * @param parsedVersion the parsed version */ Greater(Version parsedVersion) { this.parsedVersion = parsedVersion; } /** * Checks if the current version is greater than the parsed version. * * @param version the version to compare to, the left-hand * operand of the "greater than" operator * @return {@code true} if the version is greater than the * parsed version or {@code false} otherwise */ @Override public boolean interpret(Version version) { return version.greaterThan(parsedVersion); } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/GreaterOrEqual.java000066400000000000000000000044661250261441700300110ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** * Expression for the comparison "greater than or equal to" operator. * * @author Zafar Khaja * @since 0.7.0 */ class GreaterOrEqual implements Expression { /** * The parsed version, the right-hand operand * of the "greater than or equal to" operator. */ private final Version parsedVersion; /** * Constructs a {@code GreaterOrEqual} expression with the parsed version. * * @param parsedVersion the parsed version */ GreaterOrEqual(Version parsedVersion) { this.parsedVersion = parsedVersion; } /** * Checks if the current version is greater * than or equal to the parsed version. * * @param version the version to compare to, the left-hand operand * of the "greater than or equal to" operator * @return {@code true} if the version is greater than or equal * to the parsed version or {@code false} otherwise */ @Override public boolean interpret(Version version) { return version.greaterThanOrEqualTo(parsedVersion); } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/Less.java000066400000000000000000000042721250261441700260300ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** * Expression for the comparison "less than" operator. * * @author Zafar Khaja * @since 0.7.0 */ class Less implements Expression { /** * The parsed version, the right-hand * operand of the "less than" operator. */ private final Version parsedVersion; /** * Constructs a {@code Less} expression with the parsed version. * * @param parsedVersion the parsed version */ Less(Version parsedVersion) { this.parsedVersion = parsedVersion; } /** * Checks if the current version is less than the parsed version. * * @param version the version to compare to, the left-hand * operand of the "less than" operator * @return {@code true} if the version is less than the * parsed version or {@code false} otherwise */ @Override public boolean interpret(Version version) { return version.lessThan(parsedVersion); } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/LessOrEqual.java000066400000000000000000000044331250261441700273200ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** * Expression for the comparison "less than or equal to" operator. * * @author Zafar Khaja * @since 0.7.0 */ class LessOrEqual implements Expression { /** * The parsed version, the right-hand operand * of the "less than or equal to" operator. */ private final Version parsedVersion; /** * Constructs a {@code LessOrEqual} expression with the parsed version. * * @param parsedVersion the parsed version */ LessOrEqual(Version parsedVersion) { this.parsedVersion = parsedVersion; } /** * Checks if the current version is less * than or equal to the parsed version. * * @param version the version to compare to, the left-hand operand * of the "less than or equal to" operator * @return {@code true} if the version is less than or equal * to the parsed version or {@code false} otherwise */ @Override public boolean interpret(Version version) { return version.lessThanOrEqualTo(parsedVersion); } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/Lexer.java000066400000000000000000000147331250261441700262040ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.util.Stream; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * A lexer for the SemVer Expressions. * * @author Zafar Khaja * @since 0.7.0 */ class Lexer { /** * This class holds the information about lexemes in the input stream. */ static class Token { /** * Valid token types. */ enum Type implements Stream.ElementType { NUMERIC("0|[1-9][0-9]*"), DOT("\\."), HYPHEN("-"), EQUAL("="), NOT_EQUAL("!="), GREATER(">(?!=)"), GREATER_EQUAL(">="), LESS("<(?!=)"), LESS_EQUAL("<="), TILDE("~"), WILDCARD("[\\*xX]"), CARET("\\^"), AND("&"), OR("\\|"), NOT("!(?!=)"), LEFT_PAREN("\\("), RIGHT_PAREN("\\)"), WHITESPACE("\\s+"), EOI("?!"); /** * A pattern matching this type. */ final Pattern pattern; /** * Constructs a token type with a regular * expression for the pattern. * * @param regexp the regular expression for the pattern * @see #pattern */ private Type(String regexp) { pattern = Pattern.compile("^(" + regexp + ")"); } /** * Returns the string representation of this type. * * @return the string representation of this type */ @Override public String toString() { return name() + "(" + pattern + ")"; } /** * {@inheritDoc} */ @Override public boolean isMatchedBy(Token token) { if (token == null) { return false; } return this == token.type; } } /** * The type of this token. */ final Type type; /** * The lexeme of this token. */ final String lexeme; /** * The position of this token. */ final int position; /** * Constructs a {@code Token} instance * with the type, lexeme and position. * * @param type the type of this token * @param lexeme the lexeme of this token * @param position the position of this token */ Token(Type type, String lexeme, int position) { this.type = type; this.lexeme = (lexeme == null) ? "" : lexeme; this.position = position; } /** * {@inheritDoc} */ @Override public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof Token)) { return false; } Token token = (Token) other; return type.equals(token.type) && lexeme.equals(token.lexeme) && position == token.position; } /** * {@inheritDoc} */ @Override public int hashCode() { int hash = 5; hash = 71 * hash + type.hashCode(); hash = 71 * hash + lexeme.hashCode(); hash = 71 * hash + position; return hash; } /** * Returns the string representation of this token. * * @return the string representation of this token */ @Override public String toString() { return String.format( "%s(%s) at position %d", type.name(), lexeme, position ); } } /** * Constructs a {@code Lexer} instance. */ Lexer() { } /** * Tokenizes the specified input string. * * @param input the input string to tokenize * @return a stream of tokens * @throws LexerException when encounters an illegal character */ Stream tokenize(String input) { List tokens = new ArrayList(); int tokenPos = 0; while (!input.isEmpty()) { boolean matched = false; for (Token.Type tokenType : Token.Type.values()) { Matcher matcher = tokenType.pattern.matcher(input); if (matcher.find()) { matched = true; input = matcher.replaceFirst(""); if (tokenType != Token.Type.WHITESPACE) { tokens.add(new Token( tokenType, matcher.group(), tokenPos )); } tokenPos += matcher.end(); break; } } if (!matched) { throw new LexerException(input); } } tokens.add(new Token(Token.Type.EOI, null, tokenPos)); return new Stream(tokens.toArray(new Token[tokens.size()])); } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/LexerException.java000066400000000000000000000040661250261441700300610ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.ParseException; /** * Thrown during the lexical analysis when * an illegal character is encountered. * * @author Zafar Khaja * @since 0.7.0 */ public class LexerException extends ParseException { /** * The string being analyzed starting from an illegal character. */ private final String expr; /** * Constructs a {@code LexerException} instance with * a string starting from an illegal character. * * @param expr the string starting from an illegal character */ LexerException(String expr) { this.expr = expr; } /** * Returns the string representation of this exception. * * @return the string representation of this exception */ @Override public String toString() { return "Illegal character near '" + expr + "'"; } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/Not.java000066400000000000000000000037751250261441700256710ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** * Expression for the logical "negation" operator. * * @author Zafar Khaja * @since 0.7.0 */ class Not implements Expression { /** * The expression to negate. */ private final Expression expr; /** * Constructs a {@code Not} expression with an expression to negate. * * @param expr the expression to negate */ Not(Expression expr) { this.expr = expr; } /** * Negates the given expression. * * @param version the version to interpret against * @return {@code true} if the given expression evaluates to * {@code false} and {@code false} otherwise */ @Override public boolean interpret(Version version) { return !expr.interpret(version); } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/NotEqual.java000066400000000000000000000043041250261441700266460ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** * Expression for the comparison "not equal" operator. * * @author Zafar Khaja * @since 0.7.0 */ class NotEqual implements Expression { /** * The parsed version, the right-hand operand of the "not equal" operator. */ private final Version parsedVersion; /** * Constructs a {@code NotEqual} expression with the parsed version. * * @param parsedVersion the parsed version */ NotEqual(Version parsedVersion) { this.parsedVersion = parsedVersion; } /** * Checks if the current version does not equal the parsed version. * * @param version the version to compare with, the left-hand * operand of the "not equal" operator * @return {@code true} if the version does not equal the * parsed version or {@code false} otherwise */ @Override public boolean interpret(Version version) { return !version.equals(parsedVersion); } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/Or.java000066400000000000000000000044331250261441700255010ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** * Expression for the logical "or" operator. * * @author Zafar Khaja * @since 0.7.0 */ class Or implements Expression { /** * The left-hand operand of expression. */ private final Expression left; /** * The right-hand operand of expression. */ private final Expression right; /** * Constructs a {@code Or} expression with * the left-hand and right-hand operands. * * @param left the left-hand operand of expression * @param right the right-hand operand of expression */ Or(Expression left, Expression right) { this.left = left; this.right = right; } /** * Checks if one of the operands evaluates to {@code true}. * * @param version the version to interpret against * @return {@code true} if one of the operands evaluates to {@code true} * or {@code false} otherwise */ @Override public boolean interpret(Version version) { return left.interpret(version) || right.interpret(version); } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/UnexpectedTokenException.java000066400000000000000000000067341250261441700321130ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.ParseException; import com.github.zafarkhaja.semver.expr.Lexer.Token; import com.github.zafarkhaja.semver.util.UnexpectedElementException; import java.util.Arrays; /** * Thrown when a token of unexpected types is encountered during the parsing. * * @author Zafar Khaja * @since 0.7.0 */ public class UnexpectedTokenException extends ParseException { /** * The unexpected token. */ private final Token unexpected; /** * The array of the expected token types. */ private final Token.Type[] expected; /** * Constructs a {@code UnexpectedTokenException} instance with * the wrapped {@code UnexpectedElementException} exception. * * @param cause the wrapped exception */ UnexpectedTokenException(UnexpectedElementException cause) { unexpected = (Token) cause.getUnexpectedElement(); expected = (Token.Type[]) cause.getExpectedElementTypes(); } /** * Constructs a {@code UnexpectedTokenException} instance * with the unexpected token and the expected types. * * @param token the unexpected token * @param expected an array of the expected token types */ UnexpectedTokenException(Token token, Token.Type... expected) { unexpected = token; this.expected = expected; } /** * Gets the unexpected token. * * @return the unexpected token */ Token getUnexpectedToken() { return unexpected; } /** * Gets the expected token types. * * @return an array of expected token types */ Token.Type[] getExpectedTokenTypes() { return expected; } /** * Returns the string representation of this exception * containing the information about the unexpected * token and, if available, about the expected types. * * @return the string representation of this exception */ @Override public String toString() { String message = String.format( "Unexpected token '%s'", unexpected ); if (expected.length > 0) { message += String.format( ", expecting '%s'", Arrays.toString(expected) ); } return message; } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/expr/package-info.java000066400000000000000000000027421250261441700274460ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * This package contains classes that implement the SemVer Expressions. * * The main class of the package is the {@code ExpressionParser} class which * parses the specified expressions and returns the Abstract Syntax Tree. * * @author Zafar Khaja * @since 0.7.0 */ package com.github.zafarkhaja.semver.expr; jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/package-info.java000066400000000000000000000027311250261441700264660ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * This is the root package of the Java SemVer library. * * The package exports most of the public API. The main entry point of the * package is the {@code Version} class, which implements the Facade design * pattern. * * @author Zafar Khaja * @since 0.1.0 */ package com.github.zafarkhaja.semver; jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/util/000077500000000000000000000000001250261441700242515ustar00rootroot00000000000000jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/util/Stream.java000066400000000000000000000221301250261441700263450ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.util; import java.util.Arrays; import java.util.Iterator; import java.util.NoSuchElementException; /** * A simple stream class used to represent a stream of characters or tokens. * * @param the type of elements held in this stream * * @author Zafar Khaja * @see com.github.zafarkhaja.semver.VersionParser * @see com.github.zafarkhaja.semver.expr.Lexer * @see com.github.zafarkhaja.semver.expr.ExpressionParser * @since 0.7.0 */ public class Stream implements Iterable { /** * The {@code ElementType} interface represents types of the elements * held by this stream and can be used for stream filtering. * * @param type of elements held by this stream */ public static interface ElementType { /** * Checks if the specified element matches this type. * * @param element the element to be tested * @return {@code true} if the element matches this type * or {@code false} otherwise */ boolean isMatchedBy(E element); } /** * The array holding all the elements of this stream. */ private final E[] elements; /** * The current offset which is incremented when an element is consumed. * * @see #consume() */ private int offset = 0; /** * Constructs a stream containing the specified elements. * * The stream does not store the real elements but the defensive copy. * * @param elements the elements to be streamed */ public Stream(E[] elements) { this.elements = elements.clone(); } /** * Consumes the next element in this stream. * * @return the next element in this stream * or {@code null} if no more elements left */ public E consume() { if (offset >= elements.length) { return null; } return elements[offset++]; } /** * Consumes the next element in this stream * only if it is of the expected types. * * @param represents the element type of this stream, removes the * "unchecked generic array creation for varargs parameter" * warnings * @param expected the types which are expected * @return the next element in this stream * @throws UnexpectedElementException if the next element is of an unexpected type */ public > E consume(T... expected) { E lookahead = lookahead(1); for (ElementType type : expected) { if (type.isMatchedBy(lookahead)) { return consume(); } } throw new UnexpectedElementException(lookahead, offset, expected); } /** * Pushes back one element at a time. */ public void pushBack() { if (offset > 0) { offset--; } } /** * Returns the next element in this stream without consuming it. * * @return the next element in this stream */ public E lookahead() { return lookahead(1); } /** * Returns the element at the specified position * in this stream without consuming it. * * @param position the position of the element to return * @return the element at the specified position * or {@code null} if no more elements left */ public E lookahead(int position) { int idx = offset + position - 1; if (idx < elements.length) { return elements[idx]; } return null; } /** * Returns the current offset of this stream. * * @return the current offset of this stream */ public int currentOffset() { return offset; } /** * Checks if the next element in this stream is of the expected types. * * @param represents the element type of this stream, removes the * "unchecked generic array creation for varargs parameter" * warnings * @param expected the expected types * @return {@code true} if the next element is of the expected types * or {@code false} otherwise */ public > boolean positiveLookahead(T... expected) { for (ElementType type : expected) { if (type.isMatchedBy(lookahead(1))) { return true; } } return false; } /** * Checks if there exists an element in this stream of * the expected types before the specified type. * * @param represents the element type of this stream, removes the * "unchecked generic array creation for varargs parameter" * warnings * @param before the type before which to search * @param expected the expected types * @return {@code true} if there is an element of the expected types * before the specified type or {@code false} otherwise */ public > boolean positiveLookaheadBefore( ElementType before, T... expected ) { E lookahead; for (int i = 1; i <= elements.length; i++) { lookahead = lookahead(i); if (before.isMatchedBy(lookahead)) { break; } for (ElementType type : expected) { if (type.isMatchedBy(lookahead)) { return true; } } } return false; } /** * Checks if there is an element in this stream of * the expected types until the specified position. * * @param represents the element type of this stream, removes the * "unchecked generic array creation for varargs parameter" * warnings * @param until the position until which to search * @param expected the expected types * @return {@code true} if there is an element of the expected types * until the specified position or {@code false} otherwise */ public > boolean positiveLookaheadUntil( int until, T... expected ) { for (int i = 1; i <= until; i++) { for (ElementType type : expected) { if (type.isMatchedBy(lookahead(i))) { return true; } } } return false; } /** * Returns an iterator over elements that are left in this stream. * * @return an iterator of the remaining elements in this stream */ @Override public Iterator iterator() { return new Iterator() { /** * The index to indicate the current position * of this iterator. * * The starting point is set to the current * value of this stream's offset, so that it * doesn't iterate over consumed elements. */ private int index = offset; /** * {@inheritDoc} */ @Override public boolean hasNext() { return index < elements.length; } /** * {@inheritDoc} */ @Override public E next() { if (index >= elements.length) { throw new NoSuchElementException(); } return elements[index++]; } /** * {@inheritDoc} */ @Override public void remove() { throw new UnsupportedOperationException(); } }; } /** * Returns an array containing all of the * elements that are left in this stream. * * The returned array is a safe copy. * * @return an array containing all of elements in this stream */ public E[] toArray() { return Arrays.copyOfRange(elements, offset, elements.length); } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/util/UnexpectedElementException.java000066400000000000000000000071151250261441700324150ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.util; import com.github.zafarkhaja.semver.util.Stream.ElementType; import java.util.Arrays; /** * Thrown when attempting to consume a stream element of unexpected types. * * @author Zafar Khaja * @see Stream#consume(Stream.ElementType...) * @since 0.7.0 */ public class UnexpectedElementException extends RuntimeException { /** * The unexpected element in the stream. */ private final Object unexpected; /** * The position of the unexpected element in the stream. */ private final int position; /** * The array of the expected element types. */ private final ElementType[] expected; /** * Constructs a {@code UnexpectedElementException} instance * with the unexpected element and the expected types. * * @param element the unexpected element in the stream * @param position the position of the unexpected element * @param expected an array of the expected element types */ UnexpectedElementException( Object element, int position, ElementType... expected ) { unexpected = element; this.position = position; this.expected = expected; } /** * Gets the unexpected element. * * @return the unexpected element */ public Object getUnexpectedElement() { return unexpected; } /** * Gets the position of the unexpected element. * * @return the position of the unexpected element */ public int getPosition() { return position; } /** * Gets the expected element types. * * @return an array of expected element types */ public ElementType[] getExpectedElementTypes() { return expected; } /** * Returns the string representation of this exception * containing the information about the unexpected * element and, if available, about the expected types. * * @return the string representation of this exception */ @Override public String toString() { String message = String.format( "Unexpected element '%s' at position '%d'", unexpected, position ); if (expected.length > 0) { message += String.format( ", expecting '%s'", Arrays.toString(expected) ); } return message; } } jsemver-0.9.0/src/main/java/com/github/zafarkhaja/semver/util/package-info.java000066400000000000000000000024661250261441700274500ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2015 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /** * This package provides some useful utility classes. * * @author Zafar Khaja * @since 0.7.0 */ package com.github.zafarkhaja.semver.util; jsemver-0.9.0/src/test/000077500000000000000000000000001250261441700147435ustar00rootroot00000000000000jsemver-0.9.0/src/test/java/000077500000000000000000000000001250261441700156645ustar00rootroot00000000000000jsemver-0.9.0/src/test/java/com/000077500000000000000000000000001250261441700164425ustar00rootroot00000000000000jsemver-0.9.0/src/test/java/com/github/000077500000000000000000000000001250261441700177245ustar00rootroot00000000000000jsemver-0.9.0/src/test/java/com/github/zafarkhaja/000077500000000000000000000000001250261441700220265ustar00rootroot00000000000000jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/000077500000000000000000000000001250261441700233275ustar00rootroot00000000000000jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/MetadataVersionTest.java000066400000000000000000000220171250261441700301220ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver; import org.junit.Test; import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ @RunWith(Enclosed.class) public class MetadataVersionTest { public static class CoreFunctionalityTest { @Test public void mustCompareEachIdentifierSeparately() { MetadataVersion v1 = new MetadataVersion( new String[] {"beta", "2", "abc"} ); MetadataVersion v2 = new MetadataVersion( new String[] {"beta", "1", "edf"} ); assertTrue(0 < v1.compareTo(v2)); } @Test public void shouldCompareIdentifiersCountIfCommonIdentifiersAreEqual() { MetadataVersion v1 = new MetadataVersion( new String[] {"beta", "abc"} ); MetadataVersion v2 = new MetadataVersion( new String[] {"beta", "abc", "def"} ); assertTrue(0 > v1.compareTo(v2)); } @Test public void shouldComapareDigitsOnlyIdentifiersNumerically() { MetadataVersion v1 = new MetadataVersion( new String[] {"alpha", "123"} ); MetadataVersion v2 = new MetadataVersion( new String[] {"alpha", "321"} ); assertTrue(0 > v1.compareTo(v2)); } @Test public void shouldCompareMixedIdentifiersLexicallyInAsciiSortOrder() { MetadataVersion v1 = new MetadataVersion( new String[] {"beta", "abc"} ); MetadataVersion v2 = new MetadataVersion( new String[] {"beta", "111"} ); assertTrue(0 < v1.compareTo(v2)); } @Test public void shouldReturnNegativeWhenComparedToNullMetadataVersion() { MetadataVersion v1 = new MetadataVersion(new String[] {}); MetadataVersion v2 = MetadataVersion.NULL; assertTrue(0 > v1.compareTo(v2)); } @Test public void shouldOverrideEqualsMethod() { MetadataVersion v1 = new MetadataVersion( new String[] {"alpha", "123"} ); MetadataVersion v2 = new MetadataVersion( new String[] {"alpha", "123"} ); MetadataVersion v3 = new MetadataVersion( new String[] {"alpha", "321"} ); assertTrue(v1.equals(v2)); assertFalse(v1.equals(v3)); } @Test public void shouldProvideIncrementMethod() { MetadataVersion v1 = new MetadataVersion( new String[] {"alpha", "1"} ); MetadataVersion v2 = v1.increment(); assertEquals("alpha.2", v2.toString()); } @Test public void shouldAppendOneAsLastIdentifierIfLastOneIsAlphaNumericWhenIncrementing() { MetadataVersion v1 = new MetadataVersion( new String[] {"alpha"} ); MetadataVersion v2 = v1.increment(); assertEquals("alpha.1", v2.toString()); } @Test public void shouldBeImmutable() { MetadataVersion v1 = new MetadataVersion( new String[] {"alpha", "1"} ); MetadataVersion v2 = v1.increment(); assertNotSame(v1, v2); } } public static class NullMetadataVersionTest { @Test public void shouldReturnEmptyStringOnToString() { MetadataVersion v = MetadataVersion.NULL; assertTrue(v.toString().isEmpty()); } @Test public void shouldReturnZeroOnHashCode() { MetadataVersion v = MetadataVersion.NULL; assertEquals(0, v.hashCode()); } @Test public void shouldBeEqualOnlyToItsType() { MetadataVersion v1 = MetadataVersion.NULL; MetadataVersion v2 = MetadataVersion.NULL; MetadataVersion v3 = new MetadataVersion(new String[] {}); assertTrue(v1.equals(v2)); assertTrue(v2.equals(v1)); assertFalse(v1.equals(v3)); } @Test public void shouldReturnPositiveWhenComparedToNonNullMetadataVersion() { MetadataVersion v1 = MetadataVersion.NULL; MetadataVersion v2 = new MetadataVersion(new String[] {}); assertTrue(0 < v1.compareTo(v2)); } @Test public void shouldReturnZeroWhenComparedToNullMetadataVersion() { MetadataVersion v1 = MetadataVersion.NULL; MetadataVersion v2 = MetadataVersion.NULL; assertTrue(0 == v1.compareTo(v2)); } @Test public void shouldThrowNullPointerExceptionIfIncremented() { try { MetadataVersion.NULL.increment(); } catch (NullPointerException e) { return; } fail("Should throw NullPointerException when incremented"); } } public static class EqualsMethodTest { @Test public void shouldBeReflexive() { MetadataVersion v = new MetadataVersion( new String[] {"alpha", "123"} ); assertTrue(v.equals(v)); } @Test public void shouldBeSymmetric() { MetadataVersion v1 = new MetadataVersion( new String[] {"alpha", "123"} ); MetadataVersion v2 = new MetadataVersion( new String[] {"alpha", "123"} ); assertTrue(v1.equals(v2)); assertTrue(v2.equals(v1)); } @Test public void shouldBeTransitive() { MetadataVersion v1 = new MetadataVersion( new String[] {"alpha", "123"} ); MetadataVersion v2 = new MetadataVersion( new String[] {"alpha", "123"} ); MetadataVersion v3 = new MetadataVersion( new String[] {"alpha", "123"} ); assertTrue(v1.equals(v2)); assertTrue(v2.equals(v3)); assertTrue(v1.equals(v3)); } @Test public void shouldBeConsistent() { MetadataVersion v1 = new MetadataVersion( new String[] {"alpha", "123"} ); MetadataVersion v2 = new MetadataVersion( new String[] {"alpha", "123"} ); assertTrue(v1.equals(v2)); assertTrue(v1.equals(v2)); assertTrue(v1.equals(v2)); } @Test public void shouldReturnFalseIfOtherVersionIsOfDifferentType() { MetadataVersion v = new MetadataVersion( new String[] {"alpha", "123"} ); assertFalse(v.equals(new String("alpha.123"))); } @Test public void shouldReturnFalseIfOtherVersionIsNull() { MetadataVersion v1 = new MetadataVersion( new String[] {"alpha", "123"} ); MetadataVersion v2 = null; assertFalse(v1.equals(v2)); } } public static class HashCodeMethodTest { @Test public void shouldReturnSameHashCodeIfVersionsAreEqual() { MetadataVersion v1 = new MetadataVersion( new String[] {"alpha", "123"} ); MetadataVersion v2 = new MetadataVersion( new String[] {"alpha", "123"} ); assertTrue(v1.equals(v2)); assertEquals(v1.hashCode(), v2.hashCode()); } } public static class ToStringMethodTest { @Test public void shouldReturnStringRepresentation() { String value = "beta.abc.def"; MetadataVersion v = new MetadataVersion(value.split("\\.")); assertEquals(value, v.toString()); } } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/NormalVersionTest.java000066400000000000000000000163101250261441700276310ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver; import org.junit.Test; import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ @RunWith(Enclosed.class) public class NormalVersionTest { public static class CoreFunctionalityTest { @Test public void mustConsistOfMajorMinorAndPatchVersions() { NormalVersion v = new NormalVersion(1, 2, 3); assertEquals(1, v.getMajor()); assertEquals(2, v.getMinor()); assertEquals(3, v.getPatch()); } @Test public void mustTakeTheFormOfXDotYDotZWhereXyzAreNonNegativeIntegers() { NormalVersion v = new NormalVersion(1, 2, 3); assertEquals("1.2.3", v.toString()); } @Test public void shouldAcceptOnlyNonNegativeMajorMinorAndPatchVersions() { int[][] invalidVersions = {{-1, 2, 3}, {1, -2, 3}, {1, 2, -3}}; for (int[] versionParts : invalidVersions) { try { new NormalVersion( versionParts[0], versionParts[1], versionParts[2] ); } catch (IllegalArgumentException e) { continue; } fail("Major, minor and patch versions MUST be non-negative integers."); } } @Test public void mustIncreaseEachElementNumericallyByIncrementsOfOne() { int major = 1, minor = 2, patch = 3; NormalVersion v = new NormalVersion(major, minor, patch); NormalVersion incrementedPatch = v.incrementPatch(); assertEquals(patch + 1, incrementedPatch.getPatch()); NormalVersion incrementedMinor = v.incrementMinor(); assertEquals(minor + 1, incrementedMinor.getMinor()); NormalVersion incrementedMajor = v.incrementMajor(); assertEquals(major + 1, incrementedMajor.getMajor()); } @Test public void mustResetMinorAndPatchToZeroWhenMajorIsIncremented() { NormalVersion v = new NormalVersion(1, 2, 3); NormalVersion incremented = v.incrementMajor(); assertEquals(2, incremented.getMajor()); assertEquals(0, incremented.getMinor()); assertEquals(0, incremented.getPatch()); } @Test public void mustResetPatchToZeroWhenMinorIsIncremented() { NormalVersion v = new NormalVersion(1, 2, 3); NormalVersion incremented = v.incrementMinor(); assertEquals(1, incremented.getMajor()); assertEquals(3, incremented.getMinor()); assertEquals(0, incremented.getPatch()); } @Test public void mustCompareMajorMinorAndPatchNumerically() { NormalVersion v = new NormalVersion(1, 2, 3); assertTrue(0 < v.compareTo(new NormalVersion(0, 2, 3))); assertTrue(0 == v.compareTo(new NormalVersion(1, 2, 3))); assertTrue(0 > v.compareTo(new NormalVersion(1, 2, 4))); } @Test public void shouldOverrideEqualsMethod() { NormalVersion v1 = new NormalVersion(1, 2, 3); NormalVersion v2 = new NormalVersion(1, 2, 3); NormalVersion v3 = new NormalVersion(3, 2, 1); assertTrue(v1.equals(v2)); assertFalse(v1.equals(v3)); } @Test public void shoudBeImmutable() { NormalVersion version = new NormalVersion(1, 2, 3); NormalVersion incementedMajor = version.incrementMajor(); assertNotSame(version, incementedMajor); NormalVersion incementedMinor = version.incrementMinor(); assertNotSame(version, incementedMinor); NormalVersion incementedPatch = version.incrementPatch(); assertNotSame(version, incementedPatch); } } public static class EqualsMethodTest { @Test public void shouldBeReflexive() { NormalVersion v = new NormalVersion(1, 2, 3); assertTrue(v.equals(v)); } @Test public void shouldBeSymmetric() { NormalVersion v1 = new NormalVersion(1, 2, 3); NormalVersion v2 = new NormalVersion(1, 2, 3); assertTrue(v1.equals(v2)); assertTrue(v2.equals(v1)); } @Test public void shouldBeTransitive() { NormalVersion v1 = new NormalVersion(1, 2, 3); NormalVersion v2 = new NormalVersion(1, 2, 3); NormalVersion v3 = new NormalVersion(1, 2, 3); assertTrue(v1.equals(v2)); assertTrue(v2.equals(v3)); assertTrue(v1.equals(v3)); } @Test public void shouldBeConsistent() { NormalVersion v1 = new NormalVersion(1, 2, 3); NormalVersion v2 = new NormalVersion(1, 2, 3); assertTrue(v1.equals(v2)); assertTrue(v1.equals(v2)); assertTrue(v1.equals(v2)); } @Test public void shouldReturnFalseIfOtherVersionIsOfDifferentType() { NormalVersion v = new NormalVersion(1, 2, 3); assertFalse(v.equals(new String("1.2.3"))); } @Test public void shouldReturnFalseIfOtherVersionIsNull() { NormalVersion v1 = new NormalVersion(1, 2, 3); NormalVersion v2 = null; assertFalse(v1.equals(v2)); } } public static class HashCodeMethodTest { @Test public void shouldReturnSameHashCodeIfVersionsAreEqual() { NormalVersion v1 = new NormalVersion(1, 2, 3); NormalVersion v2 = new NormalVersion(1, 2, 3); assertTrue(v1.equals(v2)); assertEquals(v1.hashCode(), v2.hashCode()); } } public static class ToStringMethodTest { @Test public void shouldReturnStringRepresentation() { NormalVersion v = new NormalVersion(1, 2, 3); assertEquals("1.2.3", v.toString()); } } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/ParserErrorHandlingTest.java000066400000000000000000000120751250261441700307520ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver; import com.github.zafarkhaja.semver.VersionParser.CharType; import java.util.Arrays; import java.util.Collection; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import static com.github.zafarkhaja.semver.VersionParser.CharType.*; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ @RunWith(Parameterized.class) public class ParserErrorHandlingTest { private final String invalidVersion; private final Character unexpected; private final int position; private final CharType[] expected; public ParserErrorHandlingTest( String invalidVersion, Character unexpected, int position, CharType[] expected ) { this.invalidVersion = invalidVersion; this.unexpected = unexpected; this.position = position; this.expected = expected; } @Test public void shouldCorrectlyHandleParseErrors() { try { VersionParser.parseValidSemVer(invalidVersion); } catch (UnexpectedCharacterException e) { assertEquals(unexpected, e.getUnexpectedCharacter()); assertEquals(position, e.getPosition()); assertArrayEquals(expected, e.getExpectedCharTypes()); return; } catch (ParseException e) { if (e.getCause() != null) { UnexpectedCharacterException cause = (UnexpectedCharacterException) e.getCause(); assertEquals(unexpected, cause.getUnexpectedCharacter()); assertEquals(position, cause.getPosition()); assertArrayEquals(expected, cause.getExpectedCharTypes()); } return; } fail("Uncaught exception"); } @Parameters(name = "{0}") public static Collection parameters() { return Arrays.asList(new Object[][] { { "1", null, 1, new CharType[] { DOT } }, { "1 ", ' ', 1, new CharType[] { DOT } }, { "1.", null, 2, new CharType[] { DIGIT } }, { "1.2", null, 3, new CharType[] { DOT } }, { "1.2.", null, 4, new CharType[] { DIGIT } }, { "a.b.c", 'a', 0, new CharType[] { DIGIT } }, { "1.b.c", 'b', 2, new CharType[] { DIGIT } }, { "1.2.c", 'c', 4, new CharType[] { DIGIT } }, { "!.2.3", '!', 0, new CharType[] { DIGIT } }, { "1.!.3", '!', 2, new CharType[] { DIGIT } }, { "1.2.!", '!', 4, new CharType[] { DIGIT } }, { "v1.2.3", 'v', 0, new CharType[] { DIGIT } }, { "1.2.3-", null, 6, new CharType[] { DIGIT, LETTER, HYPHEN } }, { "1.2. 3", ' ', 4, new CharType[] { DIGIT } }, { "1.2.3=alpha", '=', 5, new CharType[] { HYPHEN, PLUS, EOI } }, { "1.2.3~beta", '~', 5, new CharType[] { HYPHEN, PLUS, EOI } }, { "1.2.3-be$ta", '$', 8, new CharType[] { PLUS, EOI } }, { "1.2.3+b1+b2", '+', 8, new CharType[] { EOI } }, { "1.2.3-rc!", '!', 8, new CharType[] { PLUS, EOI } }, { "1.2.3-+", '+', 6, new CharType[] { DIGIT, LETTER, HYPHEN } }, { "1.2.3-@", '@', 6, new CharType[] { DIGIT, LETTER, HYPHEN } }, { "1.2.3+@", '@', 6, new CharType[] { DIGIT, LETTER, HYPHEN } }, { "1.2.3-rc.", null, 9, new CharType[] { DIGIT, LETTER, HYPHEN } }, { "1.2.3+b.", null, 8, new CharType[] { DIGIT, LETTER, HYPHEN } }, { "1.2.3-b.+b", '+', 8, new CharType[] { DIGIT, LETTER, HYPHEN } }, { "1.2.3-rc..", '.', 9, new CharType[] { DIGIT, LETTER, HYPHEN } }, { "1.2.3-a+b..", '.', 10, new CharType[] { DIGIT, LETTER, HYPHEN } }, }); } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/VersionParserCharTypeTest.java000066400000000000000000000070701250261441700313000ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver; import com.github.zafarkhaja.semver.VersionParser.CharType; import org.junit.Test; import static com.github.zafarkhaja.semver.VersionParser.CharType.*; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ public class VersionParserCharTypeTest { @Test public void shouldBeMatchedByDigit() { assertTrue(DIGIT.isMatchedBy('0')); assertTrue(DIGIT.isMatchedBy('9')); assertFalse(DIGIT.isMatchedBy('a')); assertFalse(DIGIT.isMatchedBy('A')); } @Test public void shouldBeMatchedByLetter() { assertTrue(LETTER.isMatchedBy('a')); assertTrue(LETTER.isMatchedBy('A')); assertFalse(LETTER.isMatchedBy('0')); assertFalse(LETTER.isMatchedBy('9')); } @Test public void shouldBeMatchedByDot() { assertTrue(DOT.isMatchedBy('.')); assertFalse(DOT.isMatchedBy('-')); assertFalse(DOT.isMatchedBy('0')); assertFalse(DOT.isMatchedBy('9')); } @Test public void shouldBeMatchedByHyphen() { assertTrue(HYPHEN.isMatchedBy('-')); assertFalse(HYPHEN.isMatchedBy('+')); assertFalse(HYPHEN.isMatchedBy('a')); assertFalse(HYPHEN.isMatchedBy('0')); } @Test public void shouldBeMatchedByPlus() { assertTrue(PLUS.isMatchedBy('+')); assertFalse(PLUS.isMatchedBy('-')); assertFalse(PLUS.isMatchedBy('a')); assertFalse(PLUS.isMatchedBy('0')); } @Test public void shouldBeMatchedByEol() { assertTrue(EOI.isMatchedBy(null)); assertFalse(EOI.isMatchedBy('-')); assertFalse(EOI.isMatchedBy('a')); assertFalse(EOI.isMatchedBy('0')); } @Test public void shouldBeMatchedByIllegal() { assertTrue(ILLEGAL.isMatchedBy('!')); assertFalse(ILLEGAL.isMatchedBy('-')); assertFalse(ILLEGAL.isMatchedBy('a')); assertFalse(ILLEGAL.isMatchedBy('0')); } @Test public void shouldReturnCharTypeForCharacter() { assertEquals(DIGIT, CharType.forCharacter('1')); assertEquals(LETTER, CharType.forCharacter('a')); assertEquals(DOT, CharType.forCharacter('.')); assertEquals(HYPHEN, CharType.forCharacter('-')); assertEquals(PLUS, CharType.forCharacter('+')); assertEquals(EOI, CharType.forCharacter(null)); assertEquals(ILLEGAL, CharType.forCharacter('!')); } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/VersionParserTest.java000066400000000000000000000100351250261441700276330ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver; import org.junit.Test; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ public class VersionParserTest { @Test public void shouldParseNormalVersion() { NormalVersion version = VersionParser.parseVersionCore("1.0.0"); assertEquals(new NormalVersion(1, 0, 0), version); } @Test public void shouldRaiseErrorIfNumericIdentifierHasLeadingZeroes() { try { VersionParser.parseVersionCore("01.1.0"); } catch (ParseException e) { return; } fail("Numeric identifier MUST NOT contain leading zeroes"); } @Test public void shouldParsePreReleaseVersion() { MetadataVersion preRelease = VersionParser.parsePreRelease("beta-1.1"); assertEquals(new MetadataVersion(new String[] {"beta-1", "1"}), preRelease); } @Test public void shouldNotAllowDigitsInPreReleaseVersion() { try { VersionParser.parsePreRelease("alpha.01"); } catch (ParseException e) { return; } fail("Should not allow digits in pre-release version"); } @Test public void shouldRaiseErrorForEmptyPreReleaseIdentifier() { try { VersionParser.parsePreRelease("beta-1..1"); } catch (ParseException e) { return; } fail("Identifiers MUST NOT be empty"); } @Test public void shouldParseBuildMetadata() { MetadataVersion build = VersionParser.parseBuild("build.1"); assertEquals(new MetadataVersion(new String[] {"build", "1"}), build); } @Test public void shouldAllowDigitsInBuildMetadata() { try { VersionParser.parseBuild("build.01"); } catch (ParseException e) { fail("Should allow digits in build metadata"); } } @Test public void shouldRaiseErrorForEmptyBuildIdentifier() { try { VersionParser.parseBuild(".build.01"); } catch (ParseException e) { return; } fail("Identifiers MUST NOT be empty"); } @Test public void shouldParseValidSemVer() { VersionParser parser = new VersionParser("1.0.0-rc.2+build.05"); Version version = parser.parse(null); assertEquals( new Version( new NormalVersion(1, 0, 0), new MetadataVersion(new String[] {"rc", "2"}), new MetadataVersion(new String[] {"build", "05"}) ), version ); } @Test public void shouldRaiseErrorForIllegalInputString() { for (String illegal : new String[] { "", null }) { try { new VersionParser(illegal); } catch (IllegalArgumentException e) { continue; } fail("Should raise error for illegal input string"); } } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/VersionTest.java000066400000000000000000000417571250261441700264750ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver; import org.junit.Test; import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; import static com.github.zafarkhaja.semver.expr.CompositeExpression.Helper.gte; import static com.github.zafarkhaja.semver.expr.CompositeExpression.Helper.lt; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ @RunWith(Enclosed.class) public class VersionTest { public static class CoreFunctionalityTest { @Test public void mayHavePreReleaseFollowingPatchAppendedWithHyphen() { Version v = Version.valueOf("1.2.3-alpha"); assertEquals("alpha", v.getPreReleaseVersion()); } @Test public void preReleaseShouldHaveLowerPrecedenceThanAssociatedNormal() { Version v1 = Version.valueOf("1.3.7"); Version v2 = Version.valueOf("1.3.7-alpha"); assertTrue(0 < v1.compareTo(v2)); assertTrue(0 > v2.compareTo(v1)); } @Test public void mayHaveBuildFollowingPatchOrPreReleaseAppendedWithPlus() { Version v = Version.valueOf("1.2.3+build"); assertEquals("build", v.getBuildMetadata()); } @Test public void shouldIgnoreBuildMetadataWhenDeterminingVersionPrecedence() { Version v1 = Version.valueOf("1.3.7-beta"); Version v2 = Version.valueOf("1.3.7-beta+build.1"); Version v3 = Version.valueOf("1.3.7-beta+build.2"); assertTrue(0 == v1.compareTo(v2)); assertTrue(0 == v1.compareTo(v3)); assertTrue(0 == v2.compareTo(v3)); } @Test public void shouldHaveGreaterThanMethodReturningBoolean() { Version v1 = Version.valueOf("2.3.7"); Version v2 = Version.valueOf("1.3.7"); assertTrue(v1.greaterThan(v2)); assertFalse(v2.greaterThan(v1)); assertFalse(v1.greaterThan(v1)); } @Test public void shouldHaveGreaterThanOrEqualToMethodReturningBoolean() { Version v1 = Version.valueOf("2.3.7"); Version v2 = Version.valueOf("1.3.7"); assertTrue(v1.greaterThanOrEqualTo(v2)); assertFalse(v2.greaterThanOrEqualTo(v1)); assertTrue(v1.greaterThanOrEqualTo(v1)); } @Test public void shouldHaveLessThanMethodReturningBoolean() { Version v1 = Version.valueOf("2.3.7"); Version v2 = Version.valueOf("1.3.7"); assertFalse(v1.lessThan(v2)); assertTrue(v2.lessThan(v1)); assertFalse(v1.lessThan(v1)); } @Test public void shouldHaveLessThanOrEqualToMethodReturningBoolean() { Version v1 = Version.valueOf("2.3.7"); Version v2 = Version.valueOf("1.3.7"); assertFalse(v1.lessThanOrEqualTo(v2)); assertTrue(v2.lessThanOrEqualTo(v1)); assertTrue(v1.lessThanOrEqualTo(v1)); } @Test public void shouldOverrideEqualsMethod() { Version v1 = Version.valueOf("2.3.7"); Version v2 = Version.valueOf("2.3.7"); Version v3 = Version.valueOf("1.3.7"); assertTrue(v1.equals(v1)); assertTrue(v1.equals(v2)); assertFalse(v1.equals(v3)); } @Test public void shouldCorrectlyCompareAllVersionsFromSpecification() { String[] versions = { "1.0.0-alpha", "1.0.0-alpha.1", "1.0.0-alpha.beta", "1.0.0-beta", "1.0.0-beta.2", "1.0.0-beta.11", "1.0.0-rc.1", "1.0.0", "2.0.0", "2.1.0", "2.1.1" }; for (int i = 1; i < versions.length; i++) { Version v1 = Version.valueOf(versions[i-1]); Version v2 = Version.valueOf(versions[i]); assertTrue(v1.lessThan(v2)); } } @Test public void shouldHaveStaticFactoryMethod() { Version v = Version.valueOf("1.0.0-rc.1+build.1"); assertEquals(1, v.getMajorVersion()); assertEquals(0, v.getMinorVersion()); assertEquals(0, v.getPatchVersion()); assertEquals("1.0.0", v.getNormalVersion()); assertEquals("rc.1", v.getPreReleaseVersion()); assertEquals("build.1", v.getBuildMetadata()); } @Test public void shouldProvideIncrementMajorVersionMethod() { Version v = Version.valueOf("1.2.3"); Version incrementedMajor = v.incrementMajorVersion(); assertEquals("2.0.0", incrementedMajor.toString()); } @Test public void shouldIncrementMajorVersionWithPreReleaseIfProvided() { Version v = Version.valueOf("1.2.3"); Version incrementedMajor = v.incrementMajorVersion("beta"); assertEquals("2.0.0-beta", incrementedMajor.toString()); } @Test public void shouldProvideIncrementMinorVersionMethod() { Version v = Version.valueOf("1.2.3"); Version incrementedMinor = v.incrementMinorVersion(); assertEquals("1.3.0", incrementedMinor.toString()); } @Test public void shouldIncrementMinorVersionWithPreReleaseIfProvided() { Version v = Version.valueOf("1.2.3"); Version incrementedMinor = v.incrementMinorVersion("alpha"); assertEquals("1.3.0-alpha", incrementedMinor.toString()); } @Test public void shouldProvideIncrementPatchVersionMethod() { Version v = Version.valueOf("1.2.3"); Version incrementedPatch = v.incrementPatchVersion(); assertEquals("1.2.4", incrementedPatch.toString()); } @Test public void shouldIncrementPatchVersionWithPreReleaseIfProvided() { Version v = Version.valueOf("1.2.3"); Version incrementedPatch = v.incrementPatchVersion("rc"); assertEquals("1.2.4-rc", incrementedPatch.toString()); } @Test public void shouldDropBuildMetadataWhenIncrementing() { Version v = Version.valueOf("1.2.3-alpha+build"); Version major1 = v.incrementMajorVersion(); assertEquals("2.0.0", major1.toString()); Version major2 = v.incrementMajorVersion("beta"); assertEquals("2.0.0-beta", major2.toString()); Version minor1 = v.incrementMinorVersion(); assertEquals("1.3.0", minor1.toString()); Version minor2 = v.incrementMinorVersion("beta"); assertEquals("1.3.0-beta", minor2.toString()); Version patch1 = v.incrementPatchVersion(); assertEquals("1.2.4", patch1.toString()); Version patch2 = v.incrementPatchVersion("beta"); assertEquals("1.2.4-beta", patch2.toString()); } @Test public void shouldProvideSetPreReleaseVersionMethod() { Version v1 = Version.valueOf("1.0.0"); Version v2 = v1.setPreReleaseVersion("alpha"); assertEquals("1.0.0-alpha", v2.toString()); } @Test public void shouldDropBuildMetadataWhenSettingPreReleaseVersion() { Version v1 = Version.valueOf("1.0.0-alpha+build"); Version v2 = v1.setPreReleaseVersion("beta"); assertEquals("1.0.0-beta", v2.toString()); } @Test public void shouldProvideSetBuildMetadataMethod() { Version v1 = Version.valueOf("1.0.0"); Version v2 = v1.setBuildMetadata("build"); assertEquals("1.0.0+build", v2.toString()); } @Test public void shouldProvideIncrementPreReleaseVersionMethod() { Version v1 = Version.valueOf("1.0.0-beta.1"); Version v2 = v1.incrementPreReleaseVersion(); assertEquals("1.0.0-beta.2", v2.toString()); } @Test public void shouldThrowExceptionWhenIncrementingPreReleaseIfItsNull() { Version v1 = Version.valueOf("1.0.0"); try { v1.incrementPreReleaseVersion(); } catch (NullPointerException e) { return; } fail("Method was expected to throw NullPointerException"); } @Test public void shouldDropBuildMetadataWhenIncrementingPreReleaseVersion() { Version v1 = Version.valueOf("1.0.0-beta.1+build"); Version v2 = v1.incrementPreReleaseVersion(); assertEquals("1.0.0-beta.2", v2.toString()); } @Test public void shouldProvideIncrementBuildMetadataMethod() { Version v1 = Version.valueOf("1.0.0+build.1"); Version v2 = v1.incrementBuildMetadata(); assertEquals("1.0.0+build.2", v2.toString()); } @Test public void shouldThrowExceptionWhenIncrementingBuildIfItsNull() { Version v1 = Version.valueOf("1.0.0"); try { v1.incrementBuildMetadata(); } catch (NullPointerException e) { return; } fail("Method was expected to throw NullPointerException"); } @Test public void shouldBeImmutable() { Version version = Version.valueOf("1.2.3-alpha+build"); Version incementedMajor = version.incrementMajorVersion(); assertNotSame(version, incementedMajor); Version incementedMinor = version.incrementMinorVersion(); assertNotSame(version, incementedMinor); Version incementedPatch = version.incrementPatchVersion(); assertNotSame(version, incementedPatch); Version preReleaseSet = version.setPreReleaseVersion("alpha"); assertNotSame(version, preReleaseSet); Version buildSet = version.setBuildMetadata("build"); assertNotSame(version, buildSet); Version incrementedPreRelease = version.incrementPreReleaseVersion(); assertNotSame(version, incrementedPreRelease); Version incrementedBuild = version.incrementBuildMetadata(); assertNotSame(version, incrementedBuild); } @Test public void shouldBeAbleToCompareWithoutIgnoringBuildMetadata() { Version v1 = Version.valueOf("1.3.7-beta+build.1"); Version v2 = Version.valueOf("1.3.7-beta+build.2"); assertTrue(0 == v1.compareTo(v2)); assertTrue(0 > v1.compareWithBuildsTo(v2)); } @Test public void shouldCheckIfVersionSatisfiesExpression() { Version v = Version.valueOf("2.0.0-beta"); assertTrue(v.satisfies(gte("1.0.0").and(lt("2.0.0")))); assertFalse(v.satisfies(gte("2.0.0").and(lt("3.0.0")))); } } public static class EqualsMethodTest { @Test public void shouldBeReflexive() { Version v1 = Version.valueOf("2.3.7"); assertTrue(v1.equals(v1)); } @Test public void shouldBeSymmetric() { Version v1 = Version.valueOf("2.3.7"); Version v2 = Version.valueOf("2.3.7"); assertTrue(v1.equals(v2)); assertTrue(v2.equals(v1)); } @Test public void shouldBeTransitive() { Version v1 = Version.valueOf("2.3.7"); Version v2 = Version.valueOf("2.3.7"); Version v3 = Version.valueOf("2.3.7"); assertTrue(v1.equals(v2)); assertTrue(v2.equals(v3)); assertTrue(v1.equals(v3)); } @Test public void shouldBeConsistent() { Version v1 = Version.valueOf("2.3.7"); Version v2 = Version.valueOf("2.3.7"); assertTrue(v1.equals(v2)); assertTrue(v1.equals(v2)); assertTrue(v1.equals(v2)); } @Test public void shouldReturnFalseIfOtherVersionIsOfDifferentType() { Version v1 = Version.valueOf("2.3.7"); assertFalse(v1.equals(new String("2.3.7"))); } @Test public void shouldReturnFalseIfOtherVersionIsNull() { Version v1 = Version.valueOf("2.3.7"); Version v2 = null; assertFalse(v1.equals(v2)); } @Test public void shouldIgnoreBuildMetadataWhenCheckingForEquality() { Version v1 = Version.valueOf("2.3.7-beta+build"); Version v2 = Version.valueOf("2.3.7-beta"); assertTrue(v1.equals(v2)); } } public static class HashCodeMethodTest { @Test public void shouldReturnSameHashCodeIfVersionsAreEqual() { Version v1 = Version.valueOf("2.3.7-beta+build"); Version v2 = Version.valueOf("2.3.7-beta"); assertTrue(v1.equals(v2)); assertEquals(v1.hashCode(), v2.hashCode()); } } public static class ToStringMethodTest { @Test public void shouldReturnStringRepresentation() { String value = "1.2.3-beta+build"; Version v = Version.valueOf(value); assertEquals(value, v.toString()); } } public static class BuilderTest { @Test public void shouldBuildVersionInSteps() { Version.Builder builder = new Version.Builder(); builder.setNormalVersion("1.0.0"); builder.setPreReleaseVersion("alpha"); builder.setBuildMetadata("build"); assertEquals(Version.valueOf("1.0.0-alpha+build"), builder.build()); } @Test public void shouldBuildVersionFromNormalVersion() { Version.Builder builder = new Version.Builder("1.0.0"); assertEquals(Version.valueOf("1.0.0"), builder.build()); } @Test public void shouldBuildVersionWithPreReleaseVersion() { Version.Builder builder = new Version.Builder("1.0.0"); builder.setPreReleaseVersion("alpha"); assertEquals(Version.valueOf("1.0.0-alpha"), builder.build()); } @Test public void shouldBuildVersionWithBuildMetadata() { Version.Builder builder = new Version.Builder("1.0.0"); builder.setBuildMetadata("build"); assertEquals(Version.valueOf("1.0.0+build"), builder.build()); } @Test public void shouldBuildVersionWithPreReleaseVersionAndBuildMetadata() { Version.Builder builder = new Version.Builder("1.0.0"); builder.setPreReleaseVersion("alpha"); builder.setBuildMetadata("build"); assertEquals(Version.valueOf("1.0.0-alpha+build"), builder.build()); } @Test public void shouldImplementFluentInterface() { Version.Builder builder = new Version.Builder(); Version version = builder .setNormalVersion("1.0.0") .setPreReleaseVersion("alpha") .setBuildMetadata("build") .build(); assertEquals(Version.valueOf("1.0.0-alpha+build"), version); } } public static class BuildAwareOrderTest { @Test public void shouldCorrectlyCompareAllVersionsWithBuildMetadata() { String[] versions = { "1.0.0-alpha", "1.0.0-alpha.1", "1.0.0-beta.2", "1.0.0-beta.11", "1.0.0-rc.1", "1.0.0-rc.1+build.1", "1.0.0", "1.0.0+0.3.7", "1.3.7+build", "1.3.7+build.2.b8f12d7", "1.3.7+build.11.e0f985a" }; for (int i = 1; i < versions.length; i++) { Version v1 = Version.valueOf(versions[i-1]); Version v2 = Version.valueOf(versions[i]); assertTrue(0 > Version.BUILD_AWARE_ORDER.compare(v1, v2)); } } } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/expr/000077500000000000000000000000001250261441700243055ustar00rootroot00000000000000jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/expr/AndTest.java000066400000000000000000000035641250261441700265220ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; import org.junit.Test; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ public class AndTest { @Test public void shouldCheckIfBothExpressionsEvaluateToTrue() { Expression left = new Expression() { @Override public boolean interpret(Version version) { return true; } }; Expression right = new Expression() { @Override public boolean interpret(Version version) { return true; } }; And and = new And(left, right); assertTrue(and.interpret(null)); } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/expr/CompositeExpressionTest.java000066400000000000000000000075121250261441700320370ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import org.junit.Test; import static com.github.zafarkhaja.semver.expr.CompositeExpression.Helper.*; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ public class CompositeExpressionTest { @Test public void shouldSupportEqualExpression() { assertTrue(eq("1.0.0").interpret("1.0.0")); assertFalse(eq("1.0.0").interpret("2.0.0")); } @Test public void shouldSupportNotEqualExpression() { assertTrue(neq("1.0.0").interpret("2.0.0")); } @Test public void shouldSupportGreaterExpression() { assertTrue(gt("1.0.0").interpret("2.0.0")); assertFalse(gt("2.0.0").interpret("1.0.0")); } @Test public void shouldSupportGreaterOrEqualExpression() { assertTrue(gte("1.0.0").interpret("1.0.0")); assertTrue(gte("1.0.0").interpret("2.0.0")); assertFalse(gte("2.0.0").interpret("1.0.0")); } @Test public void shouldSupportLessExpression() { assertTrue(lt("2.0.0").interpret("1.0.0")); assertFalse(lt("1.0.0").interpret("2.0.0")); } @Test public void shouldSupportLessOrEqualExpression() { assertTrue(lte("1.0.0").interpret("1.0.0")); assertTrue(lte("2.0.0").interpret("1.0.0")); assertFalse(lte("1.0.0").interpret("2.0.0")); } @Test public void shouldSupportNotExpression() { assertTrue(not(eq("1.0.0")).interpret("2.0.0")); assertFalse(not(eq("1.0.0")).interpret("1.0.0")); } @Test public void shouldSupportAndExpression() { assertTrue(gt("1.0.0").and(lt("2.0.0")).interpret("1.5.0")); assertFalse(gt("1.0.0").and(lt("2.0.0")).interpret("2.5.0")); } @Test public void shouldSupportOrExpression() { assertTrue(lt("1.0.0").or(gt("1.0.0")).interpret("1.5.0")); assertFalse(gt("1.0.0").or(gt("2.0.0")).interpret("0.5.0")); } @Test public void shouldSupportComplexExpressions() { /* ((>=1.0.1 & <2) | (>=3.0 & <4)) & ((1-1.5) & (~1.5)) */ CompositeExpression expr = gte("1.0.1").and( lt("2.0.0").or( gte("3.0.0").and( lt("4.0.0").and( gte("1.0.0").and( lte("1.5.0").and( gte("1.5.0").and( lt("2.0.0") ) ) ) ) ) ) ); assertTrue(expr.interpret("1.5.0")); assertFalse(expr.interpret("2.5.0")); } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/expr/EqualTest.java000066400000000000000000000032241250261441700270600ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; import org.junit.Test; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ public class EqualTest { @Test public void shouldCheckIfVersionIsEqualToParsedVersion() { Version parsed = Version.valueOf("1.2.3"); Equal eq = new Equal(parsed); assertTrue(eq.interpret(Version.valueOf("1.2.3"))); assertFalse(eq.interpret(Version.valueOf("3.2.1"))); } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/expr/ExpressionParserTest.java000066400000000000000000000206201250261441700313240ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; import org.junit.Test; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ public class ExpressionParserTest { @Test public void shouldParseEqualComparisonRange() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression eq = parser.parse("=1.0.0"); assertTrue(eq.interpret(Version.valueOf("1.0.0"))); } @Test public void shouldParseEqualComparisonRangeIfOnlyFullVersionGiven() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression eq = parser.parse("1.0.0"); assertTrue(eq.interpret(Version.valueOf("1.0.0"))); } @Test public void shouldParseNotEqualComparisonRange() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression ne = parser.parse("!=1.0.0"); assertTrue(ne.interpret(Version.valueOf("1.2.3"))); } @Test public void shouldParseGreaterComparisonRange() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression gt = parser.parse(">1.0.0"); assertTrue(gt.interpret(Version.valueOf("1.2.3"))); } @Test public void shouldParseGreaterOrEqualComparisonRange() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression ge = parser.parse(">=1.0.0"); assertTrue(ge.interpret(Version.valueOf("1.0.0"))); assertTrue(ge.interpret(Version.valueOf("1.2.3"))); } @Test public void shouldParseLessComparisonRange() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression lt = parser.parse("<1.2.3"); assertTrue(lt.interpret(Version.valueOf("1.0.0"))); } @Test public void shouldParseLessOrEqualComparisonRange() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression le = parser.parse("<=1.2.3"); assertTrue(le.interpret(Version.valueOf("1.0.0"))); assertTrue(le.interpret(Version.valueOf("1.2.3"))); } @Test public void shouldParseTildeRange() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression expr1 = parser.parse("~1"); assertTrue(expr1.interpret(Version.valueOf("1.2.3"))); assertFalse(expr1.interpret(Version.valueOf("3.2.1"))); Expression expr2 = parser.parse("~1.2"); assertTrue(expr2.interpret(Version.valueOf("1.2.3"))); assertFalse(expr2.interpret(Version.valueOf("2.0.0"))); Expression expr3 = parser.parse("~1.2.3"); assertTrue(expr3.interpret(Version.valueOf("1.2.3"))); assertFalse(expr3.interpret(Version.valueOf("1.3.0"))); } @Test public void shouldParseCaretRange() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression expr1 = parser.parse("^1"); assertTrue(expr1.interpret(Version.valueOf("1.2.3"))); assertFalse(expr1.interpret(Version.valueOf("3.2.1"))); Expression expr2 = parser.parse("^0.2"); assertTrue(expr2.interpret(Version.valueOf("0.2.3"))); assertFalse(expr2.interpret(Version.valueOf("0.3.0"))); Expression expr3 = parser.parse("^0.0.3"); assertTrue(expr3.interpret(Version.valueOf("0.0.3"))); assertFalse(expr3.interpret(Version.valueOf("0.0.4"))); } @Test public void shouldParsePartialVersionRange() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression expr1 = parser.parse("1"); assertTrue(expr1.interpret(Version.valueOf("1.2.3"))); Expression expr2 = parser.parse("2.0"); assertTrue(expr2.interpret(Version.valueOf("2.0.9"))); } @Test public void shouldParseWildcardRange() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression expr1 = parser.parse("1.*"); assertTrue(expr1.interpret(Version.valueOf("1.2.3"))); assertFalse(expr1.interpret(Version.valueOf("3.2.1"))); Expression expr2 = parser.parse("1.2.x"); assertTrue(expr2.interpret(Version.valueOf("1.2.3"))); assertFalse(expr2.interpret(Version.valueOf("1.3.2"))); Expression expr3 = parser.parse("X"); assertTrue(expr3.interpret(Version.valueOf("1.2.3"))); } @Test public void shouldParseHyphenRange() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression range = parser.parse("1.0.0 - 2.0.0"); assertTrue(range.interpret(Version.valueOf("1.2.3"))); assertFalse(range.interpret(Version.valueOf("3.2.1"))); } @Test public void shouldParseMultipleRangesJoinedWithAnd() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression and = parser.parse(">=1.0.0 & <2.0.0"); assertTrue(and.interpret(Version.valueOf("1.2.3"))); assertFalse(and.interpret(Version.valueOf("3.2.1"))); } @Test public void shouldParseMultipleRangesJoinedWithOr() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression or = parser.parse("1.* | =2.0.0"); assertTrue(or.interpret(Version.valueOf("1.2.3"))); assertFalse(or.interpret(Version.valueOf("2.1.0"))); } @Test public void shouldParseParenthesizedExpression() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression expr = parser.parse("(1)"); assertTrue(expr.interpret(Version.valueOf("1.2.3"))); assertFalse(expr.interpret(Version.valueOf("2.0.0"))); } @Test public void shouldParseExpressionWithMultipleParentheses() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression expr = parser.parse("((1))"); assertTrue(expr.interpret(Version.valueOf("1.2.3"))); assertFalse(expr.interpret(Version.valueOf("2.0.0"))); } @Test public void shouldParseNotExpression() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression not1 = parser.parse("!(1)"); assertTrue(not1.interpret(Version.valueOf("2.0.0"))); assertFalse(not1.interpret(Version.valueOf("1.2.3"))); Expression not2 = parser.parse("0.* & !(>=1 & <2)"); assertTrue(not2.interpret(Version.valueOf("0.5.0"))); assertFalse(not2.interpret(Version.valueOf("1.0.1"))); Expression not3 = parser.parse("!(>=1 & <2) & >=2"); assertTrue(not3.interpret(Version.valueOf("2.0.0"))); assertFalse(not3.interpret(Version.valueOf("1.2.3"))); } @Test public void shouldRespectPrecedenceWhenUsedWithParentheses() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression expr1 = parser.parse("(~1.0 & <2.0) | >2.0"); assertTrue(expr1.interpret(Version.valueOf("2.5.0"))); Expression expr2 = parser.parse("~1.0 & (<2.0 | >2.0)"); assertFalse(expr2.interpret(Version.valueOf("2.5.0"))); } @Test public void shouldParseComplexExpressions() { ExpressionParser parser = new ExpressionParser(new Lexer()); Expression expr = parser.parse("((>=1.0.1 & <2) | (>=3.0 & <4)) & ((1-1.5) & (~1.5))"); assertTrue(expr.interpret(Version.valueOf("1.5.0"))); assertFalse(expr.interpret(Version.valueOf("2.5.0"))); } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/expr/GreaterOrEqualTest.java000066400000000000000000000033701250261441700306750ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; import org.junit.Test; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ public class GreaterOrEqualTest { @Test public void shouldCheckIfVersionIsGreaterThanOrEqualToParsedVersion() { Version parsed = Version.valueOf("2.0.0"); GreaterOrEqual ge = new GreaterOrEqual(parsed); assertTrue(ge.interpret(Version.valueOf("3.2.1"))); assertTrue(ge.interpret(Version.valueOf("2.0.0"))); assertFalse(ge.interpret(Version.valueOf("1.2.3"))); } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/expr/GreaterTest.java000066400000000000000000000032361250261441700274050ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; import org.junit.Test; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ public class GreaterTest { @Test public void shouldCheckIfVersionIsGreaterThanParsedVersion() { Version parsed = Version.valueOf("2.0.0"); Greater gt = new Greater(parsed); assertTrue(gt.interpret(Version.valueOf("3.2.1"))); assertFalse(gt.interpret(Version.valueOf("1.2.3"))); } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/expr/LessOrEqualTest.java000066400000000000000000000033541250261441700302140ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; import org.junit.Test; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ public class LessOrEqualTest { @Test public void shouldCheckIfVersionIsLessThanOrEqualToParsedVersion() { Version parsed = Version.valueOf("2.0.0"); LessOrEqual le = new LessOrEqual(parsed); assertTrue(le.interpret(Version.valueOf("1.2.3"))); assertTrue(le.interpret(Version.valueOf("2.0.0"))); assertFalse(le.interpret(Version.valueOf("3.2.1"))); } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/expr/LessTest.java000066400000000000000000000032221250261441700267150ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; import org.junit.Test; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ public class LessTest { @Test public void shouldCheckIfVersionIsLessThanParsedVersion() { Version parsed = Version.valueOf("2.0.0"); Less lt = new Less(parsed); assertTrue(lt.interpret(Version.valueOf("1.2.3"))); assertFalse(lt.interpret(Version.valueOf("3.2.1"))); } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/expr/LexerTest.java000066400000000000000000000061661250261441700271000ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.expr.Lexer.*; import com.github.zafarkhaja.semver.util.Stream; import org.junit.Test; import static com.github.zafarkhaja.semver.expr.Lexer.Token.Type.*; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ public class LexerTest { @Test public void shouldTokenizeVersionString() { Token[] expected = { new Token(GREATER, ">", 0), new Token(NUMERIC, "1", 1), new Token(DOT, ".", 2), new Token(NUMERIC, "0", 3), new Token(DOT, ".", 4), new Token(NUMERIC, "0", 5), new Token(EOI, null, 6), }; Lexer lexer = new Lexer(); Stream stream = lexer.tokenize(">1.0.0"); assertArrayEquals(expected, stream.toArray()); } @Test public void shouldSkipWhitespaces() { Token[] expected = { new Token(GREATER, ">", 0), new Token(NUMERIC, "1", 2), new Token(EOI, null, 3), }; Lexer lexer = new Lexer(); Stream stream = lexer.tokenize("> 1"); assertArrayEquals(expected, stream.toArray()); } @Test public void shouldEndWithEol() { Token[] expected = { new Token(NUMERIC, "1", 0), new Token(DOT, ".", 1), new Token(NUMERIC, "2", 2), new Token(DOT, ".", 3), new Token(NUMERIC, "3", 4), new Token(EOI, null, 5), }; Lexer lexer = new Lexer(); Stream stream = lexer.tokenize("1.2.3"); assertArrayEquals(expected, stream.toArray()); } @Test public void shouldRaiseErrorOnIllegalCharacter() { Lexer lexer = new Lexer(); try { lexer.tokenize("@1.0.0"); } catch (LexerException e) { return; } fail("Should raise error on illegal character"); } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/expr/LexerTokenTest.java000066400000000000000000000077771250261441700301120ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.expr.Lexer.Token; import org.junit.Test; import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; import static com.github.zafarkhaja.semver.expr.Lexer.Token.Type.*; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ @RunWith(Enclosed.class) public class LexerTokenTest { public static class EqualsMethodTest { @Test public void shouldBeReflexive() { Token token = new Token(NUMERIC, "1", 0); assertTrue(token.equals(token)); } @Test public void shouldBeSymmetric() { Token t1 = new Token(EQUAL, "=", 0); Token t2 = new Token(EQUAL, "=", 0); assertTrue(t1.equals(t2)); assertTrue(t2.equals(t1)); } @Test public void shouldBeTransitive() { Token t1 = new Token(GREATER, ">", 0); Token t2 = new Token(GREATER, ">", 0); Token t3 = new Token(GREATER, ">", 0); assertTrue(t1.equals(t2)); assertTrue(t2.equals(t3)); assertTrue(t1.equals(t3)); } @Test public void shouldBeConsistent() { Token t1 = new Token(HYPHEN, "-", 0); Token t2 = new Token(HYPHEN, "-", 0); assertTrue(t1.equals(t2)); assertTrue(t1.equals(t2)); assertTrue(t1.equals(t2)); } @Test public void shouldReturnFalseIfOtherVersionIsOfDifferentType() { Token t1 = new Token(DOT, ".", 0); assertFalse(t1.equals(new String("."))); } @Test public void shouldReturnFalseIfOtherVersionIsNull() { Token t1 = new Token(AND, "&", 0); Token t2 = null; assertFalse(t1.equals(t2)); } @Test public void shouldReturnFalseIfTypesAreDifferent() { Token t1 = new Token(EQUAL, "=", 0); Token t2 = new Token(NOT_EQUAL, "!=", 0); assertFalse(t1.equals(t2)); } @Test public void shouldReturnFalseIfLexemesAreDifferent() { Token t1 = new Token(NUMERIC, "1", 0); Token t2 = new Token(NUMERIC, "2", 0); assertFalse(t1.equals(t2)); } @Test public void shouldReturnFalseIfPositionsAreDifferent() { Token t1 = new Token(NUMERIC, "1", 1); Token t2 = new Token(NUMERIC, "1", 2); assertFalse(t1.equals(t2)); } } public static class HashCodeMethodTest { @Test public void shouldReturnSameHashCodeIfTokensAreEqual() { Token t1 = new Token(NUMERIC, "1", 0); Token t2 = new Token(NUMERIC, "1", 0); assertTrue(t1.equals(t2)); assertEquals(t1.hashCode(), t2.hashCode()); } } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/expr/NotEqualTest.java000066400000000000000000000032401250261441700275370ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; import org.junit.Test; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ public class NotEqualTest { @Test public void shouldCheckIfVersionIsNotEqualToParsedVersion() { Version parsed = Version.valueOf("1.2.3"); NotEqual ne = new NotEqual(parsed); assertTrue(ne.interpret(Version.valueOf("3.2.1"))); assertFalse(ne.interpret(Version.valueOf("1.2.3"))); } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/expr/NotTest.java000066400000000000000000000037001250261441700265500ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; import org.junit.Test; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ public class NotTest { @Test public void shouldRevertBooleanResultOfExpression() { Expression expr1 = new Expression() { @Override public boolean interpret(Version version) { return false; } }; Expression expr2 = new Expression() { @Override public boolean interpret(Version version) { return true; } }; Not not; not = new Not(expr1); assertTrue(not.interpret(null)); not = new Not(expr2); assertFalse(not.interpret(null)); } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/expr/OrTest.java000066400000000000000000000035641250261441700264000ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; import org.junit.Test; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ public class OrTest { @Test public void shouldCheckIfOneOfTwoExpressionsEvaluateToTrue() { Expression left = new Expression() { @Override public boolean interpret(Version version) { return false; } }; Expression right = new Expression() { @Override public boolean interpret(Version version) { return true; } }; Or or = new Or(left, right); assertTrue(or.interpret(null)); } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/expr/ParserErrorHandlingTest.java000066400000000000000000000061451250261441700317310ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.expr.Lexer.Token; import java.util.Arrays; import java.util.Collection; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import static com.github.zafarkhaja.semver.expr.Lexer.Token.Type.*; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ @RunWith(Parameterized.class) public class ParserErrorHandlingTest { private final String invalidExpr; private final Token unexpected; private final Token.Type[] expected; public ParserErrorHandlingTest( String invalidExpr, Token unexpected, Token.Type[] expected ) { this.invalidExpr = invalidExpr; this.unexpected = unexpected; this.expected = expected; } @Test public void shouldCorrectlyHandleParseErrors() { try { ExpressionParser.newInstance().parse(invalidExpr); } catch (UnexpectedTokenException e) { assertEquals(unexpected, e.getUnexpectedToken()); assertArrayEquals(expected, e.getExpectedTokenTypes()); return; } fail("Uncaught exception"); } @Parameters(name = "{0}") public static Collection parameters() { return Arrays.asList(new Object[][] { { "1)", new Token(RIGHT_PAREN, ")", 1), new Token.Type[] { EOI } }, { "(>1.0.1", new Token(EOI, null, 7), new Token.Type[] { RIGHT_PAREN } }, { "((>=1 & <2)", new Token(EOI, null, 11), new Token.Type[] { RIGHT_PAREN } }, { ">=1.0.0 &", new Token(EOI, null, 9), new Token.Type[] { NUMERIC } }, { "(>2.0 |)", new Token(RIGHT_PAREN, ")", 7), new Token.Type[] { NUMERIC } }, { "& 1.2", new Token(AND, "&", 0), new Token.Type[] { NUMERIC } }, }); } } jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/util/000077500000000000000000000000001250261441700243045ustar00rootroot00000000000000jsemver-0.9.0/src/test/java/com/github/zafarkhaja/semver/util/StreamTest.java000066400000000000000000000203551250261441700272470ustar00rootroot00000000000000/* * The MIT License * * Copyright 2012-2014 Zafar Khaja . * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.github.zafarkhaja.semver.util; import com.github.zafarkhaja.semver.util.Stream.ElementType; import java.util.Iterator; import org.junit.Test; import static org.junit.Assert.*; /** * * @author Zafar Khaja */ public class StreamTest { @Test public void shouldBeBackedByArray() { Character[] input = {'a', 'b', 'c'}; Stream stream = new Stream(input); assertArrayEquals(input, stream.toArray()); } @Test public void shouldImplementIterable() { Character[] input = {'a', 'b', 'c'}; Stream stream = new Stream(input); Iterator it = stream.iterator(); for (Character chr : input) { assertEquals(chr, it.next()); } assertFalse(it.hasNext()); } @Test public void shouldNotReturnRealElementsArray() { Stream stream = new Stream( new Character[] {'a', 'b', 'c'} ); Character[] charArray = stream.toArray(); charArray[0] = Character.valueOf('z'); assertEquals(Character.valueOf('z'), charArray[0]); assertEquals(Character.valueOf('a'), stream.toArray()[0]); } @Test public void shouldReturnArrayOfElementsThatAreLeftInStream() { Stream stream = new Stream( new Character[] {'a', 'b', 'c'} ); stream.consume(); stream.consume(); assertEquals(1, stream.toArray().length); assertEquals(Character.valueOf('c'), stream.toArray()[0]); } @Test public void shouldConsumeElementsOneByOne() { Stream stream = new Stream( new Character[] {'a', 'b', 'c'} ); assertEquals(Character.valueOf('a'), stream.consume()); assertEquals(Character.valueOf('b'), stream.consume()); assertEquals(Character.valueOf('c'), stream.consume()); } @Test public void shouldRaiseErrorWhenUnexpectedElementConsumed() { Stream stream = new Stream( new Character[] {'a', 'b', 'c'} ); try { stream.consume(new ElementType() { @Override public boolean isMatchedBy(Character element) { return false; } }); } catch (UnexpectedElementException e) { return; } fail("Should raise error when unexpected element type is consumed"); } @Test public void shouldLookaheadWithoutConsuming() { Stream stream = new Stream( new Character[] {'a', 'b', 'c'} ); assertEquals(Character.valueOf('a'), stream.lookahead()); assertEquals(Character.valueOf('a'), stream.lookahead()); } @Test public void shouldLookaheadArbitraryNumberOfElements() { Stream stream = new Stream( new Character[] {'a', 'b', 'c'} ); assertEquals(Character.valueOf('a'), stream.lookahead(1)); assertEquals(Character.valueOf('b'), stream.lookahead(2)); assertEquals(Character.valueOf('c'), stream.lookahead(3)); } @Test public void shouldCheckIfLookaheadIsOfExpectedTypes() { Stream stream = new Stream( new Character[] {'a', 'b', 'c'} ); assertTrue(stream.positiveLookahead( new ElementType() { @Override public boolean isMatchedBy(Character element) { return element == 'a'; } } )); assertFalse(stream.positiveLookahead( new ElementType() { @Override public boolean isMatchedBy(Character element) { return element == 'c'; } } )); } @Test public void shouldCheckIfElementOfExpectedTypesExistBeforeGivenType() { Stream stream = new Stream( new Character[] {'1', '.', '0', '.', '0'} ); assertTrue(stream.positiveLookaheadBefore( new ElementType() { @Override public boolean isMatchedBy(Character element) { return element == '.'; } }, new ElementType() { @Override public boolean isMatchedBy(Character element) { return element == '1'; } } )); assertFalse(stream.positiveLookaheadBefore( new ElementType() { @Override public boolean isMatchedBy(Character element) { return element == '1'; } }, new ElementType() { @Override public boolean isMatchedBy(Character element) { return element == '.'; } } )); } @Test public void shouldCheckIfElementOfExpectedTypesExistUntilGivenPosition() { Stream stream = new Stream( new Character[] {'1', '.', '0', '.', '0'} ); assertTrue(stream.positiveLookaheadUntil( 3, new ElementType() { @Override public boolean isMatchedBy(Character element) { return element == '0'; } } )); assertFalse(stream.positiveLookaheadUntil( 3, new ElementType() { @Override public boolean isMatchedBy(Character element) { return element == 'a'; } } )); } @Test public void shouldPushBackOneElementAtATime() { Stream stream = new Stream( new Character[] {'a', 'b', 'c'} ); assertEquals(Character.valueOf('a'), stream.consume()); stream.pushBack(); assertEquals(Character.valueOf('a'), stream.consume()); } @Test public void shouldStopPushingBackWhenThereAreNoElements() { Stream stream = new Stream( new Character[] {'a', 'b', 'c'} ); assertEquals(Character.valueOf('a'), stream.consume()); assertEquals(Character.valueOf('b'), stream.consume()); assertEquals(Character.valueOf('c'), stream.consume()); stream.pushBack(); stream.pushBack(); stream.pushBack(); stream.pushBack(); assertEquals(Character.valueOf('a'), stream.consume()); } @Test public void shouldKeepTrackOfCurrentOffset() { Stream stream = new Stream( new Character[] {'a', 'b', 'c'} ); assertEquals(0, stream.currentOffset()); stream.consume(); assertEquals(1, stream.currentOffset()); stream.consume(); stream.consume(); assertEquals(3, stream.currentOffset()); } }