• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Camelcade / Perl5-IDEA / #525521851

22 May 2026 05:53AM UTC coverage: 76.208% (+0.01%) from 76.196%
#525521851

push

github

hurricup
Build 2026.2-EAP.6228.19

14772 of 22542 branches covered (65.53%)

Branch coverage included in aggregate %.

31144 of 37709 relevant lines covered (82.59%)

0.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.16
/plugin/common/src/main/java/com/perl5/lang/perl/internals/PerlVersion.java
1
/*
2
 * Copyright 2015-2025 Alexandr Evstigneev
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package com.perl5.lang.perl.internals;
18

19
import com.intellij.openapi.diagnostic.Logger;
20
import com.intellij.openapi.util.NlsSafe;
21
import com.intellij.openapi.util.text.StringUtil;
22
import com.intellij.util.xmlb.annotations.Tag;
23
import com.perl5.PerlBundle;
24
import com.perl5.lang.perl.util.PerlUtil;
25
import org.jetbrains.annotations.Nls;
26
import org.jetbrains.annotations.NotNull;
27

28
import java.util.ArrayList;
29
import java.util.Collections;
30
import java.util.List;
31
import java.util.Map;
32
import java.util.function.Predicate;
33
import java.util.regex.Matcher;
34

35
import static java.util.Map.entry;
36

37
import static com.perl5.lang.perl.internals.PerlVersionRegexps.*;
38

39
/**
40
 * Represents perl version
41
 */
42
public final class PerlVersion implements Comparable<PerlVersion> {
43
  private static final Logger LOG = Logger.getInstance(PerlVersion.class);
1✔
44
  public static final PerlVersion V5_10 = new PerlVersion(5.010);
1✔
45
  public static final PerlVersion V5_12 = new PerlVersion(5.012);
1✔
46
  public static final PerlVersion V5_14 = new PerlVersion(5.014);
1✔
47
  public static final PerlVersion V5_16 = new PerlVersion(5.016);
1✔
48
  public static final PerlVersion V5_18 = new PerlVersion(5.018);
1✔
49
  public static final PerlVersion V5_20 = new PerlVersion(5.020);
1✔
50
  public static final PerlVersion V5_22 = new PerlVersion(5.022);
1✔
51
  public static final PerlVersion V5_24 = new PerlVersion(5.024);
1✔
52
  public static final PerlVersion V5_26 = new PerlVersion(5.026);
1✔
53
  public static final PerlVersion V5_28 = new PerlVersion(5.028);
1✔
54
  public static final PerlVersion V5_30 = new PerlVersion(5.030);
1✔
55
  public static final PerlVersion V5_32 = new PerlVersion(5.032);
1✔
56
  public static final PerlVersion V5_34 = new PerlVersion(5.034);
1✔
57
  public static final PerlVersion V5_36 = new PerlVersion(5.036);
1✔
58
  public static final PerlVersion V5_38 = new PerlVersion(5.038);
1✔
59
  public static final PerlVersion V5_40 = new PerlVersion(5.036);
1✔
60
  public static final PerlVersion V5_42 = new PerlVersion(5.038);
1✔
61
  public static final Predicate<PerlVersion> GREATER_OR_EQUAL_V520 = version -> !version.lesserThan(V5_20);
1✔
62
  public static final Predicate<PerlVersion> GREATER_OR_EQUAL_V522 = version -> !version.lesserThan(V5_22);
1✔
63
  public static final Predicate<PerlVersion> GREATER_OR_EQUAL_V532 = version -> !version.lesserThan(V5_32);
1✔
64
  public static final List<PerlVersion> ALL_VERSIONS = List.of(
1✔
65
    V5_10, V5_12, V5_14, V5_16, V5_18, V5_20, V5_22, V5_24, V5_26, V5_28, V5_30, V5_32, V5_34, V5_36, V5_38, V5_40, V5_42
66
  );
67

68
  public static final Map<PerlVersion, @Nls String> PERL_VERSION_DESCRIPTIONS = Map.ofEntries(
1✔
69
    entry(V5_10, PerlBundle.message("perl.version.description.5.10")),
1✔
70
    entry(V5_12, PerlBundle.message("perl.version.description.5.12")),
1✔
71
    entry(V5_14, PerlBundle.message("perl.version.description.5.14")),
1✔
72
    entry(V5_16, PerlBundle.message("perl.version.description.5.16")),
1✔
73
    entry(V5_18, PerlBundle.message("perl.version.description.5.18")),
1✔
74
    entry(V5_20, PerlBundle.message("perl.version.description.5.20")),
1✔
75
    entry(V5_22, PerlBundle.message("perl.version.description.5.22")),
1✔
76
    entry(V5_24, PerlBundle.message("perl.version.description.5.24")),
1✔
77
    entry(V5_26, PerlBundle.message("perl.version.description.5.26")),
1✔
78
    entry(V5_28, PerlBundle.message("perl.version.description.5.28")),
1✔
79
    entry(V5_30, PerlBundle.message("perl.version.description.5.30")),
1✔
80
    entry(V5_32, PerlBundle.message("perl.version.description.5.32")),
1✔
81
    entry(V5_34, PerlBundle.message("perl.version.description.5.34")),
1✔
82
    entry(V5_36, PerlBundle.message("perl.version.description.5.36")),
1✔
83
    entry(V5_38, PerlBundle.message("perl.version.description.5.38"))
1✔
84
  );
85

86
  @Tag("isAlpha")
87
  private boolean myIsAlpha;
88
  @Tag("isStrict")
89
  private boolean myIsStrict;
90
  @Tag("isValid")
91
  private boolean myIsValid;
92
  @Tag("revision")
93
  private int myRevision;
94
  @Tag("major")
95
  private int myMajor;
96
  @Tag("minor")
97
  private int myMinor;
98
  @Tag("extraChunks")
1✔
99
  private List<Integer> myExtraChunks = Collections.emptyList();
1✔
100

101
  @SuppressWarnings("unused")
102
  private PerlVersion() {
1✔
103
  }
1✔
104

105
  public PerlVersion(double version) {
1✔
106
    try {
107
      parseDoubleVersion(version);
1✔
108
    }
109
    catch (NumberFormatException e) {
×
110
      LOG.debug("Unable to parse version: ", version, "; message: ", e.getMessage());
×
111
    }
1✔
112
  }
1✔
113

114
  public PerlVersion(String versionString) {
1✔
115
    init(versionString);
1✔
116
  }
1✔
117

118
  private void init(String versionString) {
119
    try {
120
      Matcher matcher;
121

122
      if (NUMERIC_VERSION.matcher(versionString).matches()) {
1✔
123
        parseDoubleVersion(Double.parseDouble(versionString.replace("_", "")));
1✔
124
        myIsAlpha = versionString.contains("_");
1✔
125
      }
126
      else if ((matcher = DOTTED_VERSION.matcher(versionString)).matches()) {
1✔
127
        parseDottedVersion(versionString, matcher);
1✔
128
      }
129
      else {
130
        myIsValid = false;
1✔
131
        return;
1✔
132
      }
133
      myIsStrict = STRICT_VERSION_PATTERN.matcher(versionString).matches();
1✔
134
      myIsValid = true;
1✔
135
    }
136
    catch (NumberFormatException e) {
1✔
137
      myIsValid = myIsStrict = myIsAlpha = false;
1✔
138
      myRevision = myMajor = myMinor = 0;
1✔
139
    }
1✔
140
  }
1✔
141

142
  private void parseDottedVersion(String versionString, Matcher matcher) {
143
    List<String> versionChunks = PerlUtil.mutableList(versionString.replace("v", "").replace('_', '.').split("\\."));
1✔
144
    myIsAlpha = matcher.group(1) != null;
1✔
145
    myRevision = Integer.parseInt(versionChunks.removeFirst());
1✔
146

147
    if (versionChunks.isEmpty()) {
1✔
148
      return;
1✔
149
    }
150
    if (versionChunks.getFirst().length() > 3) {
1✔
151
      throw new NumberFormatException();
1✔
152
    }
153

154
    myMajor = Integer.parseInt(versionChunks.removeFirst());
1✔
155

156
    if (versionChunks.isEmpty()) {
1✔
157
      return;
1✔
158
    }
159
    if (versionChunks.getFirst().length() > 3) {
1!
160
      throw new NumberFormatException();
×
161
    }
162

163
    myMinor = Integer.parseInt(versionChunks.removeFirst());
1✔
164

165
    if (versionChunks.isEmpty()) {
1✔
166
      return;
1✔
167
    }
168
    myExtraChunks = new ArrayList<>();
1✔
169
    for (String chunk : versionChunks) {
1✔
170
      if (chunk.length() > 3) {
1!
171
        throw new NumberFormatException();
×
172
      }
173
      else {
174
        myExtraChunks.add(Integer.parseInt(chunk));
1✔
175
      }
176
    }
1✔
177
  }
1✔
178

179
  public void parseDoubleVersion(double version) throws NumberFormatException {
180
    if (version <= Integer.MAX_VALUE) {
1✔
181
      long longVersion = (long)(version * 1000000);
1✔
182
      myIsStrict = true;
1✔
183
      myIsAlpha = false;
1✔
184
      myIsValid = version > 0;
1✔
185
      if (myIsValid) {
1✔
186
        myRevision = (int)version;
1✔
187
        longVersion = (longVersion - myRevision * 1000000L);
1✔
188
        myMajor = (int)(longVersion / 1000);
1✔
189
        myMinor = (int)(longVersion % 1000);
1✔
190
      }
191
    }
1✔
192
    else {
193
      throw new NumberFormatException("Version is too big");
1✔
194
    }
195
  }
1✔
196

197
  public double getDoubleVersion() {
198
    double version = myRevision + ((double)myMajor / 1000) + ((double)myMinor / 1000000);
1✔
199

200
    if (!myExtraChunks.isEmpty()) {
1✔
201
      long divider = 1000000000;
1✔
202
      for (Integer chunk : myExtraChunks) {
1✔
203
        version += ((double)chunk) / divider;
1✔
204
        divider *= 1000;
1✔
205
      }
1✔
206
    }
207

208
    return version;
1✔
209
  }
210

211
  public @NlsSafe String getStrictDottedVersion() {
212
    List<String> result = new ArrayList<>(Collections.singletonList(Integer.toString(myRevision)));
1✔
213

214
    if (myMajor > 0 || myMinor > 0 || !myExtraChunks.isEmpty()) {
1!
215
      result.add(Integer.toString(myMajor));
1✔
216
    }
217

218
    if (myMinor > 0 || !myExtraChunks.isEmpty()) {
1!
219
      result.add(Integer.toString(myMinor));
1✔
220
    }
221

222
    for (Integer chunk : myExtraChunks) {
1✔
223
      result.add(Integer.toString(chunk));
1✔
224
    }
1✔
225

226
    return "v" + StringUtil.join(result, ".");
1✔
227
  }
228

229
  public int getRevision() {
230
    return myRevision;
1✔
231
  }
232

233
  public int getMajor() {
234
    return myMajor;
1✔
235
  }
236

237
  public int getMinor() {
238
    return myMinor;
1✔
239
  }
240

241
  public boolean isAlpha() {
242
    return myIsAlpha;
1✔
243
  }
244

245
  public boolean isStrict() {
246
    return myIsStrict;
1✔
247
  }
248

249
  public boolean isValid() {
250
    return myIsValid;
1✔
251
  }
252

253
  @Override
254
  public int compareTo(@NotNull PerlVersion o) {
255
    return Double.compare(getDoubleVersion(), o.getDoubleVersion());
1✔
256
  }
257

258
  @Override
259
  public boolean equals(Object o) {
260
    return o instanceof PerlVersion perlVersion && (this == o || this.getDoubleVersion() == perlVersion.getDoubleVersion());
1!
261
  }
262

263
  @Override
264
  public int hashCode() {
265
    return Double.hashCode(getDoubleVersion());
1✔
266
  }
267

268
  public boolean lesserThan(PerlVersion o) {
269
    return compareTo(o) < 0;
1✔
270
  }
271

272
  public boolean greaterThan(PerlVersion o) {
273
    return compareTo(o) > 0;
1✔
274
  }
275
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc