- initial import of revision 374 from cnc
[apt.git] / test / versiontest.cc
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 }