Fossil SCM

Improvements to error detection and reporting in the artifact parser. Add the test-parse-all-blobs command for verifying the artifact parser against historical repositories.

drh 2018-07-30 14:14 UTC forum-v2
Commit d2d1a86fa29f12a69735c90478d3638d4d50383d7134069dd5c7fe21c717cacb
1 file changed +58 -8
+58 -8
--- src/manifest.c
+++ src/manifest.c
@@ -421,11 +421,13 @@
421421
char cType;
422422
char *z;
423423
int n;
424424
char *zUuid;
425425
int sz = 0;
426
- int isRepeat, hasSelfRefTag = 0;
426
+ int isRepeat;
427
+ int nSelfTag = 0; /* Number of T cards referring to this manifest */
428
+ int nSimpleTag = 0; /* Number of T cards with "+" prefix */
427429
static Bag seen;
428430
const char *zErr = 0;
429431
unsigned int m;
430432
unsigned int seenCard = 0; /* Which card types have been seen */
431433
char zErrBuf[100]; /* Write error messages here */
@@ -882,24 +884,21 @@
882884
if( zUuid==0 ) SYNTAX("missing artifact hash on T-card");
883885
zValue = next_token(&x, 0);
884886
if( zValue ) defossilize(zValue);
885887
if( hname_validate(zUuid, sz) ){
886888
/* A valid artifact hash */
887
- if( p->zEventId ) SYNTAX("non-self-referential T-card in technote");
888889
}else if( sz==1 && zUuid[0]=='*' ){
889890
zUuid = 0;
890
- hasSelfRefTag = 1;
891
- if( p->zEventId && zName[0]!='+' ){
892
- SYNTAX("propagating T-card in event");
893
- }
891
+ nSelfTag++;
894892
}else{
895893
SYNTAX("malformed artifact hash on T-card");
896894
}
897895
defossilize(zName);
898896
if( zName[0]!='-' && zName[0]!='+' && zName[0]!='*' ){
899897
SYNTAX("T-card name does not begin with '-', '+', or '*'");
900898
}
899
+ if( zName[0]=='+' ) nSimpleTag++;
901900
if( validate16(&zName[1], strlen(&zName[1])) ){
902901
/* Do not allow tags whose names look like a hash */
903902
SYNTAX("T-card name looks like a hexadecimal hash");
904903
}
905904
if( p->nTag>=p->nTagAlloc ){
@@ -1018,10 +1017,23 @@
10181017
goto manifest_syntax_error;
10191018
}
10201019
10211020
/* Additional checks based on artifact type */
10221021
switch( p->type ){
1022
+ case CFTYPE_CONTROL: {
1023
+ if( nSelfTag ) SYNTAX("self-referential T-card in control artifact");
1024
+ break;
1025
+ }
1026
+ case CFTYPE_EVENT: {
1027
+ if( p->nTag!=nSelfTag ){
1028
+ SYNTAX("non-self-referential T-card in technote");
1029
+ }
1030
+ if( p->nTag!=nSimpleTag ){
1031
+ SYNTAX("T-card with '*' or '-' in technote");
1032
+ }
1033
+ break;
1034
+ }
10231035
case CFTYPE_FORUM: {
10241036
if( p->zThreadTitle && p->zInReplyTo ){
10251037
SYNTAX("cannot have I-card and H-card in a forum post");
10261038
}
10271039
if( p->nParent>1 ) SYNTAX("too many arguments to P-card");
@@ -1099,11 +1111,12 @@
10991111
/*
11001112
** COMMAND: test-parse-manifest
11011113
**
11021114
** Usage: %fossil test-parse-manifest FILENAME ?N?
11031115
**
1104
-** Parse the manifest and discarded. Use for testing only.
1116
+** Parse the manifest(s) given on the command-line and report any
1117
+** errors. If the N argument is given, run the parsing N times.
11051118
*/
11061119
void manifest_test_parse_cmd(void){
11071120
Manifest *p;
11081121
Blob b;
11091122
int i;
@@ -1123,10 +1136,47 @@
11231136
if( p==0 ) fossil_print("ERROR: %s\n", blob_str(&err));
11241137
blob_reset(&err);
11251138
manifest_destroy(p);
11261139
}
11271140
}
1141
+
1142
+/*
1143
+** COMMAND: test-parse-all-blobs
1144
+**
1145
+** Usage: %fossil test-parse-all-blobs
1146
+**
1147
+** Parse all entries in the BLOB table that are believed to be non-data
1148
+** artifacts and report any errors. Run this test command on historical
1149
+** repositories after making any changes to the manifest_parse()
1150
+** implementation to confirm that the changes did not break anything.
1151
+*/
1152
+void manifest_test_parse_all_blobs_cmd(void){
1153
+ Manifest *p;
1154
+ Blob err;
1155
+ Stmt q;
1156
+ int nTest = 0;
1157
+ int nErr = 0;
1158
+ db_find_and_open_repository(0, 0);
1159
+ verify_all_options();
1160
+ db_prepare(&q, "SELECT DISTINCT objid FROM EVENT");
1161
+ while( db_step(&q)==SQLITE_ROW ){
1162
+ int id = db_column_int(&q,0);
1163
+ fossil_print("Checking %d \r", id);
1164
+ nTest++;
1165
+ fflush(stdout);
1166
+ blob_init(&err, 0, 0);
1167
+ p = manifest_get(id, CFTYPE_ANY, &err);
1168
+ if( p==0 ){
1169
+ fossil_print("%d ERROR: %s\n", id, blob_str(&err));
1170
+ nErr++;
1171
+ }
1172
+ blob_reset(&err);
1173
+ manifest_destroy(p);
1174
+ }
1175
+ db_finalize(&q);
1176
+ fossil_print("%d tests with %d errors\n", nTest, nErr);
1177
+}
11281178
11291179
/*
11301180
** Fetch the baseline associated with the delta-manifest p.
11311181
** Return 0 on success. If unable to parse the baseline,
11321182
** throw an error. If the baseline is a manifest, throw an
@@ -2466,11 +2516,11 @@
24662516
blob_reset(&comment);
24672517
}
24682518
if( p->type==CFTYPE_FORUM ){
24692519
int froot, fprev, firt;
24702520
char *zFType;
2471
- const char *zTitle;
2521
+ char *zTitle;
24722522
schema_forum();
24732523
froot = p->zThreadRoot ? uuid_to_rid(p->zThreadRoot, 1) : rid;
24742524
fprev = p->nParent ? uuid_to_rid(p->azParent[0],1) : 0;
24752525
firt = p->zInReplyTo ? uuid_to_rid(p->zInReplyTo,1) : 0;
24762526
db_multi_exec(
24772527
--- src/manifest.c
+++ src/manifest.c
@@ -421,11 +421,13 @@
421 char cType;
422 char *z;
423 int n;
424 char *zUuid;
425 int sz = 0;
426 int isRepeat, hasSelfRefTag = 0;
 
 
427 static Bag seen;
428 const char *zErr = 0;
429 unsigned int m;
430 unsigned int seenCard = 0; /* Which card types have been seen */
431 char zErrBuf[100]; /* Write error messages here */
@@ -882,24 +884,21 @@
882 if( zUuid==0 ) SYNTAX("missing artifact hash on T-card");
883 zValue = next_token(&x, 0);
884 if( zValue ) defossilize(zValue);
885 if( hname_validate(zUuid, sz) ){
886 /* A valid artifact hash */
887 if( p->zEventId ) SYNTAX("non-self-referential T-card in technote");
888 }else if( sz==1 && zUuid[0]=='*' ){
889 zUuid = 0;
890 hasSelfRefTag = 1;
891 if( p->zEventId && zName[0]!='+' ){
892 SYNTAX("propagating T-card in event");
893 }
894 }else{
895 SYNTAX("malformed artifact hash on T-card");
896 }
897 defossilize(zName);
898 if( zName[0]!='-' && zName[0]!='+' && zName[0]!='*' ){
899 SYNTAX("T-card name does not begin with '-', '+', or '*'");
900 }
 
901 if( validate16(&zName[1], strlen(&zName[1])) ){
902 /* Do not allow tags whose names look like a hash */
903 SYNTAX("T-card name looks like a hexadecimal hash");
904 }
905 if( p->nTag>=p->nTagAlloc ){
@@ -1018,10 +1017,23 @@
1018 goto manifest_syntax_error;
1019 }
1020
1021 /* Additional checks based on artifact type */
1022 switch( p->type ){
 
 
 
 
 
 
 
 
 
 
 
 
 
1023 case CFTYPE_FORUM: {
1024 if( p->zThreadTitle && p->zInReplyTo ){
1025 SYNTAX("cannot have I-card and H-card in a forum post");
1026 }
1027 if( p->nParent>1 ) SYNTAX("too many arguments to P-card");
@@ -1099,11 +1111,12 @@
1099 /*
1100 ** COMMAND: test-parse-manifest
1101 **
1102 ** Usage: %fossil test-parse-manifest FILENAME ?N?
1103 **
1104 ** Parse the manifest and discarded. Use for testing only.
 
1105 */
1106 void manifest_test_parse_cmd(void){
1107 Manifest *p;
1108 Blob b;
1109 int i;
@@ -1123,10 +1136,47 @@
1123 if( p==0 ) fossil_print("ERROR: %s\n", blob_str(&err));
1124 blob_reset(&err);
1125 manifest_destroy(p);
1126 }
1127 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1128
1129 /*
1130 ** Fetch the baseline associated with the delta-manifest p.
1131 ** Return 0 on success. If unable to parse the baseline,
1132 ** throw an error. If the baseline is a manifest, throw an
@@ -2466,11 +2516,11 @@
2466 blob_reset(&comment);
2467 }
2468 if( p->type==CFTYPE_FORUM ){
2469 int froot, fprev, firt;
2470 char *zFType;
2471 const char *zTitle;
2472 schema_forum();
2473 froot = p->zThreadRoot ? uuid_to_rid(p->zThreadRoot, 1) : rid;
2474 fprev = p->nParent ? uuid_to_rid(p->azParent[0],1) : 0;
2475 firt = p->zInReplyTo ? uuid_to_rid(p->zInReplyTo,1) : 0;
2476 db_multi_exec(
2477
--- src/manifest.c
+++ src/manifest.c
@@ -421,11 +421,13 @@
421 char cType;
422 char *z;
423 int n;
424 char *zUuid;
425 int sz = 0;
426 int isRepeat;
427 int nSelfTag = 0; /* Number of T cards referring to this manifest */
428 int nSimpleTag = 0; /* Number of T cards with "+" prefix */
429 static Bag seen;
430 const char *zErr = 0;
431 unsigned int m;
432 unsigned int seenCard = 0; /* Which card types have been seen */
433 char zErrBuf[100]; /* Write error messages here */
@@ -882,24 +884,21 @@
884 if( zUuid==0 ) SYNTAX("missing artifact hash on T-card");
885 zValue = next_token(&x, 0);
886 if( zValue ) defossilize(zValue);
887 if( hname_validate(zUuid, sz) ){
888 /* A valid artifact hash */
 
889 }else if( sz==1 && zUuid[0]=='*' ){
890 zUuid = 0;
891 nSelfTag++;
 
 
 
892 }else{
893 SYNTAX("malformed artifact hash on T-card");
894 }
895 defossilize(zName);
896 if( zName[0]!='-' && zName[0]!='+' && zName[0]!='*' ){
897 SYNTAX("T-card name does not begin with '-', '+', or '*'");
898 }
899 if( zName[0]=='+' ) nSimpleTag++;
900 if( validate16(&zName[1], strlen(&zName[1])) ){
901 /* Do not allow tags whose names look like a hash */
902 SYNTAX("T-card name looks like a hexadecimal hash");
903 }
904 if( p->nTag>=p->nTagAlloc ){
@@ -1018,10 +1017,23 @@
1017 goto manifest_syntax_error;
1018 }
1019
1020 /* Additional checks based on artifact type */
1021 switch( p->type ){
1022 case CFTYPE_CONTROL: {
1023 if( nSelfTag ) SYNTAX("self-referential T-card in control artifact");
1024 break;
1025 }
1026 case CFTYPE_EVENT: {
1027 if( p->nTag!=nSelfTag ){
1028 SYNTAX("non-self-referential T-card in technote");
1029 }
1030 if( p->nTag!=nSimpleTag ){
1031 SYNTAX("T-card with '*' or '-' in technote");
1032 }
1033 break;
1034 }
1035 case CFTYPE_FORUM: {
1036 if( p->zThreadTitle && p->zInReplyTo ){
1037 SYNTAX("cannot have I-card and H-card in a forum post");
1038 }
1039 if( p->nParent>1 ) SYNTAX("too many arguments to P-card");
@@ -1099,11 +1111,12 @@
1111 /*
1112 ** COMMAND: test-parse-manifest
1113 **
1114 ** Usage: %fossil test-parse-manifest FILENAME ?N?
1115 **
1116 ** Parse the manifest(s) given on the command-line and report any
1117 ** errors. If the N argument is given, run the parsing N times.
1118 */
1119 void manifest_test_parse_cmd(void){
1120 Manifest *p;
1121 Blob b;
1122 int i;
@@ -1123,10 +1136,47 @@
1136 if( p==0 ) fossil_print("ERROR: %s\n", blob_str(&err));
1137 blob_reset(&err);
1138 manifest_destroy(p);
1139 }
1140 }
1141
1142 /*
1143 ** COMMAND: test-parse-all-blobs
1144 **
1145 ** Usage: %fossil test-parse-all-blobs
1146 **
1147 ** Parse all entries in the BLOB table that are believed to be non-data
1148 ** artifacts and report any errors. Run this test command on historical
1149 ** repositories after making any changes to the manifest_parse()
1150 ** implementation to confirm that the changes did not break anything.
1151 */
1152 void manifest_test_parse_all_blobs_cmd(void){
1153 Manifest *p;
1154 Blob err;
1155 Stmt q;
1156 int nTest = 0;
1157 int nErr = 0;
1158 db_find_and_open_repository(0, 0);
1159 verify_all_options();
1160 db_prepare(&q, "SELECT DISTINCT objid FROM EVENT");
1161 while( db_step(&q)==SQLITE_ROW ){
1162 int id = db_column_int(&q,0);
1163 fossil_print("Checking %d \r", id);
1164 nTest++;
1165 fflush(stdout);
1166 blob_init(&err, 0, 0);
1167 p = manifest_get(id, CFTYPE_ANY, &err);
1168 if( p==0 ){
1169 fossil_print("%d ERROR: %s\n", id, blob_str(&err));
1170 nErr++;
1171 }
1172 blob_reset(&err);
1173 manifest_destroy(p);
1174 }
1175 db_finalize(&q);
1176 fossil_print("%d tests with %d errors\n", nTest, nErr);
1177 }
1178
1179 /*
1180 ** Fetch the baseline associated with the delta-manifest p.
1181 ** Return 0 on success. If unable to parse the baseline,
1182 ** throw an error. If the baseline is a manifest, throw an
@@ -2466,11 +2516,11 @@
2516 blob_reset(&comment);
2517 }
2518 if( p->type==CFTYPE_FORUM ){
2519 int froot, fprev, firt;
2520 char *zFType;
2521 char *zTitle;
2522 schema_forum();
2523 froot = p->zThreadRoot ? uuid_to_rid(p->zThreadRoot, 1) : rid;
2524 fprev = p->nParent ? uuid_to_rid(p->azParent[0],1) : 0;
2525 firt = p->zInReplyTo ? uuid_to_rid(p->zInReplyTo,1) : 0;
2526 db_multi_exec(
2527

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button