| 1 | target | |
| 2 | Cargo.lock |
| 1 | [package] | |
| 2 | name = "semver-parser" | |
| 3 | version = "0.6.2" | |
| 4 | authors = ["Steve Klabnik <[email protected]>"] | |
| 5 | license = "MIT/Apache-2.0" | |
| 6 | repository = "https://github.com/steveklabnik/semver-parser" | |
| 7 | homepage = "https://github.com/steveklabnik/semver-parser" | |
| 8 | documentation = "https://docs.rs/semver-parser" | |
| 9 | description = """ | |
| 10 | Parsing of the semver spec | |
| 11 | """ | |
| 12 | ||
| 13 | [dependencies] | |
| 14 | regex = "0.1" | |
| 15 | lazy_static = "0.2.1" |
| 1 | Apache License | |
| 2 | Version 2.0, January 2004 | |
| 3 | http://www.apache.org/licenses/ | |
| 4 | ||
| 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | |
| 6 | ||
| 7 | 1. Definitions. | |
| 8 | ||
| 9 | "License" shall mean the terms and conditions for use, reproduction, | |
| 10 | and distribution as defined by Sections 1 through 9 of this document. | |
| 11 | ||
| 12 | "Licensor" shall mean the copyright owner or entity authorized by | |
| 13 | the copyright owner that is granting the License. | |
| 14 | ||
| 15 | "Legal Entity" shall mean the union of the acting entity and all | |
| 16 | other entities that control, are controlled by, or are under common | |
| 17 | control with that entity. For the purposes of this definition, | |
| 18 | "control" means (i) the power, direct or indirect, to cause the | |
| 19 | direction or management of such entity, whether by contract or | |
| 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the | |
| 21 | outstanding shares, or (iii) beneficial ownership of such entity. | |
| 22 | ||
| 23 | "You" (or "Your") shall mean an individual or Legal Entity | |
| 24 | exercising permissions granted by this License. | |
| 25 | ||
| 26 | "Source" form shall mean the preferred form for making modifications, | |
| 27 | including but not limited to software source code, documentation | |
| 28 | source, and configuration files. | |
| 29 | ||
| 30 | "Object" form shall mean any form resulting from mechanical | |
| 31 | transformation or translation of a Source form, including but | |
| 32 | not limited to compiled object code, generated documentation, | |
| 33 | and conversions to other media types. | |
| 34 | ||
| 35 | "Work" shall mean the work of authorship, whether in Source or | |
| 36 | Object form, made available under the License, as indicated by a | |
| 37 | copyright notice that is included in or attached to the work | |
| 38 | (an example is provided in the Appendix below). | |
| 39 | ||
| 40 | "Derivative Works" shall mean any work, whether in Source or Object | |
| 41 | form, that is based on (or derived from) the Work and for which the | |
| 42 | editorial revisions, annotations, elaborations, or other modifications | |
| 43 | represent, as a whole, an original work of authorship. For the purposes | |
| 44 | of this License, Derivative Works shall not include works that remain | |
| 45 | separable from, or merely link (or bind by name) to the interfaces of, | |
| 46 | the Work and Derivative Works thereof. | |
| 47 | ||
| 48 | "Contribution" shall mean any work of authorship, including | |
| 49 | the original version of the Work and any modifications or additions | |
| 50 | to that Work or Derivative Works thereof, that is intentionally | |
| 51 | submitted to Licensor for inclusion in the Work by the copyright owner | |
| 52 | or by an individual or Legal Entity authorized to submit on behalf of | |
| 53 | the copyright owner. For the purposes of this definition, "submitted" | |
| 54 | means any form of electronic, verbal, or written communication sent | |
| 55 | to the Licensor or its representatives, including but not limited to | |
| 56 | communication on electronic mailing lists, source code control systems, | |
| 57 | and issue tracking systems that are managed by, or on behalf of, the | |
| 58 | Licensor for the purpose of discussing and improving the Work, but | |
| 59 | excluding communication that is conspicuously marked or otherwise | |
| 60 | designated in writing by the copyright owner as "Not a Contribution." | |
| 61 | ||
| 62 | "Contributor" shall mean Licensor and any individual or Legal Entity | |
| 63 | on behalf of whom a Contribution has been received by Licensor and | |
| 64 | subsequently incorporated within the Work. | |
| 65 | ||
| 66 | 2. Grant of Copyright License. Subject to the terms and conditions of | |
| 67 | this License, each Contributor hereby grants to You a perpetual, | |
| 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |
| 69 | copyright license to reproduce, prepare Derivative Works of, | |
| 70 | publicly display, publicly perform, sublicense, and distribute the | |
| 71 | Work and such Derivative Works in Source or Object form. | |
| 72 | ||
| 73 | 3. Grant of Patent License. Subject to the terms and conditions of | |
| 74 | this License, each Contributor hereby grants to You a perpetual, | |
| 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |
| 76 | (except as stated in this section) patent license to make, have made, | |
| 77 | use, offer to sell, sell, import, and otherwise transfer the Work, | |
| 78 | where such license applies only to those patent claims licensable | |
| 79 | by such Contributor that are necessarily infringed by their | |
| 80 | Contribution(s) alone or by combination of their Contribution(s) | |
| 81 | with the Work to which such Contribution(s) was submitted. If You | |
| 82 | institute patent litigation against any entity (including a | |
| 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work | |
| 84 | or a Contribution incorporated within the Work constitutes direct | |
| 85 | or contributory patent infringement, then any patent licenses | |
| 86 | granted to You under this License for that Work shall terminate | |
| 87 | as of the date such litigation is filed. | |
| 88 | ||
| 89 | 4. Redistribution. You may reproduce and distribute copies of the | |
| 90 | Work or Derivative Works thereof in any medium, with or without | |
| 91 | modifications, and in Source or Object form, provided that You | |
| 92 | meet the following conditions: | |
| 93 | ||
| 94 | (a) You must give any other recipients of the Work or | |
| 95 | Derivative Works a copy of this License; and | |
| 96 | ||
| 97 | (b) You must cause any modified files to carry prominent notices | |
| 98 | stating that You changed the files; and | |
| 99 | ||
| 100 | (c) You must retain, in the Source form of any Derivative Works | |
| 101 | that You distribute, all copyright, patent, trademark, and | |
| 102 | attribution notices from the Source form of the Work, | |
| 103 | excluding those notices that do not pertain to any part of | |
| 104 | the Derivative Works; and | |
| 105 | ||
| 106 | (d) If the Work includes a "NOTICE" text file as part of its | |
| 107 | distribution, then any Derivative Works that You distribute must | |
| 108 | include a readable copy of the attribution notices contained | |
| 109 | within such NOTICE file, excluding those notices that do not | |
| 110 | pertain to any part of the Derivative Works, in at least one | |
| 111 | of the following places: within a NOTICE text file distributed | |
| 112 | as part of the Derivative Works; within the Source form or | |
| 113 | documentation, if provided along with the Derivative Works; or, | |
| 114 | within a display generated by the Derivative Works, if and | |
| 115 | wherever such third-party notices normally appear. The contents | |
| 116 | of the NOTICE file are for informational purposes only and | |
| 117 | do not modify the License. You may add Your own attribution | |
| 118 | notices within Derivative Works that You distribute, alongside | |
| 119 | or as an addendum to the NOTICE text from the Work, provided | |
| 120 | that such additional attribution notices cannot be construed | |
| 121 | as modifying the License. | |
| 122 | ||
| 123 | You may add Your own copyright statement to Your modifications and | |
| 124 | may provide additional or different license terms and conditions | |
| 125 | for use, reproduction, or distribution of Your modifications, or | |
| 126 | for any such Derivative Works as a whole, provided Your use, | |
| 127 | reproduction, and distribution of the Work otherwise complies with | |
| 128 | the conditions stated in this License. | |
| 129 | ||
| 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, | |
| 131 | any Contribution intentionally submitted for inclusion in the Work | |
| 132 | by You to the Licensor shall be under the terms and conditions of | |
| 133 | this License, without any additional terms or conditions. | |
| 134 | Notwithstanding the above, nothing herein shall supersede or modify | |
| 135 | the terms of any separate license agreement you may have executed | |
| 136 | with Licensor regarding such Contributions. | |
| 137 | ||
| 138 | 6. Trademarks. This License does not grant permission to use the trade | |
| 139 | names, trademarks, service marks, or product names of the Licensor, | |
| 140 | except as required for reasonable and customary use in describing the | |
| 141 | origin of the Work and reproducing the content of the NOTICE file. | |
| 142 | ||
| 143 | 7. Disclaimer of Warranty. Unless required by applicable law or | |
| 144 | agreed to in writing, Licensor provides the Work (and each | |
| 145 | Contributor provides its Contributions) on an "AS IS" BASIS, | |
| 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |
| 147 | implied, including, without limitation, any warranties or conditions | |
| 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | |
| 149 | PARTICULAR PURPOSE. You are solely responsible for determining the | |
| 150 | appropriateness of using or redistributing the Work and assume any | |
| 151 | risks associated with Your exercise of permissions under this License. | |
| 152 | ||
| 153 | 8. Limitation of Liability. In no event and under no legal theory, | |
| 154 | whether in tort (including negligence), contract, or otherwise, | |
| 155 | unless required by applicable law (such as deliberate and grossly | |
| 156 | negligent acts) or agreed to in writing, shall any Contributor be | |
| 157 | liable to You for damages, including any direct, indirect, special, | |
| 158 | incidental, or consequential damages of any character arising as a | |
| 159 | result of this License or out of the use or inability to use the | |
| 160 | Work (including but not limited to damages for loss of goodwill, | |
| 161 | work stoppage, computer failure or malfunction, or any and all | |
| 162 | other commercial damages or losses), even if such Contributor | |
| 163 | has been advised of the possibility of such damages. | |
| 164 | ||
| 165 | 9. Accepting Warranty or Additional Liability. While redistributing | |
| 166 | the Work or Derivative Works thereof, You may choose to offer, | |
| 167 | and charge a fee for, acceptance of support, warranty, indemnity, | |
| 168 | or other liability obligations and/or rights consistent with this | |
| 169 | License. However, in accepting such obligations, You may act only | |
| 170 | on Your own behalf and on Your sole responsibility, not on behalf | |
| 171 | of any other Contributor, and only if You agree to indemnify, | |
| 172 | defend, and hold each Contributor harmless for any liability | |
| 173 | incurred by, or claims asserted against, such Contributor by reason | |
| 174 | of your accepting any such warranty or additional liability. | |
| 175 | ||
| 176 | END OF TERMS AND CONDITIONS | |
| 177 | ||
| 178 | APPENDIX: How to apply the Apache License to your work. | |
| 179 | ||
| 180 | To apply the Apache License to your work, attach the following | |
| 181 | boilerplate notice, with the fields enclosed by brackets "[]" | |
| 182 | replaced with your own identifying information. (Don't include | |
| 183 | the brackets!) The text should be enclosed in the appropriate | |
| 184 | comment syntax for the file format. We also recommend that a | |
| 185 | file or class name and description of purpose be included on the | |
| 186 | same "printed page" as the copyright notice for easier | |
| 187 | identification within third-party archives. | |
| 188 | ||
| 189 | Copyright [yyyy] [name of copyright owner] | |
| 190 | ||
| 191 | Licensed under the Apache License, Version 2.0 (the "License"); | |
| 192 | you may not use this file except in compliance with the License. | |
| 193 | You may obtain a copy of the License at | |
| 194 | ||
| 195 | http://www.apache.org/licenses/LICENSE-2.0 | |
| 196 | ||
| 197 | Unless required by applicable law or agreed to in writing, software | |
| 198 | distributed under the License is distributed on an "AS IS" BASIS, | |
| 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 200 | See the License for the specific language governing permissions and | |
| 201 | limitations under the License. |
| 1 | Copyright (c) 2016 Steve Klabnik | |
| 2 | ||
| 3 | Permission is hereby granted, free of charge, to any | |
| 4 | person obtaining a copy of this software and associated | |
| 5 | documentation files (the "Software"), to deal in the | |
| 6 | Software without restriction, including without | |
| 7 | limitation the rights to use, copy, modify, merge, | |
| 8 | publish, distribute, sublicense, and/or sell copies of | |
| 9 | the Software, and to permit persons to whom the Software | |
| 10 | is furnished to do so, subject to the following | |
| 11 | conditions: | |
| 12 | ||
| 13 | The above copyright notice and this permission notice | |
| 14 | shall be included in all copies or substantial portions | |
| 15 | of the Software. | |
| 16 | ||
| 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | |
| 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | |
| 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | |
| 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | |
| 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |
| 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR | |
| 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | DEALINGS IN THE SOFTWARE. |
| 1 | target | |
| 2 | Cargo.lock |
| 1 | [package] | |
| 2 | name = "semver-parser" | |
| 3 | version = "0.1.0" | |
| 4 | authors = ["Steve Klabnik <[email protected]>"] | |
| 5 | ||
| 6 | [dependencies] | |
| 7 | regex = "0.1.69" |
| 2 | 2 | name = "semver-parser" |
| 3 | 3 | version = "0.1.0" |
| 4 | 4 | authors = ["Steve Klabnik <[email protected]>"] |
| 5 | license = "MIT/Apache-2.0" | |
| 6 | repository = "https://github.com/steveklabnik/semver-parser" | |
| 7 | homepage = "https://github.com/steveklabnik/semver-parser" | |
| 8 | documentation = "http://steveklabnik.github.io/semver-parser" | |
| 9 | description = """ | |
| 10 | Parsing of the semver spec | |
| 11 | """ | |
| 5 | 12 | |
| 6 | 13 | [dependencies] |
| 7 | 14 | regex = "0.1.69" |
| 1 | 1 | [package] |
| 2 | 2 | name = "semver-parser" |
| 3 | version = "0.1.0" | |
| 3 | version = "0.2.0" | |
| 4 | 4 | authors = ["Steve Klabnik <[email protected]>"] |
| 5 | 5 | license = "MIT/Apache-2.0" |
| 6 | 6 | repository = "https://github.com/steveklabnik/semver-parser" |
| 1 | 1 | [package] |
| 2 | 2 | name = "semver-parser" |
| 3 | version = "0.2.0" | |
| 3 | version = "0.3.0" | |
| 4 | 4 | authors = ["Steve Klabnik <[email protected]>"] |
| 5 | 5 | license = "MIT/Apache-2.0" |
| 6 | 6 | repository = "https://github.com/steveklabnik/semver-parser" |
| 1 | 1 | [package] |
| 2 | 2 | name = "semver-parser" |
| 3 | version = "0.3.0" | |
| 3 | version = "0.4.0" | |
| 4 | 4 | authors = ["Steve Klabnik <[email protected]>"] |
| 5 | 5 | license = "MIT/Apache-2.0" |
| 6 | 6 | repository = "https://github.com/steveklabnik/semver-parser" |
| 1 | 1 | [package] |
| 2 | 2 | name = "semver-parser" |
| 3 | version = "0.4.0" | |
| 3 | version = "0.4.1" | |
| 4 | 4 | authors = ["Steve Klabnik <[email protected]>"] |
| 5 | 5 | license = "MIT/Apache-2.0" |
| 6 | 6 | repository = "https://github.com/steveklabnik/semver-parser" |
| 1 | 1 | [package] |
| 2 | 2 | name = "semver-parser" |
| 3 | version = "0.4.1" | |
| 3 | version = "0.5.0" | |
| 4 | 4 | authors = ["Steve Klabnik <[email protected]>"] |
| 5 | 5 | license = "MIT/Apache-2.0" |
| 6 | 6 | repository = "https://github.com/steveklabnik/semver-parser" |
| 1 | 1 | [package] |
| 2 | 2 | name = "semver-parser" |
| 3 | version = "0.5.0" | |
| 3 | version = "0.5.1" | |
| 4 | 4 | authors = ["Steve Klabnik <[email protected]>"] |
| 5 | 5 | license = "MIT/Apache-2.0" |
| 6 | 6 | repository = "https://github.com/steveklabnik/semver-parser" |
| 11 | 11 | """ |
| 12 | 12 | |
| 13 | 13 | [dependencies] |
| 14 | regex = "0.1.69" | |
| 14 | regex = "0.1" | |
| 15 | lazy_static = "0.2.1" |
| 1 | 1 | [package] |
| 2 | 2 | name = "semver-parser" |
| 3 | version = "0.5.1" | |
| 3 | version = "0.6.0" | |
| 4 | 4 | authors = ["Steve Klabnik <[email protected]>"] |
| 5 | 5 | license = "MIT/Apache-2.0" |
| 6 | 6 | repository = "https://github.com/steveklabnik/semver-parser" |
| 5 | 5 | license = "MIT/Apache-2.0" |
| 6 | 6 | repository = "https://github.com/steveklabnik/semver-parser" |
| 7 | 7 | homepage = "https://github.com/steveklabnik/semver-parser" |
| 8 | documentation = "http://steveklabnik.github.io/semver-parser" | |
| 8 | documentation = "https://docs.rs/semver-parser" | |
| 9 | 9 | description = """ |
| 10 | 10 | Parsing of the semver spec |
| 11 | 11 | """ |
| 1 | 1 | [package] |
| 2 | 2 | name = "semver-parser" |
| 3 | version = "0.6.0" | |
| 3 | version = "0.6.2" | |
| 4 | 4 | authors = ["Steve Klabnik <[email protected]>"] |
| 5 | 5 | license = "MIT/Apache-2.0" |
| 6 | 6 | repository = "https://github.com/steveklabnik/semver-parser" |
| 1 | Apache License | |
| 2 | Version 2.0, January 2004 | |
| 3 | http://www.apache.org/licenses/ | |
| 4 | ||
| 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | |
| 6 | ||
| 7 | 1. Definitions. | |
| 8 | ||
| 9 | "License" shall mean the terms and conditions for use, reproduction, | |
| 10 | and distribution as defined by Sections 1 through 9 of this document. | |
| 11 | ||
| 12 | "Licensor" shall mean the copyright owner or entity authorized by | |
| 13 | the copyright owner that is granting the License. | |
| 14 | ||
| 15 | "Legal Entity" shall mean the union of the acting entity and all | |
| 16 | other entities that control, are controlled by, or are under common | |
| 17 | control with that entity. For the purposes of this definition, | |
| 18 | "control" means (i) the power, direct or indirect, to cause the | |
| 19 | direction or management of such entity, whether by contract or | |
| 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the | |
| 21 | outstanding shares, or (iii) beneficial ownership of such entity. | |
| 22 | ||
| 23 | "You" (or "Your") shall mean an individual or Legal Entity | |
| 24 | exercising permissions granted by this License. | |
| 25 | ||
| 26 | "Source" form shall mean the preferred form for making modifications, | |
| 27 | including but not limited to software source code, documentation | |
| 28 | source, and configuration files. | |
| 29 | ||
| 30 | "Object" form shall mean any form resulting from mechanical | |
| 31 | transformation or translation of a Source form, including but | |
| 32 | not limited to compiled object code, generated documentation, | |
| 33 | and conversions to other media types. | |
| 34 | ||
| 35 | "Work" shall mean the work of authorship, whether in Source or | |
| 36 | Object form, made available under the License, as indicated by a | |
| 37 | copyright notice that is included in or attached to the work | |
| 38 | (an example is provided in the Appendix below). | |
| 39 | ||
| 40 | "Derivative Works" shall mean any work, whether in Source or Object | |
| 41 | form, that is based on (or derived from) the Work and for which the | |
| 42 | editorial revisions, annotations, elaborations, or other modifications | |
| 43 | represent, as a whole, an original work of authorship. For the purposes | |
| 44 | of this License, Derivative Works shall not include works that remain | |
| 45 | separable from, or merely link (or bind by name) to the interfaces of, | |
| 46 | the Work and Derivative Works thereof. | |
| 47 | ||
| 48 | "Contribution" shall mean any work of authorship, including | |
| 49 | the original version of the Work and any modifications or additions | |
| 50 | to that Work or Derivative Works thereof, that is intentionally | |
| 51 | submitted to Licensor for inclusion in the Work by the copyright owner | |
| 52 | or by an individual or Legal Entity authorized to submit on behalf of | |
| 53 | the copyright owner. For the purposes of this definition, "submitted" | |
| 54 | means any form of electronic, verbal, or written communication sent | |
| 55 | to the Licensor or its representatives, including but not limited to | |
| 56 | communication on electronic mailing lists, source code control systems, | |
| 57 | and issue tracking systems that are managed by, or on behalf of, the | |
| 58 | Licensor for the purpose of discussing and improving the Work, but | |
| 59 | excluding communication that is conspicuously marked or otherwise | |
| 60 | designated in writing by the copyright owner as "Not a Contribution." | |
| 61 | ||
| 62 | "Contributor" shall mean Licensor and any individual or Legal Entity | |
| 63 | on behalf of whom a Contribution has been received by Licensor and | |
| 64 | subsequently incorporated within the Work. | |
| 65 | ||
| 66 | 2. Grant of Copyright License. Subject to the terms and conditions of | |
| 67 | this License, each Contributor hereby grants to You a perpetual, | |
| 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |
| 69 | copyright license to reproduce, prepare Derivative Works of, | |
| 70 | publicly display, publicly perform, sublicense, and distribute the | |
| 71 | Work and such Derivative Works in Source or Object form. | |
| 72 | ||
| 73 | 3. Grant of Patent License. Subject to the terms and conditions of | |
| 74 | this License, each Contributor hereby grants to You a perpetual, | |
| 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |
| 76 | (except as stated in this section) patent license to make, have made, | |
| 77 | use, offer to sell, sell, import, and otherwise transfer the Work, | |
| 78 | where such license applies only to those patent claims licensable | |
| 79 | by such Contributor that are necessarily infringed by their | |
| 80 | Contribution(s) alone or by combination of their Contribution(s) | |
| 81 | with the Work to which such Contribution(s) was submitted. If You | |
| 82 | institute patent litigation against any entity (including a | |
| 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work | |
| 84 | or a Contribution incorporated within the Work constitutes direct | |
| 85 | or contributory patent infringement, then any patent licenses | |
| 86 | granted to You under this License for that Work shall terminate | |
| 87 | as of the date such litigation is filed. | |
| 88 | ||
| 89 | 4. Redistribution. You may reproduce and distribute copies of the | |
| 90 | Work or Derivative Works thereof in any medium, with or without | |
| 91 | modifications, and in Source or Object form, provided that You | |
| 92 | meet the following conditions: | |
| 93 | ||
| 94 | (a) You must give any other recipients of the Work or | |
| 95 | Derivative Works a copy of this License; and | |
| 96 | ||
| 97 | (b) You must cause any modified files to carry prominent notices | |
| 98 | stating that You changed the files; and | |
| 99 | ||
| 100 | (c) You must retain, in the Source form of any Derivative Works | |
| 101 | that You distribute, all copyright, patent, trademark, and | |
| 102 | attribution notices from the Source form of the Work, | |
| 103 | excluding those notices that do not pertain to any part of | |
| 104 | the Derivative Works; and | |
| 105 | ||
| 106 | (d) If the Work includes a "NOTICE" text file as part of its | |
| 107 | distribution, then any Derivative Works that You distribute must | |
| 108 | include a readable copy of the attribution notices contained | |
| 109 | within such NOTICE file, excluding those notices that do not | |
| 110 | pertain to any part of the Derivative Works, in at least one | |
| 111 | of the following places: within a NOTICE text file distributed | |
| 112 | as part of the Derivative Works; within the Source form or | |
| 113 | documentation, if provided along with the Derivative Works; or, | |
| 114 | within a display generated by the Derivative Works, if and | |
| 115 | wherever such third-party notices normally appear. The contents | |
| 116 | of the NOTICE file are for informational purposes only and | |
| 117 | do not modify the License. You may add Your own attribution | |
| 118 | notices within Derivative Works that You distribute, alongside | |
| 119 | or as an addendum to the NOTICE text from the Work, provided | |
| 120 | that such additional attribution notices cannot be construed | |
| 121 | as modifying the License. | |
| 122 | ||
| 123 | You may add Your own copyright statement to Your modifications and | |
| 124 | may provide additional or different license terms and conditions | |
| 125 | for use, reproduction, or distribution of Your modifications, or | |
| 126 | for any such Derivative Works as a whole, provided Your use, | |
| 127 | reproduction, and distribution of the Work otherwise complies with | |
| 128 | the conditions stated in this License. | |
| 129 | ||
| 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, | |
| 131 | any Contribution intentionally submitted for inclusion in the Work | |
| 132 | by You to the Licensor shall be under the terms and conditions of | |
| 133 | this License, without any additional terms or conditions. | |
| 134 | Notwithstanding the above, nothing herein shall supersede or modify | |
| 135 | the terms of any separate license agreement you may have executed | |
| 136 | with Licensor regarding such Contributions. | |
| 137 | ||
| 138 | 6. Trademarks. This License does not grant permission to use the trade | |
| 139 | names, trademarks, service marks, or product names of the Licensor, | |
| 140 | except as required for reasonable and customary use in describing the | |
| 141 | origin of the Work and reproducing the content of the NOTICE file. | |
| 142 | ||
| 143 | 7. Disclaimer of Warranty. Unless required by applicable law or | |
| 144 | agreed to in writing, Licensor provides the Work (and each | |
| 145 | Contributor provides its Contributions) on an "AS IS" BASIS, | |
| 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |
| 147 | implied, including, without limitation, any warranties or conditions | |
| 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | |
| 149 | PARTICULAR PURPOSE. You are solely responsible for determining the | |
| 150 | appropriateness of using or redistributing the Work and assume any | |
| 151 | risks associated with Your exercise of permissions under this License. | |
| 152 | ||
| 153 | 8. Limitation of Liability. In no event and under no legal theory, | |
| 154 | whether in tort (including negligence), contract, or otherwise, | |
| 155 | unless required by applicable law (such as deliberate and grossly | |
| 156 | negligent acts) or agreed to in writing, shall any Contributor be | |
| 157 | liable to You for damages, including any direct, indirect, special, | |
| 158 | incidental, or consequential damages of any character arising as a | |
| 159 | result of this License or out of the use or inability to use the | |
| 160 | Work (including but not limited to damages for loss of goodwill, | |
| 161 | work stoppage, computer failure or malfunction, or any and all | |
| 162 | other commercial damages or losses), even if such Contributor | |
| 163 | has been advised of the possibility of such damages. | |
| 164 | ||
| 165 | 9. Accepting Warranty or Additional Liability. While redistributing | |
| 166 | the Work or Derivative Works thereof, You may choose to offer, | |
| 167 | and charge a fee for, acceptance of support, warranty, indemnity, | |
| 168 | or other liability obligations and/or rights consistent with this | |
| 169 | License. However, in accepting such obligations, You may act only | |
| 170 | on Your own behalf and on Your sole responsibility, not on behalf | |
| 171 | of any other Contributor, and only if You agree to indemnify, | |
| 172 | defend, and hold each Contributor harmless for any liability | |
| 173 | incurred by, or claims asserted against, such Contributor by reason | |
| 174 | of your accepting any such warranty or additional liability. | |
| 175 | ||
| 176 | END OF TERMS AND CONDITIONS | |
| 177 | ||
| 178 | APPENDIX: How to apply the Apache License to your work. | |
| 179 | ||
| 180 | To apply the Apache License to your work, attach the following | |
| 181 | boilerplate notice, with the fields enclosed by brackets "[]" | |
| 182 | replaced with your own identifying information. (Don't include | |
| 183 | the brackets!) The text should be enclosed in the appropriate | |
| 184 | comment syntax for the file format. We also recommend that a | |
| 185 | file or class name and description of purpose be included on the | |
| 186 | same "printed page" as the copyright notice for easier | |
| 187 | identification within third-party archives. | |
| 188 | ||
| 189 | Copyright [yyyy] [name of copyright owner] | |
| 190 | ||
| 191 | Licensed under the Apache License, Version 2.0 (the "License"); | |
| 192 | you may not use this file except in compliance with the License. | |
| 193 | You may obtain a copy of the License at | |
| 194 | ||
| 195 | http://www.apache.org/licenses/LICENSE-2.0 | |
| 196 | ||
| 197 | Unless required by applicable law or agreed to in writing, software | |
| 198 | distributed under the License is distributed on an "AS IS" BASIS, | |
| 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 200 | See the License for the specific language governing permissions and | |
| 201 | limitations under the License. |
| 1 | Copyright (c) 2016 Steve Klabnik | |
| 2 | ||
| 3 | Permission is hereby granted, free of charge, to any | |
| 4 | person obtaining a copy of this software and associated | |
| 5 | documentation files (the "Software"), to deal in the | |
| 6 | Software without restriction, including without | |
| 7 | limitation the rights to use, copy, modify, merge, | |
| 8 | publish, distribute, sublicense, and/or sell copies of | |
| 9 | the Software, and to permit persons to whom the Software | |
| 10 | is furnished to do so, subject to the following | |
| 11 | conditions: | |
| 12 | ||
| 13 | The above copyright notice and this permission notice | |
| 14 | shall be included in all copies or substantial portions | |
| 15 | of the Software. | |
| 16 | ||
| 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | |
| 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | |
| 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | |
| 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | |
| 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |
| 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR | |
| 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | DEALINGS IN THE SOFTWARE. |
| 1 | use regex::Regex; | |
| 2 | use version::Identifier; | |
| 3 | ||
| 4 | // by the time we get here, we know that it's all valid characters, so this doesn't need to return | |
| 5 | // a result or anything | |
| 6 | pub fn parse_meta(s: &str) -> Vec<Identifier> { | |
| 7 | // Originally, I wanted to implement this method via calling parse, but parse is tolerant of | |
| 8 | // leading zeroes, and we want anything with leading zeroes to be considered alphanumeric, not | |
| 9 | // numeric. So the strategy is to check with a regex first, and then call parse once we've | |
| 10 | // determined that it's a number without a leading zero. | |
| 11 | s.split(".") | |
| 12 | .map(|part| { | |
| 13 | // another wrinkle: we made sure that any number starts with a | |
| 14 | // non-zero. But there's a problem: an actual zero is a number, yet | |
| 15 | // gets left out by this heuristic. So let's also check for the | |
| 16 | // single, lone zero. | |
| 17 | if is_alpha_numeric(part) { | |
| 18 | Identifier::AlphaNumeric(part.to_string()) | |
| 19 | } else { | |
| 20 | // we can unwrap here because we know it is only digits due to the regex | |
| 21 | Identifier::Numeric(part.parse().unwrap()) | |
| 22 | } | |
| 23 | }).collect() | |
| 24 | } | |
| 25 | ||
| 26 | pub fn is_alpha_numeric(s: &str) -> bool { | |
| 27 | lazy_static! { | |
| 28 | static ref REGEX: Regex = Regex::new(r"^(0|[1-9][0-9]*)$").unwrap(); | |
| 29 | }; | |
| 30 | !REGEX.is_match(s) | |
| 31 | } |
| 1 | extern crate regex; | |
| 2 | ||
| 3 | #[macro_use] | |
| 4 | extern crate lazy_static; | |
| 5 | ||
| 6 | pub mod version; | |
| 7 | ||
| 8 | // for private stuff the two share | |
| 9 | mod common; |
| 1 | use std::fmt; | |
| 2 | ||
| 3 | use regex::Regex; | |
| 4 | use common; | |
| 5 | ||
| 6 | lazy_static! { | |
| 7 | static ref REGEX: Regex = { | |
| 8 | // a numeric identifier is either zero or multiple numbers without a leading zero | |
| 9 | let numeric_identifier = r"0|(?:[1-9][0-9]*)"; | |
| 10 | ||
| 11 | let major = numeric_identifier; | |
| 12 | let minor = numeric_identifier; | |
| 13 | let patch = numeric_identifier; | |
| 14 | ||
| 15 | let letters_numbers_dash_dot = r"[-.A-Za-z0-9]+"; | |
| 16 | ||
| 17 | // This regex does not fully parse prereleases, just extracts the whole prerelease string. | |
| 18 | // parse_version() will parse this further. | |
| 19 | let pre = letters_numbers_dash_dot; | |
| 20 | ||
| 21 | // This regex does not fully parse builds, just extracts the whole build string. | |
| 22 | // parse_version() will parse this further. | |
| 23 | let build = letters_numbers_dash_dot; | |
| 24 | ||
| 25 | let regex = format!(r"^(?x) # heck yes x mode | |
| 26 | (?P<major>{}) # major version | |
| 27 | \. # dot | |
| 28 | (?P<minor>{}) # minor version | |
| 29 | \. # dot | |
| 30 | (?P<patch>{}) # patch version | |
| 31 | (?:-(?P<pre>{}))? # optional prerelease version | |
| 32 | (?:\+(?P<build>{}))? # optional build metadata | |
| 33 | $", | |
| 34 | major, | |
| 35 | minor, | |
| 36 | patch, | |
| 37 | pre, | |
| 38 | build); | |
| 39 | let regex = Regex::new(®ex); | |
| 40 | ||
| 41 | // this unwrap is okay because everything above here is const, so this will never fail. | |
| 42 | regex.unwrap() | |
| 43 | }; | |
| 44 | } | |
| 45 | ||
| 46 | #[derive(Clone, Debug, PartialEq, Eq)] | |
| 47 | pub struct Version { | |
| 48 | pub major: u64, | |
| 49 | pub minor: u64, | |
| 50 | pub patch: u64, | |
| 51 | pub pre: Vec<Identifier>, | |
| 52 | pub build: Vec<Identifier>, | |
| 53 | } | |
| 54 | ||
| 55 | #[derive(Clone, Debug, PartialEq, Eq)] | |
| 56 | pub enum Identifier { | |
| 57 | /// An identifier that's solely numbers. | |
| 58 | Numeric(u64), | |
| 59 | /// An identifier with letters and numbers. | |
| 60 | AlphaNumeric(String), | |
| 61 | } | |
| 62 | ||
| 63 | pub fn parse(version: &str) -> Result<Version, String> { | |
| 64 | let captures = match REGEX.captures(version.trim()) { | |
| 65 | Some(captures) => captures, | |
| 66 | None => return Err(From::from("Version did not parse properly.")), | |
| 67 | }; | |
| 68 | ||
| 69 | let pre = captures.name("pre").map(common::parse_meta).unwrap_or(vec![]); | |
| 70 | ||
| 71 | let build = captures.name("build").map(common::parse_meta).unwrap_or(vec![]); | |
| 72 | ||
| 73 | Ok(Version { | |
| 74 | major: captures.name("major").unwrap().parse().unwrap(), | |
| 75 | minor: captures.name("minor").unwrap().parse().unwrap(), | |
| 76 | patch: captures.name("patch").unwrap().parse().unwrap(), | |
| 77 | pre: pre, | |
| 78 | build: build, | |
| 79 | }) | |
| 80 | } | |
| 81 | ||
| 82 | impl fmt::Display for Version { | |
| 83 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| 84 | try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch)); | |
| 85 | if !self.pre.is_empty() { | |
| 86 | let strs: Vec<_> = | |
| 87 | self.pre.iter().map(ToString::to_string).collect(); | |
| 88 | try!(write!(f, "-{}", strs.join("."))); | |
| 89 | } | |
| 90 | if !self.build.is_empty() { | |
| 91 | let strs: Vec<_> = | |
| 92 | self.build.iter().map(ToString::to_string).collect(); | |
| 93 | try!(write!(f, "+{}", strs.join("."))); | |
| 94 | } | |
| 95 | Ok(()) | |
| 96 | } | |
| 97 | } | |
| 98 | ||
| 99 | impl fmt::Display for Identifier { | |
| 100 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| 101 | match *self { | |
| 102 | Identifier::Numeric(ref id) => id.fmt(f), | |
| 103 | Identifier::AlphaNumeric(ref id) => id.fmt(f), | |
| 104 | } | |
| 105 | } | |
| 106 | } |
| 1 | extern crate regex; | |
| 2 | ||
| 3 | pub mod version; |
| 1 | use regex::Regex; | |
| 2 | ||
| 3 | pub struct Version { | |
| 4 | pub major: u64, | |
| 5 | pub minor: u64, | |
| 6 | pub patch: u64, | |
| 7 | } | |
| 8 | ||
| 9 | pub fn parse_version(version: &str) -> Version { | |
| 10 | let re = Regex::new(r"(\d+).(\d+).(\d+)").unwrap(); | |
| 11 | ||
| 12 | let captures = re.captures(version).unwrap(); | |
| 13 | ||
| 14 | Version { | |
| 15 | major: captures.at(1).unwrap().parse().unwrap(), | |
| 16 | minor: captures.at(2).unwrap().parse().unwrap(), | |
| 17 | patch: captures.at(3).unwrap().parse().unwrap(), | |
| 18 | } | |
| 19 | } |
| 1 | extern crate regex; | |
| 2 | ||
| 3 | use regex::Regex; | |
| 4 | ||
| 5 | pub struct Version { | |
| 6 | major: u64, | |
| 7 | minor: u64, | |
| 8 | patch: u64, | |
| 9 | } | |
| 10 | ||
| 11 | pub fn parse_version(version: &str) -> Version { | |
| 12 | let re = Regex::new(r"(\d+).(\d+).(\d+)").unwrap(); | |
| 13 | ||
| 14 | let captures = re.captures(version).unwrap(); | |
| 15 | ||
| 16 | Version { | |
| 17 | major: captures.at(1).unwrap().parse().unwrap(), | |
| 18 | minor: captures.at(2).unwrap().parse().unwrap(), | |
| 19 | patch: captures.at(3).unwrap().parse().unwrap(), | |
| 20 | } | |
| 21 | } |
| 3 | 3 | use regex::Regex; |
| 4 | 4 | |
| 5 | 5 | pub struct Version { |
| 6 | major: u64, | |
| 7 | minor: u64, | |
| 8 | patch: u64, | |
| 6 | pub major: u64, | |
| 7 | pub minor: u64, | |
| 8 | pub patch: u64, | |
| 9 | 9 | } |
| 10 | 10 | |
| 11 | 11 | pub fn parse_version(version: &str) -> Version { |
| 1 | extern crate regex; | |
| 2 | ||
| 3 | pub mod version; |
| 1 | extern crate regex; | |
| 2 | ||
| 3 | 1 | use regex::Regex; |
| 4 | 2 | |
| 5 | 3 | pub struct Version { |
| 1 | 1 | extern crate regex; |
| 2 | 2 | |
| 3 | #[macro_use] | |
| 4 | extern crate lazy_static; | |
| 5 | ||
| 3 | 6 | pub mod version; |
| 1 | 1 | use regex::Regex; |
| 2 | 2 | |
| 3 | lazy_static! { | |
| 4 | static ref REGEX: Regex = { | |
| 5 | // a numeric identifier is either zero or multiple numbers without a leading zero | |
| 6 | let numeric_identifier = r"0|(?:[1-9][0-9]*)"; | |
| 7 | ||
| 8 | let major = numeric_identifier; | |
| 9 | let minor = numeric_identifier; | |
| 10 | let patch = numeric_identifier; | |
| 11 | ||
| 12 | let regex = format!(r"^(?P<major>{})\.(?P<minor>{})\.(?P<patch>{})$", major, minor, patch); | |
| 13 | let regex = Regex::new(®ex); | |
| 14 | ||
| 15 | // this unwrap is okay because everything above here is const, so this will never fail. | |
| 16 | regex.unwrap() | |
| 17 | }; | |
| 18 | } | |
| 19 | ||
| 3 | 20 | pub struct Version { |
| 4 | 21 | pub major: u64, |
| 5 | 22 | pub minor: u64, |
| 6 | 23 | pub patch: u64, |
| 7 | 24 | } |
| 8 | 25 | |
| 9 | pub fn parse_version(version: &str) -> Version { | |
| 10 | let re = Regex::new(r"(\d+).(\d+).(\d+)").unwrap(); | |
| 11 | ||
| 12 | let captures = re.captures(version).unwrap(); | |
| 26 | pub fn parse_version(version: &str) -> Result<Version, String> { | |
| 27 | let captures = match REGEX.captures(version.trim()) { | |
| 28 | Some(captures) => captures, | |
| 29 | None => return Err(From::from("Version did not parse properly.")), | |
| 30 | }; | |
| 13 | 31 | |
| 14 | Version { | |
| 15 | major: captures.at(1).unwrap().parse().unwrap(), | |
| 16 | minor: captures.at(2).unwrap().parse().unwrap(), | |
| 17 | patch: captures.at(3).unwrap().parse().unwrap(), | |
| 18 | } | |
| 32 | Ok(Version { | |
| 33 | major: captures.name("major").unwrap().parse().unwrap(), | |
| 34 | minor: captures.name("minor").unwrap().parse().unwrap(), | |
| 35 | patch: captures.name("patch").unwrap().parse().unwrap(), | |
| 36 | }) | |
| 19 | 37 | } |
| 1 | #[macro_use] | |
| 2 | extern crate lazy_static; | |
| 3 | ||
| 1 | 4 | use regex::Regex; |
| 2 | 5 | |
| 6 | use std::error::Error; | |
| 7 | ||
| 8 | lazy_static! { | |
| 9 | static ref REGEX: Regex = { | |
| 10 | let major = r"0|(:?[1-9][0-9]*)"; | |
| 11 | let minor = r"0|(:?[1-9][0-9]*)"; | |
| 12 | let patch = r"0|(:?[1-9][0-9]*)"; | |
| 13 | ||
| 14 | let regex = format!(r"^(?P<major>{})\.(?P<minor>{})\.(?P<patch>{})$", major, minor, patch); | |
| 15 | let regex = Regex::new(®ex); | |
| 16 | ||
| 17 | // this unwrap is okay because everything above here is const, so this will never fail. | |
| 18 | regex.unwrap() | |
| 19 | }; | |
| 20 | } | |
| 21 | ||
| 3 | 22 | pub struct Version { |
| 4 | 23 | pub major: u64, |
| 5 | 24 | pub minor: u64, |
| 6 | 25 | pub patch: u64, |
| 7 | 26 | } |
| 8 | 27 | |
| 9 | pub fn parse_version(version: &str) -> Version { | |
| 10 | let re = Regex::new(r"(\d+).(\d+).(\d+)").unwrap(); | |
| 11 | ||
| 12 | let captures = re.captures(version).unwrap(); | |
| 28 | pub fn parse_version(version: &str) -> Result<Version, Box<Error>> { | |
| 29 | let captures = match REGEX.captures(version) { | |
| 30 | Some(captures) => captures, | |
| 31 | None => return Err(From::from("Version did not parse properly.")), | |
| 32 | }; | |
| 13 | 33 | |
| 14 | Version { | |
| 15 | major: captures.at(1).unwrap().parse().unwrap(), | |
| 16 | minor: captures.at(2).unwrap().parse().unwrap(), | |
| 17 | patch: captures.at(3).unwrap().parse().unwrap(), | |
| 18 | } | |
| 34 | Ok(Version { | |
| 35 | major: captures.name("major").unwrap().parse().unwrap(), | |
| 36 | minor: captures.name("minor").unwrap().parse().unwrap(), | |
| 37 | patch: captures.name("patch").unwrap().parse().unwrap(), | |
| 38 | }) | |
| 19 | 39 | } |
| 7 | 7 | |
| 8 | 8 | lazy_static! { |
| 9 | 9 | static ref REGEX: Regex = { |
| 10 | let major = r"0|(:?[1-9][0-9]*)"; | |
| 11 | let minor = r"0|(:?[1-9][0-9]*)"; | |
| 12 | let patch = r"0|(:?[1-9][0-9]*)"; | |
| 10 | // a numeric identifier is either zero or multiple numbers without a leading zero | |
| 11 | let numeric_identifier = r"0|(:?[1-9][0-9]*)"; | |
| 13 | 12 | |
| 13 | let major = numeric_identifier; | |
| 14 | let minor = numeric_identifier; | |
| 15 | let patch = numeric_identifier; | |
| 16 | ||
| 14 | 17 | let regex = format!(r"^(?P<major>{})\.(?P<minor>{})\.(?P<patch>{})$", major, minor, patch); |
| 15 | 18 | let regex = Regex::new(®ex); |
| 16 | 19 |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | 31 | pub fn parse_version(version: &str) -> Result<Version, Box<Error>> { |
| 32 | let captures = match REGEX.captures(version) { | |
| 32 | let captures = match REGEX.captures(version.trim()) { | |
| 33 | 33 | Some(captures) => captures, |
| 34 | 34 | None => return Err(From::from("Version did not parse properly.")), |
| 35 | 35 | }; |
| 3 | 3 | |
| 4 | 4 | use regex::Regex; |
| 5 | 5 | |
| 6 | use std::error::Error; | |
| 7 | ||
| 8 | 6 | lazy_static! { |
| 9 | 7 | static ref REGEX: Regex = { |
| 10 | 8 | // a numeric identifier is either zero or multiple numbers without a leading zero |
⋮
| 28 | 26 | pub patch: u64, |
| 29 | 27 | } |
| 30 | 28 | |
| 31 | pub fn parse_version(version: &str) -> Result<Version, Box<Error>> { | |
| 29 | pub fn parse_version(version: &str) -> Result<Version, String> { | |
| 32 | 30 | let captures = match REGEX.captures(version.trim()) { |
| 33 | 31 | Some(captures) => captures, |
| 34 | 32 | None => return Err(From::from("Version did not parse properly.")), |
| 1 | 1 | extern crate regex; |
| 2 | 2 | |
| 3 | #[macro_use] | |
| 4 | extern crate lazy_static; | |
| 5 | ||
| 3 | 6 | pub mod version; |
| 1 | #[macro_use] | |
| 2 | extern crate lazy_static; | |
| 3 | ||
| 4 | 1 | use regex::Regex; |
| 5 | 2 | |
| 6 | 3 | lazy_static! { |
| 8 | 8 | let major = numeric_identifier; |
| 9 | 9 | let minor = numeric_identifier; |
| 10 | 10 | let patch = numeric_identifier; |
| 11 | ||
| 11 | ||
| 12 | 12 | let regex = format!(r"^(?P<major>{})\.(?P<minor>{})\.(?P<patch>{})$", major, minor, patch); |
| 13 | 13 | let regex = Regex::new(®ex); |
| 14 | ||
| 14 | ||
| 15 | 15 | // this unwrap is okay because everything above here is const, so this will never fail. |
| 16 | 16 | regex.unwrap() |
| 17 | 17 | }; |
| 3 | 3 | lazy_static! { |
| 4 | 4 | static ref REGEX: Regex = { |
| 5 | 5 | // a numeric identifier is either zero or multiple numbers without a leading zero |
| 6 | let numeric_identifier = r"0|(:?[1-9][0-9]*)"; | |
| 6 | let numeric_identifier = r"0|(?:[1-9][0-9]*)"; | |
| 7 | 7 | |
| 8 | 8 | let major = numeric_identifier; |
| 9 | 9 | let minor = numeric_identifier; |
| 9 | 9 | let minor = numeric_identifier; |
| 10 | 10 | let patch = numeric_identifier; |
| 11 | 11 | |
| 12 | let regex = format!(r"^(?P<major>{})\.(?P<minor>{})\.(?P<patch>{})$", major, minor, patch); | |
| 12 | let letters_numbers_dash_dot = r"[-.A-Za-z0-9]+"; | |
| 13 | ||
| 14 | // This regex does not fully parse prereleases, just extracts the whole prerelease string. | |
| 15 | // parse_version() will parse this further. | |
| 16 | let pre = letters_numbers_dash_dot; | |
| 17 | ||
| 18 | let regex = format!(r"^(?x) # heck yes x mode | |
| 19 | (?P<major>{}) # major version | |
| 20 | \. # dot | |
| 21 | (?P<minor>{}) # minor version | |
| 22 | \. # dot | |
| 23 | (?P<patch>{}) # patch version | |
| 24 | (?:-(?P<pre>{}))? # optional prerelease version | |
| 25 | $", | |
| 26 | major, | |
| 27 | minor, | |
| 28 | patch, | |
| 29 | pre); | |
| 13 | 30 | let regex = Regex::new(®ex); |
| 14 | 31 | |
| 15 | 32 | // this unwrap is okay because everything above here is const, so this will never fail. |
⋮
| 21 | 38 | pub major: u64, |
| 22 | 39 | pub minor: u64, |
| 23 | 40 | pub patch: u64, |
| 41 | pub pre: Option<Vec<String>>, | |
| 24 | 42 | } |
| 25 | 43 | |
| 26 | 44 | pub fn parse_version(version: &str) -> Result<Version, String> { |
⋮
| 29 | 47 | None => return Err(From::from("Version did not parse properly.")), |
| 30 | 48 | }; |
| 31 | 49 | |
| 50 | let pre = captures.name("pre").map(|pre| { | |
| 51 | vec![pre.to_string()] | |
| 52 | }); | |
| 53 | ||
| 32 | 54 | Ok(Version { |
| 33 | 55 | major: captures.name("major").unwrap().parse().unwrap(), |
| 34 | 56 | minor: captures.name("minor").unwrap().parse().unwrap(), |
| 35 | 57 | patch: captures.name("patch").unwrap().parse().unwrap(), |
| 58 | pre: pre, | |
| 36 | 59 | }) |
| 37 | 60 | } |
| 9 | 9 | let minor = numeric_identifier; |
| 10 | 10 | let patch = numeric_identifier; |
| 11 | 11 | |
| 12 | let regex = format!(r"^(?P<major>{})\.(?P<minor>{})\.(?P<patch>{})$", major, minor, patch); | |
| 12 | let pre = r"\w+"; | |
| 13 | ||
| 14 | let regex = format!(r"^(?P<major>{})\.(?P<minor>{})\.(?P<patch>{})(:?-(?P<pre>{}))?$", major, minor, patch, pre); | |
| 15 | println!("{}", regex); | |
| 13 | 16 | let regex = Regex::new(®ex); |
| 14 | 17 | |
| 15 | 18 | // this unwrap is okay because everything above here is const, so this will never fail. |
⋮
| 21 | 24 | pub major: u64, |
| 22 | 25 | pub minor: u64, |
| 23 | 26 | pub patch: u64, |
| 27 | pub pre: Option<String>, | |
| 24 | 28 | } |
| 25 | 29 | |
| 26 | 30 | pub fn parse_version(version: &str) -> Result<Version, String> { |
⋮
| 33 | 37 | major: captures.name("major").unwrap().parse().unwrap(), |
| 34 | 38 | minor: captures.name("minor").unwrap().parse().unwrap(), |
| 35 | 39 | patch: captures.name("patch").unwrap().parse().unwrap(), |
| 40 | pre: captures.name("pre").map(ToString::to_string) | |
| 36 | 41 | }) |
| 37 | 42 | } |
| 9 | 9 | let minor = numeric_identifier; |
| 10 | 10 | let patch = numeric_identifier; |
| 11 | 11 | |
| 12 | let pre = r"\w+"; | |
| 12 | let letters_numbers_dash_dot = r"[.-A-Za-z0-9]+"; | |
| 13 | ||
| 14 | // This regex does not fully parse prereleases, just extracts the whole prerelease string. | |
| 15 | // parse_version() will parse this further. | |
| 16 | let pre = letters_numbers_dash_dot; | |
| 13 | 17 | |
| 14 | 18 | let regex = format!(r"^(?P<major>{})\.(?P<minor>{})\.(?P<patch>{})(:?-(?P<pre>{}))?$", major, minor, patch, pre); |
| 15 | 19 | println!("{}", regex); |
⋮
| 24 | 28 | pub major: u64, |
| 25 | 29 | pub minor: u64, |
| 26 | 30 | pub patch: u64, |
| 27 | pub pre: Option<String>, | |
| 31 | pub pre: Option<Vec<String>>, | |
| 28 | 32 | } |
| 29 | 33 | |
| 30 | 34 | pub fn parse_version(version: &str) -> Result<Version, String> { |
⋮
| 33 | 37 | None => return Err(From::from("Version did not parse properly.")), |
| 34 | 38 | }; |
| 35 | 39 | |
| 40 | let pre = captures.name("pre").map(|pre| { | |
| 41 | vec![pre.to_string()] | |
| 42 | }); | |
| 43 | ||
| 36 | 44 | Ok(Version { |
| 37 | 45 | major: captures.name("major").unwrap().parse().unwrap(), |
| 38 | 46 | minor: captures.name("minor").unwrap().parse().unwrap(), |
| 39 | 47 | patch: captures.name("patch").unwrap().parse().unwrap(), |
| 40 | pre: captures.name("pre").map(ToString::to_string) | |
| 48 | pre: pre, | |
| 41 | 49 | }) |
| 42 | 50 | } |
| 16 | 16 | let pre = letters_numbers_dash_dot; |
| 17 | 17 | |
| 18 | 18 | let regex = format!(r"^(?P<major>{})\.(?P<minor>{})\.(?P<patch>{})(:?-(?P<pre>{}))?$", major, minor, patch, pre); |
| 19 | println!("{}", regex); | |
| 20 | 19 | let regex = Regex::new(®ex); |
| 21 | 20 | |
| 22 | 21 | // this unwrap is okay because everything above here is const, so this will never fail. |
| 9 | 9 | let minor = numeric_identifier; |
| 10 | 10 | let patch = numeric_identifier; |
| 11 | 11 | |
| 12 | let letters_numbers_dash_dot = r"[.-A-Za-z0-9]+"; | |
| 12 | let letters_numbers_dash_dot = r"[-.A-Za-z0-9]+"; | |
| 13 | 13 | |
| 14 | 14 | // This regex does not fully parse prereleases, just extracts the whole prerelease string. |
| 15 | 15 | // parse_version() will parse this further. |
| 16 | 16 | let pre = letters_numbers_dash_dot; |
| 17 | 17 | |
| 18 | let regex = format!(r"^(?P<major>{})\.(?P<minor>{})\.(?P<patch>{})(:?-(?P<pre>{}))?$", major, minor, patch, pre); | |
| 18 | let regex = format!(r"^(?x) # heck yes x mode | |
| 19 | (?P<major>{}) # major version | |
| 20 | \. # dot | |
| 21 | (?P<minor>{}) # minor version | |
| 22 | \. # dot | |
| 23 | (?P<patch>{}) # patch version | |
| 24 | (:?-(?P<pre>{}))? # optional prerelease version | |
| 25 | (:?\+(?P<build>{}))? # optional build metadata | |
| 26 | $", | |
| 27 | major, | |
| 28 | minor, | |
| 29 | patch, | |
| 30 | pre, | |
| 31 | build); | |
| 19 | 32 | let regex = Regex::new(®ex); |
| 20 | 33 | |
| 21 | 34 | // this unwrap is okay because everything above here is const, so this will never fail. |
| 21 | 21 | (?P<minor>{}) # minor version |
| 22 | 22 | \. # dot |
| 23 | 23 | (?P<patch>{}) # patch version |
| 24 | (:?-(?P<pre>{}))? # optional prerelease version | |
| 25 | (:?\+(?P<build>{}))? # optional build metadata | |
| 24 | (?:-(?P<pre>{}))? # optional prerelease version | |
| 26 | 25 | $", |
| 27 | 26 | major, |
| 28 | 27 | minor, |
| 29 | 28 | patch, |
| 30 | pre, | |
| 31 | build); | |
| 29 | pre); | |
| 32 | 30 | let regex = Regex::new(®ex); |
| 33 | 31 | |
| 34 | 32 | // this unwrap is okay because everything above here is const, so this will never fail. |
| 15 | 15 | // parse_version() will parse this further. |
| 16 | 16 | let pre = letters_numbers_dash_dot; |
| 17 | 17 | |
| 18 | // This regex does not fully parse builds, just extracts the whole build string. | |
| 19 | // parse_version() will parse this further. | |
| 20 | let build = letters_numbers_dash_dot; | |
| 21 | ||
| 18 | 22 | let regex = format!(r"^(?x) # heck yes x mode |
| 19 | 23 | (?P<major>{}) # major version |
| 20 | 24 | \. # dot |
⋮
| 22 | 26 | \. # dot |
| 23 | 27 | (?P<patch>{}) # patch version |
| 24 | 28 | (?:-(?P<pre>{}))? # optional prerelease version |
| 29 | (?:\+(?P<build>{}))? # optional build metadata | |
| 25 | 30 | $", |
| 26 | 31 | major, |
| 27 | 32 | minor, |
| 28 | 33 | patch, |
| 29 | pre); | |
| 34 | pre, | |
| 35 | build); | |
| 30 | 36 | let regex = Regex::new(®ex); |
| 31 | 37 | |
| 32 | 38 | // this unwrap is okay because everything above here is const, so this will never fail. |
⋮
| 39 | 45 | pub minor: u64, |
| 40 | 46 | pub patch: u64, |
| 41 | 47 | pub pre: Option<Vec<String>>, |
| 48 | pub build: Option<Vec<String>>, | |
| 42 | 49 | } |
| 43 | 50 | |
| 44 | 51 | pub fn parse_version(version: &str) -> Result<Version, String> { |
⋮
| 51 | 58 | vec![pre.to_string()] |
| 52 | 59 | }); |
| 53 | 60 | |
| 61 | let build = captures.name("build").map(|build| { | |
| 62 | vec![build.to_string()] | |
| 63 | }); | |
| 64 | ||
| 54 | 65 | Ok(Version { |
| 55 | 66 | major: captures.name("major").unwrap().parse().unwrap(), |
| 56 | 67 | minor: captures.name("minor").unwrap().parse().unwrap(), |
| 57 | 68 | patch: captures.name("patch").unwrap().parse().unwrap(), |
| 58 | 69 | pre: pre, |
| 70 | build: build, | |
| 59 | 71 | }) |
| 60 | 72 | } |
| 15 | 15 | // parse_version() will parse this further. |
| 16 | 16 | let pre = letters_numbers_dash_dot; |
| 17 | 17 | |
| 18 | // This regex does not fully parse builds, just extracts the whole build string. | |
| 19 | // parse_version() will parse this further. | |
| 20 | let build = letters_numbers_dash_dot; | |
| 21 | ||
| 18 | 22 | let regex = format!(r"^(?x) # heck yes x mode |
| 19 | 23 | (?P<major>{}) # major version |
| 20 | 24 | \. # dot |
⋮
| 22 | 26 | \. # dot |
| 23 | 27 | (?P<patch>{}) # patch version |
| 24 | 28 | (?:-(?P<pre>{}))? # optional prerelease version |
| 29 | (:?\+(?P<build>{}))? # optional build metadata | |
| 25 | 30 | $", |
| 26 | 31 | major, |
| 27 | 32 | minor, |
| 28 | 33 | patch, |
| 29 | pre); | |
| 34 | pre, | |
| 35 | build); | |
| 36 | println!("{}", regex); | |
| 30 | 37 | let regex = Regex::new(®ex); |
| 31 | 38 | |
| 32 | 39 | // this unwrap is okay because everything above here is const, so this will never fail. |
⋮
| 39 | 46 | pub minor: u64, |
| 40 | 47 | pub patch: u64, |
| 41 | 48 | pub pre: Option<Vec<String>>, |
| 49 | pub build: Option<Vec<String>>, | |
| 42 | 50 | } |
| 43 | 51 | |
| 44 | 52 | pub fn parse_version(version: &str) -> Result<Version, String> { |
⋮
| 51 | 59 | vec![pre.to_string()] |
| 52 | 60 | }); |
| 53 | 61 | |
| 62 | let build = captures.name("build").map(|build| { | |
| 63 | vec![build.to_string()] | |
| 64 | }); | |
| 65 | ||
| 54 | 66 | Ok(Version { |
| 55 | 67 | major: captures.name("major").unwrap().parse().unwrap(), |
| 56 | 68 | minor: captures.name("minor").unwrap().parse().unwrap(), |
| 57 | 69 | patch: captures.name("patch").unwrap().parse().unwrap(), |
| 58 | 70 | pre: pre, |
| 71 | build: build, | |
| 59 | 72 | }) |
| 60 | 73 | } |
| 26 | 26 | \. # dot |
| 27 | 27 | (?P<patch>{}) # patch version |
| 28 | 28 | (?:-(?P<pre>{}))? # optional prerelease version |
| 29 | (:?\+(?P<build>{}))? # optional build metadata | |
| 29 | (?:\+(?P<build>{}))? # optional build metadata | |
| 30 | 30 | $", |
| 31 | 31 | major, |
| 32 | 32 | minor, |
| 33 | 33 | patch, |
| 34 | 34 | pre, |
| 35 | 35 | build); |
| 36 | println!("{}", regex); | |
| 37 | 36 | let regex = Regex::new(®ex); |
| 38 | 37 | |
| 39 | 38 | // this unwrap is okay because everything above here is const, so this will never fail. |
| 44 | 44 | pub major: u64, |
| 45 | 45 | pub minor: u64, |
| 46 | 46 | pub patch: u64, |
| 47 | pub pre: Option<Vec<String>>, | |
| 48 | pub build: Option<Vec<String>>, | |
| 47 | pub pre: Vec<Identifier>, | |
| 48 | pub build: Vec<Identifier>, | |
| 49 | } | |
| 50 | ||
| 51 | pub enum Identifier { | |
| 52 | /// An identifier that's solely numbers. | |
| 53 | Numeric(u64), | |
| 54 | /// An identifier with letters and numbers. | |
| 55 | AlphaNumeric(String), | |
| 49 | 56 | } |
| 50 | 57 | |
| 51 | 58 | pub fn parse_version(version: &str) -> Result<Version, String> { |
⋮
| 54 | 61 | None => return Err(From::from("Version did not parse properly.")), |
| 55 | 62 | }; |
| 56 | 63 | |
| 57 | let pre = captures.name("pre").map(|pre| { | |
| 58 | vec![pre.to_string()] | |
| 59 | }); | |
| 64 | let pre = captures.name("pre").map(parse_meta).unwrap_or(vec![]); | |
| 60 | 65 | |
| 61 | let build = captures.name("build").map(|build| { | |
| 62 | vec![build.to_string()] | |
| 63 | }); | |
| 66 | let build = captures.name("build").map(parse_meta).unwrap_or(vec![]); | |
| 64 | 67 | |
| 65 | 68 | Ok(Version { |
| 66 | 69 | major: captures.name("major").unwrap().parse().unwrap(), |
⋮
| 70 | 73 | build: build, |
| 71 | 74 | }) |
| 72 | 75 | } |
| 76 | ||
| 77 | // by the time we get here, we know that it's all valid characters, so this doesn't need to return | |
| 78 | // a result or anything | |
| 79 | fn parse_meta(pre: &str) -> Vec<Identifier> { | |
| 80 | // Originally, I wanted to implement this method via calling parse, but parse is tolerant of | |
| 81 | // leading zeroes, and we want anything with leading zeroes to be considered alphanumeric, not | |
| 82 | // numeric. So the strategy is to check with a regex first, and then call parse once we've | |
| 83 | // determined that it's a number without a leading zero. | |
| 84 | let regex = Regex::new(r"^[1-9][0-9]*$").unwrap(); | |
| 85 | ||
| 86 | pre.split(".") | |
| 87 | .map(|part| { | |
| 88 | // another wrinkle: we made sure that any number starts with a non-zero. But there's a | |
| 89 | // problem: an actual zero is a number, yet gets left out by this heuristic. So let's | |
| 90 | // also check for the single, lone zero. | |
| 91 | if regex.is_match(part) || part == "0" { | |
| 92 | // we can unwrap here because we know it is only digits due to the regex | |
| 93 | Identifier::Numeric(part.parse().unwrap()) | |
| 94 | } else { | |
| 95 | Identifier::AlphaNumeric(part.to_string()) | |
| 96 | } | |
| 97 | }).collect() | |
| 98 | } |
| 44 | 44 | pub major: u64, |
| 45 | 45 | pub minor: u64, |
| 46 | 46 | pub patch: u64, |
| 47 | pub pre: Option<Vec<String>>, | |
| 48 | pub build: Option<Vec<String>>, | |
| 47 | pub pre: Option<Vec<Identifier>>, | |
| 48 | pub build: Option<Vec<Identifier>>, | |
| 49 | } | |
| 50 | ||
| 51 | #[derive(Debug,PartialEq)] | |
| 52 | pub enum Identifier { | |
| 53 | /// An identifier that's solely numbers. | |
| 54 | Numeric(u64), | |
| 55 | /// An identifier with letters and numbers. | |
| 56 | AlphaNumeric(String), | |
| 49 | 57 | } |
| 50 | 58 | |
| 51 | 59 | pub fn parse_version(version: &str) -> Result<Version, String> { |
⋮
| 54 | 62 | None => return Err(From::from("Version did not parse properly.")), |
| 55 | 63 | }; |
| 56 | 64 | |
| 57 | let pre = captures.name("pre").map(|pre| { | |
| 58 | vec![pre.to_string()] | |
| 59 | }); | |
| 65 | let pre = captures.name("pre").map(parse_meta); | |
| 60 | 66 | |
| 61 | let build = captures.name("build").map(|build| { | |
| 62 | vec![build.to_string()] | |
| 63 | }); | |
| 67 | let build = captures.name("build").map(parse_meta); | |
| 64 | 68 | |
| 65 | 69 | Ok(Version { |
| 66 | 70 | major: captures.name("major").unwrap().parse().unwrap(), |
⋮
| 70 | 74 | build: build, |
| 71 | 75 | }) |
| 72 | 76 | } |
| 77 | ||
| 78 | // by the time we get here, we know that it's all valid characters, so this doesn't need to return | |
| 79 | // a result or anything | |
| 80 | fn parse_meta(pre: &str) -> Vec<Identifier> { | |
| 81 | // Originally, I wanted to implement this method via calling parse, but parse is tolerant of | |
| 82 | // leading zeroes, and we want anything with leading zeroes to be considered alphanumeric, not | |
| 83 | // numeric. So the strategy is to check with a regex first, and then call parse once we've | |
| 84 | // determined that it's a number without a leading zero. | |
| 85 | let regex = Regex::new(r"^[1-9][0-9]*$").unwrap(); | |
| 86 | ||
| 87 | pre.split(".") | |
| 88 | .map(|part| { | |
| 89 | if regex.is_match(part) { | |
| 90 | // we can unwrap here because we know it is only digits due to the regex | |
| 91 | Identifier::Numeric(part.parse().unwrap()) | |
| 92 | } else { | |
| 93 | Identifier::AlphaNumeric(part.to_string()) | |
| 94 | } | |
| 95 | }).collect() | |
| 96 | } |
| 86 | 86 | |
| 87 | 87 | pre.split(".") |
| 88 | 88 | .map(|part| { |
| 89 | if regex.is_match(part) { | |
| 89 | // another wrinkle: we made sure that any number starts with a non-zero. But there's a | |
| 90 | // problem: an actual zero is a number, yet gets left out by this heuristic. So let's | |
| 91 | // also check for the single, lone zero. | |
| 92 | if regex.is_match(part) || part == "0" { | |
| 90 | 93 | // we can unwrap here because we know it is only digits due to the regex |
| 91 | 94 | Identifier::Numeric(part.parse().unwrap()) |
| 92 | 95 | } else { |
| 48 | 48 | pub build: Option<Vec<Identifier>>, |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | #[derive(Debug,PartialEq)] | |
| 52 | 51 | pub enum Identifier { |
| 53 | 52 | /// An identifier that's solely numbers. |
| 54 | 53 | Numeric(u64), |
| 44 | 44 | pub major: u64, |
| 45 | 45 | pub minor: u64, |
| 46 | 46 | pub patch: u64, |
| 47 | pub pre: Option<Vec<Identifier>>, | |
| 48 | pub build: Option<Vec<Identifier>>, | |
| 47 | pub pre: Vec<Identifier>, | |
| 48 | pub build: Vec<Identifier>, | |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | 51 | pub enum Identifier { |
⋮
| 61 | 61 | None => return Err(From::from("Version did not parse properly.")), |
| 62 | 62 | }; |
| 63 | 63 | |
| 64 | let pre = captures.name("pre").map(parse_meta); | |
| 64 | let pre = captures.name("pre").map(parse_meta).unwrap_or(vec![]); | |
| 65 | 65 | |
| 66 | let build = captures.name("build").map(parse_meta); | |
| 66 | let build = captures.name("build").map(parse_meta).unwrap_or(vec![]); | |
| 67 | 67 | |
| 68 | 68 | Ok(Version { |
| 69 | 69 | major: captures.name("major").unwrap().parse().unwrap(), |
| 1 | use std::fmt; | |
| 2 | ||
| 1 | 3 | use regex::Regex; |
| 2 | 4 | |
| 3 | 5 | lazy_static! { |
⋮
| 40 | 42 | }; |
| 41 | 43 | } |
| 42 | 44 | |
| 45 | #[derive(Clone, Debug, PartialEq, Eq)] | |
| 43 | 46 | pub struct Version { |
| 44 | 47 | pub major: u64, |
| 45 | 48 | pub minor: u64, |
⋮
| 48 | 51 | pub build: Vec<Identifier>, |
| 49 | 52 | } |
| 50 | 53 | |
| 54 | #[derive(Clone, Debug, PartialEq, Eq)] | |
| 51 | 55 | pub enum Identifier { |
| 52 | 56 | /// An identifier that's solely numbers. |
| 53 | 57 | Numeric(u64), |
⋮
| 95 | 99 | Identifier::AlphaNumeric(part.to_string()) |
| 96 | 100 | } |
| 97 | 101 | }).collect() |
| 102 | ||
| 103 | impl fmt::Display for Version { | |
| 104 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| 105 | try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch)); | |
| 106 | if !self.pre.is_empty() { | |
| 107 | let strs: Vec<_> = | |
| 108 | self.pre.iter().map(ToString::to_string).collect(); | |
| 109 | try!(write!(f, "-{}", strs.join("."))); | |
| 110 | } | |
| 111 | if !self.build.is_empty() { | |
| 112 | let strs: Vec<_> = | |
| 113 | self.build.iter().map(ToString::to_string).collect(); | |
| 114 | try!(write!(f, "+{}", strs.join("."))); | |
| 115 | } | |
| 116 | Ok(()) | |
| 117 | } | |
| 118 | } | |
| 119 | ||
| 120 | impl fmt::Display for Identifier { | |
| 121 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| 122 | match *self { | |
| 123 | Identifier::Numeric(ref id) => id.fmt(f), | |
| 124 | Identifier::AlphaNumeric(ref id) => id.fmt(f), | |
| 125 | } | |
| 126 | } | |
| 98 | 127 | } |
| 1 | use std::fmt; | |
| 2 | ||
| 1 | 3 | use regex::Regex; |
| 2 | 4 | |
| 3 | 5 | lazy_static! { |
⋮
| 40 | 42 | }; |
| 41 | 43 | } |
| 42 | 44 | |
| 45 | #[derive(Clone, Debug, PartialEq, Eq)] | |
| 43 | 46 | pub struct Version { |
| 44 | 47 | pub major: u64, |
| 45 | 48 | pub minor: u64, |
⋮
| 48 | 51 | pub build: Vec<Identifier>, |
| 49 | 52 | } |
| 50 | 53 | |
| 54 | #[derive(Clone, Debug, PartialEq, Eq)] | |
| 51 | 55 | pub enum Identifier { |
| 52 | 56 | /// An identifier that's solely numbers. |
| 53 | 57 | Numeric(u64), |
⋮
| 95 | 99 | Identifier::AlphaNumeric(part.to_string()) |
| 96 | 100 | } |
| 97 | 101 | }).collect() |
| 102 | ||
| 103 | impl fmt::Display for Version { | |
| 104 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| 105 | try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch)); | |
| 106 | if !self.pre.is_empty() { | |
| 107 | let strs: Vec<_> = | |
| 108 | self.pre.iter().map(ToString::to_string).collect(); | |
| 109 | try!(write!(f, "-{}", strs.join("."))); | |
| 110 | } | |
| 111 | if !self.build.is_empty() { | |
| 112 | let strs: Vec<_> = | |
| 113 | self.build.iter().map(ToString::to_string).collect(); | |
| 114 | try!(write!(f, "+{}", strs.join("."))); | |
| 115 | } | |
| 116 | Ok(()) | |
| 117 | } | |
| 118 | } | |
| 119 | ||
| 120 | impl fmt::Display for Identifier { | |
| 121 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| 122 | match *self { | |
| 123 | Identifier::Numeric(ref id) => id.fmt(f), | |
| 124 | Identifier::AlphaNumeric(ref id) => id.fmt(f), | |
| 125 | } | |
| 126 | } | |
| 98 | 127 | } |
| 1 | use regex::Regex; | |
| 2 | use version::Identifier; | |
| 3 | ||
| 4 | // by the time we get here, we know that it's all valid characters, so this doesn't need to return | |
| 5 | // a result or anything | |
| 6 | pub fn parse_meta(s: &str) -> Vec<Identifier> { | |
| 7 | // Originally, I wanted to implement this method via calling parse, but parse is tolerant of | |
| 8 | // leading zeroes, and we want anything with leading zeroes to be considered alphanumeric, not | |
| 9 | // numeric. So the strategy is to check with a regex first, and then call parse once we've | |
| 10 | // determined that it's a number without a leading zero. | |
| 11 | s.split(".") | |
| 12 | .map(|part| { | |
| 13 | // another wrinkle: we made sure that any number starts with a | |
| 14 | // non-zero. But there's a problem: an actual zero is a number, yet | |
| 15 | // gets left out by this heuristic. So let's also check for the | |
| 16 | // single, lone zero. | |
| 17 | if is_alpha_numeric(part) { | |
| 18 | Identifier::AlphaNumeric(part.to_string()) | |
| 19 | } else { | |
| 20 | // we can unwrap here because we know it is only digits due to the regex | |
| 21 | Identifier::Numeric(part.parse().unwrap()) | |
| 22 | } | |
| 23 | }).collect() | |
| 24 | } | |
| 25 | ||
| 26 | pub fn is_alpha_numeric(s: &str) -> bool { | |
| 27 | lazy_static! { | |
| 28 | static ref REGEX: Regex = Regex::new(r"^(0|[1-9][0-9]*)$").unwrap(); | |
| 29 | }; | |
| 30 | !REGEX.is_match(s) | |
| 31 | } |
| 4 | 4 | extern crate lazy_static; |
| 5 | 5 | |
| 6 | 6 | pub mod version; |
| 7 | ||
| 8 | // for private stuff the two share | |
| 9 | mod common; |
| 1 | 1 | use std::fmt; |
| 2 | 2 | |
| 3 | 3 | use regex::Regex; |
| 4 | use common; | |
| 4 | 5 | |
| 5 | 6 | lazy_static! { |
| 6 | 7 | static ref REGEX: Regex = { |
⋮
| 59 | 60 | AlphaNumeric(String), |
| 60 | 61 | } |
| 61 | 62 | |
| 62 | pub fn parse_version(version: &str) -> Result<Version, String> { | |
| 63 | pub fn parse(version: &str) -> Result<Version, String> { | |
| 63 | 64 | let captures = match REGEX.captures(version.trim()) { |
| 64 | 65 | Some(captures) => captures, |
| 65 | 66 | None => return Err(From::from("Version did not parse properly.")), |
| 66 | 67 | }; |
| 67 | 68 | |
| 68 | let pre = captures.name("pre").map(parse_meta).unwrap_or(vec![]); | |
| 69 | let pre = captures.name("pre").map(common::parse_meta).unwrap_or(vec![]); | |
| 69 | 70 | |
| 70 | let build = captures.name("build").map(parse_meta).unwrap_or(vec![]); | |
| 71 | let build = captures.name("build").map(common::parse_meta).unwrap_or(vec![]); | |
| 71 | 72 | |
| 72 | 73 | Ok(Version { |
| 73 | 74 | major: captures.name("major").unwrap().parse().unwrap(), |
⋮
| 78 | 79 | }) |
| 79 | 80 | } |
| 80 | 81 | |
| 81 | // by the time we get here, we know that it's all valid characters, so this doesn't need to return | |
| 82 | // a result or anything | |
| 83 | fn parse_meta(pre: &str) -> Vec<Identifier> { | |
| 84 | // Originally, I wanted to implement this method via calling parse, but parse is tolerant of | |
| 85 | // leading zeroes, and we want anything with leading zeroes to be considered alphanumeric, not | |
| 86 | // numeric. So the strategy is to check with a regex first, and then call parse once we've | |
| 87 | // determined that it's a number without a leading zero. | |
| 88 | let regex = Regex::new(r"^[1-9][0-9]*$").unwrap(); | |
| 89 | ||
| 90 | pre.split(".") | |
| 91 | .map(|part| { | |
| 92 | // another wrinkle: we made sure that any number starts with a non-zero. But there's a | |
| 93 | // problem: an actual zero is a number, yet gets left out by this heuristic. So let's | |
| 94 | // also check for the single, lone zero. | |
| 95 | if regex.is_match(part) || part == "0" { | |
| 96 | // we can unwrap here because we know it is only digits due to the regex | |
| 97 | Identifier::Numeric(part.parse().unwrap()) | |
| 98 | } else { | |
| 99 | Identifier::AlphaNumeric(part.to_string()) | |
| 100 | } | |
| 101 | }).collect() | |
| 102 | ||
| 103 | 82 | impl fmt::Display for Version { |
| 104 | 83 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 105 | 84 | try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch)); |
| 1 | use regex::Regex; | |
| 2 | use version::Identifier; | |
| 3 | ||
| 4 | // by the time we get here, we know that it's all valid characters, so this doesn't need to return | |
| 5 | // a result or anything | |
| 6 | pub fn parse_meta(pre: &str) -> Vec<Identifier> { | |
| 7 | // Originally, I wanted to implement this method via calling parse, but parse is tolerant of | |
| 8 | // leading zeroes, and we want anything with leading zeroes to be considered alphanumeric, not | |
| 9 | // numeric. So the strategy is to check with a regex first, and then call parse once we've | |
| 10 | // determined that it's a number without a leading zero. | |
| 11 | let regex = Regex::new(r"^[1-9][0-9]*$").unwrap(); | |
| 12 | ||
| 13 | pre.split(".") | |
| 14 | .map(|part| { | |
| 15 | // another wrinkle: we made sure that any number starts with a non-zero. But there's a | |
| 16 | // problem: an actual zero is a number, yet gets left out by this heuristic. So let's | |
| 17 | // also check for the single, lone zero. | |
| 18 | if regex.is_match(part) || part == "0" { | |
| 19 | // we can unwrap here because we know it is only digits due to the regex | |
| 20 | Identifier::Numeric(part.parse().unwrap()) | |
| 21 | } else { | |
| 22 | Identifier::AlphaNumeric(part.to_string()) | |
| 23 | } | |
| 24 | }).collect() | |
| 25 | } | |
| 26 |
| 4 | 4 | extern crate lazy_static; |
| 5 | 5 | |
| 6 | 6 | pub mod version; |
| 7 | ||
| 8 | // for private stuff the two share | |
| 9 | mod common; |
| 1 | 1 | use std::fmt; |
| 2 | 2 | |
| 3 | 3 | use regex::Regex; |
| 4 | use common; | |
| 4 | 5 | |
| 5 | 6 | lazy_static! { |
| 6 | 7 | static ref REGEX: Regex = { |
⋮
| 59 | 60 | AlphaNumeric(String), |
| 60 | 61 | } |
| 61 | 62 | |
| 62 | pub fn parse_version(version: &str) -> Result<Version, String> { | |
| 63 | pub fn parse(version: &str) -> Result<Version, String> { | |
| 63 | 64 | let captures = match REGEX.captures(version.trim()) { |
| 64 | 65 | Some(captures) => captures, |
| 65 | 66 | None => return Err(From::from("Version did not parse properly.")), |
| 66 | 67 | }; |
| 67 | 68 | |
| 68 | let pre = captures.name("pre").map(parse_meta).unwrap_or(vec![]); | |
| 69 | let pre = captures.name("pre").map(common::parse_meta).unwrap_or(vec![]); | |
| 69 | 70 | |
| 70 | let build = captures.name("build").map(parse_meta).unwrap_or(vec![]); | |
| 71 | let build = captures.name("build").map(common::parse_meta).unwrap_or(vec![]); | |
| 71 | 72 | |
| 72 | 73 | Ok(Version { |
| 73 | 74 | major: captures.name("major").unwrap().parse().unwrap(), |
⋮
| 78 | 79 | }) |
| 79 | 80 | } |
| 80 | 81 | |
| 81 | // by the time we get here, we know that it's all valid characters, so this doesn't need to return | |
| 82 | // a result or anything | |
| 83 | fn parse_meta(pre: &str) -> Vec<Identifier> { | |
| 84 | // Originally, I wanted to implement this method via calling parse, but parse is tolerant of | |
| 85 | // leading zeroes, and we want anything with leading zeroes to be considered alphanumeric, not | |
| 86 | // numeric. So the strategy is to check with a regex first, and then call parse once we've | |
| 87 | // determined that it's a number without a leading zero. | |
| 88 | let regex = Regex::new(r"^[1-9][0-9]*$").unwrap(); | |
| 89 | ||
| 90 | pre.split(".") | |
| 91 | .map(|part| { | |
| 92 | // another wrinkle: we made sure that any number starts with a non-zero. But there's a | |
| 93 | // problem: an actual zero is a number, yet gets left out by this heuristic. So let's | |
| 94 | // also check for the single, lone zero. | |
| 95 | if regex.is_match(part) || part == "0" { | |
| 96 | // we can unwrap here because we know it is only digits due to the regex | |
| 97 | Identifier::Numeric(part.parse().unwrap()) | |
| 98 | } else { | |
| 99 | Identifier::AlphaNumeric(part.to_string()) | |
| 100 | } | |
| 101 | }).collect() | |
| 102 | ||
| 103 | 82 | impl fmt::Display for Version { |
| 104 | 83 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 105 | 84 | try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch)); |
| 3 | 3 | |
| 4 | 4 | // by the time we get here, we know that it's all valid characters, so this doesn't need to return |
| 5 | 5 | // a result or anything |
| 6 | pub fn parse_meta(pre: &str) -> Vec<Identifier> { | |
| 6 | pub fn parse_meta(s: &str) -> Vec<Identifier> { | |
| 7 | 7 | // Originally, I wanted to implement this method via calling parse, but parse is tolerant of |
| 8 | 8 | // leading zeroes, and we want anything with leading zeroes to be considered alphanumeric, not |
| 9 | 9 | // numeric. So the strategy is to check with a regex first, and then call parse once we've |
| 10 | 10 | // determined that it's a number without a leading zero. |
| 11 | let regex = Regex::new(r"^[1-9][0-9]*$").unwrap(); | |
| 12 | ||
| 13 | pre.split(".") | |
| 11 | s.split(".") | |
| 14 | 12 | .map(|part| { |
| 15 | // another wrinkle: we made sure that any number starts with a non-zero. But there's a | |
| 16 | // problem: an actual zero is a number, yet gets left out by this heuristic. So let's | |
| 17 | // also check for the single, lone zero. | |
| 18 | if regex.is_match(part) || part == "0" { | |
| 13 | // another wrinkle: we made sure that any number starts with a | |
| 14 | // non-zero. But there's a problem: an actual zero is a number, yet | |
| 15 | // gets left out by this heuristic. So let's also check for the | |
| 16 | // single, lone zero. | |
| 17 | if is_alpha_numeric(part) { | |
| 18 | Identifier::AlphaNumeric(part.to_string()) | |
| 19 | } else { | |
| 19 | 20 | // we can unwrap here because we know it is only digits due to the regex |
| 20 | 21 | Identifier::Numeric(part.parse().unwrap()) |
| 21 | } else { | |
| 22 | Identifier::AlphaNumeric(part.to_string()) | |
| 23 | 22 | } |
| 24 | 23 | }).collect() |
| 25 | 24 | } |
| 26 | 25 | |
| 26 | pub fn is_alpha_numeric(s: &str) -> bool { | |
| 27 | lazy_static! { | |
| 28 | static ref REGEX: Regex = Regex::new(r"^(0|[1-9][0-9]*)$").unwrap(); | |
| 29 | }; | |
| 30 | !REGEX.is_match(s) | |
| 31 | } |
| 4 | 4 | extern crate lazy_static; |
| 5 | 5 | |
| 6 | 6 | pub mod version; |
| 7 | pub mod range; | |
| 7 | 8 | |
| 8 | 9 | // for private stuff the two share |
| 9 | 10 | mod common; |
| 1 | use regex::Regex; | |
| 2 | use common; | |
| 3 | use version::Identifier; | |
| 4 | use std::str::FromStr; | |
| 5 | use std::error::Error; | |
| 6 | use std::num::ParseIntError; | |
| 7 | ||
| 8 | lazy_static! { | |
| 9 | static ref REGEX: Regex = { | |
| 10 | // an operation can be: | |
| 11 | // | |
| 12 | // * = | |
| 13 | // * > | |
| 14 | // * >= | |
| 15 | // * < | |
| 16 | // * <= | |
| 17 | // * ~ | |
| 18 | // * ^ | |
| 19 | let operation = r"=|>|>=|<|<=|~|\^"; | |
| 20 | ||
| 21 | // a numeric identifier is either zero or multiple numbers without a leading zero | |
| 22 | let numeric_identifier = r"0|[1-9][0-9]*"; | |
| 23 | ||
| 24 | let major = numeric_identifier; | |
| 25 | ||
| 26 | // minor can be either a number or a wildcard. *, x, and X are wildcards. | |
| 27 | let minor = format!(r"{}|\*|[xX]", numeric_identifier); | |
| 28 | ||
| 29 | // patch can be either a number or a wildcard. *, x, and X are wildcards. | |
| 30 | let patch = format!(r"{}|\*|[xX]", numeric_identifier); | |
| 31 | ||
| 32 | let letters_numbers_dash_dot = r"[-.A-Za-z0-9]+"; | |
| 33 | ||
| 34 | // This regex does not fully parse prereleases, just extracts the whole prerelease string. | |
| 35 | // parse_version() will parse this further. | |
| 36 | let pre = letters_numbers_dash_dot; | |
| 37 | ||
| 38 | // This regex does not fully parse builds, just extracts the whole build string. | |
| 39 | // parse_version() will parse this further. | |
| 40 | let build = letters_numbers_dash_dot; | |
| 41 | ||
| 42 | let regex = format!(r"(?x) # heck yes x mode | |
| 43 | ^\s* # leading whitespace | |
| 44 | (?P<operation>{})?\s* # optional operation | |
| 45 | (?P<major>{}) # major version | |
| 46 | (?:\.(?P<minor>{}))? # optional dot and then minor | |
| 47 | (?:\.(?P<patch>{}))? # optional dot and then patch | |
| 48 | (?:-(?P<pre>{}))? # optional prerelease version | |
| 49 | (?:\+(?P<build>{}))? # optional build metadata | |
| 50 | \s*$ # trailing whitespace | |
| 51 | ", | |
| 52 | operation, | |
| 53 | major, | |
| 54 | minor, | |
| 55 | patch, | |
| 56 | pre, | |
| 57 | build); | |
| 58 | let regex = Regex::new(®ex); | |
| 59 | ||
| 60 | // this unwrap is okay because everything above here is const, so this will never fail. | |
| 61 | regex.unwrap() | |
| 62 | }; | |
| 63 | } | |
| 64 | ||
| 65 | #[derive(Debug)] | |
| 66 | pub struct VersionReq { | |
| 67 | pub predicates: Vec<Predicate>, | |
| 68 | } | |
| 69 | ||
| 70 | #[derive(PartialEq,Debug)] | |
| 71 | pub enum WildcardVersion { | |
| 72 | Major, | |
| 73 | Minor, | |
| 74 | Patch, | |
| 75 | } | |
| 76 | ||
| 77 | #[derive(PartialEq,Debug)] | |
| 78 | pub enum Op { | |
| 79 | Ex, // Exact | |
| 80 | Gt, // Greater than | |
| 81 | GtEq, // Greater than or equal to | |
| 82 | Lt, // Less than | |
| 83 | LtEq, // Less than or equal to | |
| 84 | Tilde, // e.g. ~1.0.0 | |
| 85 | Compatible, // compatible by definition of semver, indicated by ^ | |
| 86 | Wildcard(WildcardVersion), // x.y.*, x.*, * | |
| 87 | } | |
| 88 | ||
| 89 | impl FromStr for Op { | |
| 90 | type Err = String; | |
| 91 | ||
| 92 | fn from_str(s: &str) -> Result<Op, String> { | |
| 93 | match s { | |
| 94 | "=" => Ok(Op::Ex), | |
| 95 | ">" => Ok(Op::Gt), | |
| 96 | ">=" => Ok(Op::GtEq), | |
| 97 | "<" => Ok(Op::Lt), | |
| 98 | "<=" => Ok(Op::LtEq), | |
| 99 | "~" => Ok(Op::Tilde), | |
| 100 | "^" => Ok(Op::Compatible), | |
| 101 | _ => Err(String::from("Could not parse Op")), | |
| 102 | } | |
| 103 | } | |
| 104 | } | |
| 105 | ||
| 106 | #[derive(PartialEq,Debug)] | |
| 107 | pub struct Predicate { | |
| 108 | pub op: Op, | |
| 109 | pub major: u64, | |
| 110 | pub minor: Option<u64>, | |
| 111 | pub patch: Option<u64>, | |
| 112 | pub pre: Vec<Identifier>, | |
| 113 | } | |
| 114 | ||
| 115 | pub fn parse(ranges: &str) -> Result<VersionReq, String> { | |
| 116 | // null is an error | |
| 117 | if ranges == "\0" { | |
| 118 | return Err(String::from("Null is not a valid VersionReq")); | |
| 119 | } | |
| 120 | ||
| 121 | // an empty range is a major version wildcard | |
| 122 | // so is a lone * or x of either capitalization | |
| 123 | if (ranges == "") | |
| 124 | || (ranges == "*") | |
| 125 | || (ranges == "x") | |
| 126 | || (ranges == "X") { | |
| 127 | return Ok(VersionReq { | |
| 128 | predicates: vec![Predicate { | |
| 129 | op: Op::Wildcard(WildcardVersion::Major), | |
| 130 | major: 0, | |
| 131 | minor: None, | |
| 132 | patch: None, | |
| 133 | pre: Vec::new(), | |
| 134 | }], | |
| 135 | }); | |
| 136 | } | |
| 137 | ||
| 138 | ||
| 139 | let ranges = ranges.trim(); | |
| 140 | ||
| 141 | let predicates: Result<Vec<_>, String> = ranges | |
| 142 | .split(",") | |
| 143 | .map(|range| { | |
| 144 | parse_predicate(range) | |
| 145 | }) | |
| 146 | .collect(); | |
| 147 | ||
| 148 | let predicates = try!(predicates); | |
| 149 | ||
| 150 | if predicates.len() == 0 { | |
| 151 | return Err(String::from("VersionReq did not parse properly")); | |
| 152 | } | |
| 153 | ||
| 154 | Ok(VersionReq { | |
| 155 | predicates: predicates, | |
| 156 | }) | |
| 157 | } | |
| 158 | ||
| 159 | pub fn parse_predicate(range: &str) -> Result<Predicate, String> { | |
| 160 | let captures = match REGEX.captures(range.trim()) { | |
| 161 | Some(captures) => captures, | |
| 162 | None => return Err(From::from("VersionReq did not parse properly.")), | |
| 163 | }; | |
| 164 | ||
| 165 | // operations default to Compatible | |
| 166 | // unwrap is okay because we validate that we only have correct strings in the regex | |
| 167 | let mut operation = captures.name("operation") | |
| 168 | .map(str::parse) | |
| 169 | .map(Result::unwrap) | |
| 170 | .unwrap_or(Op::Compatible); | |
| 171 | ||
| 172 | // unwrap is okay because we always have major | |
| 173 | let major: Result<_, ParseIntError> = captures.name("major") | |
| 174 | .unwrap() | |
| 175 | .parse(); | |
| 176 | ||
| 177 | let major = match major { | |
| 178 | Ok(number) => number, | |
| 179 | Err(err) => return Err("Error parsing major version number: ".to_string() + err.description()) | |
| 180 | }; | |
| 181 | ||
| 182 | let minor = match captures.name("minor") { | |
| 183 | Some(minor) => { | |
| 184 | match minor.parse::<u64>() { | |
| 185 | Ok(number) => Some(number), | |
| 186 | Err(err) => { | |
| 187 | match minor { | |
| 188 | "*" | "x" | "X" => { | |
| 189 | operation = Op::Wildcard(WildcardVersion::Minor); | |
| 190 | None | |
| 191 | }, | |
| 192 | _ => return Err("Error parsing minor version number: ".to_string() + err.description()), | |
| 193 | } | |
| 194 | }, | |
| 195 | } | |
| 196 | }, | |
| 197 | None => None, | |
| 198 | }; | |
| 199 | ||
| 200 | let patch = match captures.name("patch") { | |
| 201 | Some(patch) => { | |
| 202 | match patch.parse::<u64>() { | |
| 203 | Ok(number) => Some(number), | |
| 204 | Err(err) => { | |
| 205 | match patch { | |
| 206 | "*" | "x" | "X" => { | |
| 207 | operation = Op::Wildcard(WildcardVersion::Patch); | |
| 208 | None | |
| 209 | }, | |
| 210 | _ => return Err("Error parsing patch version number: ".to_string() + err.description()), | |
| 211 | } | |
| 212 | }, | |
| 213 | } | |
| 214 | }, | |
| 215 | None => None, | |
| 216 | }; | |
| 217 | ||
| 218 | let pre = captures.name("pre").map(common::parse_meta).unwrap_or_else(Vec::new); | |
| 219 | ||
| 220 | Ok(Predicate { | |
| 221 | op: operation, | |
| 222 | major: major, | |
| 223 | minor: minor, | |
| 224 | patch: patch, | |
| 225 | pre: pre, | |
| 226 | }) | |
| 227 | } |
| 4 | 4 | extern crate lazy_static; |
| 5 | 5 | |
| 6 | 6 | pub mod version; |
| 7 | pub mod range; | |
| 7 | 8 | |
| 8 | 9 | // for private stuff the two share |
| 9 | 10 | mod common; |
| 1 | use regex::Regex; | |
| 2 | ||
| 3 | lazy_static! { | |
| 4 | static ref REGEX: Regex = { | |
| 5 | // an operation can be: | |
| 6 | // | |
| 7 | // * = | |
| 8 | // * > | |
| 9 | // * >= | |
| 10 | // * < | |
| 11 | // * <= | |
| 12 | // * ~ | |
| 13 | // * ^ | |
| 14 | let operation = r"=|>|>=|<|<=|~|\^"; | |
| 15 | ||
| 16 | // a numeric identifier is either zero or multiple numbers without a leading zero | |
| 17 | let numeric_identifier = r"0|[1-9][0-9]*"; | |
| 18 | ||
| 19 | let major = numeric_identifier; | |
| 20 | ||
| 21 | // minor can be either a number or a wildcard. *, x, and X are wildcards. | |
| 22 | let minor = format!(r"{}|\*|[xX]", numeric_identifier); | |
| 23 | ||
| 24 | // patch can be either a number or a wildcard. *, x, and X are wildcards. | |
| 25 | let patch = format!(r"{}|\*|[xX]", numeric_identifier); | |
| 26 | ||
| 27 | let letters_numbers_dash_dot = r"[-.A-Za-z0-9]+"; | |
| 28 | ||
| 29 | // This regex does not fully parse prereleases, just extracts the whole prerelease string. | |
| 30 | // parse_version() will parse this further. | |
| 31 | let pre = letters_numbers_dash_dot; | |
| 32 | ||
| 33 | let regex = format!(r"(?x) # heck yes x mode | |
| 34 | ^\s* # leading whitespace | |
| 35 | (?P<operation>{})?\s* # optional operation | |
| 36 | (?P<major>{}) # major version | |
| 37 | (?:\.(?P<minor>{}))? # optional dot and then minor | |
| 38 | (?:\.(?P<patch>{}))? # optional dot and then patch | |
| 39 | (?:-(?P<pre>{}))? # optional prerelease version | |
| 40 | \s*$ # trailing whitespace | |
| 41 | ", | |
| 42 | operation, | |
| 43 | major, | |
| 44 | minor, | |
| 45 | patch, | |
| 46 | pre); | |
| 47 | let regex = Regex::new(®ex); | |
| 48 | ||
| 49 | // this unwrap is okay because everything above here is const, so this will never fail. | |
| 50 | regex.unwrap() | |
| 51 | }; | |
| 52 | } |
| 4 | 4 | extern crate lazy_static; |
| 5 | 5 | |
| 6 | 6 | pub mod version; |
| 7 | pub mod range; | |
| 7 | 8 | |
| 8 | 9 | // for private stuff the two share |
| 9 | 10 | mod common; |
| 1 | use regex::Regex; | |
| 2 | ||
| 3 | lazy_static! { | |
| 4 | static ref REGEX: Regex = { | |
| 5 | // an operation can be: | |
| 6 | // | |
| 7 | // * = | |
| 8 | // * > | |
| 9 | // * >= | |
| 10 | // * < | |
| 11 | // * <= | |
| 12 | // * ~ | |
| 13 | // * ^ | |
| 14 | let operation = r"=|>|(:?>=)|<|(:?<=)|~|\^"; | |
| 15 | ||
| 16 | // a numeric identifier is either zero or multiple numbers without a leading zero | |
| 17 | let numeric_identifier = r"0|(:?[1-9][0-9]*)"; | |
| 18 | ||
| 19 | let major = numeric_identifier; | |
| 20 | ||
| 21 | // minor can be either a number or a wildcard. *, x, and X are wildcards. | |
| 22 | let minor = format!(r"(:?{})|\*|[xX]", numeric_identifier); | |
| 23 | ||
| 24 | // patch can be either a number or a wildcard. *, x, and X are wildcards. | |
| 25 | let patch = format!(r"(:?{})|\*|[xX]", numeric_identifier); | |
| 26 | ||
| 27 | let letters_numbers_dash_dot = r"[-.A-Za-z0-9]+"; | |
| 28 | ||
| 29 | // This regex does not fully parse prereleases, just extracts the whole prerelease string. | |
| 30 | // parse_version() will parse this further. | |
| 31 | let pre = letters_numbers_dash_dot; | |
| 32 | ||
| 33 | let regex = format!(r"^(?x) # heck yes x mode | |
| 34 | (?P<operation>{})?\s* # optional operation | |
| 35 | (?P<major>{}) # major version | |
| 36 | (:?\.(?P<minor>{}))? # optional dot and then minor | |
| 37 | (:?\.(?P<patch>{}))? # optional dot and then patch | |
| 38 | (:?-(?P<pre>{}))? # optional prerelease version | |
| 39 | $", | |
| 40 | operation, | |
| 41 | major, | |
| 42 | minor, | |
| 43 | patch, | |
| 44 | pre); | |
| 45 | let regex = Regex::new(®ex); | |
| 46 | ||
| 47 | // this unwrap is okay because everything above here is const, so this will never fail. | |
| 48 | regex.unwrap() | |
| 49 | }; | |
| 50 | } |
| 11 | 11 | // * <= |
| 12 | 12 | // * ~ |
| 13 | 13 | // * ^ |
| 14 | let operation = r"=|>|(:?>=)|<|(:?<=)|~|\^"; | |
| 14 | let operation = r"=|>|>=|<|<=|~|\^"; | |
| 15 | 15 | |
| 16 | 16 | // a numeric identifier is either zero or multiple numbers without a leading zero |
| 17 | let numeric_identifier = r"0|(:?[1-9][0-9]*)"; | |
| 17 | let numeric_identifier = r"0|[1-9][0-9]*"; | |
| 18 | 18 | |
| 19 | 19 | let major = numeric_identifier; |
| 20 | 20 | |
| 21 | 21 | // minor can be either a number or a wildcard. *, x, and X are wildcards. |
| 22 | let minor = format!(r"(:?{})|\*|[xX]", numeric_identifier); | |
| 22 | let minor = format!(r"{}|\*|[xX]", numeric_identifier); | |
| 23 | 23 | |
| 24 | 24 | // patch can be either a number or a wildcard. *, x, and X are wildcards. |
| 25 | let patch = format!(r"(:?{})|\*|[xX]", numeric_identifier); | |
| 25 | let patch = format!(r"{}|\*|[xX]", numeric_identifier); | |
| 26 | 26 | |
| 27 | 27 | let letters_numbers_dash_dot = r"[-.A-Za-z0-9]+"; |
| 28 | 28 | |
| 29 | 29 | // This regex does not fully parse prereleases, just extracts the whole prerelease string. |
| 30 | 30 | // parse_version() will parse this further. |
| 31 | 31 | let pre = letters_numbers_dash_dot; |
| 32 | ||
| 33 | let regex = format!(r"^(?x) # heck yes x mode | |
| 32 | ||
| 33 | let regex = format!(r"(?x) # heck yes x mode | |
| 34 | ^\s* # leading whitespace | |
| 34 | 35 | (?P<operation>{})?\s* # optional operation |
| 35 | 36 | (?P<major>{}) # major version |
| 36 | (:?\.(?P<minor>{}))? # optional dot and then minor | |
| 37 | (:?\.(?P<patch>{}))? # optional dot and then patch | |
| 38 | (:?-(?P<pre>{}))? # optional prerelease version | |
| 39 | $", | |
| 37 | (?:\.(?P<minor>{}))? # optional dot and then minor | |
| 38 | (?:\.(?P<patch>{}))? # optional dot and then patch | |
| 39 | (?:-(?P<pre>{}))? # optional prerelease version | |
| 40 | \s*$ # trailing whitespace | |
| 41 | ", | |
| 40 | 42 | operation, |
| 41 | 43 | major, |
| 42 | 44 | minor, |
| 43 | 45 | patch, |
| 44 | 46 | pre); |
| 45 | 47 | let regex = Regex::new(®ex); |
| 46 | ||
| 48 | ||
| 47 | 49 | // this unwrap is okay because everything above here is const, so this will never fail. |
| 48 | 50 | regex.unwrap() |
| 49 | 51 | }; |
| 1 | 1 | use regex::Regex; |
| 2 | use version::Identifier; | |
| 2 | 3 | |
| 3 | 4 | lazy_static! { |
| 4 | 5 | static ref REGEX: Regex = { |
⋮
| 50 | 51 | regex.unwrap() |
| 51 | 52 | }; |
| 52 | 53 | } |
| 54 | ||
| 55 | pub struct VersionReq { | |
| 56 | pub predicates: Vec<Predicate>, | |
| 57 | } | |
| 58 | ||
| 59 | pub enum WildcardVersion { | |
| 60 | Major, | |
| 61 | Minor, | |
| 62 | Patch, | |
| 63 | } | |
| 64 | ||
| 65 | pub enum Op { | |
| 66 | Ex, // Exact | |
| 67 | Gt, // Greater than | |
| 68 | GtEq, // Greater than or equal to | |
| 69 | Lt, // Less than | |
| 70 | LtEq, // Less than or equal to | |
| 71 | Tilde, // e.g. ~1.0.0 | |
| 72 | Compatible, // compatible by definition of semver, indicated by ^ | |
| 73 | Wildcard(WildcardVersion), // x.y.*, x.*, * | |
| 74 | } | |
| 75 | ||
| 76 | pub struct Predicate { | |
| 77 | pub op: Op, | |
| 78 | pub major: u64, | |
| 79 | pub minor: Option<u64>, | |
| 80 | pub patch: Option<u64>, | |
| 81 | pub pre: Vec<Identifier>, | |
| 82 | } |
| 1 | 1 | use regex::Regex; |
| 2 | use version::Identifier; | |
| 2 | 3 | |
| 3 | 4 | lazy_static! { |
| 4 | 5 | static ref REGEX: Regex = { |
⋮
| 50 | 51 | regex.unwrap() |
| 51 | 52 | }; |
| 52 | 53 | } |
| 54 | ||
| 55 | pub struct VersionReq { | |
| 56 | pub predicates: Vec<Predicate>, | |
| 57 | } | |
| 58 | ||
| 59 | pub enum WildcardVersion { | |
| 60 | Major, | |
| 61 | Minor, | |
| 62 | Patch, | |
| 63 | } | |
| 64 | ||
| 65 | pub enum Op { | |
| 66 | Ex, // Exact | |
| 67 | Gt, // Greater than | |
| 68 | GtEq, // Greater than or equal to | |
| 69 | Lt, // Less than | |
| 70 | LtEq, // Less than or equal to | |
| 71 | Tilde, // e.g. ~1.0.0 | |
| 72 | Compatible, // compatible by definition of semver, indicated by ^ | |
| 73 | Wildcard(WildcardVersion), // x.y.*, x.*, * | |
| 74 | } | |
| 75 | ||
| 76 | pub struct Predicate { | |
| 77 | op: Op, | |
| 78 | major: u64, | |
| 79 | minor: Option<u64>, | |
| 80 | patch: Option<u64>, | |
| 81 | pre: Vec<Identifier>, | |
| 82 | } |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | 76 | pub struct Predicate { |
| 77 | op: Op, | |
| 78 | major: u64, | |
| 79 | minor: Option<u64>, | |
| 80 | patch: Option<u64>, | |
| 81 | pre: Vec<Identifier>, | |
| 77 | pub op: Op, | |
| 78 | pub major: u64, | |
| 79 | pub minor: Option<u64>, | |
| 80 | pub patch: Option<u64>, | |
| 81 | pub pre: Vec<Identifier>, | |
| 82 | 82 | } |
| 1 | 1 | use regex::Regex; |
| 2 | 2 | use version::Identifier; |
| 3 | use std::str::FromStr; | |
| 3 | 4 | |
| 4 | 5 | lazy_static! { |
| 5 | 6 | static ref REGEX: Regex = { |
⋮
| 52 | 53 | }; |
| 53 | 54 | } |
| 54 | 55 | |
| 56 | #[derive(Debug)] | |
| 55 | 57 | pub struct VersionReq { |
| 56 | 58 | pub predicates: Vec<Predicate>, |
| 57 | 59 | } |
| 58 | 60 | |
| 61 | #[derive(PartialEq,Debug)] | |
| 59 | 62 | pub enum WildcardVersion { |
| 60 | 63 | Major, |
| 61 | 64 | Minor, |
| 62 | 65 | Patch, |
| 63 | 66 | } |
| 64 | 67 | |
| 68 | #[derive(PartialEq,Debug)] | |
| 65 | 69 | pub enum Op { |
| 66 | 70 | Ex, // Exact |
| 67 | 71 | Gt, // Greater than |
⋮
| 73 | 77 | Wildcard(WildcardVersion), // x.y.*, x.*, * |
| 74 | 78 | } |
| 75 | 79 | |
| 80 | impl FromStr for Op { | |
| 81 | type Err = String; | |
| 82 | ||
| 83 | fn from_str(s: &str) -> Result<Op, String> { | |
| 84 | match s { | |
| 85 | "=" => Ok(Op::Ex), | |
| 86 | ">" => Ok(Op::Gt), | |
| 87 | ">=" => Ok(Op::GtEq), | |
| 88 | "<" => Ok(Op::Lt), | |
| 89 | "<=" => Ok(Op::LtEq), | |
| 90 | "~" => Ok(Op::Tilde), | |
| 91 | "^" => Ok(Op::Compatible), | |
| 92 | _ => Err(String::from("Could not parse Op")), | |
| 93 | } | |
| 94 | } | |
| 95 | } | |
| 96 | ||
| 97 | #[derive(PartialEq,Debug)] | |
| 76 | 98 | pub struct Predicate { |
| 77 | 99 | pub op: Op, |
| 78 | 100 | pub major: u64, |
| 1 | 1 | use regex::Regex; |
| 2 | 2 | use version::Identifier; |
| 3 | use std::str::FromStr; | |
| 3 | 4 | |
| 4 | 5 | lazy_static! { |
| 5 | 6 | static ref REGEX: Regex = { |
⋮
| 56 | 57 | pub predicates: Vec<Predicate>, |
| 57 | 58 | } |
| 58 | 59 | |
| 60 | #[derive(PartialEq,Debug)] | |
| 59 | 61 | pub enum WildcardVersion { |
| 60 | 62 | Major, |
| 61 | 63 | Minor, |
| 62 | 64 | Patch, |
| 63 | 65 | } |
| 64 | 66 | |
| 67 | #[derive(PartialEq,Debug)] | |
| 65 | 68 | pub enum Op { |
| 66 | 69 | Ex, // Exact |
| 67 | 70 | Gt, // Greater than |
⋮
| 73 | 76 | Wildcard(WildcardVersion), // x.y.*, x.*, * |
| 74 | 77 | } |
| 75 | 78 | |
| 79 | impl FromStr for Op { | |
| 80 | type Err = String; | |
| 81 | ||
| 82 | fn from_str(s: &str) -> Result<Op, String> { | |
| 83 | match s { | |
| 84 | "=" => Ok(Op::Ex), | |
| 85 | ">" => Ok(Op::Gt), | |
| 86 | ">=" => Ok(Op::GtEq), | |
| 87 | "<" => Ok(Op::Lt), | |
| 88 | "<=" => Ok(Op::LtEq), | |
| 89 | "~" => Ok(Op::Tilde), | |
| 90 | "^" => Ok(Op::Compatible), | |
| 91 | _ => Err(String::from("Could not parse Op")), | |
| 92 | } | |
| 93 | } | |
| 94 | } | |
| 95 | ||
| 96 | #[derive(PartialEq,Debug)] | |
| 76 | 97 | pub struct Predicate { |
| 77 | 98 | pub op: Op, |
| 78 | 99 | pub major: u64, |
| 53 | 53 | }; |
| 54 | 54 | } |
| 55 | 55 | |
| 56 | #[derive(Debug)] | |
| 56 | 57 | pub struct VersionReq { |
| 57 | 58 | pub predicates: Vec<Predicate>, |
| 58 | 59 | } |
| 102 | 102 | pub patch: Option<u64>, |
| 103 | 103 | pub pre: Vec<Identifier>, |
| 104 | 104 | } |
| 105 | ||
| 106 | pub fn parse(ranges: &str) -> Result<VersionReq, String> { | |
| 107 | // null is an error | |
| 108 | if ranges == "\0" { | |
| 109 | return Err(String::from("Null is not a valid VersionReq")); | |
| 110 | } | |
| 111 | ||
| 112 | // an empty range is a major version wildcard | |
| 113 | // so is a lone * or x of either capitalization | |
| 114 | if (ranges == "") | |
| 115 | || (ranges == "*") | |
| 116 | || (ranges == "x") | |
| 117 | || (ranges == "X") { | |
| 118 | return Ok(VersionReq { | |
| 119 | predicates: vec![Predicate { | |
| 120 | op: Op::Wildcard(WildcardVersion::Major), | |
| 121 | major: 0, | |
| 122 | minor: None, | |
| 123 | patch: None, | |
| 124 | pre: Vec::new(), | |
| 125 | }], | |
| 126 | }); | |
| 127 | } | |
| 128 | } |
| 102 | 102 | pub patch: Option<u64>, |
| 103 | 103 | pub pre: Vec<Identifier>, |
| 104 | 104 | } |
| 105 | ||
| 106 | pub fn parse(range: &str) -> Result<VersionReq, String> { | |
| 107 | // an empty range is a major version wildcard | |
| 108 | // so is a lone * or x of either capitalization | |
| 109 | if (range == "") | |
| 110 | || (range == "*") | |
| 111 | || (range == "x") | |
| 112 | || (range == "X") { | |
| 113 | return Ok(VersionReq { | |
| 114 | predicates: vec![Predicate { | |
| 115 | op: Op::Wildcard(WildcardVersion::Major), | |
| 116 | major: 0, | |
| 117 | minor: None, | |
| 118 | patch: None, | |
| 119 | pre: Vec::new(), | |
| 120 | }], | |
| 121 | }); | |
| 122 | } | |
| 123 | } |
| 104 | 104 | } |
| 105 | 105 | |
| 106 | 106 | pub fn parse(range: &str) -> Result<VersionReq, String> { |
| 107 | // null is an error | |
| 108 | if range == "\0" { | |
| 109 | return Err(String::from("Null is not a valid VersionReq")); | |
| 110 | } | |
| 111 | ||
| 107 | 112 | // an empty range is a major version wildcard |
| 108 | 113 | // so is a lone * or x of either capitalization |
| 109 | 114 | if (range == "") |
| 103 | 103 | pub pre: Vec<Identifier>, |
| 104 | 104 | } |
| 105 | 105 | |
| 106 | pub fn parse(range: &str) -> Result<VersionReq, String> { | |
| 106 | pub fn parse(ranges: &str) -> Result<VersionReq, String> { | |
| 107 | 107 | // null is an error |
| 108 | if range == "\0" { | |
| 108 | if ranges == "\0" { | |
| 109 | 109 | return Err(String::from("Null is not a valid VersionReq")); |
| 110 | 110 | } |
| 111 | ||
| 111 | ||
| 112 | 112 | // an empty range is a major version wildcard |
| 113 | 113 | // so is a lone * or x of either capitalization |
| 114 | if (range == "") | |
| 115 | || (range == "*") | |
| 116 | || (range == "x") | |
| 117 | || (range == "X") { | |
| 114 | if (ranges == "") | |
| 115 | || (ranges == "*") | |
| 116 | || (ranges == "x") | |
| 117 | || (ranges == "X") { | |
| 118 | 118 | return Ok(VersionReq { |
| 119 | 119 | predicates: vec![Predicate { |
| 120 | 120 | op: Op::Wildcard(WildcardVersion::Major), |
| 1 | 1 | use regex::Regex; |
| 2 | use common; | |
| 2 | 3 | use version::Identifier; |
| 3 | 4 | use std::str::FromStr; |
| 5 | use std::error::Error; | |
| 6 | use std::num::ParseIntError; | |
| 4 | 7 | |
| 5 | 8 | lazy_static! { |
| 6 | 9 | static ref REGEX: Regex = { |
⋮
| 125 | 128 | }], |
| 126 | 129 | }); |
| 127 | 130 | } |
| 131 | ||
| 132 | let captures = match REGEX.captures(range.trim()) { | |
| 133 | Some(captures) => captures, | |
| 134 | None => return Err(From::from("VersionReq did not parse properly.")), | |
| 135 | }; | |
| 136 | ||
| 137 | // operations default to Compatible | |
| 138 | // unwrap is okay because we validate that we only have correct strings in the regex | |
| 139 | let mut operation = captures.name("operation") | |
| 140 | .map(str::parse) | |
| 141 | .map(Result::unwrap) | |
| 142 | .unwrap_or(Op::Compatible); | |
| 143 | ||
| 144 | // unwrap is okay because we always have major | |
| 145 | let major: Result<_, ParseIntError> = captures.name("major") | |
| 146 | .unwrap() | |
| 147 | .parse(); | |
| 148 | ||
| 149 | let major = match major { | |
| 150 | Ok(number) => number, | |
| 151 | Err(err) => return Err("Error parsing major version number: ".to_string() + err.description()) | |
| 152 | }; | |
| 153 | ||
| 154 | let minor = match captures.name("minor") { | |
| 155 | Some(minor) => { | |
| 156 | match minor.parse::<u64>() { | |
| 157 | Ok(number) => Some(number), | |
| 158 | Err(err) => { | |
| 159 | match minor { | |
| 160 | "*" | "x" | "X" => { | |
| 161 | operation = Op::Wildcard(WildcardVersion::Minor); | |
| 162 | None | |
| 163 | }, | |
| 164 | _ => return Err("Error parsing minor version number: ".to_string() + err.description()), | |
| 165 | } | |
| 166 | }, | |
| 167 | } | |
| 168 | }, | |
| 169 | None => None, | |
| 170 | }; | |
| 171 | ||
| 172 | let patch = match captures.name("patch") { | |
| 173 | Some(patch) => { | |
| 174 | match patch.parse::<u64>() { | |
| 175 | Ok(number) => Some(number), | |
| 176 | Err(err) => { | |
| 177 | match patch { | |
| 178 | "*" | "x" | "X" => { | |
| 179 | operation = Op::Wildcard(WildcardVersion::Patch); | |
| 180 | None | |
| 181 | }, | |
| 182 | _ => return Err("Error parsing patch version number: ".to_string() + err.description()), | |
| 183 | } | |
| 184 | }, | |
| 185 | } | |
| 186 | }, | |
| 187 | None => None, | |
| 188 | }; | |
| 189 | ||
| 190 | let pre = captures.name("pre").map(common::parse_meta).unwrap_or_else(Vec::new); | |
| 191 | ||
| 192 | let predicate = Predicate { | |
| 193 | op: operation, | |
| 194 | major: major, | |
| 195 | minor: minor, | |
| 196 | patch: patch, | |
| 197 | pre: pre, | |
| 198 | }; | |
| 199 | ||
| 200 | Ok(VersionReq { | |
| 201 | predicates: vec![predicate], | |
| 202 | }) | |
| 128 | 203 | } |
| 1 | 1 | use regex::Regex; |
| 2 | use common; | |
| 2 | 3 | use version::Identifier; |
| 3 | 4 | use std::str::FromStr; |
| 4 | 5 |
⋮
| 125 | 126 | }], |
| 126 | 127 | }); |
| 127 | 128 | } |
| 129 | ||
| 130 | let captures = match REGEX.captures(range.trim()) { | |
| 131 | Some(captures) => captures, | |
| 132 | None => return Err(From::from("VersionReq did not parse properly.")), | |
| 133 | }; | |
| 134 | ||
| 135 | // operations default to Compatible | |
| 136 | // unwrap is okay because we validate that we only have correct strings in the regex | |
| 137 | let mut operation = captures.name("operation") | |
| 138 | .map(str::parse) | |
| 139 | .map(Result::unwrap) | |
| 140 | .unwrap_or(Op::Compatible); | |
| 141 | ||
| 142 | // first unwrap is okay because we always have major | |
| 143 | // second unwrap is okay becasue we know it's a number | |
| 144 | let major = captures.name("major") | |
| 145 | .unwrap() | |
| 146 | .parse() | |
| 147 | .unwrap(); | |
| 148 | ||
| 149 | let minor = captures.name("minor"); | |
| 150 | ||
| 151 | // oh my what have I done? This code is gross. | |
| 152 | let minor = if minor.is_some() { | |
| 153 | let minor = minor.unwrap(); | |
| 154 | match minor.parse() { | |
| 155 | Ok(number) => Some(number), | |
| 156 | Err(_) => { | |
| 157 | // if we get an error, it's because it's a wildcard | |
| 158 | operation = Op::Wildcard(WildcardVersion::Minor); | |
| 159 | ||
| 160 | None | |
| 161 | }, | |
| 162 | } | |
| 163 | } else { | |
| 164 | None | |
| 165 | }; | |
| 166 | ||
| 167 | let patch = captures.name("patch"); | |
| 168 | ||
| 169 | // oh my what have I done? This code is gross. | |
| 170 | let patch = if patch.is_some() { | |
| 171 | let patch = patch.unwrap(); | |
| 172 | match patch.parse() { | |
| 173 | Ok(number) => Some(number), | |
| 174 | Err(_) => { | |
| 175 | // if we get an error, it's because it's a wildcard | |
| 176 | operation = Op::Wildcard(WildcardVersion::Patch); | |
| 177 | ||
| 178 | None | |
| 179 | }, | |
| 180 | } | |
| 181 | } else { | |
| 182 | None | |
| 183 | }; | |
| 184 | ||
| 185 | let pre = captures.name("pre").map(common::parse_meta).unwrap_or_else(Vec::new); | |
| 186 | ||
| 187 | let predicate = Predicate { | |
| 188 | op: operation, | |
| 189 | major: major, | |
| 190 | minor: minor, | |
| 191 | patch: patch, | |
| 192 | pre: pre, | |
| 193 | }; | |
| 194 | ||
| 195 | Ok(VersionReq { | |
| 196 | predicates: vec![predicate], | |
| 197 | }) | |
| 128 | 198 | } |
| 147 | 147 | .unwrap(); |
| 148 | 148 | |
| 149 | 149 | let minor = captures.name("minor"); |
| 150 | ||
| 150 | ||
| 151 | 151 | // oh my what have I done? This code is gross. |
| 152 | 152 | let minor = if minor.is_some() { |
| 153 | 153 | let minor = minor.unwrap(); |
⋮
| 163 | 163 | } else { |
| 164 | 164 | None |
| 165 | 165 | }; |
| 166 | ||
| 166 | ||
| 167 | 167 | let patch = captures.name("patch"); |
| 168 | ||
| 168 | ||
| 169 | 169 | // oh my what have I done? This code is gross. |
| 170 | 170 | let patch = if patch.is_some() { |
| 171 | 171 | let patch = patch.unwrap(); |
| 2 | 2 | use common; |
| 3 | 3 | use version::Identifier; |
| 4 | 4 | use std::str::FromStr; |
| 5 | use std::error::Error; | |
| 6 | use std::num::ParseIntError; | |
| 5 | 7 | |
| 6 | 8 | lazy_static! { |
| 7 | 9 | static ref REGEX: Regex = { |
⋮
| 140 | 142 | .unwrap_or(Op::Compatible); |
| 141 | 143 | |
| 142 | 144 | // first unwrap is okay because we always have major |
| 143 | // second unwrap is okay becasue we know it's a number | |
| 144 | let major = captures.name("major") | |
| 145 | let major: Result<_, ParseIntError> = captures.name("major") | |
| 145 | 146 | .unwrap() |
| 146 | .parse() | |
| 147 | .unwrap(); | |
| 147 | .parse(); | |
| 148 | ||
| 149 | let major = match major { | |
| 150 | Ok(number) => number, | |
| 151 | Err(err) => return Err("Error parsing major version number: ".to_string() + err.description()) | |
| 152 | }; | |
| 148 | 153 | |
| 149 | 154 | let minor = captures.name("minor"); |
| 150 | 155 |
| 141 | 141 | .map(Result::unwrap) |
| 142 | 142 | .unwrap_or(Op::Compatible); |
| 143 | 143 | |
| 144 | // first unwrap is okay because we always have major | |
| 144 | // unwrap is okay because we always have major | |
| 145 | 145 | let major: Result<_, ParseIntError> = captures.name("major") |
| 146 | 146 | .unwrap() |
| 147 | 147 | .parse(); |
| 151 | 151 | Err(err) => return Err("Error parsing major version number: ".to_string() + err.description()) |
| 152 | 152 | }; |
| 153 | 153 | |
| 154 | let minor = captures.name("minor"); | |
| 155 | ||
| 156 | // oh my what have I done? This code is gross. | |
| 157 | let minor = if minor.is_some() { | |
| 158 | let minor = minor.unwrap(); | |
| 159 | match minor.parse() { | |
| 160 | Ok(number) => Some(number), | |
| 161 | Err(_) => { | |
| 162 | // if we get an error, it's because it's a wildcard | |
| 163 | operation = Op::Wildcard(WildcardVersion::Minor); | |
| 164 | ||
| 165 | None | |
| 166 | }, | |
| 167 | } | |
| 168 | } else { | |
| 169 | None | |
| 154 | let minor = match captures.name("minor") { | |
| 155 | Some(minor) => { | |
| 156 | match minor.parse::<u64>() { | |
| 157 | Ok(number) => Some(number), | |
| 158 | Err(err) => { | |
| 159 | match minor { | |
| 160 | "*" | "x" | "X" => { | |
| 161 | operation = Op::Wildcard(WildcardVersion::Minor); | |
| 162 | None | |
| 163 | }, | |
| 164 | _ => return Err("Error parsing minor version number: ".to_string() + err.description()), | |
| 165 | } | |
| 166 | }, | |
| 167 | } | |
| 168 | }, | |
| 169 | None => None, | |
| 170 | 170 | }; |
| 171 | 171 | |
| 172 | 172 | let patch = captures.name("patch"); |
| 169 | 169 | None => None, |
| 170 | 170 | }; |
| 171 | 171 | |
| 172 | let patch = captures.name("patch"); | |
| 173 | ||
| 174 | // oh my what have I done? This code is gross. | |
| 175 | let patch = if patch.is_some() { | |
| 176 | let patch = patch.unwrap(); | |
| 177 | match patch.parse() { | |
| 178 | Ok(number) => Some(number), | |
| 179 | Err(_) => { | |
| 180 | // if we get an error, it's because it's a wildcard | |
| 181 | operation = Op::Wildcard(WildcardVersion::Patch); | |
| 182 | ||
| 183 | None | |
| 184 | }, | |
| 185 | } | |
| 186 | } else { | |
| 187 | None | |
| 172 | let patch = match captures.name("patch") { | |
| 173 | Some(patch) => { | |
| 174 | match patch.parse::<u64>() { | |
| 175 | Ok(number) => Some(number), | |
| 176 | Err(err) => { | |
| 177 | match patch { | |
| 178 | "*" | "x" | "X" => { | |
| 179 | operation = Op::Wildcard(WildcardVersion::Patch); | |
| 180 | None | |
| 181 | }, | |
| 182 | _ => return Err("Error parsing patch version number: ".to_string() + err.description()), | |
| 183 | } | |
| 184 | }, | |
| 185 | } | |
| 186 | }, | |
| 187 | None => None, | |
| 188 | 188 | }; |
| 189 | 189 | |
| 190 | 190 | let pre = captures.name("pre").map(common::parse_meta).unwrap_or_else(Vec::new); |
| 129 | 129 | }); |
| 130 | 130 | } |
| 131 | 131 | |
| 132 | ||
| 133 | let ranges = ranges.trim(); | |
| 134 | ||
| 135 | let predicates: Result<Vec<_>, String> = ranges | |
| 136 | .split(",") | |
| 137 | .map(|range| { | |
| 138 | parse_predicate(range) | |
| 139 | }) | |
| 140 | .collect(); | |
| 141 | ||
| 142 | let predicates = try!(predicates); | |
| 143 | ||
| 144 | if predicates.len() == 0 { | |
| 145 | return Err(String::from("VersionReq did not parse properly")); | |
| 146 | } | |
| 147 | ||
| 148 | Ok(VersionReq { | |
| 149 | predicates: predicates, | |
| 150 | }) | |
| 151 | } | |
| 152 | ||
| 153 | pub fn parse_predicate(range: &str) -> Result<Predicate, String> { | |
| 132 | 154 | let captures = match REGEX.captures(range.trim()) { |
| 133 | 155 | Some(captures) => captures, |
| 134 | 156 | None => return Err(From::from("VersionReq did not parse properly.")), |
⋮
| 189 | 211 | |
| 190 | 212 | let pre = captures.name("pre").map(common::parse_meta).unwrap_or_else(Vec::new); |
| 191 | 213 | |
| 192 | let predicate = Predicate { | |
| 214 | Ok(Predicate { | |
| 193 | 215 | op: operation, |
| 194 | 216 | major: major, |
| 195 | 217 | minor: minor, |
| 196 | 218 | patch: patch, |
| 197 | 219 | pre: pre, |
| 198 | }; | |
| 199 | ||
| 200 | Ok(VersionReq { | |
| 201 | predicates: vec![predicate], | |
| 202 | 220 | }) |
| 203 | 221 | } |
| 129 | 129 | }); |
| 130 | 130 | } |
| 131 | 131 | |
| 132 | ||
| 133 | let range = range.trim(); | |
| 134 | ||
| 135 | let predicates: Result<Vec<_>, String> = REGEX.find_iter(range) | |
| 136 | .map(|pos| { | |
| 137 | let range = &range[pos.0..pos.1]; | |
| 138 | ||
| 139 | parse_predicate(range) | |
| 140 | }).collect(); | |
| 141 | ||
| 142 | let predicates = try!(predicates); | |
| 143 | ||
| 144 | if predicates.len() == 0 { | |
| 145 | return Err(String::from("VersionReq did not parse properly")); | |
| 146 | } | |
| 147 | ||
| 148 | Ok(VersionReq { | |
| 149 | predicates: predicates, | |
| 150 | }) | |
| 151 | } | |
| 152 | ||
| 153 | pub fn parse_predicate(range: &str) -> Result<Predicate, String> { | |
| 132 | 154 | let captures = match REGEX.captures(range.trim()) { |
| 133 | 155 | Some(captures) => captures, |
| 134 | 156 | None => return Err(From::from("VersionReq did not parse properly.")), |
⋮
| 189 | 211 | |
| 190 | 212 | let pre = captures.name("pre").map(common::parse_meta).unwrap_or_else(Vec::new); |
| 191 | 213 | |
| 192 | let predicate = Predicate { | |
| 214 | Ok(Predicate { | |
| 193 | 215 | op: operation, |
| 194 | 216 | major: major, |
| 195 | 217 | minor: minor, |
| 196 | 218 | patch: patch, |
| 197 | 219 | pre: pre, |
| 198 | }; | |
| 199 | ||
| 200 | Ok(VersionReq { | |
| 201 | predicates: vec![predicate], | |
| 202 | 220 | }) |
| 203 | 221 | } |
| 130 | 130 | } |
| 131 | 131 | |
| 132 | 132 | |
| 133 | let range = range.trim(); | |
| 134 | ||
| 135 | let predicates: Result<Vec<_>, String> = REGEX.find_iter(range) | |
| 136 | .map(|pos| { | |
| 137 | let range = &range[pos.0..pos.1]; | |
| 133 | let ranges = ranges.trim(); | |
| 138 | 134 | |
| 135 | let predicates: Result<Vec<_>, String> = ranges | |
| 136 | .split(",") | |
| 137 | .map(|range| { | |
| 139 | 138 | parse_predicate(range) |
| 140 | }).collect(); | |
| 139 | }) | |
| 140 | .collect(); | |
| 141 | 141 | |
| 142 | 142 | let predicates = try!(predicates); |
| 143 | 143 |
| 35 | 35 | // parse_version() will parse this further. |
| 36 | 36 | let pre = letters_numbers_dash_dot; |
| 37 | 37 | |
| 38 | // This regex does not fully parse builds, just extracts the whole build string. | |
| 39 | // parse_version() will parse this further. | |
| 40 | let build = letters_numbers_dash_dot; | |
| 41 | ||
| 38 | 42 | let regex = format!(r"(?x) # heck yes x mode |
| 39 | 43 | ^\s* # leading whitespace |
| 40 | 44 | (?P<operation>{})?\s* # optional operation |
⋮
| 42 | 46 | (?:\.(?P<minor>{}))? # optional dot and then minor |
| 43 | 47 | (?:\.(?P<patch>{}))? # optional dot and then patch |
| 44 | 48 | (?:-(?P<pre>{}))? # optional prerelease version |
| 49 | (?:\+(?P<build>{}))? # optional build metadata | |
| 45 | 50 | \s*$ # trailing whitespace |
| 46 | 51 | ", |
| 47 | 52 | operation, |
| 48 | 53 | major, |
| 49 | 54 | minor, |
| 50 | 55 | patch, |
| 51 | pre); | |
| 56 | pre, | |
| 57 | build); | |
| 52 | 58 | let regex = Regex::new(®ex); |
| 53 | 59 | |
| 54 | 60 | // this unwrap is okay because everything above here is const, so this will never fail. |
| 35 | 35 | // parse_version() will parse this further. |
| 36 | 36 | let pre = letters_numbers_dash_dot; |
| 37 | 37 | |
| 38 | // This regex does not fully parse builds, just extracts the whole build string. | |
| 39 | // parse_version() will parse this further. | |
| 40 | let build = letters_numbers_dash_dot; | |
| 41 | ||
| 38 | 42 | let regex = format!(r"(?x) # heck yes x mode |
| 39 | 43 | ^\s* # leading whitespace |
| 40 | 44 | (?P<operation>{})?\s* # optional operation |
⋮
| 42 | 46 | (?:\.(?P<minor>{}))? # optional dot and then minor |
| 43 | 47 | (?:\.(?P<patch>{}))? # optional dot and then patch |
| 44 | 48 | (?:-(?P<pre>{}))? # optional prerelease version |
| 49 | (:?\+(?P<build>{}))? # optional build metadata | |
| 45 | 50 | \s*$ # trailing whitespace |
| 46 | 51 | ", |
| 47 | 52 | operation, |
| 48 | 53 | major, |
| 49 | 54 | minor, |
| 50 | 55 | patch, |
| 51 | pre); | |
| 56 | pre, | |
| 57 | build); | |
| 52 | 58 | let regex = Regex::new(®ex); |
| 53 | 59 | |
| 54 | 60 | // this unwrap is okay because everything above here is const, so this will never fail. |
| 46 | 46 | (?:\.(?P<minor>{}))? # optional dot and then minor |
| 47 | 47 | (?:\.(?P<patch>{}))? # optional dot and then patch |
| 48 | 48 | (?:-(?P<pre>{}))? # optional prerelease version |
| 49 | (:?\+(?P<build>{}))? # optional build metadata | |
| 49 | (?:\+(?P<build>{}))? # optional build metadata | |
| 50 | 50 | \s*$ # trailing whitespace |
| 51 | 51 | ", |
| 52 | 52 | operation, |
| 225 | 225 | pre: pre, |
| 226 | 226 | }) |
| 227 | 227 | } |
| 228 | ||
| 229 | #[cfg(test)] | |
| 230 | mod tests { | |
| 231 | use super::*; | |
| 232 | use range; | |
| 233 | use version::Identifier; | |
| 234 | ||
| 235 | #[test] | |
| 236 | fn test_parsing_default() { | |
| 237 | let r = range::parse("1.0.0").unwrap(); | |
| 238 | ||
| 239 | assert_eq!(Predicate { | |
| 240 | op: Op::Compatible, | |
| 241 | major: 1, | |
| 242 | minor: Some(0), | |
| 243 | patch: Some(0), | |
| 244 | pre: Vec::new(), | |
| 245 | }, | |
| 246 | r.predicates[0] | |
| 247 | ); | |
| 248 | } | |
| 249 | ||
| 250 | #[test] | |
| 251 | fn test_parsing_exact_01() { | |
| 252 | let r = range::parse("=1.0.0").unwrap(); | |
| 253 | ||
| 254 | assert_eq!(Predicate { | |
| 255 | op: Op::Ex, | |
| 256 | major: 1, | |
| 257 | minor: Some(0), | |
| 258 | patch: Some(0), | |
| 259 | pre: Vec::new(), | |
| 260 | }, | |
| 261 | r.predicates[0] | |
| 262 | ); | |
| 263 | } | |
| 264 | ||
| 265 | #[test] | |
| 266 | fn test_parsing_exact_02() { | |
| 267 | let r = range::parse("=0.9.0").unwrap(); | |
| 268 | ||
| 269 | assert_eq!(Predicate { | |
| 270 | op: Op::Ex, | |
| 271 | major: 0, | |
| 272 | minor: Some(9), | |
| 273 | patch: Some(0), | |
| 274 | pre: Vec::new(), | |
| 275 | }, | |
| 276 | r.predicates[0] | |
| 277 | ); | |
| 278 | } | |
| 279 | ||
| 280 | #[test] | |
| 281 | fn test_parsing_exact_03() { | |
| 282 | let r = range::parse("=0.1.0-beta2.a").unwrap(); | |
| 283 | ||
| 284 | assert_eq!(Predicate { | |
| 285 | op: Op::Ex, | |
| 286 | major: 0, | |
| 287 | minor: Some(1), | |
| 288 | patch: Some(0), | |
| 289 | pre: vec![Identifier::AlphaNumeric(String::from("beta2")), | |
| 290 | Identifier::AlphaNumeric(String::from("a"))], | |
| 291 | }, | |
| 292 | r.predicates[0] | |
| 293 | ); | |
| 294 | } | |
| 295 | ||
| 296 | #[test] | |
| 297 | pub fn test_parsing_greater_than() { | |
| 298 | let r = range::parse("> 1.0.0").unwrap(); | |
| 299 | ||
| 300 | assert_eq!(Predicate { | |
| 301 | op: Op::Gt, | |
| 302 | major: 1, | |
| 303 | minor: Some(0), | |
| 304 | patch: Some(0), | |
| 305 | pre: Vec::new(), | |
| 306 | }, | |
| 307 | r.predicates[0] | |
| 308 | ); | |
| 309 | } | |
| 310 | ||
| 311 | #[test] | |
| 312 | pub fn test_parsing_greater_than_01() { | |
| 313 | let r = range::parse(">= 1.0.0").unwrap(); | |
| 314 | ||
| 315 | assert_eq!(Predicate { | |
| 316 | op: Op::GtEq, | |
| 317 | major: 1, | |
| 318 | minor: Some(0), | |
| 319 | patch: Some(0), | |
| 320 | pre: Vec::new(), | |
| 321 | }, | |
| 322 | r.predicates[0] | |
| 323 | ); | |
| 324 | } | |
| 325 | ||
| 326 | #[test] | |
| 327 | pub fn test_parsing_greater_than_02() { | |
| 328 | let r = range::parse(">= 2.1.0-alpha2").unwrap(); | |
| 329 | ||
| 330 | assert_eq!(Predicate { | |
| 331 | op: Op::GtEq, | |
| 332 | major: 2, | |
| 333 | minor: Some(1), | |
| 334 | patch: Some(0), | |
| 335 | pre: vec![Identifier::AlphaNumeric(String::from("alpha2"))], | |
| 336 | }, | |
| 337 | r.predicates[0] | |
| 338 | ); | |
| 339 | } | |
| 340 | ||
| 341 | #[test] | |
| 342 | pub fn test_parsing_less_than() { | |
| 343 | let r = range::parse("< 1.0.0").unwrap(); | |
| 344 | ||
| 345 | assert_eq!(Predicate { | |
| 346 | op: Op::Lt, | |
| 347 | major: 1, | |
| 348 | minor: Some(0), | |
| 349 | patch: Some(0), | |
| 350 | pre: Vec::new(), | |
| 351 | }, | |
| 352 | r.predicates[0] | |
| 353 | ); | |
| 354 | } | |
| 355 | ||
| 356 | #[test] | |
| 357 | pub fn test_parsing_less_than_eq() { | |
| 358 | let r = range::parse("<= 2.1.0-alpha2").unwrap(); | |
| 359 | ||
| 360 | assert_eq!(Predicate { | |
| 361 | op: Op::LtEq, | |
| 362 | major: 2, | |
| 363 | minor: Some(1), | |
| 364 | patch: Some(0), | |
| 365 | pre: vec![Identifier::AlphaNumeric(String::from("alpha2"))], | |
| 366 | }, | |
| 367 | r.predicates[0] | |
| 368 | ); | |
| 369 | } | |
| 370 | ||
| 371 | #[test] | |
| 372 | pub fn test_parsing_tilde() { | |
| 373 | let r = range::parse("~1").unwrap(); | |
| 374 | ||
| 375 | assert_eq!(Predicate { | |
| 376 | op: Op::Tilde, | |
| 377 | major: 1, | |
| 378 | minor: None, | |
| 379 | patch: None, | |
| 380 | pre: Vec::new(), | |
| 381 | }, | |
| 382 | r.predicates[0] | |
| 383 | ); | |
| 384 | } | |
| 385 | ||
| 386 | #[test] | |
| 387 | pub fn test_parsing_compatible() { | |
| 388 | let r = range::parse("^0").unwrap(); | |
| 389 | ||
| 390 | assert_eq!(Predicate { | |
| 391 | op: Op::Compatible, | |
| 392 | major: 0, | |
| 393 | minor: None, | |
| 394 | patch: None, | |
| 395 | pre: Vec::new(), | |
| 396 | }, | |
| 397 | r.predicates[0] | |
| 398 | ); | |
| 399 | } | |
| 400 | ||
| 401 | #[test] | |
| 402 | fn test_parsing_blank() { | |
| 403 | let r = range::parse("").unwrap(); | |
| 404 | ||
| 405 | assert_eq!(Predicate { | |
| 406 | op: Op::Wildcard(WildcardVersion::Major), | |
| 407 | major: 0, | |
| 408 | minor: None, | |
| 409 | patch: None, | |
| 410 | pre: Vec::new(), | |
| 411 | }, | |
| 412 | r.predicates[0] | |
| 413 | ); | |
| 414 | } | |
| 415 | ||
| 416 | #[test] | |
| 417 | fn test_parsing_wildcard() { | |
| 418 | let r = range::parse("*").unwrap(); | |
| 419 | ||
| 420 | assert_eq!(Predicate { | |
| 421 | op: Op::Wildcard(WildcardVersion::Major), | |
| 422 | major: 0, | |
| 423 | minor: None, | |
| 424 | patch: None, | |
| 425 | pre: Vec::new(), | |
| 426 | }, | |
| 427 | r.predicates[0] | |
| 428 | ); | |
| 429 | } | |
| 430 | ||
| 431 | #[test] | |
| 432 | fn test_parsing_x() { | |
| 433 | let r = range::parse("x").unwrap(); | |
| 434 | ||
| 435 | assert_eq!(Predicate { | |
| 436 | op: Op::Wildcard(WildcardVersion::Major), | |
| 437 | major: 0, | |
| 438 | minor: None, | |
| 439 | patch: None, | |
| 440 | pre: Vec::new(), | |
| 441 | }, | |
| 442 | r.predicates[0] | |
| 443 | ); | |
| 444 | } | |
| 445 | ||
| 446 | #[test] | |
| 447 | fn test_parsing_capital_x() { | |
| 448 | let r = range::parse("X").unwrap(); | |
| 449 | ||
| 450 | assert_eq!(Predicate { | |
| 451 | op: Op::Wildcard(WildcardVersion::Major), | |
| 452 | major: 0, | |
| 453 | minor: None, | |
| 454 | patch: None, | |
| 455 | pre: Vec::new(), | |
| 456 | }, | |
| 457 | r.predicates[0] | |
| 458 | ); | |
| 459 | } | |
| 460 | ||
| 461 | #[test] | |
| 462 | fn test_parsing_minor_wildcard_star() { | |
| 463 | let r = range::parse("1.*").unwrap(); | |
| 464 | ||
| 465 | assert_eq!(Predicate { | |
| 466 | op: Op::Wildcard(WildcardVersion::Minor), | |
| 467 | major: 1, | |
| 468 | minor: None, | |
| 469 | patch: None, | |
| 470 | pre: Vec::new(), | |
| 471 | }, | |
| 472 | r.predicates[0] | |
| 473 | ); | |
| 474 | } | |
| 475 | ||
| 476 | #[test] | |
| 477 | fn test_parsing_minor_wildcard_x() { | |
| 478 | let r = range::parse("1.x").unwrap(); | |
| 479 | ||
| 480 | assert_eq!(Predicate { | |
| 481 | op: Op::Wildcard(WildcardVersion::Minor), | |
| 482 | major: 1, | |
| 483 | minor: None, | |
| 484 | patch: None, | |
| 485 | pre: Vec::new(), | |
| 486 | }, | |
| 487 | r.predicates[0] | |
| 488 | ); | |
| 489 | } | |
| 490 | ||
| 491 | #[test] | |
| 492 | fn test_parsing_minor_wildcard_capital_x() { | |
| 493 | let r = range::parse("1.X").unwrap(); | |
| 494 | ||
| 495 | assert_eq!(Predicate { | |
| 496 | op: Op::Wildcard(WildcardVersion::Minor), | |
| 497 | major: 1, | |
| 498 | minor: None, | |
| 499 | patch: None, | |
| 500 | pre: Vec::new(), | |
| 501 | }, | |
| 502 | r.predicates[0] | |
| 503 | ); | |
| 504 | } | |
| 505 | ||
| 506 | #[test] | |
| 507 | fn test_parsing_patch_wildcard_star() { | |
| 508 | let r = range::parse("1.2.*").unwrap(); | |
| 509 | ||
| 510 | assert_eq!(Predicate { | |
| 511 | op: Op::Wildcard(WildcardVersion::Patch), | |
| 512 | major: 1, | |
| 513 | minor: Some(2), | |
| 514 | patch: None, | |
| 515 | pre: Vec::new(), | |
| 516 | }, | |
| 517 | r.predicates[0] | |
| 518 | ); | |
| 519 | } | |
| 520 | ||
| 521 | #[test] | |
| 522 | fn test_parsing_patch_wildcard_x() { | |
| 523 | let r = range::parse("1.2.x").unwrap(); | |
| 524 | ||
| 525 | assert_eq!(Predicate { | |
| 526 | op: Op::Wildcard(WildcardVersion::Patch), | |
| 527 | major: 1, | |
| 528 | minor: Some(2), | |
| 529 | patch: None, | |
| 530 | pre: Vec::new(), | |
| 531 | }, | |
| 532 | r.predicates[0] | |
| 533 | ); | |
| 534 | } | |
| 535 | ||
| 536 | #[test] | |
| 537 | fn test_parsing_patch_wildcard_capital_x() { | |
| 538 | let r = range::parse("1.2.X").unwrap(); | |
| 539 | ||
| 540 | assert_eq!(Predicate { | |
| 541 | op: Op::Wildcard(WildcardVersion::Patch), | |
| 542 | major: 1, | |
| 543 | minor: Some(2), | |
| 544 | patch: None, | |
| 545 | pre: Vec::new(), | |
| 546 | }, | |
| 547 | r.predicates[0] | |
| 548 | ); | |
| 549 | } | |
| 550 | ||
| 551 | #[test] | |
| 552 | pub fn test_multiple_01() { | |
| 553 | let r = range::parse("> 0.0.9, <= 2.5.3").unwrap(); | |
| 554 | ||
| 555 | assert_eq!(Predicate { | |
| 556 | op: Op::Gt, | |
| 557 | major: 0, | |
| 558 | minor: Some(0), | |
| 559 | patch: Some(9), | |
| 560 | pre: Vec::new(), | |
| 561 | }, | |
| 562 | r.predicates[0] | |
| 563 | ); | |
| 564 | ||
| 565 | assert_eq!(Predicate { | |
| 566 | op: Op::LtEq, | |
| 567 | major: 2, | |
| 568 | minor: Some(5), | |
| 569 | patch: Some(3), | |
| 570 | pre: Vec::new(), | |
| 571 | }, | |
| 572 | r.predicates[1] | |
| 573 | ); | |
| 574 | } | |
| 575 | ||
| 576 | #[test] | |
| 577 | pub fn test_multiple_02() { | |
| 578 | let r = range::parse("0.3.0, 0.4.0").unwrap(); | |
| 579 | ||
| 580 | assert_eq!(Predicate { | |
| 581 | op: Op::Compatible, | |
| 582 | major: 0, | |
| 583 | minor: Some(3), | |
| 584 | patch: Some(0), | |
| 585 | pre: Vec::new(), | |
| 586 | }, | |
| 587 | r.predicates[0] | |
| 588 | ); | |
| 589 | ||
| 590 | assert_eq!(Predicate { | |
| 591 | op: Op::Compatible, | |
| 592 | major: 0, | |
| 593 | minor: Some(4), | |
| 594 | patch: Some(0), | |
| 595 | pre: Vec::new(), | |
| 596 | }, | |
| 597 | r.predicates[1] | |
| 598 | ); | |
| 599 | } | |
| 600 | ||
| 601 | #[test] | |
| 602 | pub fn test_multiple_03() { | |
| 603 | let r = range::parse("<= 0.2.0, >= 0.5.0").unwrap(); | |
| 604 | ||
| 605 | assert_eq!(Predicate { | |
| 606 | op: Op::LtEq, | |
| 607 | major: 0, | |
| 608 | minor: Some(2), | |
| 609 | patch: Some(0), | |
| 610 | pre: Vec::new(), | |
| 611 | }, | |
| 612 | r.predicates[0] | |
| 613 | ); | |
| 614 | ||
| 615 | assert_eq!(Predicate { | |
| 616 | op: Op::GtEq, | |
| 617 | major: 0, | |
| 618 | minor: Some(5), | |
| 619 | patch: Some(0), | |
| 620 | pre: Vec::new(), | |
| 621 | }, | |
| 622 | r.predicates[1] | |
| 623 | ); | |
| 624 | } | |
| 625 | ||
| 626 | #[test] | |
| 627 | pub fn test_multiple_04() { | |
| 628 | let r = range::parse("0.1.0, 0.1.4, 0.1.6").unwrap(); | |
| 629 | ||
| 630 | assert_eq!(Predicate { | |
| 631 | op: Op::Compatible, | |
| 632 | major: 0, | |
| 633 | minor: Some(1), | |
| 634 | patch: Some(0), | |
| 635 | pre: Vec::new(), | |
| 636 | }, | |
| 637 | r.predicates[0] | |
| 638 | ); | |
| 639 | ||
| 640 | assert_eq!(Predicate { | |
| 641 | op: Op::Compatible, | |
| 642 | major: 0, | |
| 643 | minor: Some(1), | |
| 644 | patch: Some(4), | |
| 645 | pre: Vec::new(), | |
| 646 | }, | |
| 647 | r.predicates[1] | |
| 648 | ); | |
| 649 | ||
| 650 | assert_eq!(Predicate { | |
| 651 | op: Op::Compatible, | |
| 652 | major: 0, | |
| 653 | minor: Some(1), | |
| 654 | patch: Some(6), | |
| 655 | pre: Vec::new(), | |
| 656 | }, | |
| 657 | r.predicates[2] | |
| 658 | ); | |
| 659 | } | |
| 660 | ||
| 661 | #[test] | |
| 662 | pub fn test_multiple_05() { | |
| 663 | let r = range::parse(">=0.5.1-alpha3, <0.6").unwrap(); | |
| 664 | ||
| 665 | assert_eq!(Predicate { | |
| 666 | op: Op::GtEq, | |
| 667 | major: 0, | |
| 668 | minor: Some(5), | |
| 669 | patch: Some(1), | |
| 670 | pre: vec![Identifier::AlphaNumeric(String::from("alpha3"))], | |
| 671 | }, | |
| 672 | r.predicates[0] | |
| 673 | ); | |
| 674 | ||
| 675 | assert_eq!(Predicate { | |
| 676 | op: Op::Lt, | |
| 677 | major: 0, | |
| 678 | minor: Some(6), | |
| 679 | patch: None, | |
| 680 | pre: Vec::new(), | |
| 681 | }, | |
| 682 | r.predicates[1] | |
| 683 | ); | |
| 684 | } | |
| 685 | ||
| 686 | #[test] | |
| 687 | fn test_parse_build_metadata_with_predicate() { | |
| 688 | assert_eq!(range::parse("^1.2.3+meta").unwrap().predicates[0].op, | |
| 689 | Op::Compatible); | |
| 690 | assert_eq!(range::parse("~1.2.3+meta").unwrap().predicates[0].op, | |
| 691 | Op::Tilde); | |
| 692 | assert_eq!(range::parse("=1.2.3+meta").unwrap().predicates[0].op, | |
| 693 | Op::Ex); | |
| 694 | assert_eq!(range::parse("<=1.2.3+meta").unwrap().predicates[0].op, | |
| 695 | Op::LtEq); | |
| 696 | assert_eq!(range::parse(">=1.2.3+meta").unwrap().predicates[0].op, | |
| 697 | Op::GtEq); | |
| 698 | assert_eq!(range::parse("<1.2.3+meta").unwrap().predicates[0].op, | |
| 699 | Op::Lt); | |
| 700 | assert_eq!(range::parse(">1.2.3+meta").unwrap().predicates[0].op, | |
| 701 | Op::Gt); | |
| 702 | } | |
| 703 | ||
| 704 | #[test] | |
| 705 | pub fn test_parse_errors() { | |
| 706 | assert!(range::parse("\0").is_err()); | |
| 707 | assert!(range::parse(">= >= 0.0.2").is_err()); | |
| 708 | assert!(range::parse(">== 0.0.2").is_err()); | |
| 709 | assert!(range::parse("a.0.0").is_err()); | |
| 710 | assert!(range::parse("1.0.0-").is_err()); | |
| 711 | assert!(range::parse(">=").is_err()); | |
| 712 | assert!(range::parse("> 0.1.0,").is_err()); | |
| 713 | assert!(range::parse("> 0.3.0, ,").is_err()); | |
| 714 | } | |
| 715 | ||
| 716 | #[test] | |
| 717 | pub fn test_large_major_version() { | |
| 718 | assert!(range::parse("18446744073709551617.0.0").is_err()); | |
| 719 | } | |
| 720 | ||
| 721 | #[test] | |
| 722 | pub fn test_large_minor_version() { | |
| 723 | assert!(range::parse("0.18446744073709551617.0").is_err()); | |
| 724 | } | |
| 725 | ||
| 726 | #[test] | |
| 727 | pub fn test_large_patch_version() { | |
| 728 | assert!(range::parse("0.0.18446744073709551617").is_err()); | |
| 729 | } | |
| 730 | } |
| 104 | 104 | } |
| 105 | 105 | } |
| 106 | 106 | } |
| 107 | ||
| 108 | #[cfg(test)] | |
| 109 | mod tests { | |
| 110 | use version; | |
| 111 | use super::*; | |
| 112 | ||
| 113 | #[test] | |
| 114 | fn parse_empty() { | |
| 115 | let version = ""; | |
| 116 | ||
| 117 | let parsed = version::parse(version); | |
| 118 | ||
| 119 | assert!(parsed.is_err(), "empty string incorrectly considered a valid parse"); | |
| 120 | } | |
| 121 | ||
| 122 | #[test] | |
| 123 | fn parse_blank() { | |
| 124 | let version = " "; | |
| 125 | ||
| 126 | let parsed = version::parse(version); | |
| 127 | ||
| 128 | assert!(parsed.is_err(), "blank string incorrectly considered a valid parse"); | |
| 129 | } | |
| 130 | ||
| 131 | #[test] | |
| 132 | fn parse_no_minor_patch() { | |
| 133 | let version = "1"; | |
| 134 | ||
| 135 | let parsed = version::parse(version); | |
| 136 | ||
| 137 | assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); | |
| 138 | } | |
| 139 | ||
| 140 | #[test] | |
| 141 | fn parse_no_patch() { | |
| 142 | let version = "1.2"; | |
| 143 | ||
| 144 | let parsed = version::parse(version); | |
| 145 | ||
| 146 | assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); | |
| 147 | } | |
| 148 | ||
| 149 | #[test] | |
| 150 | fn parse_empty_pre() { | |
| 151 | let version = "1.2.3-"; | |
| 152 | ||
| 153 | let parsed = version::parse(version); | |
| 154 | ||
| 155 | assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); | |
| 156 | } | |
| 157 | ||
| 158 | #[test] | |
| 159 | fn parse_letters() { | |
| 160 | let version = "a.b.c"; | |
| 161 | ||
| 162 | let parsed = version::parse(version); | |
| 163 | ||
| 164 | assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); | |
| 165 | } | |
| 166 | ||
| 167 | #[test] | |
| 168 | fn parse_with_letters() { | |
| 169 | let version = "1.2.3 a.b.c"; | |
| 170 | ||
| 171 | let parsed = version::parse(version); | |
| 172 | ||
| 173 | assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); | |
| 174 | } | |
| 175 | ||
| 176 | #[test] | |
| 177 | fn parse_basic_version() { | |
| 178 | let version = "1.2.3"; | |
| 179 | ||
| 180 | let parsed = version::parse(version).unwrap(); | |
| 181 | ||
| 182 | assert_eq!(1, parsed.major); | |
| 183 | assert_eq!(2, parsed.minor); | |
| 184 | assert_eq!(3, parsed.patch); | |
| 185 | } | |
| 186 | ||
| 187 | #[test] | |
| 188 | fn parse_trims_input() { | |
| 189 | let version = " 1.2.3 "; | |
| 190 | ||
| 191 | let parsed = version::parse(version).unwrap(); | |
| 192 | ||
| 193 | assert_eq!(1, parsed.major); | |
| 194 | assert_eq!(2, parsed.minor); | |
| 195 | assert_eq!(3, parsed.patch); | |
| 196 | } | |
| 197 | ||
| 198 | #[test] | |
| 199 | fn parse_no_major_leading_zeroes() { | |
| 200 | let version = "01.0.0"; | |
| 201 | ||
| 202 | let parsed = version::parse(version); | |
| 203 | ||
| 204 | assert!(parsed.is_err(), "01 incorrectly considered a valid major version"); | |
| 205 | } | |
| 206 | ||
| 207 | #[test] | |
| 208 | fn parse_no_minor_leading_zeroes() { | |
| 209 | let version = "0.01.0"; | |
| 210 | ||
| 211 | let parsed = version::parse(version); | |
| 212 | ||
| 213 | assert!(parsed.is_err(), "01 incorrectly considered a valid minor version"); | |
| 214 | } | |
| 215 | ||
| 216 | #[test] | |
| 217 | fn parse_no_patch_leading_zeroes() { | |
| 218 | let version = "0.0.01"; | |
| 219 | ||
| 220 | let parsed = version::parse(version); | |
| 221 | ||
| 222 | assert!(parsed.is_err(), "01 incorrectly considered a valid patch version"); | |
| 223 | } | |
| 224 | ||
| 225 | #[test] | |
| 226 | fn parse_basic_prerelease() { | |
| 227 | let version = "1.2.3-pre"; | |
| 228 | ||
| 229 | let parsed = version::parse(version).unwrap(); | |
| 230 | ||
| 231 | let expected_pre = vec![Identifier::AlphaNumeric(String::from("pre"))]; | |
| 232 | assert_eq!(expected_pre, parsed.pre); | |
| 233 | } | |
| 234 | ||
| 235 | #[test] | |
| 236 | fn parse_prerelease_alphanumeric() { | |
| 237 | let version = "1.2.3-alpha1"; | |
| 238 | ||
| 239 | let parsed = version::parse(version).unwrap(); | |
| 240 | ||
| 241 | let expected_pre = vec![Identifier::AlphaNumeric(String::from("alpha1"))]; | |
| 242 | assert_eq!(expected_pre, parsed.pre); | |
| 243 | } | |
| 244 | ||
| 245 | #[test] | |
| 246 | fn parse_prerelease_zero() { | |
| 247 | let version = "1.2.3-pre.0"; | |
| 248 | ||
| 249 | let parsed = version::parse(version).unwrap(); | |
| 250 | ||
| 251 | let expected_pre = vec![Identifier::AlphaNumeric(String::from("pre")), | |
| 252 | Identifier::Numeric(0)]; | |
| 253 | assert_eq!(expected_pre, parsed.pre); | |
| 254 | } | |
| 255 | ||
| 256 | #[test] | |
| 257 | fn parse_basic_build() { | |
| 258 | let version = "1.2.3+build"; | |
| 259 | ||
| 260 | let parsed = version::parse(version).unwrap(); | |
| 261 | ||
| 262 | let expected_build = vec![Identifier::AlphaNumeric(String::from("build"))]; | |
| 263 | assert_eq!(expected_build, parsed.build); | |
| 264 | } | |
| 265 | ||
| 266 | #[test] | |
| 267 | fn parse_build_alphanumeric() { | |
| 268 | let version = "1.2.3+build5"; | |
| 269 | ||
| 270 | let parsed = version::parse(version).unwrap(); | |
| 271 | ||
| 272 | let expected_build = vec![Identifier::AlphaNumeric(String::from("build5"))]; | |
| 273 | assert_eq!(expected_build, parsed.build); | |
| 274 | } | |
| 275 | ||
| 276 | #[test] | |
| 277 | fn parse_pre_and_build() { | |
| 278 | let version = "1.2.3-alpha1+build5"; | |
| 279 | ||
| 280 | let parsed = version::parse(version).unwrap(); | |
| 281 | ||
| 282 | let expected_pre = vec![Identifier::AlphaNumeric(String::from("alpha1"))]; | |
| 283 | assert_eq!(expected_pre, parsed.pre); | |
| 284 | ||
| 285 | let expected_build = vec![Identifier::AlphaNumeric(String::from("build5"))]; | |
| 286 | assert_eq!(expected_build, parsed.build); | |
| 287 | } | |
| 288 | ||
| 289 | #[test] | |
| 290 | fn parse_complex_metadata_01() { | |
| 291 | let version = "1.2.3-1.alpha1.9+build5.7.3aedf "; | |
| 292 | ||
| 293 | let parsed = version::parse(version).unwrap(); | |
| 294 | ||
| 295 | let expected_pre = vec![Identifier::Numeric(1), | |
| 296 | Identifier::AlphaNumeric(String::from("alpha1")), | |
| 297 | Identifier::Numeric(9)]; | |
| 298 | assert_eq!(expected_pre, parsed.pre); | |
| 299 | ||
| 300 | let expected_build = vec![Identifier::AlphaNumeric(String::from("build5")), | |
| 301 | Identifier::Numeric(7), | |
| 302 | Identifier::AlphaNumeric(String::from("3aedf"))]; | |
| 303 | assert_eq!(expected_build, parsed.build); | |
| 304 | } | |
| 305 | ||
| 306 | #[test] | |
| 307 | fn parse_complex_metadata_02() { | |
| 308 | let version = "0.4.0-beta.1+0851523"; | |
| 309 | ||
| 310 | let parsed = version::parse(version).unwrap(); | |
| 311 | ||
| 312 | let expected_pre = vec![Identifier::AlphaNumeric(String::from("beta")), | |
| 313 | Identifier::Numeric(1)]; | |
| 314 | assert_eq!(expected_pre, parsed.pre); | |
| 315 | ||
| 316 | let expected_build = vec![Identifier::AlphaNumeric(String::from("0851523"))]; | |
| 317 | assert_eq!(expected_build, parsed.build); | |
| 318 | } | |
| 319 | ||
| 320 | #[test] | |
| 321 | fn parse_regression_01() { | |
| 322 | let version = "0.0.0-WIP"; | |
| 323 | ||
| 324 | let parsed = version::parse(version).unwrap(); | |
| 325 | ||
| 326 | assert_eq!(0, parsed.major); | |
| 327 | assert_eq!(0, parsed.minor); | |
| 328 | assert_eq!(0, parsed.patch); | |
| 329 | ||
| 330 | let expected_pre = vec![Identifier::AlphaNumeric(String::from("WIP"))]; | |
| 331 | assert_eq!(expected_pre, parsed.pre); | |
| 332 | } | |
| 333 | } |
| 104 | 104 | } |
| 105 | 105 | } |
| 106 | 106 | } |
| 107 | ||
| 108 | #[cfg(test)] | |
| 109 | mod tests { | |
| 110 | use super::*; | |
| 111 | ||
| 112 | #[test] | |
| 113 | fn parse_version_core_01() { | |
| 114 | let version = "1.2.3"; | |
| 115 | ||
| 116 | let parsed = parse_version(version); | |
| 117 | ||
| 118 | assert_eq!(1, parsed.major); | |
| 119 | assert_eq!(2, parsed.minor); | |
| 120 | assert_eq!(3, parsed.patch); | |
| 121 | } | |
| 122 | } |
| 110 | 110 | use super::*; |
| 111 | 111 | |
| 112 | 112 | #[test] |
| 113 | fn parse_version_core_01() { | |
| 113 | fn parse_version_core() { | |
| 114 | 114 | let version = "1.2.3"; |
| 115 | 115 | |
| 116 | let parsed = parse_version(version); | |
| 116 | let parsed = parse_version(version).unwrap(); | |
| 117 | 117 | |
| 118 | 118 | assert_eq!(1, parsed.major); |
| 119 | 119 | assert_eq!(2, parsed.minor); |
| 120 | 120 | assert_eq!(3, parsed.patch); |
| 121 | 121 | } |
| 122 | ||
| 123 | #[test] | |
| 124 | fn parse_version_no_major_leading_zeroes() { | |
| 125 | let version = "01.0.0"; | |
| 126 | ||
| 127 | let parsed = parse_version(version); | |
| 128 | ||
| 129 | assert!(parsed.is_err(), "01 incorrectly considered a valid major version"); | |
| 130 | } | |
| 131 | ||
| 132 | #[test] | |
| 133 | fn parse_version_no_minor_leading_zeroes() { | |
| 134 | let version = "0.01.0"; | |
| 135 | ||
| 136 | let parsed = parse_version(version); | |
| 137 | ||
| 138 | assert!(parsed.is_err(), "01 incorrectly considered a valid minor version"); | |
| 139 | } | |
| 140 | ||
| 141 | #[test] | |
| 142 | fn parse_version_no_patch_leading_zeroes() { | |
| 143 | let version = "0.0.01"; | |
| 144 | ||
| 145 | let parsed = parse_version(version); | |
| 146 | ||
| 147 | assert!(parsed.is_err(), "01 incorrectly considered a valid patch version"); | |
| 148 | } | |
| 122 | 149 | } |
| 146 | 146 | |
| 147 | 147 | assert!(parsed.is_err(), "01 incorrectly considered a valid patch version"); |
| 148 | 148 | } |
| 149 | ||
| 150 | #[test] | |
| 151 | fn parse_version_basic_prerelease() { | |
| 152 | let version = "1.2.3-pre"; | |
| 153 | ||
| 154 | let parsed = parse_version(version).unwrap(); | |
| 155 | ||
| 156 | assert_eq!(Some(String::from("pre")), parsed.pre); | |
| 157 | } | |
| 149 | 158 | } |
| 110 | 110 | use super::*; |
| 111 | 111 | |
| 112 | 112 | #[test] |
| 113 | fn parse_version_core() { | |
| 113 | fn parse_empty() { | |
| 114 | let version = ""; | |
| 115 | ||
| 116 | let parsed = parse_version(version); | |
| 117 | ||
| 118 | assert!(parsed.is_err(), "empty string incorrectly considered a valid parse"); | |
| 119 | } | |
| 120 | ||
| 121 | #[test] | |
| 122 | fn parse_blank() { | |
| 123 | let version = " "; | |
| 124 | ||
| 125 | let parsed = parse_version(version); | |
| 126 | ||
| 127 | assert!(parsed.is_err(), "blank string incorrectly considered a valid parse"); | |
| 128 | } | |
| 129 | ||
| 130 | #[test] | |
| 131 | fn parse_no_minor_patch() { | |
| 132 | let version = "1"; | |
| 133 | ||
| 134 | let parsed = parse_version(version); | |
| 135 | ||
| 136 | assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); | |
| 137 | } | |
| 138 | ||
| 139 | #[test] | |
| 140 | fn parse_no_patch() { | |
| 141 | let version = "1.2"; | |
| 142 | ||
| 143 | let parsed = parse_version(version); | |
| 144 | ||
| 145 | assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); | |
| 146 | } | |
| 147 | ||
| 148 | #[test] | |
| 149 | fn parse_empty_pre() { | |
| 150 | let version = "1.2.3-"; | |
| 151 | ||
| 152 | let parsed = parse_version(version); | |
| 153 | ||
| 154 | assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); | |
| 155 | } | |
| 156 | ||
| 157 | #[test] | |
| 158 | fn parse_letters() { | |
| 159 | let version = "a.b.c"; | |
| 160 | ||
| 161 | let parsed = parse_version(version); | |
| 162 | ||
| 163 | assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); | |
| 164 | } | |
| 165 | ||
| 166 | #[test] | |
| 167 | fn parse_version_with_letters() { | |
| 168 | let version = "1.2.3 a.b.c"; | |
| 169 | ||
| 170 | let parsed = parse_version(version); | |
| 171 | ||
| 172 | assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); | |
| 173 | } | |
| 174 | ||
| 175 | #[test] | |
| 176 | fn parse_basic_version() { | |
| 114 | 177 | let version = "1.2.3"; |
| 115 | 178 | |
| 116 | 179 | let parsed = parse_version(version).unwrap(); |
⋮
| 121 | 184 | } |
| 122 | 185 | |
| 123 | 186 | #[test] |
| 187 | fn parse_trims_input() { | |
| 188 | let version = " 1.2.3 "; | |
| 189 | ||
| 190 | let parsed = parse_version(version).unwrap(); | |
| 191 | ||
| 192 | assert_eq!(1, parsed.major); | |
| 193 | assert_eq!(2, parsed.minor); | |
| 194 | assert_eq!(3, parsed.patch); | |
| 195 | } | |
| 196 | ||
| 197 | #[test] | |
| 124 | 198 | fn parse_version_no_major_leading_zeroes() { |
| 125 | 199 | let version = "01.0.0"; |
| 126 | 200 |
⋮
| 153 | 227 | |
| 154 | 228 | let parsed = parse_version(version).unwrap(); |
| 155 | 229 | |
| 156 | assert_eq!(Some(String::from("pre")), parsed.pre); | |
| 230 | let expected_pre = Some(vec![String::from("pre")]); | |
| 231 | assert_eq!(expected_pre, parsed.pre); | |
| 232 | } | |
| 233 | ||
| 234 | #[test] | |
| 235 | fn parse_version_prerelease_alphanumeric() { | |
| 236 | let version = "1.2.3-alpha1"; | |
| 237 | ||
| 238 | let parsed = parse_version(version).unwrap(); | |
| 239 | ||
| 240 | let expected_pre = Some(vec![String::from("alpha1")]); | |
| 241 | assert_eq!(expected_pre, parsed.pre); | |
| 242 | } | |
| 243 | ||
| 244 | #[test] | |
| 245 | fn parse_version_basic_build() { | |
| 246 | let version = "1.2.3+build"; | |
| 247 | ||
| 248 | let parsed = parse_version(version).unwrap(); | |
| 249 | ||
| 250 | let expected_build = Some(vec![String::from("build")]); | |
| 251 | assert_eq!(expected_build, parsed.build); | |
| 252 | } | |
| 253 | ||
| 254 | #[test] | |
| 255 | fn parse_version_build_alphanumeric() { | |
| 256 | let version = "1.2.3+build5"; | |
| 257 | ||
| 258 | let parsed = parse_version(version).unwrap(); | |
| 259 | ||
| 260 | let expected_build = Some(vec![String::from("build5")]); | |
| 261 | assert_eq!(expected_build, parsed.build); | |
| 262 | } | |
| 263 | ||
| 264 | #[test] | |
| 265 | fn parse_version_pre_and_build() { | |
| 266 | let version = "1.2.3-alpha1+build5"; | |
| 267 | ||
| 268 | let parsed = parse_version(version).unwrap(); | |
| 269 | ||
| 270 | let expected_pre = Some(vec![String::from("alpha1")]); | |
| 271 | assert_eq!(expected_pre, parsed.pre); | |
| 272 | ||
| 273 | let expected_build = Some(vec![String::from("build5")]); | |
| 274 | assert_eq!(expected_build, parsed.build); | |
| 275 | } | |
| 276 | ||
| 277 | #[test] | |
| 278 | fn parse_version_complex_metadata_01() { | |
| 279 | let version = "1.2.3-1.alpha1.9+build5.7.3aedf "; | |
| 280 | ||
| 281 | let parsed = parse_version(version).unwrap(); | |
| 282 | ||
| 283 | let expected_pre = Some(vec![String::from("1.alpha1.9")]); | |
| 284 | assert_eq!(expected_pre, parsed.pre); | |
| 285 | ||
| 286 | let expected_build = Some(vec![String::from("build5.7.3aedf")]); | |
| 287 | assert_eq!(expected_build, parsed.build); | |
| 288 | } | |
| 289 | ||
| 290 | #[test] | |
| 291 | fn parse_version_complex_metadata_02() { | |
| 292 | let version = "0.4.0-beta.1+0851523"; | |
| 293 | ||
| 294 | let parsed = parse_version(version).unwrap(); | |
| 295 | ||
| 296 | let expected_pre = Some(vec![String::from("beta.1")]); | |
| 297 | assert_eq!(expected_pre, parsed.pre); | |
| 298 | ||
| 299 | let expected_build = Some(vec![String::from("0851523")]); | |
| 300 | assert_eq!(expected_build, parsed.build); | |
| 157 | 301 | } |
| 158 | 302 | } |
| 227 | 227 | |
| 228 | 228 | let parsed = parse_version(version).unwrap(); |
| 229 | 229 | |
| 230 | let expected_pre = Some(vec![String::from("pre")]); | |
| 230 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("pre"))]); | |
| 231 | 231 | assert_eq!(expected_pre, parsed.pre); |
| 232 | 232 | } |
| 233 | 233 |
⋮
| 237 | 237 | |
| 238 | 238 | let parsed = parse_version(version).unwrap(); |
| 239 | 239 | |
| 240 | let expected_pre = Some(vec![String::from("alpha1")]); | |
| 240 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("alpha1"))]); | |
| 241 | 241 | assert_eq!(expected_pre, parsed.pre); |
| 242 | 242 | } |
| 243 | 243 |
⋮
| 247 | 247 | |
| 248 | 248 | let parsed = parse_version(version).unwrap(); |
| 249 | 249 | |
| 250 | let expected_build = Some(vec![String::from("build")]); | |
| 250 | let expected_build = Some(vec![Identifier::AlphaNumeric(String::from("build"))]); | |
| 251 | 251 | assert_eq!(expected_build, parsed.build); |
| 252 | 252 | } |
| 253 | 253 |
⋮
| 257 | 257 | |
| 258 | 258 | let parsed = parse_version(version).unwrap(); |
| 259 | 259 | |
| 260 | let expected_build = Some(vec![String::from("build5")]); | |
| 260 | let expected_build = Some(vec![Identifier::AlphaNumeric(String::from("build5"))]); | |
| 261 | 261 | assert_eq!(expected_build, parsed.build); |
| 262 | 262 | } |
| 263 | 263 |
⋮
| 267 | 267 | |
| 268 | 268 | let parsed = parse_version(version).unwrap(); |
| 269 | 269 | |
| 270 | let expected_pre = Some(vec![String::from("alpha1")]); | |
| 270 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("alpha1"))]); | |
| 271 | 271 | assert_eq!(expected_pre, parsed.pre); |
| 272 | 272 | |
| 273 | let expected_build = Some(vec![String::from("build5")]); | |
| 273 | let expected_build = Some(vec![Identifier::AlphaNumeric(String::from("build5"))]); | |
| 274 | 274 | assert_eq!(expected_build, parsed.build); |
| 275 | 275 | } |
| 276 | 276 |
⋮
| 280 | 280 | |
| 281 | 281 | let parsed = parse_version(version).unwrap(); |
| 282 | 282 | |
| 283 | let expected_pre = Some(vec![String::from("1.alpha1.9")]); | |
| 283 | let expected_pre = Some(vec![Identifier::Numeric(1), | |
| 284 | Identifier::AlphaNumeric(String::from("alpha1")), | |
| 285 | Identifier::Numeric(9)]); | |
| 284 | 286 | assert_eq!(expected_pre, parsed.pre); |
| 285 | 287 | |
| 286 | let expected_build = Some(vec![String::from("build5.7.3aedf")]); | |
| 288 | let expected_build = Some(vec![Identifier::AlphaNumeric(String::from("build5")), | |
| 289 | Identifier::Numeric(7), | |
| 290 | Identifier::AlphaNumeric(String::from("3aedf"))]); | |
| 287 | 291 | assert_eq!(expected_build, parsed.build); |
| 288 | 292 | } |
| 289 | 293 |
⋮
| 293 | 297 | |
| 294 | 298 | let parsed = parse_version(version).unwrap(); |
| 295 | 299 | |
| 296 | let expected_pre = Some(vec![String::from("beta.1")]); | |
| 300 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("beta")), | |
| 301 | Identifier::Numeric(1)]); | |
| 297 | 302 | assert_eq!(expected_pre, parsed.pre); |
| 298 | 303 | |
| 299 | let expected_build = Some(vec![String::from("0851523")]); | |
| 304 | let expected_build = Some(vec![Identifier::AlphaNumeric(String::from("0851523"))]); | |
| 300 | 305 | assert_eq!(expected_build, parsed.build); |
| 301 | 306 | } |
| 302 | 307 | } |
| 242 | 242 | } |
| 243 | 243 | |
| 244 | 244 | #[test] |
| 245 | fn parse_version_prerelease_zero() { | |
| 246 | let version = "1.2.3-pre.0"; | |
| 247 | ||
| 248 | let parsed = parse_version(version).unwrap(); | |
| 249 | ||
| 250 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("pre")), | |
| 251 | Identifier::Numeric(0)]); | |
| 252 | assert_eq!(expected_pre, parsed.pre); | |
| 253 | } | |
| 254 | ||
| 255 | #[test] | |
| 245 | 256 | fn parse_version_basic_build() { |
| 246 | 257 | let version = "1.2.3+build"; |
| 247 | 258 |
| 315 | 315 | let expected_build = Some(vec![Identifier::AlphaNumeric(String::from("0851523"))]); |
| 316 | 316 | assert_eq!(expected_build, parsed.build); |
| 317 | 317 | } |
| 318 | ||
| 319 | #[test] | |
| 320 | fn parse_regression_01() { | |
| 321 | let version = "0.0.0-WIP"; | |
| 322 | ||
| 323 | let parsed = parse_version(version).unwrap(); | |
| 324 | ||
| 325 | assert_eq!(0, parsed.major); | |
| 326 | assert_eq!(0, parsed.minor); | |
| 327 | assert_eq!(0, parsed.patch); | |
| 328 | ||
| 329 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("WIP"))]); | |
| 330 | assert_eq!(expected_pre, parsed.pre); | |
| 331 | } | |
| 318 | 332 | } |
| 225 | 225 | pre: pre, |
| 226 | 226 | }) |
| 227 | 227 | } |
| 228 | ||
| 229 | #[cfg(test)] | |
| 230 | mod tests { | |
| 231 | use super::*; | |
| 232 | use range; | |
| 233 | use version::Identifier; | |
| 234 | ||
| 235 | #[test] | |
| 236 | fn test_parsing_default() { | |
| 237 | let r = range::parse("1.0.0").unwrap(); | |
| 238 | ||
| 239 | assert_eq!(Predicate { | |
| 240 | op: Op::Compatible, | |
| 241 | major: 1, | |
| 242 | minor: Some(0), | |
| 243 | patch: Some(0), | |
| 244 | pre: Vec::new(), | |
| 245 | }, | |
| 246 | r.predicates[0] | |
| 247 | ); | |
| 248 | } | |
| 249 | ||
| 250 | #[test] | |
| 251 | fn test_parsing_exact_01() { | |
| 252 | let r = range::parse("=1.0.0").unwrap(); | |
| 253 | ||
| 254 | assert_eq!(Predicate { | |
| 255 | op: Op::Ex, | |
| 256 | major: 1, | |
| 257 | minor: Some(0), | |
| 258 | patch: Some(0), | |
| 259 | pre: Vec::new(), | |
| 260 | }, | |
| 261 | r.predicates[0] | |
| 262 | ); | |
| 263 | } | |
| 264 | ||
| 265 | #[test] | |
| 266 | fn test_parsing_exact_02() { | |
| 267 | let r = range::parse("=0.9.0").unwrap(); | |
| 268 | ||
| 269 | assert_eq!(Predicate { | |
| 270 | op: Op::Ex, | |
| 271 | major: 0, | |
| 272 | minor: Some(9), | |
| 273 | patch: Some(0), | |
| 274 | pre: Vec::new(), | |
| 275 | }, | |
| 276 | r.predicates[0] | |
| 277 | ); | |
| 278 | } | |
| 279 | ||
| 280 | #[test] | |
| 281 | fn test_parsing_exact_03() { | |
| 282 | let r = range::parse("=0.1.0-beta2.a").unwrap(); | |
| 283 | ||
| 284 | assert_eq!(Predicate { | |
| 285 | op: Op::Ex, | |
| 286 | major: 0, | |
| 287 | minor: Some(1), | |
| 288 | patch: Some(0), | |
| 289 | pre: vec![Identifier::AlphaNumeric(String::from("beta2")), | |
| 290 | Identifier::AlphaNumeric(String::from("a"))], | |
| 291 | }, | |
| 292 | r.predicates[0] | |
| 293 | ); | |
| 294 | } | |
| 295 | ||
| 296 | #[test] | |
| 297 | pub fn test_parsing_greater_than() { | |
| 298 | let r = range::parse("> 1.0.0").unwrap(); | |
| 299 | ||
| 300 | assert_eq!(Predicate { | |
| 301 | op: Op::Gt, | |
| 302 | major: 1, | |
| 303 | minor: Some(0), | |
| 304 | patch: Some(0), | |
| 305 | pre: Vec::new(), | |
| 306 | }, | |
| 307 | r.predicates[0] | |
| 308 | ); | |
| 309 | } | |
| 310 | ||
| 311 | #[test] | |
| 312 | pub fn test_parsing_greater_than_01() { | |
| 313 | let r = range::parse(">= 1.0.0").unwrap(); | |
| 314 | ||
| 315 | assert_eq!(Predicate { | |
| 316 | op: Op::GtEq, | |
| 317 | major: 1, | |
| 318 | minor: Some(0), | |
| 319 | patch: Some(0), | |
| 320 | pre: Vec::new(), | |
| 321 | }, | |
| 322 | r.predicates[0] | |
| 323 | ); | |
| 324 | } | |
| 325 | ||
| 326 | #[test] | |
| 327 | pub fn test_parsing_greater_than_02() { | |
| 328 | let r = range::parse(">= 2.1.0-alpha2").unwrap(); | |
| 329 | ||
| 330 | assert_eq!(Predicate { | |
| 331 | op: Op::GtEq, | |
| 332 | major: 2, | |
| 333 | minor: Some(1), | |
| 334 | patch: Some(0), | |
| 335 | pre: vec![Identifier::AlphaNumeric(String::from("alpha2"))], | |
| 336 | }, | |
| 337 | r.predicates[0] | |
| 338 | ); | |
| 339 | } | |
| 340 | ||
| 341 | #[test] | |
| 342 | pub fn test_parsing_less_than() { | |
| 343 | let r = range::parse("< 1.0.0").unwrap(); | |
| 344 | ||
| 345 | assert_eq!(Predicate { | |
| 346 | op: Op::Lt, | |
| 347 | major: 1, | |
| 348 | minor: Some(0), | |
| 349 | patch: Some(0), | |
| 350 | pre: Vec::new(), | |
| 351 | }, | |
| 352 | r.predicates[0] | |
| 353 | ); | |
| 354 | } | |
| 355 | ||
| 356 | #[test] | |
| 357 | pub fn test_parsing_less_than_eq() { | |
| 358 | let r = range::parse("<= 2.1.0-alpha2").unwrap(); | |
| 359 | ||
| 360 | assert_eq!(Predicate { | |
| 361 | op: Op::LtEq, | |
| 362 | major: 2, | |
| 363 | minor: Some(1), | |
| 364 | patch: Some(0), | |
| 365 | pre: vec![Identifier::AlphaNumeric(String::from("alpha2"))], | |
| 366 | }, | |
| 367 | r.predicates[0] | |
| 368 | ); | |
| 369 | } | |
| 370 | ||
| 371 | #[test] | |
| 372 | pub fn test_parsing_tilde() { | |
| 373 | let r = range::parse("~1").unwrap(); | |
| 374 | ||
| 375 | assert_eq!(Predicate { | |
| 376 | op: Op::Tilde, | |
| 377 | major: 1, | |
| 378 | minor: None, | |
| 379 | patch: None, | |
| 380 | pre: Vec::new(), | |
| 381 | }, | |
| 382 | r.predicates[0] | |
| 383 | ); | |
| 384 | } | |
| 385 | ||
| 386 | #[test] | |
| 387 | pub fn test_parsing_compatible() { | |
| 388 | let r = range::parse("^0").unwrap(); | |
| 389 | ||
| 390 | assert_eq!(Predicate { | |
| 391 | op: Op::Compatible, | |
| 392 | major: 0, | |
| 393 | minor: None, | |
| 394 | patch: None, | |
| 395 | pre: Vec::new(), | |
| 396 | }, | |
| 397 | r.predicates[0] | |
| 398 | ); | |
| 399 | } | |
| 400 | ||
| 401 | #[test] | |
| 402 | fn test_parsing_blank() { | |
| 403 | let r = range::parse("").unwrap(); | |
| 404 | ||
| 405 | assert_eq!(Predicate { | |
| 406 | op: Op::Wildcard(WildcardVersion::Major), | |
| 407 | major: 0, | |
| 408 | minor: None, | |
| 409 | patch: None, | |
| 410 | pre: Vec::new(), | |
| 411 | }, | |
| 412 | r.predicates[0] | |
| 413 | ); | |
| 414 | } | |
| 415 | ||
| 416 | #[test] | |
| 417 | fn test_parsing_wildcard() { | |
| 418 | let r = range::parse("*").unwrap(); | |
| 419 | ||
| 420 | assert_eq!(Predicate { | |
| 421 | op: Op::Wildcard(WildcardVersion::Major), | |
| 422 | major: 0, | |
| 423 | minor: None, | |
| 424 | patch: None, | |
| 425 | pre: Vec::new(), | |
| 426 | }, | |
| 427 | r.predicates[0] | |
| 428 | ); | |
| 429 | } | |
| 430 | ||
| 431 | #[test] | |
| 432 | fn test_parsing_x() { | |
| 433 | let r = range::parse("x").unwrap(); | |
| 434 | ||
| 435 | assert_eq!(Predicate { | |
| 436 | op: Op::Wildcard(WildcardVersion::Major), | |
| 437 | major: 0, | |
| 438 | minor: None, | |
| 439 | patch: None, | |
| 440 | pre: Vec::new(), | |
| 441 | }, | |
| 442 | r.predicates[0] | |
| 443 | ); | |
| 444 | } | |
| 445 | ||
| 446 | #[test] | |
| 447 | fn test_parsing_capital_x() { | |
| 448 | let r = range::parse("X").unwrap(); | |
| 449 | ||
| 450 | assert_eq!(Predicate { | |
| 451 | op: Op::Wildcard(WildcardVersion::Major), | |
| 452 | major: 0, | |
| 453 | minor: None, | |
| 454 | patch: None, | |
| 455 | pre: Vec::new(), | |
| 456 | }, | |
| 457 | r.predicates[0] | |
| 458 | ); | |
| 459 | } | |
| 460 | ||
| 461 | #[test] | |
| 462 | fn test_parsing_minor_wildcard_star() { | |
| 463 | let r = range::parse("1.*").unwrap(); | |
| 464 | ||
| 465 | assert_eq!(Predicate { | |
| 466 | op: Op::Wildcard(WildcardVersion::Minor), | |
| 467 | major: 1, | |
| 468 | minor: None, | |
| 469 | patch: None, | |
| 470 | pre: Vec::new(), | |
| 471 | }, | |
| 472 | r.predicates[0] | |
| 473 | ); | |
| 474 | } | |
| 475 | ||
| 476 | #[test] | |
| 477 | fn test_parsing_minor_wildcard_x() { | |
| 478 | let r = range::parse("1.x").unwrap(); | |
| 479 | ||
| 480 | assert_eq!(Predicate { | |
| 481 | op: Op::Wildcard(WildcardVersion::Minor), | |
| 482 | major: 1, | |
| 483 | minor: None, | |
| 484 | patch: None, | |
| 485 | pre: Vec::new(), | |
| 486 | }, | |
| 487 | r.predicates[0] | |
| 488 | ); | |
| 489 | } | |
| 490 | ||
| 491 | #[test] | |
| 492 | fn test_parsing_minor_wildcard_capital_x() { | |
| 493 | let r = range::parse("1.X").unwrap(); | |
| 494 | ||
| 495 | assert_eq!(Predicate { | |
| 496 | op: Op::Wildcard(WildcardVersion::Minor), | |
| 497 | major: 1, | |
| 498 | minor: None, | |
| 499 | patch: None, | |
| 500 | pre: Vec::new(), | |
| 501 | }, | |
| 502 | r.predicates[0] | |
| 503 | ); | |
| 504 | } | |
| 505 | ||
| 506 | #[test] | |
| 507 | fn test_parsing_patch_wildcard_star() { | |
| 508 | let r = range::parse("1.2.*").unwrap(); | |
| 509 | ||
| 510 | assert_eq!(Predicate { | |
| 511 | op: Op::Wildcard(WildcardVersion::Patch), | |
| 512 | major: 1, | |
| 513 | minor: Some(2), | |
| 514 | patch: None, | |
| 515 | pre: Vec::new(), | |
| 516 | }, | |
| 517 | r.predicates[0] | |
| 518 | ); | |
| 519 | } | |
| 520 | ||
| 521 | #[test] | |
| 522 | fn test_parsing_patch_wildcard_x() { | |
| 523 | let r = range::parse("1.2.x").unwrap(); | |
| 524 | ||
| 525 | assert_eq!(Predicate { | |
| 526 | op: Op::Wildcard(WildcardVersion::Patch), | |
| 527 | major: 1, | |
| 528 | minor: Some(2), | |
| 529 | patch: None, | |
| 530 | pre: Vec::new(), | |
| 531 | }, | |
| 532 | r.predicates[0] | |
| 533 | ); | |
| 534 | } | |
| 535 | ||
| 536 | #[test] | |
| 537 | fn test_parsing_patch_wildcard_capital_x() { | |
| 538 | let r = range::parse("1.2.X").unwrap(); | |
| 539 | ||
| 540 | assert_eq!(Predicate { | |
| 541 | op: Op::Wildcard(WildcardVersion::Patch), | |
| 542 | major: 1, | |
| 543 | minor: Some(2), | |
| 544 | patch: None, | |
| 545 | pre: Vec::new(), | |
| 546 | }, | |
| 547 | r.predicates[0] | |
| 548 | ); | |
| 549 | } | |
| 550 | ||
| 551 | // #[test] | |
| 552 | // pub fn test_multiple() { | |
| 553 | // let r = req("> 0.0.9, <= 2.5.3"); | |
| 554 | // assert_eq!(r.to_string(), "> 0.0.9, <= 2.5.3".to_string()); | |
| 555 | // assert_match(&r, &["0.0.10", "1.0.0", "2.5.3"]); | |
| 556 | // assert_not_match(&r, &["0.0.8", "2.5.4"]); | |
| 557 | // | |
| 558 | // let r = req("0.3.0, 0.4.0"); | |
| 559 | // assert_eq!(r.to_string(), "^0.3.0, ^0.4.0".to_string()); | |
| 560 | // assert_not_match(&r, &["0.0.8", "0.3.0", "0.4.0"]); | |
| 561 | // | |
| 562 | // let r = req("<= 0.2.0, >= 0.5.0"); | |
| 563 | // assert_eq!(r.to_string(), "<= 0.2.0, >= 0.5.0".to_string()); | |
| 564 | // assert_not_match(&r, &["0.0.8", "0.3.0", "0.5.1"]); | |
| 565 | // | |
| 566 | // let r = req("0.1.0, 0.1.4, 0.1.6"); | |
| 567 | // assert_eq!(r.to_string(), "^0.1.0, ^0.1.4, ^0.1.6".to_string()); | |
| 568 | // assert_match(&r, &["0.1.6", "0.1.9"]); | |
| 569 | // assert_not_match(&r, &["0.1.0", "0.1.4", "0.2.0"]); | |
| 570 | // | |
| 571 | // assert!(VersionReq::parse("> 0.1.0,").is_err()); | |
| 572 | // assert!(VersionReq::parse("> 0.3.0, ,").is_err()); | |
| 573 | // | |
| 574 | // let r = req(">=0.5.1-alpha3, <0.6"); | |
| 575 | // assert_eq!(r.to_string(), ">= 0.5.1-alpha3, < 0.6".to_string()); | |
| 576 | // assert_match(&r, | |
| 577 | // &["0.5.1-alpha3", "0.5.1-alpha4", "0.5.1-beta", "0.5.1", "0.5.5"]); | |
| 578 | // assert_not_match(&r, | |
| 579 | // &["0.5.1-alpha1", "0.5.2-alpha3", "0.5.5-pre", "0.5.0-pre"]); | |
| 580 | // assert_not_match(&r, &["0.6.0", "0.6.0-pre"]); | |
| 581 | // } | |
| 582 | ||
| 583 | #[test] | |
| 584 | pub fn test_parse_errors() { | |
| 585 | assert!(range::parse("\0").is_err()); | |
| 586 | assert!(range::parse(">= >= 0.0.2").is_err()); | |
| 587 | assert!(range::parse(">== 0.0.2").is_err()); | |
| 588 | assert!(range::parse("a.0.0").is_err()); | |
| 589 | assert!(range::parse("1.0.0-").is_err()); | |
| 590 | assert!(range::parse(">=").is_err()); | |
| 591 | } | |
| 592 | ||
| 593 | } |
| 107 | 107 | |
| 108 | 108 | #[cfg(test)] |
| 109 | 109 | mod tests { |
| 110 | use version; | |
| 110 | 111 | use super::*; |
| 111 | 112 | |
| 112 | 113 | #[test] |
| 113 | 114 | fn parse_empty() { |
| 114 | 115 | let version = ""; |
| 115 | 116 | |
| 116 | let parsed = parse_version(version); | |
| 117 | let parsed = version::parse(version); | |
| 117 | 118 | |
| 118 | 119 | assert!(parsed.is_err(), "empty string incorrectly considered a valid parse"); |
| 119 | 120 | } |
⋮
| 122 | 123 | fn parse_blank() { |
| 123 | 124 | let version = " "; |
| 124 | 125 | |
| 125 | let parsed = parse_version(version); | |
| 126 | let parsed = version::parse(version); | |
| 126 | 127 | |
| 127 | 128 | assert!(parsed.is_err(), "blank string incorrectly considered a valid parse"); |
| 128 | 129 | } |
⋮
| 131 | 132 | fn parse_no_minor_patch() { |
| 132 | 133 | let version = "1"; |
| 133 | 134 | |
| 134 | let parsed = parse_version(version); | |
| 135 | let parsed = version::parse(version); | |
| 135 | 136 | |
| 136 | 137 | assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); |
| 137 | 138 | } |
⋮
| 140 | 141 | fn parse_no_patch() { |
| 141 | 142 | let version = "1.2"; |
| 142 | 143 | |
| 143 | let parsed = parse_version(version); | |
| 144 | let parsed = version::parse(version); | |
| 144 | 145 | |
| 145 | 146 | assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); |
| 146 | 147 | } |
⋮
| 149 | 150 | fn parse_empty_pre() { |
| 150 | 151 | let version = "1.2.3-"; |
| 151 | 152 | |
| 152 | let parsed = parse_version(version); | |
| 153 | let parsed = version::parse(version); | |
| 153 | 154 | |
| 154 | 155 | assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); |
| 155 | 156 | } |
⋮
| 158 | 159 | fn parse_letters() { |
| 159 | 160 | let version = "a.b.c"; |
| 160 | 161 | |
| 161 | let parsed = parse_version(version); | |
| 162 | let parsed = version::parse(version); | |
| 162 | 163 | |
| 163 | 164 | assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); |
| 164 | 165 | } |
| 165 | 166 | |
| 166 | 167 | #[test] |
| 167 | fn parse_version_with_letters() { | |
| 168 | fn parse_with_letters() { | |
| 168 | 169 | let version = "1.2.3 a.b.c"; |
| 169 | 170 | |
| 170 | let parsed = parse_version(version); | |
| 171 | let parsed = version::parse(version); | |
| 171 | 172 | |
| 172 | 173 | assert!(parsed.is_err(), format!("'{}' incorrectly considered a valid parse", version)); |
| 173 | 174 | } |
⋮
| 176 | 177 | fn parse_basic_version() { |
| 177 | 178 | let version = "1.2.3"; |
| 178 | 179 | |
| 179 | let parsed = parse_version(version).unwrap(); | |
| 180 | let parsed = version::parse(version).unwrap(); | |
| 180 | 181 | |
| 181 | 182 | assert_eq!(1, parsed.major); |
| 182 | 183 | assert_eq!(2, parsed.minor); |
⋮
| 187 | 188 | fn parse_trims_input() { |
| 188 | 189 | let version = " 1.2.3 "; |
| 189 | 190 | |
| 190 | let parsed = parse_version(version).unwrap(); | |
| 191 | let parsed = version::parse(version).unwrap(); | |
| 191 | 192 | |
| 192 | 193 | assert_eq!(1, parsed.major); |
| 193 | 194 | assert_eq!(2, parsed.minor); |
⋮
| 195 | 196 | } |
| 196 | 197 | |
| 197 | 198 | #[test] |
| 198 | fn parse_version_no_major_leading_zeroes() { | |
| 199 | fn parse_no_major_leading_zeroes() { | |
| 199 | 200 | let version = "01.0.0"; |
| 200 | 201 | |
| 201 | let parsed = parse_version(version); | |
| 202 | let parsed = version::parse(version); | |
| 202 | 203 | |
| 203 | 204 | assert!(parsed.is_err(), "01 incorrectly considered a valid major version"); |
| 204 | 205 | } |
| 205 | 206 | |
| 206 | 207 | #[test] |
| 207 | fn parse_version_no_minor_leading_zeroes() { | |
| 208 | fn parse_no_minor_leading_zeroes() { | |
| 208 | 209 | let version = "0.01.0"; |
| 209 | 210 | |
| 210 | let parsed = parse_version(version); | |
| 211 | let parsed = version::parse(version); | |
| 211 | 212 | |
| 212 | 213 | assert!(parsed.is_err(), "01 incorrectly considered a valid minor version"); |
| 213 | 214 | } |
| 214 | 215 | |
| 215 | 216 | #[test] |
| 216 | fn parse_version_no_patch_leading_zeroes() { | |
| 217 | fn parse_no_patch_leading_zeroes() { | |
| 217 | 218 | let version = "0.0.01"; |
| 218 | 219 | |
| 219 | let parsed = parse_version(version); | |
| 220 | let parsed = version::parse(version); | |
| 220 | 221 | |
| 221 | 222 | assert!(parsed.is_err(), "01 incorrectly considered a valid patch version"); |
| 222 | 223 | } |
| 223 | 224 | |
| 224 | 225 | #[test] |
| 225 | fn parse_version_basic_prerelease() { | |
| 226 | fn parse_basic_prerelease() { | |
| 226 | 227 | let version = "1.2.3-pre"; |
| 227 | 228 | |
| 228 | let parsed = parse_version(version).unwrap(); | |
| 229 | let parsed = version::parse(version).unwrap(); | |
| 229 | 230 | |
| 230 | 231 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("pre"))]); |
| 231 | 232 | assert_eq!(expected_pre, parsed.pre); |
| 232 | 233 | } |
| 233 | 234 | |
| 234 | 235 | #[test] |
| 235 | fn parse_version_prerelease_alphanumeric() { | |
| 236 | fn parse_prerelease_alphanumeric() { | |
| 236 | 237 | let version = "1.2.3-alpha1"; |
| 237 | 238 | |
| 238 | let parsed = parse_version(version).unwrap(); | |
| 239 | let parsed = version::parse(version).unwrap(); | |
| 239 | 240 | |
| 240 | 241 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("alpha1"))]); |
| 241 | 242 | assert_eq!(expected_pre, parsed.pre); |
| 242 | 243 | } |
| 243 | 244 | |
| 244 | 245 | #[test] |
| 245 | fn parse_version_prerelease_zero() { | |
| 246 | fn parse_prerelease_zero() { | |
| 246 | 247 | let version = "1.2.3-pre.0"; |
| 247 | 248 | |
| 248 | let parsed = parse_version(version).unwrap(); | |
| 249 | let parsed = version::parse(version).unwrap(); | |
| 249 | 250 | |
| 250 | 251 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("pre")), |
| 251 | 252 | Identifier::Numeric(0)]); |
⋮
| 253 | 254 | } |
| 254 | 255 | |
| 255 | 256 | #[test] |
| 256 | fn parse_version_basic_build() { | |
| 257 | fn parse_basic_build() { | |
| 257 | 258 | let version = "1.2.3+build"; |
| 258 | 259 | |
| 259 | let parsed = parse_version(version).unwrap(); | |
| 260 | let parsed = version::parse(version).unwrap(); | |
| 260 | 261 | |
| 261 | 262 | let expected_build = Some(vec![Identifier::AlphaNumeric(String::from("build"))]); |
| 262 | 263 | assert_eq!(expected_build, parsed.build); |
| 263 | 264 | } |
| 264 | 265 | |
| 265 | 266 | #[test] |
| 266 | fn parse_version_build_alphanumeric() { | |
| 267 | fn parse_build_alphanumeric() { | |
| 267 | 268 | let version = "1.2.3+build5"; |
| 268 | 269 | |
| 269 | let parsed = parse_version(version).unwrap(); | |
| 270 | let parsed = version::parse(version).unwrap(); | |
| 270 | 271 | |
| 271 | 272 | let expected_build = Some(vec![Identifier::AlphaNumeric(String::from("build5"))]); |
| 272 | 273 | assert_eq!(expected_build, parsed.build); |
| 273 | 274 | } |
| 274 | 275 | |
| 275 | 276 | #[test] |
| 276 | fn parse_version_pre_and_build() { | |
| 277 | fn parse_pre_and_build() { | |
| 277 | 278 | let version = "1.2.3-alpha1+build5"; |
| 278 | 279 | |
| 279 | let parsed = parse_version(version).unwrap(); | |
| 280 | let parsed = version::parse(version).unwrap(); | |
| 280 | 281 | |
| 281 | 282 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("alpha1"))]); |
| 282 | 283 | assert_eq!(expected_pre, parsed.pre); |
⋮
| 286 | 287 | } |
| 287 | 288 | |
| 288 | 289 | #[test] |
| 289 | fn parse_version_complex_metadata_01() { | |
| 290 | fn parse_complex_metadata_01() { | |
| 290 | 291 | let version = "1.2.3-1.alpha1.9+build5.7.3aedf "; |
| 291 | 292 | |
| 292 | let parsed = parse_version(version).unwrap(); | |
| 293 | let parsed = version::parse(version).unwrap(); | |
| 293 | 294 | |
| 294 | 295 | let expected_pre = Some(vec![Identifier::Numeric(1), |
| 295 | 296 | Identifier::AlphaNumeric(String::from("alpha1")), |
⋮
| 303 | 304 | } |
| 304 | 305 | |
| 305 | 306 | #[test] |
| 306 | fn parse_version_complex_metadata_02() { | |
| 307 | fn parse_complex_metadata_02() { | |
| 307 | 308 | let version = "0.4.0-beta.1+0851523"; |
| 308 | 309 | |
| 309 | let parsed = parse_version(version).unwrap(); | |
| 310 | let parsed = version::parse(version).unwrap(); | |
| 310 | 311 | |
| 311 | 312 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("beta")), |
| 312 | 313 | Identifier::Numeric(1)]); |
⋮
| 320 | 321 | fn parse_regression_01() { |
| 321 | 322 | let version = "0.0.0-WIP"; |
| 322 | 323 | |
| 323 | let parsed = parse_version(version).unwrap(); | |
| 324 | let parsed = version::parse(version).unwrap(); | |
| 324 | 325 | |
| 325 | 326 | assert_eq!(0, parsed.major); |
| 326 | 327 | assert_eq!(0, parsed.minor); |
| 548 | 548 | ); |
| 549 | 549 | } |
| 550 | 550 | |
| 551 | // #[test] | |
| 552 | // pub fn test_multiple() { | |
| 553 | // let r = req("> 0.0.9, <= 2.5.3"); | |
| 554 | // assert_eq!(r.to_string(), "> 0.0.9, <= 2.5.3".to_string()); | |
| 555 | // assert_match(&r, &["0.0.10", "1.0.0", "2.5.3"]); | |
| 556 | // assert_not_match(&r, &["0.0.8", "2.5.4"]); | |
| 557 | // | |
| 558 | // let r = req("0.3.0, 0.4.0"); | |
| 559 | // assert_eq!(r.to_string(), "^0.3.0, ^0.4.0".to_string()); | |
| 560 | // assert_not_match(&r, &["0.0.8", "0.3.0", "0.4.0"]); | |
| 561 | // | |
| 562 | // let r = req("<= 0.2.0, >= 0.5.0"); | |
| 563 | // assert_eq!(r.to_string(), "<= 0.2.0, >= 0.5.0".to_string()); | |
| 564 | // assert_not_match(&r, &["0.0.8", "0.3.0", "0.5.1"]); | |
| 565 | // | |
| 566 | // let r = req("0.1.0, 0.1.4, 0.1.6"); | |
| 567 | // assert_eq!(r.to_string(), "^0.1.0, ^0.1.4, ^0.1.6".to_string()); | |
| 568 | // assert_match(&r, &["0.1.6", "0.1.9"]); | |
| 569 | // assert_not_match(&r, &["0.1.0", "0.1.4", "0.2.0"]); | |
| 570 | // | |
| 571 | // assert!(VersionReq::parse("> 0.1.0,").is_err()); | |
| 572 | // assert!(VersionReq::parse("> 0.3.0, ,").is_err()); | |
| 573 | // | |
| 574 | // let r = req(">=0.5.1-alpha3, <0.6"); | |
| 575 | // assert_eq!(r.to_string(), ">= 0.5.1-alpha3, < 0.6".to_string()); | |
| 576 | // assert_match(&r, | |
| 577 | // &["0.5.1-alpha3", "0.5.1-alpha4", "0.5.1-beta", "0.5.1", "0.5.5"]); | |
| 578 | // assert_not_match(&r, | |
| 579 | // &["0.5.1-alpha1", "0.5.2-alpha3", "0.5.5-pre", "0.5.0-pre"]); | |
| 580 | // assert_not_match(&r, &["0.6.0", "0.6.0-pre"]); | |
| 581 | // } | |
| 551 | #[test] | |
| 552 | pub fn test_multiple_01() { | |
| 553 | let r = range::parse("> 0.0.9, <= 2.5.3").unwrap(); | |
| 554 | ||
| 555 | assert_eq!(Predicate { | |
| 556 | op: Op::Gt, | |
| 557 | major: 0, | |
| 558 | minor: Some(0), | |
| 559 | patch: Some(9), | |
| 560 | pre: Vec::new(), | |
| 561 | }, | |
| 562 | r.predicates[0] | |
| 563 | ); | |
| 564 | ||
| 565 | assert_eq!(Predicate { | |
| 566 | op: Op::LtEq, | |
| 567 | major: 2, | |
| 568 | minor: Some(5), | |
| 569 | patch: Some(3), | |
| 570 | pre: Vec::new(), | |
| 571 | }, | |
| 572 | r.predicates[1] | |
| 573 | ); | |
| 574 | } | |
| 575 | ||
| 576 | #[test] | |
| 577 | pub fn test_multiple_02() { | |
| 578 | let r = range::parse("0.3.0, 0.4.0").unwrap(); | |
| 579 | ||
| 580 | assert_eq!(Predicate { | |
| 581 | op: Op::Compatible, | |
| 582 | major: 0, | |
| 583 | minor: Some(3), | |
| 584 | patch: Some(0), | |
| 585 | pre: Vec::new(), | |
| 586 | }, | |
| 587 | r.predicates[0] | |
| 588 | ); | |
| 589 | ||
| 590 | assert_eq!(Predicate { | |
| 591 | op: Op::Compatible, | |
| 592 | major: 0, | |
| 593 | minor: Some(4), | |
| 594 | patch: Some(0), | |
| 595 | pre: Vec::new(), | |
| 596 | }, | |
| 597 | r.predicates[1] | |
| 598 | ); | |
| 599 | } | |
| 600 | ||
| 601 | #[test] | |
| 602 | pub fn test_multiple_03() { | |
| 603 | let r = range::parse("<= 0.2.0, >= 0.5.0").unwrap(); | |
| 604 | ||
| 605 | assert_eq!(Predicate { | |
| 606 | op: Op::LtEq, | |
| 607 | major: 0, | |
| 608 | minor: Some(2), | |
| 609 | patch: Some(0), | |
| 610 | pre: Vec::new(), | |
| 611 | }, | |
| 612 | r.predicates[0] | |
| 613 | ); | |
| 614 | ||
| 615 | assert_eq!(Predicate { | |
| 616 | op: Op::GtEq, | |
| 617 | major: 0, | |
| 618 | minor: Some(5), | |
| 619 | patch: Some(0), | |
| 620 | pre: Vec::new(), | |
| 621 | }, | |
| 622 | r.predicates[1] | |
| 623 | ); | |
| 624 | } | |
| 625 | ||
| 626 | #[test] | |
| 627 | pub fn test_multiple_04() { | |
| 628 | let r = range::parse("0.1.0, 0.1.4, 0.1.6").unwrap(); | |
| 629 | ||
| 630 | assert_eq!(Predicate { | |
| 631 | op: Op::Compatible, | |
| 632 | major: 0, | |
| 633 | minor: Some(1), | |
| 634 | patch: Some(0), | |
| 635 | pre: Vec::new(), | |
| 636 | }, | |
| 637 | r.predicates[0] | |
| 638 | ); | |
| 639 | ||
| 640 | assert_eq!(Predicate { | |
| 641 | op: Op::Compatible, | |
| 642 | major: 0, | |
| 643 | minor: Some(1), | |
| 644 | patch: Some(4), | |
| 645 | pre: Vec::new(), | |
| 646 | }, | |
| 647 | r.predicates[1] | |
| 648 | ); | |
| 649 | ||
| 650 | assert_eq!(Predicate { | |
| 651 | op: Op::Compatible, | |
| 652 | major: 0, | |
| 653 | minor: Some(1), | |
| 654 | patch: Some(6), | |
| 655 | pre: Vec::new(), | |
| 656 | }, | |
| 657 | r.predicates[2] | |
| 658 | ); | |
| 659 | } | |
| 660 | ||
| 661 | #[test] | |
| 662 | pub fn test_multiple_05() { | |
| 663 | let r = range::parse(">=0.5.1-alpha3, <0.6").unwrap(); | |
| 664 | ||
| 665 | assert_eq!(Predicate { | |
| 666 | op: Op::GtEq, | |
| 667 | major: 0, | |
| 668 | minor: Some(5), | |
| 669 | patch: Some(1), | |
| 670 | pre: vec![Identifier::AlphaNumeric(String::from("alpha3"))], | |
| 671 | }, | |
| 672 | r.predicates[0] | |
| 673 | ); | |
| 674 | ||
| 675 | assert_eq!(Predicate { | |
| 676 | op: Op::Lt, | |
| 677 | major: 0, | |
| 678 | minor: Some(6), | |
| 679 | patch: None, | |
| 680 | pre: Vec::new(), | |
| 681 | }, | |
| 682 | r.predicates[1] | |
| 683 | ); | |
| 684 | } | |
| 582 | 685 | |
| 583 | 686 | #[test] |
| 584 | 687 | pub fn test_parse_errors() { |
| 585 | 688 | assert!(range::parse("\0").is_err()); |
| 586 | assert!(range::parse(">= >= 0.0.2").is_err()); | |
| 587 | assert!(range::parse(">== 0.0.2").is_err()); | |
| 588 | assert!(range::parse("a.0.0").is_err()); | |
| 589 | assert!(range::parse("1.0.0-").is_err()); | |
| 689 | // assert!(range::parse(">= >= 0.0.2").is_err()); | |
| 690 | // assert!(range::parse(">== 0.0.2").is_err()); | |
| 691 | // assert!(range::parse("a.0.0").is_err()); | |
| 692 | // assert!(range::parse("1.0.0-").is_err()); | |
| 590 | 693 | assert!(range::parse(">=").is_err()); |
| 694 | // assert!(range::parse("> 0.1.0,").is_err()); | |
| 695 | // assert!(range::parse("> 0.3.0, ,").is_err()); | |
| 591 | 696 | } |
| 592 | 697 | |
| 593 | 698 | } |
| 686 | 686 | #[test] |
| 687 | 687 | pub fn test_parse_errors() { |
| 688 | 688 | assert!(range::parse("\0").is_err()); |
| 689 | // assert!(range::parse(">= >= 0.0.2").is_err()); | |
| 690 | // assert!(range::parse(">== 0.0.2").is_err()); | |
| 691 | // assert!(range::parse("a.0.0").is_err()); | |
| 692 | // assert!(range::parse("1.0.0-").is_err()); | |
| 689 | assert!(range::parse(">= >= 0.0.2").is_err()); | |
| 690 | assert!(range::parse(">== 0.0.2").is_err()); | |
| 691 | assert!(range::parse("a.0.0").is_err()); | |
| 692 | assert!(range::parse("1.0.0-").is_err()); | |
| 693 | 693 | assert!(range::parse(">=").is_err()); |
| 694 | // assert!(range::parse("> 0.1.0,").is_err()); | |
| 695 | // assert!(range::parse("> 0.3.0, ,").is_err()); | |
| 694 | assert!(range::parse("> 0.1.0,").is_err()); | |
| 695 | assert!(range::parse("> 0.3.0, ,").is_err()); | |
| 696 | 696 | } |
| 697 | ||
| 697 | ||
| 698 | 698 | } |
| 107 | 107 | |
| 108 | 108 | #[cfg(test)] |
| 109 | 109 | mod tests { |
| 110 | use common::is_alpha_numeric; | |
| 110 | 111 | use version; |
| 111 | 112 | use super::*; |
| 112 | 113 |
⋮
| 228 | 229 | |
| 229 | 230 | let parsed = version::parse(version).unwrap(); |
| 230 | 231 | |
| 231 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("pre"))]); | |
| 232 | let expected_pre = vec![Identifier::AlphaNumeric(String::from("pre"))]; | |
| 232 | 233 | assert_eq!(expected_pre, parsed.pre); |
| 233 | 234 | } |
| 234 | 235 |
⋮
| 238 | 239 | |
| 239 | 240 | let parsed = version::parse(version).unwrap(); |
| 240 | 241 | |
| 241 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("alpha1"))]); | |
| 242 | let expected_pre = vec![Identifier::AlphaNumeric(String::from("alpha1"))]; | |
| 242 | 243 | assert_eq!(expected_pre, parsed.pre); |
| 243 | 244 | } |
| 244 | 245 |
⋮
| 248 | 249 | |
| 249 | 250 | let parsed = version::parse(version).unwrap(); |
| 250 | 251 | |
| 251 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("pre")), | |
| 252 | Identifier::Numeric(0)]); | |
| 252 | let expected_pre = vec![Identifier::AlphaNumeric(String::from("pre")), | |
| 253 | Identifier::Numeric(0)]; | |
| 253 | 254 | assert_eq!(expected_pre, parsed.pre); |
| 254 | 255 | } |
| 255 | 256 |
⋮
| 259 | 260 | |
| 260 | 261 | let parsed = version::parse(version).unwrap(); |
| 261 | 262 | |
| 262 | let expected_build = Some(vec![Identifier::AlphaNumeric(String::from("build"))]); | |
| 263 | let expected_build = vec![Identifier::AlphaNumeric(String::from("build"))]; | |
| 263 | 264 | assert_eq!(expected_build, parsed.build); |
| 264 | 265 | } |
| 265 | 266 |
⋮
| 269 | 270 | |
| 270 | 271 | let parsed = version::parse(version).unwrap(); |
| 271 | 272 | |
| 272 | let expected_build = Some(vec![Identifier::AlphaNumeric(String::from("build5"))]); | |
| 273 | let expected_build = vec![Identifier::AlphaNumeric(String::from("build5"))]; | |
| 273 | 274 | assert_eq!(expected_build, parsed.build); |
| 274 | 275 | } |
| 275 | 276 |
⋮
| 279 | 280 | |
| 280 | 281 | let parsed = version::parse(version).unwrap(); |
| 281 | 282 | |
| 282 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("alpha1"))]); | |
| 283 | let expected_pre = vec![Identifier::AlphaNumeric(String::from("alpha1"))]; | |
| 283 | 284 | assert_eq!(expected_pre, parsed.pre); |
| 284 | 285 | |
| 285 | let expected_build = Some(vec![Identifier::AlphaNumeric(String::from("build5"))]); | |
| 286 | let expected_build = vec![Identifier::AlphaNumeric(String::from("build5"))]; | |
| 286 | 287 | assert_eq!(expected_build, parsed.build); |
| 287 | 288 | } |
| 288 | 289 |
⋮
| 292 | 293 | |
| 293 | 294 | let parsed = version::parse(version).unwrap(); |
| 294 | 295 | |
| 295 | let expected_pre = Some(vec![Identifier::Numeric(1), | |
| 296 | Identifier::AlphaNumeric(String::from("alpha1")), | |
| 297 | Identifier::Numeric(9)]); | |
| 296 | let expected_pre = vec![Identifier::Numeric(1), | |
| 297 | Identifier::AlphaNumeric(String::from("alpha1")), | |
| 298 | Identifier::Numeric(9)]; | |
| 298 | 299 | assert_eq!(expected_pre, parsed.pre); |
| 299 | 300 | |
| 300 | let expected_build = Some(vec![Identifier::AlphaNumeric(String::from("build5")), | |
| 301 | Identifier::Numeric(7), | |
| 302 | Identifier::AlphaNumeric(String::from("3aedf"))]); | |
| 301 | let expected_build = vec![Identifier::AlphaNumeric(String::from("build5")), | |
| 302 | Identifier::Numeric(7), | |
| 303 | Identifier::AlphaNumeric(String::from("3aedf"))]; | |
| 303 | 304 | assert_eq!(expected_build, parsed.build); |
| 304 | 305 | } |
| 305 | 306 |
⋮
| 309 | 310 | |
| 310 | 311 | let parsed = version::parse(version).unwrap(); |
| 311 | 312 | |
| 312 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("beta")), | |
| 313 | Identifier::Numeric(1)]); | |
| 313 | let expected_pre = vec![Identifier::AlphaNumeric(String::from("beta")), | |
| 314 | Identifier::Numeric(1)]; | |
| 314 | 315 | assert_eq!(expected_pre, parsed.pre); |
| 315 | 316 | |
| 316 | let expected_build = Some(vec![Identifier::AlphaNumeric(String::from("0851523"))]); | |
| 317 | let expected_build = vec![Identifier::AlphaNumeric(String::from("0851523"))]; | |
| 317 | 318 | assert_eq!(expected_build, parsed.build); |
| 318 | 319 | } |
| 319 | 320 |
⋮
| 327 | 328 | assert_eq!(0, parsed.minor); |
| 328 | 329 | assert_eq!(0, parsed.patch); |
| 329 | 330 | |
| 330 | let expected_pre = Some(vec![Identifier::AlphaNumeric(String::from("WIP"))]); | |
| 331 | let expected_pre = vec![Identifier::AlphaNumeric(String::from("WIP"))]; | |
| 331 | 332 | assert_eq!(expected_pre, parsed.pre); |
| 332 | 333 | } |
| 333 | 334 | } |
| 107 | 107 | |
| 108 | 108 | #[cfg(test)] |
| 109 | 109 | mod tests { |
| 110 | use common::is_alpha_numeric; | |
| 111 | 110 | use version; |
| 112 | 111 | use super::*; |
| 113 | 112 |
| 684 | 684 | } |
| 685 | 685 | |
| 686 | 686 | #[test] |
| 687 | fn test_parse_build_metadata_with_predicate() { | |
| 688 | assert_eq!(range::parse("^1.2.3+meta").unwrap().predicates[0].op, | |
| 689 | Op::Compatible); | |
| 690 | assert_eq!(range::parse("~1.2.3+meta").unwrap().predicates[0].op, | |
| 691 | Op::Tilde); | |
| 692 | assert_eq!(range::parse("=1.2.3+meta").unwrap().predicates[0].op, | |
| 693 | Op::Ex); | |
| 694 | assert_eq!(range::parse("<=1.2.3+meta").unwrap().predicates[0].op, | |
| 695 | Op::LtEq); | |
| 696 | assert_eq!(range::parse(">=1.2.3+meta").unwrap().predicates[0].op, | |
| 697 | Op::GtEq); | |
| 698 | assert_eq!(range::parse("<1.2.3+meta").unwrap().predicates[0].op, | |
| 699 | Op::Lt); | |
| 700 | assert_eq!(range::parse(">1.2.3+meta").unwrap().predicates[0].op, | |
| 701 | Op::Gt); | |
| 702 | } | |
| 703 | ||
| 704 | #[test] | |
| 687 | 705 | pub fn test_parse_errors() { |
| 688 | 706 | assert!(range::parse("\0").is_err()); |
| 689 | 707 | assert!(range::parse(">= >= 0.0.2").is_err()); |
| 712 | 712 | assert!(range::parse("> 0.1.0,").is_err()); |
| 713 | 713 | assert!(range::parse("> 0.3.0, ,").is_err()); |
| 714 | 714 | } |
| 715 | ||
| 716 | #[test] | |
| 717 | pub fn test_large_version() { | |
| 718 | assert!(range::parse("18446744073709551617.0.0").is_err()); | |
| 719 | } | |
| 715 | 720 | |
| 716 | 721 | } |
| 712 | 712 | assert!(range::parse("> 0.1.0,").is_err()); |
| 713 | 713 | assert!(range::parse("> 0.3.0, ,").is_err()); |
| 714 | 714 | } |
| 715 | ||
| 715 | ||
| 716 | 716 | #[test] |
| 717 | pub fn test_large_version() { | |
| 717 | pub fn test_large_major_version() { | |
| 718 | 718 | assert!(range::parse("18446744073709551617.0.0").is_err()); |
| 719 | 719 | } |
| 720 | 720 | |
| 721 | #[test] | |
| 722 | pub fn test_large_minor_version() { | |
| 723 | assert!(range::parse("0.18446744073709551617.0").is_err()); | |
| 724 | } | |
| 725 | ||
| 721 | 726 | } |
| 723 | 723 | assert!(range::parse("0.18446744073709551617.0").is_err()); |
| 724 | 724 | } |
| 725 | 725 | |
| 726 | #[test] | |
| 727 | pub fn test_large_patch_version() { | |
| 728 | assert!(range::parse("0.0.18446744073709551617").is_err()); | |
| 729 | } | |
| 726 | 730 | } |