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 | } |