Created
June 20, 2025 14:20
-
-
Save camilajenny/2059145ad34e4e5c3adbff47ccca7657 to your computer and use it in GitHub Desktop.
test program for comparing debian versions in the project Eddy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void main () { | |
// test("31.2.3", "31.2.10"); | |
// test("31.2.3", "31.2"); | |
// test_greater_method("31.2.10", "31.2.3", compare_versions_contributor); | |
// test_greater_method("31.2.3", "31.2", compare_versions_contributor); | |
test_greater_method("1.2.3", "1.2.2", compare_versions_improved); | |
test_greater_method("1.2.10", "1.2.2", compare_versions_improved); | |
test_greater_method("1.2.3-2", "1.2.3-1", compare_versions_improved); | |
test_greater_method("2.4.5", "2.4", compare_versions_improved); | |
test_greater_method("1:1.0", "0:2.0", compare_versions_improved); // Epoch wins | |
test_greater_method("10:2.0", "3:2.0", compare_versions_improved); // Epoch wins | |
test_greater_method("1:1.2.3", "1.2.3", compare_versions_improved); // Epoch vs no epoch | |
test_greater_method("2.0", "2.0~beta1", compare_versions_improved); // ~ sorts lower | |
test_greater_method("2.1~beta", "2.0", compare_versions_improved); // but upstream version wins | |
test_greater_method("1.0+git20240501", "1.0", compare_versions_improved); | |
test_greater_method("1.0.0-1ubuntu2", "1.0.0-1ubuntu1", compare_versions_improved); | |
test_greater_method("1.0.0-1ubuntu2", "1.0.0-1", compare_versions_improved); // ubuntu suffix is still >= | |
test_greater_method("2.0~rc2", "2.0~rc1", compare_versions_improved); | |
test_greater_method("3.4.1", "3.4.1~rc1", compare_versions_improved); | |
test_greater_method("1.0.0+build2", "1.0.0+build1", compare_versions_improved); | |
test_greater_method("1.0.0", "1.0.0~", compare_versions_improved); // trailing tilde means it's earlier | |
test_greater_method("1.0.0-1", "1.0.0~rc1-1", compare_versions_improved); | |
test_greater_method("1.0.0-10", "1.0.0-3", compare_versions_improved); // debian revision higher | |
test_greater_method("1.0.0-0ubuntu2", "1.0.0-0ubuntu1", compare_versions_improved); | |
test_greater_method("1.0.0-0ubuntu1", "1.0.0-0", compare_versions_improved); // ubuntu suffix greater than none | |
test_greater_method("1.2.3-4", "1.2.3-4~beta1", compare_versions_improved); | |
test_greater_method("1.0.0-0ubuntu2build2", "1.0.0-0ubuntu2build1", compare_versions_improved); | |
println(""); | |
test_equal_method("0:2.4.1", "2.4.1", compare_versions_improved); // Explicit vs implicit epoch | |
test_equal_method("1.2.3", "1.2.3", compare_versions_improved); | |
test_equal_method("1.0.0-1", "1.0.0-1", compare_versions_improved); | |
test_equal_method("1.2.3+git", "1.2.3+git", compare_versions_improved); | |
} | |
delegate int Compare(string a, string b); | |
int compare_versions_improved (string v1, string v2) { | |
// https://www.debian.org/doc/debian-policy/ch-controlfields.html#version | |
string a = v1; | |
string b = v2; | |
// check for empty strings - later we split the strings and it would break on an empty array | |
if (a == "") | |
return -1; | |
if (b == "") | |
return 1; | |
// check epochs | |
string[] atok = a.split(":"); | |
string[] btok = b.split(":"); | |
int a_epoch, b_epoch; | |
if (atok.length >= 2 ) { | |
bool a_is_epoch = int.try_parse(atok[0], out a_epoch); | |
if(!a_is_epoch) | |
a_epoch = 0; | |
} else { | |
a_epoch = 0; | |
} | |
if (btok.length >= 2) { | |
bool b_is_epoch = int.try_parse(btok[0], out b_epoch); | |
if(!b_is_epoch) | |
b_epoch = 0; | |
} else { | |
b_epoch = 0; | |
} | |
// print(@"epochs: $a_epoch, $b_epoch "); | |
if (a_epoch != b_epoch) | |
return a_epoch - b_epoch; | |
// trim epochs when the same (including assumed 0 when none) | |
a = join_sliced_from_1(atok); | |
b = join_sliced_from_1(btok); | |
//check upstream version | |
Regex regex = new Regex("[+~-]"); | |
atok = regex.split(a); | |
btok = regex.split(b); | |
string[] aparts = atok[0].split ("."); | |
string[] bparts = btok[0].split ("."); | |
// int at = atok.length, bt = btok.length; | |
// print(@"upstream $a, $b "); | |
int length = int.min (aparts.length, bparts.length); | |
// print(@"$length "); | |
for (int i = 0; i < length; i++) { | |
int a_num, b_num; | |
bool a_is_num = int.try_parse(aparts[i], out a_num); | |
bool b_is_num = int.try_parse(bparts[i], out b_num); | |
if (a_is_num && b_is_num) { | |
int diff = a_num - b_num; | |
if (diff != 0) { | |
return diff; | |
} | |
} else { | |
int rc = strcmp (aparts[i], bparts[i]); | |
if (rc != 0) { | |
return rc; | |
} | |
} | |
if (i == length - 1) { | |
if(aparts.length != bparts.length) { | |
return aparts.length - bparts.length; | |
} | |
} | |
} | |
// print(@"tilde $a, $b "); | |
// a tilde sorts before anything, even the end of a part | |
atok = a.split ("~"); | |
btok = b.split ("~"); | |
if (atok.length < 2 && btok.length >= 2) { | |
return 1; | |
} else if (atok.length >= 2 && btok.length < 2) { | |
return -1; | |
} | |
// check debian revision if present | |
atok = a.split("-"); | |
btok = b.split("-"); | |
int a_dr, b_dr; | |
bool a_dr_is_num = int.try_parse(atok[atok.length - 1], out a_dr); | |
bool b_dr_is_num = int.try_parse(btok[btok.length - 1], out b_dr); | |
if (a_dr_is_num && b_dr_is_num) { | |
if (a_dr != b_dr) | |
return a_dr - b_dr; | |
} | |
return strcmp(a, b); | |
} | |
string join_sliced_from_1(string[] arr) { | |
if (arr.length == 0) | |
return ""; | |
if (arr.length == 1) | |
return arr[0]; | |
string result = ""; | |
for (int i = 1; i < arr.length; i++) { | |
result += arr[i]; | |
} | |
return result; | |
} | |
int compare_versions_original (string a, string b) { | |
if (a == b) { | |
return 0; | |
} | |
string[] atok = a.split ("~"); | |
string[] btok = b.split ("~"); | |
if (atok.length < 2 && btok.length >= 2) { | |
return -1; | |
} else if (atok.length >= 2 && btok.length < 2) { | |
return 1; | |
} | |
string aver = atok[0]; | |
string bver = btok[0]; | |
string[] aparts = aver.split ("."); | |
string[] bparts = bver.split ("."); | |
int length = int.max (aparts.length, bparts.length); | |
for (int i = 0; i < length; i++) { | |
int rc = strcmp (aparts[i], bparts[i]); | |
if (i == length - 1) { | |
if (bparts[i] > aparts[i]) { | |
return 1; | |
} | |
else if (bparts[i] < aparts[i]) { | |
return -1; | |
} | |
} | |
if (rc < 0) { | |
return -1; | |
} else if (rc > 0) { | |
return 1; | |
} | |
} | |
return 0; | |
} | |
int compare_versions_contributor (string a, string b) { | |
if (a == b) { | |
return 0; | |
} | |
string[] atok = a.split ("~"); | |
string[] btok = b.split ("~"); | |
if (atok.length < 2 && btok.length >= 2) { | |
return -1; | |
} else if (atok.length >= 2 && btok.length < 2) { | |
return 1; | |
} | |
string aver = atok[0]; | |
string bver = btok[0]; | |
string[] aparts = aver.split ("."); | |
string[] bparts = bver.split ("."); | |
int length = int.max (aparts.length, bparts.length); | |
// printlni(length); | |
for (int i = 0; i < length; i++) { | |
int a_num, b_num; | |
bool a_is_num = int.try_parse(aparts[i], out a_num); | |
bool b_is_num = int.try_parse(bparts[i], out b_num); | |
// print(a_is_num.to_string()); | |
// print(b_is_num.to_string()); | |
if (a_is_num && b_is_num) { | |
if (a_num < b_num) { | |
return -1; | |
} else if (a_num > b_num) { | |
return 1; | |
} | |
return 0; | |
} else { | |
return strcmp (aparts[i], bparts[i]); | |
} | |
} | |
return 0; | |
} | |
void println(string message) { | |
print("%s\n", message); | |
} | |
void printlni(int message) { | |
print("%d\n", message); | |
} | |
void test_greater_method(string left, string right, Compare compare) { | |
string result = test_greater( | |
compare(left, right) | |
); | |
println(@"$left, $right$SEPARATOR$result"); | |
} | |
void test_equal_method(string left, string right, Compare compare) { | |
string result = test_equal( | |
compare(left, right) | |
); | |
println(@"$left, $right$SEPARATOR$result"); | |
} | |
const string OK = "ok"; | |
const string FAILED = "failed"; | |
const string SEPARATOR = " ======> "; | |
string test_greater(int val) { | |
return val > 0 ? OK : FAILED; | |
} | |
string test_equal(int val) { | |
return val == 0 ? OK : FAILED; | |
} | |
// ------------------------------------------------------ | |
void test(string left, string right) { | |
string result = test_equal_versions( | |
compare_versions_original(left, right), | |
compare_versions_contributor(left, right) | |
); | |
println(@"$left, $right: $result"); | |
} | |
string test_equal_versions(int left, int right) { | |
return left == right ? OK : FAILED; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Result:
For testing of: donadigo/eddy#140