chr
2026-04-05 fe750b791d5b517cc4e9bc8e99a9a75139a0cfba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//            Copyright Keysight Technologies 2012-2019
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at http://mozilla.org/MPL/2.0/.
using System;
using System.Text.RegularExpressions;
 
namespace OpenTap.Package
{
    /// <summary> This interface specifies how to convert from a version string to a SemanticVersion. </summary>
    public interface IVersionConverter : ITapPlugin
    {
        /// <summary> Try to convert 'versionString' to a SemanticVersion. Will throw on exceptions. </summary>
        SemanticVersion Convert(string versionString);
    }
 
    /// <summary> Plugin type like IVersionConverter, that can TryConvert, which does will not throw an exception. </summary>
    public interface IVersionTryConverter : ITapPlugin
    {
        /// <summary>  Try to convert 'versionString' to a SemanticVersion. Returns false on failure.  </summary>
        bool TryConvert(string versionString, out SemanticVersion version);
    }
 
    [Display("ConvertMajorMinorBuildRevision", 
        "Supports a four value number (x.x.x.x) which will be interpreted as Major.Minor.BuildMetadata.Patch. This is compatible with Microsofts definition of version numbers (e.g. for .NET assemblies), see https://docs.microsoft.com/en-us/dotnet/api/system.version",
        Order: 2)]
    internal class MajorMinorBuildRevisionVersionConverter : IVersionTryConverter
    {
        public SemanticVersion Convert(string versionString)
        {
            string[] parts = versionString.Split('.');
            if (parts.Length != 4)
                throw new ArgumentException("Version number must have 4 values.");
            return new SemanticVersion(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[3]),null,parts[2]);
        }
 
        public bool TryConvert(string versionString, out SemanticVersion version)
        {
            version = null;
            string[] parts = versionString.Split('.');
            if (parts.Length != 4)
                return false;
 
            if(int.TryParse(parts[0], out var maj) && int.TryParse(parts[1], out var min) && int.TryParse(parts[3], out var rev))
            {
                version = new SemanticVersion(maj, min, rev, null, parts[2]);
                return true;
            }
 
            return false;
        }
    }
 
    [Display("ConvertFourValue", 
        "Supports a four value number (x.y.z.w) which will be converted to the semantic version number x.y.z+w.",
        Order: 1)]
    internal class FourValueVersionConverter : IVersionTryConverter
    {
        public SemanticVersion Convert(string versionString)
        {
            string[] parts = versionString.Split('.');
            if (parts.Length != 4)
                throw new ArgumentException("Version number must have 4 values.");
            return new SemanticVersion(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), null, parts[3]);
        }
 
        public bool TryConvert(string versionString, out SemanticVersion version)
        {
            version = null;
            string[] parts = versionString.Split('.');
            if (parts.Length != 4)
                return false;
 
            if (int.TryParse(parts[0], out var maj) && int.TryParse(parts[1], out var min) && int.TryParse(parts[2], out var rev))
            {
                version = new SemanticVersion(maj, min, rev, null, parts[3]);
                return true;
            }
 
            return false;
        }
    }
 
    [Display("Compatibility",
    "For compatibility with TAP 8.x parsing.",
    Order: 1)]
    internal class Tap8CompatibilityVersionConverter : IVersionConverter
    {
        public SemanticVersion Convert(string versionString)
        {
            int major, minor, build = 0;
            // Otherwise fall back to legacy code.
            var full_parts = versionString.Trim().Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
            if (full_parts.Length == 0)
                return new SemanticVersion(0,0,0,null,null);
            var version_string = full_parts[0];
 
            var parts = version_string.Split('.');
            bool isok = int.TryParse(parts[0], out major);
            if (!isok) return new SemanticVersion(0, 0, 0, null, null);
            if (parts.Length == 1) return new SemanticVersion(major, 0, 0, null, null); ;
            isok = int.TryParse(parts[1], out minor);
 
            if (!isok)
            {
                if (parts[1].Length > 0 && parts.Length == 2)
                {
                    return new SemanticVersion(major, 0, 0, null, parts[1]);
                }
                return new SemanticVersion(major, 0, 0, null, null);
            }
            if (parts.Length > 2)
                isok = int.TryParse(parts[2], out build);
            else if (full_parts.Length > 1)
            {
                // When developing and using a OpenTAP version that is built on the local machine
                // (not by pushing to git and have the CI system do the build), we would like
                // for OpenTAP not to complain about incompatible build versions.
                string type = full_parts[1];
                if (type == "Development")
                    build = int.MaxValue;
            }
            string commit = null;
            string prerelease = null;
            if (parts.Length > 3)
                commit = parts[3];
            if (!isok)
            {
                var match = Regex.Match(version_string, ".*?-(.*?)(\\+|$)");
                if (match.Success && match.Groups.Count > 1 && match.Groups[1].Value != "")
                    prerelease = match.Groups[1].Value;
 
                match = Regex.Match(parts[2], ".*?\\+(.*)");
                if (match.Success && match.Groups.Count > 1)
                    commit = match.Groups[1].Value;
 
                version_string = parts[2];
                version_string = version_string.Split('-')[0];
                version_string = version_string.Split('+')[0];
 
                isok = int.TryParse(version_string, out build);
                if (isok == false)
                    build = 0;
            }
 
            return new SemanticVersion(major,minor,build,prerelease,commit);
        }
    }
 
}