]>
Commit | Line | Data |
---|---|---|
1 | // -*- mode: cpp; mode: fold -*- | |
2 | // Description /*{{{*/ | |
3 | // $Id: versiontest.cc,v 1.5 2003/08/18 15:55:19 mdz Exp $ | |
4 | /* ###################################################################### | |
5 | ||
6 | Version Test - Simple program to run through a file and comare versions. | |
7 | ||
8 | Each version is compared and the result is checked against an expected | |
9 | result in the file. The format of the file is | |
10 | a b Res | |
11 | Where Res is -1, 1, 0. dpkg -D=1 --compare-versions a "<" b can be | |
12 | used to determine what Res should be. # at the start of the line | |
13 | is a comment and blank lines are skipped | |
14 | ||
15 | ##################################################################### */ | |
16 | /*}}}*/ | |
17 | #include <system.h> | |
18 | #include <apt-pkg/error.h> | |
19 | #include <apt-pkg/version.h> | |
20 | #include <apt-pkg/debversion.h> | |
21 | #include <iostream> | |
22 | #include <fstream> | |
23 | ||
24 | using namespace std; | |
25 | ||
26 | static int verrevcmp(const char *val, const char *ref) | |
27 | { | |
28 | int vc, rc; | |
29 | long vl, rl; | |
30 | const char *vp, *rp; | |
31 | ||
32 | if (!val) | |
33 | val = ""; | |
34 | if (!ref) | |
35 | ref = ""; | |
36 | for (;;) | |
37 | { | |
38 | vp = val; | |
39 | while (*vp && !isdigit(*vp)) | |
40 | vp++; | |
41 | rp = ref; | |
42 | while (*rp && !isdigit(*rp)) | |
43 | rp++; | |
44 | for (;;) | |
45 | { | |
46 | vc= val == vp ? 0 : *val++; | |
47 | rc= ref == rp ? 0 : *ref++; | |
48 | if (!rc && !vc) | |
49 | break; | |
50 | if (vc && !isalpha(vc)) | |
51 | vc += 256; /* assumes ASCII character set */ | |
52 | if (rc && !isalpha(rc)) | |
53 | rc += 256; | |
54 | if (vc != rc) | |
55 | return vc - rc; | |
56 | } | |
57 | val = vp; | |
58 | ref = rp; | |
59 | vl = 0; | |
60 | if (isdigit(*vp)) | |
61 | vl = strtol(val,(char**)&val,10); | |
62 | rl = 0; | |
63 | if (isdigit(*rp)) | |
64 | rl = strtol(ref,(char**)&ref,10); | |
65 | if (vl != rl) | |
66 | return vl - rl; | |
67 | if (!*val && !*ref) | |
68 | return 0; | |
69 | if (!*val) | |
70 | return -1; | |
71 | if (!*ref) | |
72 | return +1; | |
73 | } | |
74 | } | |
75 | ||
76 | #if 0 | |
77 | static int verrevcmp(const char *val, const char *ref) | |
78 | { | |
79 | int vc, rc; | |
80 | long vl, rl; | |
81 | const char *vp, *rp; | |
82 | ||
83 | if (!val) val= ""; | |
84 | if (!ref) ref= ""; | |
85 | for (;;) | |
86 | { | |
87 | vp= val; while (*vp && !isdigit(*vp) && *vp != '~') vp++; | |
88 | rp= ref; while (*rp && !isdigit(*rp) && *rp != '~') rp++; | |
89 | for (;;) | |
90 | { | |
91 | vc= val == vp ? 0 : *val++; | |
92 | rc= ref == rp ? 0 : *ref++; | |
93 | if (!rc && !vc) break; | |
94 | if (vc && !isalpha(vc)) vc += 256; /* assumes ASCII character set */ | |
95 | if (rc && !isalpha(rc)) rc += 256; | |
96 | if (vc != rc) return vc - rc; | |
97 | } | |
98 | ||
99 | val= vp; | |
100 | ref= rp; | |
101 | if (*vp == '~') val++; | |
102 | if (*rp == '~') ref++; | |
103 | vl=0; if (isdigit(*val)) vl= strtol(val,(char**)&val,10); | |
104 | rl=0; if (isdigit(*ref)) rl= strtol(ref,(char**)&ref,10); | |
105 | if (vl == 0 && rl == 0) | |
106 | { | |
107 | if (*vp == '~' && *rp != '~') return -1; | |
108 | if (*vp != '~' && *rp == '~') return +1; | |
109 | } | |
110 | if (*vp == '~') | |
111 | vl *= -1; | |
112 | if (*rp == '~') | |
113 | rl *= -1; | |
114 | if (vl != rl) return vl - rl; | |
115 | if (!*val && !*ref) return 0; | |
116 | if (!*val) | |
117 | { | |
118 | if (*ref == '~') | |
119 | return +1; | |
120 | else | |
121 | return -1; | |
122 | } | |
123 | ||
124 | if (!*ref) | |
125 | { | |
126 | if (*val == '~') | |
127 | return -1; | |
128 | else | |
129 | return +1; | |
130 | } | |
131 | } | |
132 | } | |
133 | #endif | |
134 | ||
135 | bool RunTest(const char *File) | |
136 | { | |
137 | ifstream F(File,ios::in); | |
138 | if (!F != 0) | |
139 | return false; | |
140 | ||
141 | char Buffer[300]; | |
142 | int CurLine = 0; | |
143 | ||
144 | while (1) | |
145 | { | |
146 | F.getline(Buffer,sizeof(Buffer)); | |
147 | CurLine++; | |
148 | if (F.eof() != 0) | |
149 | return true; | |
150 | if (!F != 0) | |
151 | return _error->Error("Line %u in %s is too long",CurLine,File); | |
152 | ||
153 | // Comment | |
154 | if (Buffer[0] == '#' || Buffer[0] == 0) | |
155 | continue; | |
156 | ||
157 | // First version | |
158 | char *I; | |
159 | char *Start = Buffer; | |
160 | for (I = Buffer; *I != 0 && *I != ' '; I++); | |
161 | string A(Start, I - Start); | |
162 | ||
163 | if (*I == 0) | |
164 | return _error->Error("Invalid line %u",CurLine); | |
165 | ||
166 | // Second version | |
167 | I++; | |
168 | Start = I; | |
169 | for (I = Start; *I != 0 && *I != ' '; I++); | |
170 | string B(Start,I - Start); | |
171 | ||
172 | if (*I == 0 || I[1] == 0) | |
173 | return _error->Error("Invalid line %u",CurLine); | |
174 | ||
175 | // Result | |
176 | I++; | |
177 | int Expected = atoi(I); | |
178 | int Res = debVS.CmpVersion(A.c_str(), B.c_str()); | |
179 | int Res2 = verrevcmp(A.c_str(),B.c_str()); | |
180 | cout << "'" << A << "' ? '" << B << "' = " << Res << " (= " << Expected << ") " << Res2 << endl; | |
181 | ||
182 | if (Res < 0) | |
183 | Res = -1; | |
184 | else if (Res > 0) | |
185 | Res = 1; | |
186 | ||
187 | if (Res != Expected) | |
188 | _error->Error("Comparison failed on line %u. '%s' ? '%s' %i != %i",CurLine,A.c_str(),B.c_str(),Res,Expected); | |
189 | ||
190 | // Check the reverse as well | |
191 | Expected = -1*Expected; | |
192 | Res = debVS.CmpVersion(B.c_str(), A.c_str()); | |
193 | Res2 = verrevcmp(B.c_str(),A.c_str()); | |
194 | ||
195 | cout << "'" << B << "' ? '" << A << "' = " << Res << " (= " << Expected << ") " << Res2 << endl; | |
196 | ||
197 | if (Res < 0) | |
198 | Res = -1; | |
199 | else if (Res > 0) | |
200 | Res = 1; | |
201 | ||
202 | if (Res != Expected) | |
203 | _error->Error("Comparison failed on line %u. '%s' ? '%s' %i != %i",CurLine,B.c_str(),A.c_str(),Res,Expected); | |
204 | } | |
205 | } | |
206 | ||
207 | int main(int argc, char *argv[]) | |
208 | { | |
209 | if (argc <= 1) | |
210 | { | |
211 | cerr << "You must specify a test file" << endl; | |
212 | return 0; | |
213 | } | |
214 | ||
215 | RunTest(argv[1]); | |
216 | ||
217 | // Print any errors or warnings found | |
218 | if (_error->empty() == false) | |
219 | { | |
220 | string Err; | |
221 | while (_error->empty() == false) | |
222 | { | |
223 | ||
224 | bool Type = _error->PopMessage(Err); | |
225 | if (Type == true) | |
226 | cout << "E: " << Err << endl; | |
227 | else | |
228 | cout << "W: " << Err << endl; | |
229 | } | |
230 | ||
231 | return 0; | |
232 | } | |
233 | } |