├── .travis.yml ├── LICENSE ├── README.md ├── VERSION ├── package.json ├── semver.sh └── tests ├── input.sh ├── node_semver_tests.sh ├── output.sh ├── run.sh ├── strict_rules_tests.sh └── tests.sh /.travis.yml: -------------------------------------------------------------------------------- 1 | language: sh 2 | script: 3 | - ./tests/run.sh 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Józef Sokołowski 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sh-semver 2 | 3 | [![NPM Version][npm-image]][npm-url] 4 | [![Build][travis-image]][travis-url] 5 | 6 | The semantic versioner for Bourne Shell. 7 | 8 | ## CLI 9 | 10 | ``` 11 | semver.sh [-r ] [... ] 12 | ``` 13 | 14 | Given a rule and one or many versions, it will return all of the provided versions that satisfy the rule, in sorted order, one per line. 15 | 16 | If versions are omitted from the command line, it will read them from STDIN. 17 | 18 | If the rule is omitted from the command line, it will simply sort all the provided versions. 19 | 20 | ## Ranges 21 | 22 | Every *version range* contains one or more *sets of comparators*. To satisfy *version range* version must satisfies all *comparators* from at least one set. Sets are separated with two vertical bars ``||``. Rules in each set are separated with whitespaces. Empty set are treated as wildcard comparator ``*``. 23 | 24 | ### Basic comparators 25 | There are five basic comparators: 26 | 27 | * Equal to ``=A.B.C`` (``=`` operator is optional, it may be provided but usually it isn't). 28 | * Less than ``A.B.C`` 30 | * Less than or equal to ``<=A.B.C`` 31 | * Greater than or equal to ``>=A.B.C`` 32 | 33 | ### Advanced comparators 34 | 35 | ##### Wildcards ``*`` ``*.*`` ``*.*.*`` 36 | Wildcard comparators can be satisfied by any version, even prerelease one. 37 | 38 | Instead of ``*`` character can be used ``x`` or ``X``. 39 | 40 | ##### Wildcard ranges ``A.*.*`` ``A.B.*`` 41 | Wildcard ranges can be satisfied when only part of version is matching. In contrast to wildcards, wildcard ranges cannot be satisfied by prerelease versions. 42 | 43 | * ``A.*.*`` is satisfied when majors are the same, 44 | * ``A.B.*`` is satisfied when majors and minors are the same. 45 | 46 | The special character (``*``, ``x`` or ``X``) is optional. 47 | 48 | ###### Examples 49 | * ``1.2`` := ``>=1.2.0 <1.3.0`` 50 | * ``5.*.*`` := ``>=5.0.0 <6.0.0`` 51 | 52 | ##### Caret ranges ``^A.B.C`` 53 | Matches to compatible versions. 54 | 55 | ###### Examples 56 | * ``^1.2.3`` := ``>=1.2.3 <2.0.0`` 57 | * ``^0.1.2`` := ``>=0.1.2 <0.2.0`` 58 | * ``^0.0.1`` := ``>=0.0.1 <0.0.2`` 59 | 60 | ##### Tilde ranges ``~A.B.C`` ``~A.B`` ``~A`` 61 | If patch version is specified tilde ranges matches to all greater or equal versions with the same minor version. Otherwise is equivalent of ``A.B.*`` when minor version is specified or ``A.*.*`` when not. 62 | 63 | ##### Hyphen ranges ``A.B.C - X.Y.Z`` 64 | Hyphen range ``A.B.C - X.Y.Z`` equivalent of ``>=A.B.C <=X.Y.Z``. 65 | 66 | ### Prerelease versions 67 | Prerelease versions can satisfy comparators set only when have the same minor major and patch numbers as at least one of comparators. 68 | 69 | 70 | [npm-image]: https://img.shields.io/npm/v/sh-semver.svg 71 | [npm-url]: https://npmjs.org/package/sh-semver.sh 72 | [travis-image]: https://travis-ci.org/qzb/sh-semver.svg?branch=master 73 | [travis-url]: https://travis-ci.org/qzb/sh-semver 74 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.0.0 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sh-semver", 3 | "version": "1.1.0", 4 | "description": "The semantic versioner for bash", 5 | "homepage": "https://github.com/qzb/sh-semver#readme", 6 | "author": { 7 | "name": "Józef Sokołowski", 8 | "url": "http://qzb.me" 9 | }, 10 | "license": "MIT", 11 | "bin": { 12 | "sh-semver": "./semver.sh" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/qzb/sh-semver.git" 17 | }, 18 | "bugs": { 19 | "url": "https://github.com/qzb/sh-semver/issues" 20 | }, 21 | "files": [ 22 | "semver.sh" 23 | ], 24 | "directories": { 25 | "test": "tests" 26 | }, 27 | "scripts": { 28 | "test": "tests/run.sh" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /semver.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | _num_part='([0-9]|[1-9][0-9]*)' 4 | _lab_part='([0-9]|[1-9][0-9]*|[0-9]*[a-zA-Z-][a-zA-Z0-9-]*)' 5 | _met_part='([0-9A-Za-z-]+)' 6 | 7 | RE_NUM="$_num_part(\.$_num_part)*" 8 | RE_LAB="$_lab_part(\.$_lab_part)*" 9 | RE_MET="$_met_part(\.$_met_part)*" 10 | RE_VER="[ \t]*$RE_NUM(-$RE_LAB)?(\+$RE_MET)?" 11 | 12 | BRE_DIGIT='[0-9]\{1,\}' 13 | BRE_ALNUM='[0-9a-zA-Z-]\{1,\}' 14 | BRE_IDENT="$BRE_ALNUM\(\.$BRE_ALNUM\)*" 15 | 16 | BRE_MAJOR="$BRE_DIGIT" 17 | BRE_MINOR="\(\.$BRE_DIGIT\)\{0,1\}" 18 | BRE_PATCH="\(\.$BRE_DIGIT\)\{0,1\}" 19 | BRE_PRERE="\(-$BRE_IDENT\)\{0,1\}" 20 | BRE_BUILD="\(+$BRE_IDENT\)\{0,1\}" 21 | BRE_VERSION="${BRE_MAJOR}${BRE_MINOR}${BRE_PATCH}${BRE_PRERE}${BRE_BUILD}" 22 | 23 | filter() 24 | { 25 | local text="$1" 26 | local regex="$2" 27 | shift 2 28 | echo "$text" | grep -E "$@" "$regex" 29 | } 30 | 31 | # Gets number part from normalized version 32 | get_number() 33 | { 34 | echo "${1%%-*}" 35 | } 36 | 37 | # Gets prerelase part from normalized version 38 | get_prerelease() 39 | { 40 | local pre_and_meta=${1%+*} 41 | local pre=${pre_and_meta#*-} 42 | if [ "$pre" = "$1" ]; then 43 | echo 44 | else 45 | echo "$pre" 46 | fi 47 | } 48 | 49 | # Gets major number from normalized version 50 | get_major() 51 | { 52 | echo "${1%%.*}" 53 | } 54 | 55 | # Gets minor number from normalized version 56 | get_minor() 57 | { 58 | local minor_major_bug=${1%%-*} 59 | local minor_major=${minor_major_bug%.*} 60 | local minor=${minor_major#*.} 61 | 62 | if [ "$minor" = "$minor_major" ]; then 63 | echo 64 | else 65 | echo "$minor" 66 | fi 67 | } 68 | 69 | get_bugfix() 70 | { 71 | local minor_major_bug=${1%%-*} 72 | local bugfix=${minor_major_bug##*.*.} 73 | 74 | if [ "$bugfix" = "$minor_major_bug" ]; then 75 | echo 76 | else 77 | echo "$bugfix" 78 | fi 79 | } 80 | 81 | strip_metadata() 82 | { 83 | echo "${1%+*}" 84 | } 85 | 86 | semver_eq() 87 | { 88 | local ver1 ver2 part1 part2 89 | ver1=$(get_number "$1") 90 | ver2=$(get_number "$2") 91 | 92 | local count=1 93 | while true; do 94 | part1=$(echo "$ver1"'.' | cut -d '.' -f $count) 95 | part2=$(echo "$ver2"'.' | cut -d '.' -f $count) 96 | 97 | if [ -z "$part1" ] || [ -z "$part2" ]; then 98 | break 99 | fi 100 | 101 | if [ "$part1" != "$part2" ]; then 102 | return 1 103 | fi 104 | 105 | local count=$(( count + 1 )) 106 | done 107 | 108 | if [ "$(get_prerelease "$1")" = "$(get_prerelease "$2")" ]; then 109 | return 0 110 | else 111 | return 1 112 | fi 113 | } 114 | 115 | semver_lt() 116 | { 117 | local number_a number_b prerelease_a prerelease_b 118 | number_a=$(get_number "$1") 119 | number_b=$(get_number "$2") 120 | prerelease_a=$(get_prerelease "$1") 121 | prerelease_b=$(get_prerelease "$2") 122 | 123 | 124 | local head_a='' 125 | local head_b='' 126 | local rest_a=$number_a. 127 | local rest_b=$number_b. 128 | while [ -n "$rest_a" ] || [ -n "$rest_b" ]; do 129 | head_a=${rest_a%%.*} 130 | head_b=${rest_b%%.*} 131 | rest_a=${rest_a#*.} 132 | rest_b=${rest_b#*.} 133 | 134 | if [ -z "$head_a" ] || [ -z "$head_b" ]; then 135 | return 1 136 | fi 137 | 138 | if [ "$head_a" -eq "$head_b" ]; then 139 | continue 140 | fi 141 | 142 | if [ "$head_a" -lt "$head_b" ]; then 143 | return 0 144 | else 145 | return 1 146 | fi 147 | done 148 | 149 | if [ -n "$prerelease_a" ] && [ -z "$prerelease_b" ]; then 150 | return 0 151 | elif [ -z "$prerelease_a" ] && [ -n "$prerelease_b" ]; then 152 | return 1 153 | fi 154 | 155 | local head_a='' 156 | local head_b='' 157 | local rest_a=$prerelease_a. 158 | local rest_b=$prerelease_b. 159 | while [ -n "$rest_a" ] || [ -n "$rest_b" ]; do 160 | head_a=${rest_a%%.*} 161 | head_b=${rest_b%%.*} 162 | rest_a=${rest_a#*.} 163 | rest_b=${rest_b#*.} 164 | 165 | if [ -z "$head_a" ] && [ -n "$head_b" ]; then 166 | return 0 167 | elif [ -n "$head_a" ] && [ -z "$head_b" ]; then 168 | return 1 169 | fi 170 | 171 | if [ "$head_a" = "$head_b" ]; then 172 | continue 173 | fi 174 | 175 | # If both are numbers then compare numerically 176 | if [ "$head_a" = "${head_a%[!0-9]*}" ] && [ "$head_b" = "${head_b%[!0-9]*}" ]; then 177 | [ "$head_a" -lt "$head_b" ] && return 0 || return 1 178 | # If only a is a number then return true (number has lower precedence than strings) 179 | elif [ "$head_a" = "${head_a%[!0-9]*}" ]; then 180 | return 0 181 | # If only b is a number then return false 182 | elif [ "$head_b" = "${head_b%[!0-9]*}" ]; then 183 | return 1 184 | # Finally if of identifiers is a number compare them lexically 185 | else 186 | test "$head_a" \< "$head_b" && return 0 || return 1 187 | fi 188 | done 189 | 190 | return 1 191 | } 192 | 193 | semver_gt() 194 | { 195 | if semver_lt "$1" "$2" || semver_eq "$1" "$2"; then 196 | return 1 197 | else 198 | return 0 199 | fi 200 | } 201 | 202 | semver_le() 203 | { 204 | semver_gt "$1" "$2" && return 1 || return 0 205 | } 206 | 207 | semver_ge() 208 | { 209 | semver_lt "$1" "$2" && return 1 || return 0 210 | } 211 | 212 | semver_sort() 213 | { 214 | if [ $# -le 1 ]; then 215 | echo "$1" 216 | return 217 | fi 218 | 219 | local pivot=$1 220 | local args_a=() 221 | local args_b=() 222 | 223 | shift 1 224 | 225 | for ver in "$@"; do 226 | if semver_le "$ver" "$pivot"; then 227 | args_a=( "${args_a[@]}" "$ver" ) 228 | else 229 | args_b=( "$ver" "${args_b[@]}" ) 230 | fi 231 | done 232 | 233 | args_a=( $(semver_sort "${args_a[@]}") ) 234 | args_b=( $(semver_sort "${args_b[@]}") ) 235 | echo "${args_a[@]}" "$pivot" "${args_b[@]}" 236 | } 237 | 238 | regex_match() 239 | { 240 | local string="$1 " 241 | local regexp="$2" 242 | local match 243 | match="$(eval "echo '$string' | grep -E -o '^[ \t]*($regexp)[ \t]+'")"; 244 | 245 | for i in $(seq 0 9); do 246 | unset "MATCHED_VER_$i" 247 | unset "MATCHED_NUM_$i" 248 | done 249 | unset REST 250 | 251 | if [ -z "$match" ]; then 252 | return 1 253 | fi 254 | 255 | local match_len=${#match} 256 | REST="${string:$match_len}" 257 | 258 | local part 259 | local i=1 260 | for part in $string; do 261 | local ver num 262 | ver="$(eval "echo '$part' | grep -E -o '$RE_VER' | head -n 1 | sed 's/ \t//g'")"; 263 | num=$(get_number "$ver") 264 | 265 | if [ -n "$ver" ]; then 266 | eval "MATCHED_VER_$i='$ver'" 267 | eval "MATCHED_NUM_$i='$num'" 268 | i=$(( i + 1 )) 269 | fi 270 | done 271 | 272 | return 0 273 | } 274 | 275 | # Normalizes rules string 276 | # 277 | # * replaces chains of whitespaces with single spaces 278 | # * replaces whitespaces around hyphen operator with "_" 279 | # * removes wildcards from version numbers (1.2.* -> 1.2) 280 | # * replaces "x" with "*" 281 | # * removes whitespace between operators and version numbers 282 | # * removes leading "v" from version numbers 283 | # * removes leading and trailing spaces 284 | normalize_rules() 285 | { 286 | echo " $1" \ 287 | | sed 's/\\t/ /g' \ 288 | | sed 's/ / /g' \ 289 | | sed 's/ \{2,\}/ /g' \ 290 | | sed 's/ - /_-_/g' \ 291 | | sed 's/\([~^<>=]\) /\1/g' \ 292 | | sed 's/\([ _~^<>=]\)v/\1/g' \ 293 | | sed 's/\.[xX*]//g' \ 294 | | sed 's/[xX]/*/g' \ 295 | | sed 's/^ //g' \ 296 | | sed 's/ $//g' 297 | } 298 | 299 | # Reads rule from provided string 300 | resolve_rule() 301 | { 302 | local rule operator operands 303 | rule="$1" 304 | operator="$( echo "$rule" | sed "s/$BRE_VERSION/#/g" )" 305 | operands=( $( echo "$rule" | grep -o "$BRE_VERSION") ) 306 | 307 | case "$operator" in 308 | '*') echo "all" ;; 309 | '#') echo "eq ${operands[0]}" ;; 310 | '=#') echo "eq ${operands[0]}" ;; 311 | '<#') echo "lt ${operands[0]}" ;; 312 | '>#') echo "gt ${operands[0]}" ;; 313 | '<=#') echo "le ${operands[0]}" ;; 314 | '>=#') echo "ge ${operands[0]}" ;; 315 | '#_-_#') echo "ge ${operands[0]}" 316 | echo "le ${operands[1]}" ;; 317 | '~#') echo "tilde ${operands[0]}" ;; 318 | '^#') echo "caret ${operands[0]}" ;; 319 | *) return 1 320 | esac 321 | } 322 | 323 | resolve_rules() 324 | { 325 | local rules 326 | rules="$(normalize_rules "$1")" 327 | IFS=' ' read -ra rules <<< "${rules:-all}" 328 | 329 | for rule in "${rules[@]}"; do 330 | resolve_rule "$rule" 331 | done 332 | } 333 | 334 | rule_eq() 335 | { 336 | local rule_ver="$1" 337 | local tested_ver="$2" 338 | 339 | semver_eq "$tested_ver" "$rule_ver" && return 0 || return 1; 340 | } 341 | 342 | rule_le() 343 | { 344 | local rule_ver="$1" 345 | local tested_ver="$2" 346 | 347 | semver_le "$tested_ver" "$rule_ver" && return 0 || return 1; 348 | } 349 | 350 | rule_lt() 351 | { 352 | local rule_ver="$1" 353 | local tested_ver="$2" 354 | 355 | semver_lt "$tested_ver" "$rule_ver" && return 0 || return 1; 356 | } 357 | 358 | rule_ge() 359 | { 360 | local rule_ver="$1" 361 | local tested_ver="$2" 362 | 363 | semver_ge "$tested_ver" "$rule_ver" && return 0 || return 1; 364 | } 365 | 366 | rule_gt() 367 | { 368 | local rule_ver="$1" 369 | local tested_ver="$2" 370 | 371 | semver_gt "$tested_ver" "$rule_ver" && return 0 || return 1; 372 | } 373 | 374 | rule_tilde() 375 | { 376 | local rule_ver="$1" 377 | local tested_ver="$2" 378 | 379 | if rule_ge "$rule_ver" "$tested_ver"; then 380 | local rule_major rule_minor 381 | rule_major=$(get_major "$rule_ver") 382 | rule_minor=$(get_minor "$rule_ver") 383 | 384 | if [ -n "$rule_minor" ] && rule_eq "$rule_major.$rule_minor" "$(get_number "$tested_ver")"; then 385 | return 0 386 | fi 387 | if [ -z "$rule_minor" ] && rule_eq "$rule_major" "$(get_number "$tested_ver")"; then 388 | return 0 389 | fi 390 | fi 391 | 392 | return 1 393 | } 394 | 395 | rule_caret() 396 | { 397 | local rule_ver="$1" 398 | local tested_ver="$2" 399 | 400 | if rule_ge "$rule_ver" "$tested_ver"; then 401 | local rule_major 402 | rule_major="$(get_major "$rule_ver")" 403 | 404 | if [ "$rule_major" != "0" ] && rule_eq "$rule_major" "$(get_number "$tested_ver")"; then 405 | return 0 406 | fi 407 | if [ "$rule_major" = "0" ] && rule_eq "$rule_ver" "$(get_number "$tested_ver")"; then 408 | return 0 409 | fi 410 | fi 411 | 412 | return 1 413 | } 414 | 415 | rule_all() 416 | { 417 | return 0 418 | } 419 | 420 | apply_rules() 421 | { 422 | local rules_string="$1" 423 | shift 424 | local versions=( "$@" ) 425 | 426 | # Loop over sets of rules (sets of rules are separated with ||) 427 | for ver in "${versions[@]}"; do 428 | rules_tail="$rules_string"; 429 | 430 | while [ -n "$rules_tail" ]; do 431 | head="${rules_tail%%||*}" 432 | 433 | if [ "$head" = "$rules_tail" ]; then 434 | rules_string="" 435 | else 436 | rules_tail="${rules_tail#*||}" 437 | fi 438 | 439 | #if [ -z "$head" ] || [ -n "$(echo "$head" | grep -E -x '[ \t]*')" ]; then 440 | #group=$(( $group + 1 )) 441 | #continue 442 | #fi 443 | 444 | rules="$(resolve_rules "$head")" 445 | 446 | # If specified rule cannot be recognised - end with error 447 | if [ $? -eq 1 ]; then 448 | exit 1 449 | fi 450 | 451 | if ! echo "$ver" | grep -q -E -x "[v=]?[ \t]*$RE_VER"; then 452 | continue 453 | fi 454 | 455 | ver=$(echo "$ver" | grep -E -x "$RE_VER") 456 | 457 | success=true 458 | allow_prerel=false 459 | if $FORCE_ALLOW_PREREL; then 460 | allow_prerel=true 461 | fi 462 | 463 | while read -r rule; do 464 | comparator="${rule%% *}" 465 | operand="${rule#* }" 466 | 467 | if [ -n "$(get_prerelease "$operand")" ] && semver_eq "$(get_number "$operand")" "$(get_number "$ver")" || [ "$rule" = "all" ]; then 468 | allow_prerel=true 469 | fi 470 | 471 | "rule_$comparator" "$operand" "$ver" 472 | if [ $? -eq 1 ]; then 473 | success=false 474 | break 475 | fi 476 | done <<< "$rules" 477 | 478 | if $success; then 479 | if [ -z "$(get_prerelease "$ver")" ] || $allow_prerel; then 480 | echo "$ver" 481 | break; 482 | fi 483 | fi 484 | done 485 | 486 | group=$(( group + 1 )) 487 | done 488 | } 489 | 490 | 491 | 492 | FORCE_ALLOW_PREREL=false 493 | USAGE="Usage: $0 [-r ] [... ] 494 | 495 | Omitting s reads them from STDIN. 496 | Omitting -r simply sorts the versions according to semver ordering." 497 | 498 | while getopts ar:h o; do 499 | case "$o" in 500 | a) FORCE_ALLOW_PREREL=true ;; 501 | r) RULES_STRING="$OPTARG||";; 502 | h) echo "$USAGE" && exit ;; 503 | ?) echo "$USAGE" && exit 1;; 504 | esac 505 | done 506 | 507 | shift $(( OPTIND-1 )) 508 | 509 | VERSIONS=( ${@:-$(cat -)} ) 510 | 511 | # Sort versions 512 | VERSIONS=( $(semver_sort "${VERSIONS[@]}") ) 513 | 514 | if [ -z "$RULES_STRING" ]; then 515 | printf '%s\n' "${VERSIONS[@]}" 516 | else 517 | apply_rules "$RULES_STRING" "${VERSIONS[@]}" 518 | fi 519 | -------------------------------------------------------------------------------- /tests/input.sh: -------------------------------------------------------------------------------- 1 | describe 'Command input' 2 | RET=$(echo 4.0.0 4.2.1 5.0.0 | ./semver.sh -r '^4.0.0') 3 | assert "$RET" "4.0.0\\n4.2.1" 'should accept versions on STDIN' 4 | 5 | describe 'When not given a rule' 6 | RET=$(./semver.sh 4.2.1 4.0.0 3.1.2 5.0.0) 7 | assert "$RET" "3.1.2\\n4.0.0\\n4.2.1\\n5.0.0" 'should sort versions' 8 | 9 | RET=$(echo 4.2.1 4.0.0 3.1.2 5.0.0 | ./semver.sh) 10 | assert "$RET" "3.1.2\\n4.0.0\\n4.2.1\\n5.0.0" 'should sort versions from STDIN' 11 | -------------------------------------------------------------------------------- /tests/node_semver_tests.sh: -------------------------------------------------------------------------------- 1 | # 2 | # All tests in this file are taken directly from node-semver tests suite: 3 | # https://github.com/npm/node-semver/blob/master/test/index.js 4 | # 5 | 6 | describe 'Positive range tests' 7 | 8 | while read -r line; do 9 | parts=$(echo "$line" | grep -E -o "'[^']+'") 10 | if [ $(echo "$parts" | wc -l) = "2" ]; then 11 | rule=$(echo "$parts" | head -n1 | cut -d "'" -f 2) 12 | ver=$(echo "$parts" | tail -n1 | cut -d "'" -f 2) 13 | ret=$(eval "./semver.sh -r '$rule' '$ver'") 14 | assert "$ret" "$ver" "$ver should match the range $rule" 15 | fi 16 | done <=*', '0.2.4'], 20 | ['', '1.0.0'], 21 | ['*', '1.2.3'], 22 | ['*', 'v1.2.3-foo', true], 23 | ['>=1.0.0', '1.0.0'], 24 | ['>=1.0.0', '1.0.1'], 25 | ['>=1.0.0', '1.1.0'], 26 | ['>1.0.0', '1.0.1'], 27 | ['>1.0.0', '1.1.0'], 28 | ['<=2.0.0', '2.0.0'], 29 | ['<=2.0.0', '1.9999.9999'], 30 | ['<=2.0.0', '0.2.9'], 31 | ['<2.0.0', '1.9999.9999'], 32 | ['<2.0.0', '0.2.9'], 33 | ['>= 1.0.0', '1.0.0'], 34 | ['>= 1.0.0', '1.0.1'], 35 | ['>= 1.0.0', '1.1.0'], 36 | ['> 1.0.0', '1.0.1'], 37 | ['> 1.0.0', '1.1.0'], 38 | ['<= 2.0.0', '2.0.0'], 39 | ['<= 2.0.0', '1.9999.9999'], 40 | ['<= 2.0.0', '0.2.9'], 41 | ['< 2.0.0', '1.9999.9999'], 42 | ['<\t2.0.0', '0.2.9'], 43 | ['>=0.1.97', 'v0.1.97', true], 44 | ['>=0.1.97', '0.1.97'], 45 | ['0.1.20 || 1.2.4', '1.2.4'], 46 | ['>=0.2.3 || <0.0.1', '0.0.0'], 47 | ['>=0.2.3 || <0.0.1', '0.2.3'], 48 | ['>=0.2.3 || <0.0.1', '0.2.4'], 49 | ['||', '1.3.4'], 50 | ['2.x.x', '2.1.3'], 51 | ['1.2.x', '1.2.3'], 52 | ['1.2.x || 2.x', '2.1.3'], 53 | ['1.2.x || 2.x', '1.2.3'], 54 | ['x', '1.2.3'], 55 | ['2.*.*', '2.1.3'], 56 | ['1.2.*', '1.2.3'], 57 | ['1.2.* || 2.*', '2.1.3'], 58 | ['1.2.* || 2.*', '1.2.3'], 59 | ['*', '1.2.3'], 60 | ['2', '2.1.2'], 61 | ['2.3', '2.3.1'], 62 | ['~2.4', '2.4.0'], // >=2.4.0 <2.5.0 63 | ['~2.4', '2.4.5'], 64 | ['~>3.2.1', '3.2.2'], // >=3.2.1 <3.3.0, 65 | ['~1', '1.2.3'], // >=1.0.0 <2.0.0 66 | ['~>1', '1.2.3'], 67 | ['~> 1', '1.2.3'], 68 | ['~1.0', '1.0.2'], // >=1.0.0 <1.1.0, 69 | ['~ 1.0', '1.0.2'], 70 | ['~ 1.0.3', '1.0.12'], 71 | ['>=1', '1.0.0'], 72 | ['>= 1', '1.0.0'], 73 | ['<1.2', '1.1.1'], 74 | ['< 1.2', '1.1.1'], 75 | ['1', '1.0.0beta', true], 76 | ['~v0.5.4-pre', '0.5.5'], 77 | ['~v0.5.4-pre', '0.5.4'], 78 | ['=0.7.x', '0.7.2'], 79 | ['>=0.7.x', '0.7.2'], 80 | ['=0.7.x', '0.7.0-asdf'], 81 | ['>=0.7.x', '0.7.0-asdf'], 82 | ['<=0.7.x', '0.6.2'], 83 | ['~1.2.1 >=1.2.3', '1.2.3'], 84 | ['~1.2.1 =1.2.3', '1.2.3'], 85 | ['~1.2.1 1.2.3', '1.2.3'], 86 | ['~1.2.1 >=1.2.3 1.2.3', '1.2.3'], 87 | ['~1.2.1 1.2.3 >=1.2.3', '1.2.3'], 88 | ['~1.2.1 1.2.3', '1.2.3'], 89 | ['>=1.2.1 1.2.3', '1.2.3'], 90 | ['1.2.3 >=1.2.1', '1.2.3'], 91 | ['>=1.2.3 >=1.2.1', '1.2.3'], 92 | ['>=1.2.1 >=1.2.3', '1.2.3'], 93 | ['<=1.2.3', '1.2.3-beta'], 94 | ['>1.2', '1.3.0-beta'], 95 | ['>=1.2', '1.2.8'], 96 | ['^1.2.3', '1.8.1'], 97 | ['^1.2.3', '1.2.3-beta'], 98 | ['^0.1.2', '0.1.2'], 99 | ['^0.1', '0.1.2'], 100 | ['^1.2', '1.4.2'], 101 | ['^1.2 ^1', '1.4.2'], 102 | ['^1.2', '1.2.0-pre'], 103 | ['^1.2.3', '1.2.3-pre'] 104 | EOF 105 | 106 | 107 | 108 | describe "Negative range tests" 109 | 110 | while read -r line; do 111 | parts=$(echo "$line" | grep -E -o "'[^']+'") 112 | if [ $(echo "$parts" | wc -l) = "2" ]; then 113 | rule=$(echo "$parts" | head -n1 | cut -d "'" -f 2) 114 | ver=$(echo "$parts" | tail -n1 | cut -d "'" -f 2) 115 | ret=$(eval "./semver.sh -r '$rule' '$ver'") 116 | assert "$ret" "" "$ver should not match the range $rule" 117 | fi 118 | done <=1.0.0', '0.0.0'], 122 | ['>=1.0.0', '0.0.1'], 123 | ['>=1.0.0', '0.1.0'], 124 | ['>1.0.0', '0.0.1'], 125 | ['>1.0.0', '0.1.0'], 126 | ['<=2.0.0', '3.0.0'], 127 | ['<=2.0.0', '2.9999.9999'], 128 | ['<=2.0.0', '2.2.9'], 129 | ['<2.0.0', '2.9999.9999'], 130 | ['<2.0.0', '2.2.9'], 131 | ['>=0.1.97', 'v0.1.93', true], 132 | ['>=0.1.97', '0.1.93'], 133 | ['0.1.20 || 1.2.4', '1.2.3'], 134 | ['>=0.2.3 || <0.0.1', '0.0.3'], 135 | ['>=0.2.3 || <0.0.1', '0.2.2'], 136 | ['2.x.x', '1.1.3'], 137 | ['2.x.x', '3.1.3'], 138 | ['1.2.x', '1.3.3'], 139 | ['1.2.x || 2.x', '3.1.3'], 140 | ['1.2.x || 2.x', '1.1.3'], 141 | ['2.*.*', '1.1.3'], 142 | ['2.*.*', '3.1.3'], 143 | ['1.2.*', '1.3.3'], 144 | ['1.2.* || 2.*', '3.1.3'], 145 | ['1.2.* || 2.*', '1.1.3'], 146 | ['2', '1.1.2'], 147 | ['2.3', '2.4.1'], 148 | ['~2.4', '2.5.0'], // >=2.4.0 <2.5.0 149 | ['~2.4', '2.3.9'], 150 | ['~>3.2.1', '3.3.2'], // >=3.2.1 <3.3.0 151 | ['~>3.2.1', '3.2.0'], // >=3.2.1 <3.3.0 152 | ['~1', '0.2.3'], // >=1.0.0 <2.0.0 153 | ['~>1', '2.2.3'], 154 | ['~1.0', '1.1.0'], // >=1.0.0 <1.1.0 155 | ['<1', '1.0.0'], 156 | ['>=1.2', '1.1.1'], 157 | ['1', '2.0.0beta', true], 158 | ['~v0.5.4-beta', '0.5.4-alpha'], 159 | ['<1', '1.0.0beta', true], 160 | ['< 1', '1.0.0beta', true], 161 | ['=0.7.x', '0.8.2'], 162 | ['>=0.7.x', '0.6.2'], 163 | ['<=0.7.x', '0.7.2'], 164 | ['<1.2.3', '1.2.3-beta'], 165 | ['=1.2.3', '1.2.3-beta'], 166 | ['>1.2', '1.2.8'], 167 | ['^1.2.3', '2.0.0-alpha'], 168 | ['^1.2.3', '1.2.2'], 169 | ['^1.2', '1.1.9'], 170 | // invalid ranges never satisfied! 171 | ['blerg', '1.2.3'], 172 | ['git+https://user:password0123@github.com/foo', '123.0.0', true], 173 | ['^1.2.3', '2.0.0-pre'] 174 | EOF 175 | -------------------------------------------------------------------------------- /tests/output.sh: -------------------------------------------------------------------------------- 1 | describe 'Command output (printing)' 2 | RET=$(./semver.sh -r '^4.0.0' 4.0.0 4.2.1 | tail -1) 3 | assert "$RET" "4.2.1" '"\\n" should be printed as newlines' 4 | -------------------------------------------------------------------------------- /tests/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Tools 4 | 5 | OK_COUNT=0 6 | FAIL_COUNT=0 7 | 8 | describe() 9 | { 10 | if [ -n "$CURRENT_SECTION" ]; then 11 | printf "\n" 12 | fi 13 | 14 | CURRENT_SECTION="$1" 15 | CURRENT_COUNTER=1 16 | } 17 | 18 | assert() 19 | { 20 | if [ "$CURRENT_COUNTER" = 1 ]; then 21 | echo "$CURRENT_SECTION:" 22 | fi 23 | 24 | LABEL=${3:-Test $CURRENT_COUNTER} 25 | 26 | # This echoes are required for multiline strings comparison. 27 | # Belive me or not, but this is not true: 28 | # a="a\nb" 29 | # b="$(echo 'a'; echo 'b')" 30 | # [ "$a" = "$b" ] 31 | if [ "$(printf "$1")" = "$(printf "$2")" ]; then 32 | printf " \033[32m$LABEL\033[0m\n" 33 | OK_COUNT=$(( OK_COUNT + 1 )) 34 | else 35 | printf " \033[31m$LABEL\n" 36 | printf " \"$1\" != \"$2\"\033[0m\n" 37 | FAIL_COUNT=$(( FAIL_COUNT + 1 )) 38 | fi 39 | 40 | CURRENT_COUNTER=$(( CURRENT_COUNTER + 1 )) 41 | } 42 | 43 | summary() 44 | { 45 | printf "\n" 46 | printf "Total: $(( OK_COUNT + FAIL_COUNT))\n" 47 | printf "Succeed: $OK_COUNT\n" 48 | printf "Failed: $FAIL_COUNT\n" 49 | 50 | if [ "$FAIL_COUNT" != 0 ]; then 51 | exit 1 52 | fi 53 | } 54 | 55 | 56 | # Import semver 57 | . ./semver.sh < <(echo) # need to provide some stdin since no args are provided 58 | 59 | 60 | # Import specs 61 | . ./tests/input.sh 62 | . ./tests/tests.sh 63 | . ./tests/strict_rules_tests.sh 64 | . ./tests/output.sh 65 | #. ./tests/node_semver_tests.sh 66 | 67 | 68 | # Summarize 69 | summary 70 | -------------------------------------------------------------------------------- /tests/strict_rules_tests.sh: -------------------------------------------------------------------------------- 1 | 2 | describe 'Strict ranges' 3 | 4 | while read -r line; do 5 | if [ -z "$line" ] || [ "${line#\#}" != "${line}" ]; then 6 | continue 7 | fi 8 | 9 | parts=$(echo "$line" | sed 's/ \{2,\}/#/g') 10 | 11 | rule=$( echo "$parts" | cut -d "#" -f 1) 12 | ver=$( echo "$parts" | cut -d "#" -f 2) 13 | mode=$( echo "$parts" | cut -d "#" -f 3) 14 | ret=$( eval "./semver.sh -r '$rule' '$ver'") 15 | #ret=$( eval "semver -r '$rule' '$ver'") 16 | 17 | if [ "$mode" = "false" ]; then 18 | assert "$ret" "" "$ver should not match the range $rule" 19 | else 20 | assert "$ret" "$ver" "$ver should match the range $rule" 21 | fi 22 | 23 | done <1.0.0 0.9.99 false 69 | >1.0.0 1.0.0 false 70 | >1.0.0 1.0.1-b false 71 | >1.0.0 1.0.1 true 72 | >1.0.0 2.0.0-0 false 73 | >1.0.0 2.0.0 true 74 | >1.0.0-a.b 0.9.99 false 75 | >1.0.0-a.b 1.0.0-a false 76 | >1.0.0-a.b 1.0.0-a.b false 77 | >1.0.0-a.b 1.0.0-a.c true 78 | >1.0.0-a.b 1.0.0 true 79 | >1.0.0-a.b 2.5.0-4 false 80 | >1.0.0-a.b 2.5.0 true 81 | >1.2.x 1.3.0 true 82 | >1.2.x 1.2.9 false 83 | >1.x.x 2.0.0 true 84 | >1.x.x 1.9.9 false 85 | 86 | 87 | # Greater than or equal 88 | 89 | >=1.0.0 0.9.99 false 90 | >=1.0.0 1.0.0 true 91 | >=1.0.0 1.0.1-b false 92 | >=1.0.0 1.0.1 true 93 | >=1.0.0 2.0.0-0 false 94 | >=1.0.0 2.0.0 true 95 | >=1.0.0-a.b 0.9.99 false 96 | >=1.0.0-a.b 1.0.0-a false 97 | >=1.0.0-a.b 1.0.0-a.b true 98 | >=1.0.0-a.b 1.0.0-a.c true 99 | >=1.0.0-a.b 1.0.0 true 100 | >=1.0.0-a.b 2.5.0-4 false 101 | >=1.0.0-a.b 2.5.0 true 102 | >=1.2.x 1.2.0 true 103 | >=1.2.x 1.1.9 false 104 | >=1.x.x 1.0.0 true 105 | >=1.x.x 0.9.9 false 106 | 107 | 108 | # Specific version 109 | 110 | 1 0.0.99 false 111 | 1 1.0.0 true 112 | 1 1.2.3-0 false 113 | 1 1.2.3 true 114 | 1 2.0.0 false 115 | 1.2 1.1.99 false 116 | 1.2 1.2.0 true 117 | 1.2 1.2.3-0 false 118 | 1.2 1.2.3 true 119 | 1.2 1.3.0 false 120 | 1.2.3 1.2.3-b false 121 | 1.2.3 1.2.3 true 122 | 1.2.3 1.2.4 false 123 | 1.2.3-b 1.2.3-a false 124 | 1.2.3-b 1.2.3-b true 125 | 1.2.3-b 1.2.3-b.2 false 126 | 127 | 128 | # Hyphen range 129 | 130 | 1.2.3 - 1.2.5 1.2.2 false 131 | 1.2.3 - 1.2.5 1.2.3-0 false 132 | 1.2.3 - 1.2.5 1.2.3 true 133 | 1.2.3 - 1.2.5 1.2.4-0 false 134 | 1.2.3 - 1.2.5 1.2.5-0 false 135 | 1.2.3 - 1.2.5 1.2.5 true 136 | 1.2.3 - 1.2.5 1.2.6-0 false 137 | 1.2.3 - 1.2.5 1.2.6 false 138 | 2 - 5 1.0.0 false 139 | 2 - 5 2.0.0 true 140 | 2 - 5 3.0.0-1 false 141 | 2 - 5 5.0.0 true 142 | 2 - 5 6.0.0 false 143 | 1.2.3-a - 1.2.5-c 1.2.3-0 false 144 | 1.2.3-a - 1.2.5-c 1.2.3-a true 145 | 1.2.3-a - 1.2.5-c 1.2.3-b true 146 | 1.2.3-a - 1.2.5-c 1.2.3 true 147 | 1.2.3-a - 1.2.5-c 1.2.4-0 false 148 | 1.2.3-a - 1.2.5-c 1.2.4 true 149 | 1.2.3-a - 1.2.5-c 1.2.5-b true 150 | 1.2.3-a - 1.2.5-c 1.2.5-c true 151 | 1.2.3-a - 1.2.5-c 1.2.5-d false 152 | 1.2.3-a - 1.2.5-c 1.2.5 false 153 | 154 | 155 | # Wildcards 156 | 157 | * 0.0.0-0 true 158 | x.x 0.0.0-0 true 159 | *.*.* 0.0.0-0 true 160 | * 0.0.0 true 161 | x.x 0.0.0 true 162 | *.*.* 0.0.0 true 163 | * 1.2.3-a.b.c true 164 | x.x 1.2.3-a.b.c true 165 | *.*.* 1.2.3-a.b.c true 166 | * 9999.9999.9999 true 167 | x.x 9999.9999.9999 true 168 | *.*.* 9999.9999.9999 true 169 | 1.*.* 0.0.99 false 170 | 1.*.* 1.0.0-0 false 171 | 1.*.* 1.0.0 true 172 | 1.*.* 1.5.7-0 false 173 | 1.*.* 1.5.7 true 174 | 1.*.* 2.0.0-0 false 175 | 1.*.* 2.0.0 false 176 | 1.2.x 1.1.99 false 177 | 1.2.x 1.2.0-0 false 178 | 1.2.x 1.2.0 true 179 | 1.2.x 1.2.5-0 false 180 | 1.2.x 1.2.5 true 181 | 1.2.x 1.3.0-0 false 182 | 1.2.x 1.3.0 false 183 | 184 | 185 | # Tilde 186 | 187 | ~4.5.6 4.5.5 false 188 | ~4.5.6 4.5.6-0 false 189 | ~4.5.6 4.5.6 true 190 | ~4.5.6 4.5.7-0 false 191 | ~4.5.6 4.5.7 true 192 | ~4.5.6 4.6.0 false 193 | ~6.2 6.2.0 true 194 | ~6.2 6.2.3-0 false 195 | ~6.2 6.2.3 true 196 | ~6.2 7.0.0 false 197 | ~7 6.2.3 false 198 | ~7 7.0.0-0 false 199 | ~7 7.8.9 true 200 | ~7 8.0.0 false 201 | ~4.5.6-1 4.5.5 false 202 | ~4.5.6-1 4.5.6-0 false 203 | ~4.5.6-1 4.5.6-1 true 204 | ~4.5.6-1 4.5.6-2 true 205 | ~4.5.6-1 4.5.6 true 206 | ~4.5.6-1 4.5.7-0 false 207 | ~4.5.6-1 4.5.7 true 208 | ~4.5.6-1 4.6.0 false 209 | 210 | 211 | # Caret 212 | 213 | ^0.5.1 0.5.0 false 214 | ^0.5.1 0.5.1-0 false 215 | ^0.5.1 0.5.1 true 216 | ^0.5.1 0.5.2-0 false 217 | ^0.5 0.4.9999 false 218 | ^0.5 0.5.0 true 219 | ^0.5 0.5.1-0 false 220 | ^0.5 0.5.1 true 221 | ^0.5 0.6.0 false 222 | ^1.5.9 1.4.9999 false 223 | ^1.5.9 1.5.0 false 224 | ^1.5.9 1.5.9-0 false 225 | ^1.5.9 1.5.9 true 226 | ^1.5.9 1.7.12-0 false 227 | ^1.5.9 1.7.12 true 228 | ^1.5.9 2.0.0 false 229 | ^5 4.9.99 false 230 | ^5 5.0.0 true 231 | ^5 5.100.0-0 false 232 | ^5 5.100.0 true 233 | ^5 6.0.0-0 false 234 | ^1.5.9-1 1.4.9999 false 235 | ^1.5.9-1 1.5.0 false 236 | ^1.5.9-1 1.5.9-0 false 237 | ^1.5.9-1 1.5.9-1 true 238 | ^1.5.9-1 1.5.9-2 true 239 | ^1.5.9-1 1.5.9 true 240 | ^1.5.9-1 1.5.10-0 false 241 | ^1.5.9-1 1.5.10 true 242 | ^1.5.9-1 1.7.12 true 243 | ^1.5.9-1 2.0.0 false 244 | 245 | 246 | # Multiple rules 247 | 248 | >1.2.3-c <=2.7.0 1.2.3-c false 249 | >1.2.3-c <=2.7.0 1.2.3-d true 250 | >1.2.3-c <=2.7.0 1.4.0-d false 251 | >1.2.3-c <=2.7.0 2.7.0-0 false 252 | >1.2.3-c <=2.7.0 2.7.0 true 253 | >1.2.3-c <=2.7.0 2.7.1 false 254 | >1.2.3-c <=2.7.0 * 1.2.3-c false 255 | >1.2.3-c <=2.7.0 * 1.2.3-d true 256 | >1.2.3-c <=2.7.0 * 1.4.0-d true 257 | >1.2.3-c <=2.7.0 * 2.7.0-0 true 258 | >1.2.3-c <=2.7.0 * 2.7.0 true 259 | >1.2.3-c <=2.7.0 * 2.7.1 false 260 | >1.2.3-c <=2.7.0-9 1.2.3-c false 261 | >1.2.3-c <=2.7.0-9 1.2.3-d true 262 | >1.2.3-c <=2.7.0-9 1.4.0-d false 263 | >1.2.3-c <=2.7.0-9 2.7.0-0 true 264 | >1.2.3-c <=2.7.0-9 2.7.0 false 265 | >1.2.3-c <=2.7.0-9 2.7.1 false 266 | 267 | 268 | # Multiple ranges 269 | 270 | ~1.2.3 || ~4.5.6 1.2.2 false 271 | ~1.2.3 || ~4.5.6 1.2.3 true 272 | ~1.2.3 || ~4.5.6 1.2.4-0 false 273 | ~1.2.3 || ~4.5.6 1.2.4 true 274 | ~1.2.3 || ~4.5.6 1.3.0 false 275 | ~1.2.3 || ~4.5.6 4.5.5 false 276 | ~1.2.3 || ~4.5.6 4.5.6 true 277 | ~1.2.3 || ~4.5.6 4.5.9-0 false 278 | ~1.2.3 || ~4.5.6 4.5.9 true 279 | ~1.2.3 || ~4.5.6 4.6.0 false 280 | <5.0.0 * || 5.*.* 4.4.4-4 true 281 | <5.0.0 * || 5.*.* 4.4.4 true 282 | <5.0.0 * || 5.*.* 5.5.5-5 false 283 | <5.0.0 * || 5.*.* 5.5.5 true 284 | 285 | 286 | EOF 287 | -------------------------------------------------------------------------------- /tests/tests.sh: -------------------------------------------------------------------------------- 1 | describe 'get_number' 2 | RET=$(get_number '1.2.3-a-b-3.2.1+meta') 3 | assert "$RET" "1.2.3" 4 | 5 | RET=$(get_number '1-1.2.3') 6 | assert "$RET" "1" 7 | 8 | describe 'get_prerelease' 9 | RET=$(get_prerelease '1.2.3-a-b-3.2.1+meta') 10 | assert "$RET" "a-b-3.2.1" 11 | 12 | describe 'strip_metadata' 13 | RET=$(strip_metadata '1.2.3-a-b-3.2.1+meta') 14 | assert "$RET" "1.2.3-a-b-3.2.1" 15 | 16 | describe 'get_major' 17 | RET=$(get_major 1.2.3) 18 | assert "$RET" "1" 19 | 20 | describe 'get_minor' 21 | RET=$(get_minor 1.2.3) 22 | assert "$RET" "2" 23 | 24 | RET=$(get_minor 1) 25 | assert "$RET" "" 26 | 27 | describe 'get_bugfix' 28 | RET=$(get_bugfix 1.2.3) 29 | assert "$RET" "3" 30 | 31 | RET=$(get_bugfix 1.2) 32 | assert "$RET" "" 33 | 34 | RET=$(get_bugfix 1) 35 | assert "$RET" "" 36 | 37 | describe 'semver_eq' 38 | semver_eq 1.2.3 1.2.3 39 | assert $? 0 40 | 41 | semver_eq 1.2.3 1.2.4 42 | assert $? 1 43 | 44 | semver_eq 1.2.3 1.2 45 | assert $? 0 46 | 47 | semver_eq 1.2.3 1 48 | assert $? 0 49 | 50 | semver_eq 2.2 1 51 | assert $? 1 52 | 53 | describe 'semver_lt' 54 | assert_lt() 55 | { 56 | local msg="$1 < $2 => $3" 57 | semver_lt $1 $2 58 | assert $? $3 "$msg" 59 | } 60 | 61 | assert_lt 1.2.2 1.2.3 0 62 | assert_lt 1.2.3 1.2.3 1 63 | assert_lt 1.2.4 1.2.3 1 64 | assert_lt 1.0.0-alpha 1.0.0-alpha.1 0 65 | assert_lt 1.0.0-alpha.1 1.0.0-alpha 1 66 | assert_lt 1.0.0-alpha.1 1.0.0-alpha.beta 0 67 | assert_lt 1.0.0-alpha.beta 1.0.0-alpha.1 1 68 | assert_lt 1.0.0-alpha.beta 1.0.0-beta 0 69 | assert_lt 1.0.0-beta 1.0.0-alpha.beta 1 70 | assert_lt 1.0.0-beta 1.0.0-beta.2 0 71 | assert_lt 1.0.0-beta.2 1.0.0-beta 1 72 | assert_lt 1.0.0-beta.2 1.0.0-beta.11 0 73 | assert_lt 1.0.0-beta.11 1.0.0-beta.2 1 74 | assert_lt 1.0.0-beta.11 1.0.0-rc.1 0 75 | assert_lt 1.0.0-rc.1 1.0.0-beta.11 1 76 | assert_lt 1.0.0-rc.1 1.0.0 0 77 | assert_lt 1.0.0 1.0.0-rc.1 1 78 | 79 | describe 'semver_le' 80 | semver_le 1.2.2 1.2.3 81 | assert $? 0 82 | 83 | semver_le 1.2.3 1.2.3 84 | assert $? 0 85 | 86 | semver_le 1.2.4 1.2.3 87 | assert $? 1 88 | 89 | describe 'semver_gt' 90 | semver_gt 1.2.2 1.2.3 91 | assert $? 1 92 | 93 | semver_gt 1.2.3 1.2.3 94 | assert $? 1 95 | 96 | semver_gt 1.2.4 1.2.3 97 | assert $? 0 98 | 99 | describe 'semver_ge' 100 | semver_ge 1.2.2 1.2.3 101 | assert $? 1 102 | 103 | semver_ge 1.2.3 1.2.3 104 | assert $? 0 105 | 106 | semver_ge 1.2.4 1.2.3 107 | assert $? 0 108 | 109 | describe 'semver_sort' 110 | RET=$(semver_sort) 111 | assert "$RET" "" "should return nothing when no arguments passed" 112 | 113 | RET=$(semver_sort 1.2.3) 114 | assert "$RET" "1.2.3" "should sort input - 1.2.3" 115 | 116 | RET=$(semver_sort 1.2.3 4.5.6 7.8.9) 117 | assert "$RET" "1.2.3 4.5.6 7.8.9" "should sort input - 1.2.3 4.5.6 7.8.9" 118 | 119 | RET=$(semver_sort 7.8.9 4.5.6 1.2.3) 120 | assert "$RET" "1.2.3 4.5.6 7.8.9" "should sort input - 1.2.3 4.5.6 7.8.9" 121 | 122 | RET=$(semver_sort 1 2 8 5 2 4 9 5 2 6 4 1 2 0 4 2 5 8 7 4 3) 123 | assert "$RET" "0 1 1 2 2 2 2 2 3 4 4 4 4 5 5 5 6 7 8 8 9" "should sort input - long input" 124 | 125 | describe 'regex_match' 126 | regex_match "1.22.333 - 1.2.3-3.2.1-a.b.c-def+011.a.1" "$RE_VER - $RE_VER" 127 | assert $? 0 "Exit code should be 0 when match" 128 | assert "$MATCHED_VER_1" "1.22.333" "Should set MATCHED_VER_1" 129 | assert "$MATCHED_VER_2" "1.2.3-3.2.1-a.b.c-def+011.a.1" "Should set MATCHED_VER_2" 130 | assert "$MATCHED_NUM_1" "1.22.333" "Should set MATCHED_NUM_1" 131 | assert "$MATCHED_NUM_2" "1.2.3" "Should set MATCHED_NUM_2" 132 | 133 | regex_match '1.2.3 - 5.6.7' '5.6.7' 134 | assert $? 1 "Exit code should be 1 when don't match" 135 | assert "$MATCHED_VER_1" "" "When don't match MATCHED_VER_x should be empty" 136 | assert "$MATCHED_VER_1" "" "When don't match MATCHED_NUM_x should be empty" 137 | 138 | describe 'resolve_rules' 139 | RET=$(resolve_rules 'v1.2.3') 140 | assert "$RET" "eq 1.2.3" "Specific (v1.2.3)" 141 | 142 | RET=$(resolve_rules '=1.2.3') 143 | assert "$RET" "eq 1.2.3" "Specific (=1.2.3)" 144 | 145 | RET=$(resolve_rules '1') 146 | assert "$RET" "eq 1" "Specific (1)" 147 | 148 | RET=$(resolve_rules '=1.2.3-a.2-c') 149 | assert "$RET" "eq 1.2.3-a.2-c" "Specific (=1.2.3-a.2-c)" 150 | 151 | RET=$(resolve_rules '=1.2.3-a.2+meta') 152 | assert "$RET" "eq 1.2.3-a.2+meta" "Specific (=1.2.3-a.2+meta)" 153 | 154 | RET=$(resolve_rules '=1.2.3-a.2+meta.data') 155 | assert "$RET" "eq 1.2.3-a.2+meta.data" "Specific (=1.2.3-a.2+meta.data)" 156 | 157 | RET=$(resolve_rules '>1.2.3') 158 | assert "$RET" "gt 1.2.3" "Greater than (>1.2.3)" 159 | 160 | RET=$(resolve_rules '<1.2.3') 161 | assert "$RET" "lt 1.2.3" "Less than (<1.2.3)" 162 | 163 | RET=$(resolve_rules '>=1.2.3') 164 | assert "$RET" "ge 1.2.3" "Greater than or equal to (>=1.2.3)" 165 | 166 | RET=$(resolve_rules '<=1.2.3') 167 | assert "$RET" "le 1.2.3" "Less than or equal to (<=1.2.3)" 168 | 169 | RET=$(resolve_rules '1.2.3 - 4.5.6') 170 | assert "$RET" "ge 1.2.3\nle 4.5.6" "Range (1.2.3 - 4.5.6)" 171 | 172 | RET=$(resolve_rules '>1.2.3 <4.5.6') 173 | assert "$RET" "gt 1.2.3\nlt 4.5.6" "Range (>1.2.3 <4.5.6)" 174 | 175 | RET=$(resolve_rules '>1.2.3 <=4.5.6') 176 | assert "$RET" "gt 1.2.3\nle 4.5.6" "Range (>1.2.3 <=4.5.6)" 177 | 178 | RET=$(resolve_rules '>=1.2.3 <4.5.6') 179 | assert "$RET" "ge 1.2.3\nlt 4.5.6" "Range (>=1.2.3 <4.5.6)" 180 | 181 | RET=$(resolve_rules '>=1.2.3 <=4.5.6') 182 | assert "$RET" "ge 1.2.3\nle 4.5.6" "Range (>=1.2.3 <=4.5.6)" 183 | 184 | RET=$(resolve_rules '~1.2.3') 185 | assert "$RET" "tilde 1.2.3" "Tilde (~1.2.3)" 186 | 187 | RET=$(resolve_rules '*') 188 | assert "$RET" "all" "Wildcard (*)" 189 | 190 | RET=$(resolve_rules 'x') 191 | assert "$RET" "all" "Wildcard (x)" 192 | 193 | RET=$(resolve_rules 'X') 194 | assert "$RET" "all" "Wildcard (X)" 195 | 196 | RET=$(resolve_rules '1.2.x') 197 | assert "$RET" "eq 1.2" "Wildcard (1.2.x)" 198 | 199 | RET=$(resolve_rules '1.2.*') 200 | assert "$RET" "eq 1.2" "Wildcard (1.2.*)" 201 | 202 | RET=$(resolve_rules '1.*.*') 203 | assert "$RET" "eq 1" "Wildcard (1.*.*)" 204 | 205 | RET=$(resolve_rules '=1.2.x') 206 | assert "$RET" "eq 1.2" "Wildcard (=1.2.x)" 207 | 208 | RET=$(resolve_rules '=1.2.X') 209 | assert "$RET" "eq 1.2" "Wildcard (=1.2.X)" 210 | 211 | RET=$(resolve_rules '=1.2.*') 212 | assert "$RET" "eq 1.2" "Wildcard (=1.2.*)" 213 | 214 | RET=$(resolve_rules '=1.*.*') 215 | assert "$RET" "eq 1" "Wildcard (=1.*.*)" 216 | 217 | RET=$(resolve_rules '*.*.*') 218 | assert "$RET" "all" "Wildcard (*.*.*)" 219 | 220 | RET=$(resolve_rules '^1.2.3') 221 | assert "$RET" "caret 1.2.3" "Caret (^1.2.3)" 222 | 223 | RET=$(resolve_rules '~1.2.3 4.5.6_-_7.8.9 *') 224 | assert "$RET" "tilde 1.2.3 225 | ge 4.5.6 226 | le 7.8.9 227 | all" "Tilde (~1.2.3) and Range (4.5.6 - 7.8.9) and Wildcard (*)" 228 | 229 | describe 'normalize_rules' 230 | RET="$(normalize_rules ' \t > \t1.2.3.4-abc.def+a \t 123.123 -\t\t\t v5.3.2 ~ \tv5.5.* x ')" 231 | assert "$RET" '>1.2.3.4-abc.def+a 123.123_-_5.3.2 ~5.5 *' 232 | --------------------------------------------------------------------------------