-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
265 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
#include "fvversioncomparator.h" | ||
#include <string> | ||
#include <algorithm> | ||
#include <cctype> | ||
|
||
// | ||
// Clone of Sparkle's SUStandardVersionComparator.m, so here's original author's | ||
// copyright too: | ||
// | ||
// Copyright 2007 Andy Matuschak. All rights reserved. | ||
// | ||
// Everything's the same except for TypeOfCharacter() | ||
// (because who knows how Foundation does isdigit() and such.) | ||
// | ||
|
||
|
||
FvVersionComparator::FvVersionComparator() | ||
{ | ||
// noop | ||
} | ||
|
||
FvVersionComparator::CharacterType FvVersionComparator::TypeOfCharacter(std::string character) | ||
{ | ||
if (character == ".") { | ||
return kSeparatorType; | ||
} else if (isdigit(character[0])) { | ||
return kNumberType; | ||
} else if (isspace(character[0])) { | ||
return kSeparatorType; | ||
} else if (ispunct(character[0])) { | ||
return kSeparatorType; | ||
} else { | ||
return kStringType; | ||
} | ||
|
||
} | ||
|
||
std::vector<std::string> FvVersionComparator::SplitVersionString(std::string version) | ||
{ | ||
std::string character; | ||
std::string s; | ||
unsigned long i = 0, n = 0; | ||
CharacterType oldType, newType; | ||
std::vector<std::string> parts; | ||
|
||
if (version.length() == 0) { | ||
// Nothing to do here | ||
return parts; | ||
} | ||
|
||
s = version.substr(0, 1); | ||
oldType = TypeOfCharacter(s); | ||
n = version.length() - 1; | ||
for (i = 1; i <= n; ++i) { | ||
character = version.substr(i, 1)[0]; | ||
newType = TypeOfCharacter(character); | ||
if (oldType != newType || oldType == kSeparatorType) { | ||
// We've reached a new segment | ||
std::string aPart = s; | ||
parts.push_back(aPart); | ||
s = character; | ||
} else { | ||
// Add character to string and continue | ||
s.append(character); | ||
} | ||
oldType = newType; | ||
} | ||
|
||
// Add the last part onto the array | ||
parts.push_back(s); | ||
return parts; | ||
} | ||
|
||
|
||
FvVersionComparator::ComparatorResult FvVersionComparator::CompareVersions(std::string versionA, | ||
std::string versionB) | ||
{ | ||
std::vector<std::string> partsA = SplitVersionString(versionA); | ||
std::vector<std::string> partsB = SplitVersionString(versionB); | ||
|
||
std::string partA = std::string(""), partB = std::string(""); | ||
unsigned long i = 0, n = 0; | ||
int intA, intB; | ||
CharacterType typeA, typeB; | ||
|
||
n = std::min(partsA.size(), partsB.size()); | ||
for (i = 0; i < n; ++i) { | ||
partA = partsA.at(i); | ||
partB = partsB.at(i); | ||
|
||
typeA = TypeOfCharacter(partA); | ||
typeB = TypeOfCharacter(partB); | ||
|
||
// Compare types | ||
if (typeA == typeB) { | ||
// Same type; we can compare | ||
if (typeA == kNumberType) { | ||
intA = atoi(partA.c_str()); | ||
intB = atoi(partB.c_str()); | ||
|
||
if (intA > intB) { | ||
return kDescending; | ||
} else if (intA < intB) { | ||
return kAscending; | ||
} | ||
} else if (typeA == kStringType) { | ||
short result = partA.compare(partB); | ||
switch (result) { | ||
case -1: return kAscending; break; | ||
case 1: return kDescending; break; | ||
case 0: /* do nothing */ break; | ||
}; | ||
} | ||
} else { | ||
// Not the same type? Now we have to do some validity checking | ||
if (typeA != kStringType && typeB == kStringType) { | ||
// typeA wins | ||
return kDescending; | ||
} else if (typeA == kStringType && typeB != kStringType) { | ||
// typeB wins | ||
return kAscending; | ||
} else { | ||
// One is a number and the other is a period. The period is invalid | ||
if (typeA == kNumberType) { | ||
return kDescending; | ||
} else { | ||
return kAscending; | ||
} | ||
} | ||
} | ||
} | ||
// The versions are equal up to the point where they both still have parts | ||
// Lets check to see if one is larger than the other | ||
if (partsA.size() != partsB.size()) { | ||
// Yep. Lets get the next part of the larger | ||
// n holds the index of the part we want. | ||
std::string missingPart = std::string(""); | ||
CharacterType missingType; | ||
ComparatorResult shorterResult, largerResult; | ||
|
||
if (partsA.size() > partsB.size()) { | ||
missingPart = partsA.at(n); | ||
shorterResult = kAscending; | ||
largerResult = kDescending; | ||
} else { | ||
missingPart = partsB.at(n); | ||
shorterResult = kDescending; | ||
largerResult = kAscending; | ||
} | ||
|
||
missingType = TypeOfCharacter(missingPart); | ||
// Check the type | ||
if (missingType == kStringType) { | ||
// It's a string. Shorter version wins | ||
return shorterResult; | ||
} else { | ||
// It's a number/period. Larger version wins | ||
return largerResult; | ||
} | ||
} | ||
|
||
// The 2 strings are identical | ||
return kSame; | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#ifndef FVVERSIONCOMPARATOR_H | ||
#define FVVERSIONCOMPARATOR_H | ||
|
||
#include <iosfwd> | ||
#include <vector> | ||
|
||
|
||
class FvVersionComparator | ||
{ | ||
public: | ||
|
||
typedef enum { | ||
kSame = 0, | ||
kDescending = 1, | ||
kAscending = -1 | ||
} ComparatorResult; | ||
|
||
static ComparatorResult CompareVersions(std::string versionA, | ||
std::string versionB); | ||
|
||
private: | ||
|
||
FvVersionComparator(); | ||
|
||
typedef enum { | ||
kNumberType, | ||
kStringType, | ||
kSeparatorType | ||
} CharacterType; | ||
|
||
static CharacterType TypeOfCharacter(std::string character); | ||
static std::vector<std::string> SplitVersionString(std::string version); | ||
|
||
}; | ||
|
||
#endif // FVVERSIONCOMPARATOR_H |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
#include "fvversioncomparatortest.h" | ||
#include "fvversioncomparator.h" | ||
|
||
|
||
void FvVersionComparatorTest::runAll() | ||
{ | ||
testNumbers(); | ||
testPrereleases(); | ||
testVersionsWithBuildNumbers(); | ||
} | ||
|
||
void FvVersionComparatorTest::testNumbers() | ||
{ | ||
QVERIFY(FvVersionComparator::CompareVersions("1.0", "1.1") == FvVersionComparator::kAscending); | ||
QVERIFY(FvVersionComparator::CompareVersions("1.0", "1.0") == FvVersionComparator::kSame); | ||
QVERIFY(FvVersionComparator::CompareVersions("2.0", "1.1") == FvVersionComparator::kDescending); | ||
QVERIFY(FvVersionComparator::CompareVersions("0.1", "0.0.1") == FvVersionComparator::kDescending); | ||
QVERIFY(FvVersionComparator::CompareVersions("0.1", "0.1.2") == FvVersionComparator::kAscending); | ||
} | ||
|
||
void FvVersionComparatorTest::testPrereleases() | ||
{ | ||
QVERIFY(FvVersionComparator::CompareVersions("1.0a1", "1.0b1") == FvVersionComparator::kAscending); | ||
QVERIFY(FvVersionComparator::CompareVersions("1.0b1", "1.0") == FvVersionComparator::kAscending); | ||
QVERIFY(FvVersionComparator::CompareVersions("0.9", "1.0a1") == FvVersionComparator::kAscending); | ||
QVERIFY(FvVersionComparator::CompareVersions("1.0b", "1.0b2") == FvVersionComparator::kAscending); | ||
QVERIFY(FvVersionComparator::CompareVersions("1.0b10", "1.0b11") == FvVersionComparator::kAscending); | ||
QVERIFY(FvVersionComparator::CompareVersions("1.0b9", "1.0b10") == FvVersionComparator::kAscending); | ||
QVERIFY(FvVersionComparator::CompareVersions("1.0rc", "1.0") == FvVersionComparator::kAscending); | ||
QVERIFY(FvVersionComparator::CompareVersions("1.0b", "1.0") == FvVersionComparator::kAscending); | ||
QVERIFY(FvVersionComparator::CompareVersions("1.0pre1", "1.0") == FvVersionComparator::kAscending); | ||
|
||
QVERIFY(FvVersionComparator::CompareVersions("1.0", "1.0pre1") == FvVersionComparator::kDescending); | ||
} | ||
|
||
void FvVersionComparatorTest::testVersionsWithBuildNumbers() | ||
{ | ||
QVERIFY(FvVersionComparator::CompareVersions("1.0 (1234)", "1.0 (1235)") == FvVersionComparator::kAscending); | ||
QVERIFY(FvVersionComparator::CompareVersions("1.0b1 (1234)", "1.0 (1234)") == FvVersionComparator::kAscending); | ||
QVERIFY(FvVersionComparator::CompareVersions("1.0b5 (1234)", "1.0b5 (1235)") == FvVersionComparator::kAscending); | ||
QVERIFY(FvVersionComparator::CompareVersions("1.0b5 (1234)", "1.0.1b5 (1234)") == FvVersionComparator::kAscending); | ||
QVERIFY(FvVersionComparator::CompareVersions("1.0.1b5 (1234)", "1.0.1b6 (1234)") == FvVersionComparator::kAscending); | ||
QVERIFY(FvVersionComparator::CompareVersions("3.3 (5847)", "3.3.1b1 (5902)") == FvVersionComparator::kAscending); | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#ifndef FVVERSIONCOMPARATORTEST_H | ||
#define FVVERSIONCOMPARATORTEST_H | ||
|
||
#include <QtTest/QtTest> | ||
|
||
|
||
class FvVersionComparatorTest : public QObject | ||
{ | ||
Q_OBJECT | ||
|
||
public slots: | ||
|
||
void runAll(); | ||
|
||
void testNumbers(); | ||
void testPrereleases(); | ||
void testVersionsWithBuildNumbers(); | ||
|
||
}; | ||
|
||
#endif // FVVERSIONCOMPARATORTEST_H |