1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-06 15:49:35 +03:00

Add the ".testcase" and ".check" dot-commands in the shell, when compiled

using SQLITE_DEBUG.

FossilOrigin-Name: 62289f27ee276090a855982bd8216a465e7d0a27
This commit is contained in:
drh
2016-09-15 21:35:24 +00:00
parent 98365be030
commit 2db8211526
3 changed files with 174 additions and 21 deletions

View File

@@ -1,5 +1,5 @@
C Omit\sthe\ssqlite3Apis\sconstant\sobject\swhen\scompiling\swith\nSQLITE_OMIT_LOAD_EXTENSION,\ssince\sit\sis\snot\sused. C Add\sthe\s".testcase"\sand\s".check"\sdot-commands\sin\sthe\sshell,\swhen\scompiled\nusing\sSQLITE_DEBUG.
D 2016-09-15T19:15:19.226 D 2016-09-15T21:35:24.532
F Makefile.in 6fd48ffcf7c2deea7499062d1f3747f986c19678 F Makefile.in 6fd48ffcf7c2deea7499062d1f3747f986c19678
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc e1aa788e84f926e42239ee167c53f785bedacacd F Makefile.msc e1aa788e84f926e42239ee167c53f785bedacacd
@@ -387,7 +387,7 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
F src/resolve.c 24f40fd0c3475821d1ad762a3f2c3455cc839b42 F src/resolve.c 24f40fd0c3475821d1ad762a3f2c3455cc839b42
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c 244f9cc5e4662987cd2ef5c22d1b7027560f3425 F src/select.c 244f9cc5e4662987cd2ef5c22d1b7027560f3425
F src/shell.c de7c7e98846cacbfbe062cbd98bca899dfb720e3 F src/shell.c 89a3adbfcaac17070372ce631161bbbf21ec2010
F src/sqlite.h.in 46ed821aeed0ba45559fb15597d9a400083154a2 F src/sqlite.h.in 46ed821aeed0ba45559fb15597d9a400083154a2
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 8648034aa702469afb553231677306cc6492a1ae F src/sqlite3ext.h 8648034aa702469afb553231677306cc6492a1ae
@@ -1525,7 +1525,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P b9f5bdbf40ac6382e48f09ebcd53cc908e065527 P 7b10461370828b9c57acaaaea518031d53986fa3
R 1e31cb38dfd2c7bbbb492df3fcbfb729 R 1d8691a695a03272769e683d2ed4d0b4
U drh U drh
Z 8ce374e092d6c15d6e5f3b801f1063a4 Z 15bb0e2011d42f4d3abf5a593439e046

View File

@@ -1 +1 @@
7b10461370828b9c57acaaaea518031d53986fa3 62289f27ee276090a855982bd8216a465e7d0a27

View File

@@ -2136,6 +2136,9 @@ static char zHelp[] =
".bail on|off Stop after hitting an error. Default OFF\n" ".bail on|off Stop after hitting an error. Default OFF\n"
".binary on|off Turn binary output on or off. Default OFF\n" ".binary on|off Turn binary output on or off. Default OFF\n"
".changes on|off Show number of rows changed by SQL\n" ".changes on|off Show number of rows changed by SQL\n"
#ifdef SQLITE_DEBUG
".check GLOB Fail if output since .testcase does not match\n"
#endif
".clone NEWDB Clone data into NEWDB from the existing database\n" ".clone NEWDB Clone data into NEWDB from the existing database\n"
".databases List names and files of attached databases\n" ".databases List names and files of attached databases\n"
".dbinfo ?DB? Show status information about the database\n" ".dbinfo ?DB? Show status information about the database\n"
@@ -2196,6 +2199,9 @@ static char zHelp[] =
".tables ?TABLE? List names of tables\n" ".tables ?TABLE? List names of tables\n"
" If TABLE specified, only list tables matching\n" " If TABLE specified, only list tables matching\n"
" LIKE pattern TABLE.\n" " LIKE pattern TABLE.\n"
#ifdef SQLITE_DEBUG
".testcase Begin redirecting output to 'testcase-out.txt'\n"
#endif
".timeout MS Try opening locked tables for MS milliseconds\n" ".timeout MS Try opening locked tables for MS milliseconds\n"
".timer on|off Turn SQL timer on or off\n" ".timer on|off Turn SQL timer on or off\n"
".trace FILE|off Output each SQL statement as it is run\n" ".trace FILE|off Output each SQL statement as it is run\n"
@@ -2232,6 +2238,31 @@ void session_help(ShellState *p){
/* Forward reference */ /* Forward reference */
static int process_input(ShellState *p, FILE *in); static int process_input(ShellState *p, FILE *in);
/*
** Read the content of a file into memory obtained from sqlite3_malloc64().
** The caller is responsible for freeing the memory.
**
** NULL is returned if any error is encountered.
*/
static char *readFile(const char *zName){
FILE *in = fopen(zName, "rb");
long nIn;
char *pBuf;
if( in==0 ) return 0;
fseek(in, 0, SEEK_END);
nIn = ftell(in);
rewind(in);
pBuf = sqlite3_malloc64( nIn );
if( pBuf==0 ) return 0;
if( 1!=fread(pBuf, nIn, 1, in) ){
sqlite3_free(pBuf);
return 0;
}
return pBuf;
}
/* /*
** Implementation of the "readfile(X)" SQL function. The entire content ** Implementation of the "readfile(X)" SQL function. The entire content
** of the file named X is read and returned as a BLOB. NULL is returned ** of the file named X is read and returned as a BLOB. NULL is returned
@@ -2243,25 +2274,13 @@ static void readfileFunc(
sqlite3_value **argv sqlite3_value **argv
){ ){
const char *zName; const char *zName;
FILE *in;
long nIn;
void *pBuf; void *pBuf;
UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argc);
zName = (const char*)sqlite3_value_text(argv[0]); zName = (const char*)sqlite3_value_text(argv[0]);
if( zName==0 ) return; if( zName==0 ) return;
in = fopen(zName, "rb"); pBuf = readFile(zName);
if( in==0 ) return; if( pBuf ) sqlite3_result_blob(context, pBuf, -1, sqlite3_free);
fseek(in, 0, SEEK_END);
nIn = ftell(in);
rewind(in);
pBuf = sqlite3_malloc64( nIn );
if( pBuf && 1==fread(pBuf, nIn, 1, in) ){
sqlite3_result_blob(context, pBuf, nIn, sqlite3_free);
}else{
sqlite3_free(pBuf);
}
fclose(in);
} }
/* /*
@@ -3063,6 +3082,106 @@ static int shellNomemError(void){
return 1; return 1;
} }
#ifdef SQLITE_DEBUG
/*
** Compare the pattern in zGlob[] against the text in z[]. Return TRUE
** if they match and FALSE (0) if they do not match.
**
** Globbing rules:
**
** '*' Matches any sequence of zero or more characters.
**
** '?' Matches exactly one character.
**
** [...] Matches one character from the enclosed list of
** characters.
**
** [^...] Matches one character not in the enclosed list.
**
** '#' Matches any sequence of one or more digits with an
** optional + or - sign in front
**
** ' ' Any span of whitespace matches any other span of
** whitespace.
**
** Extra whitespace at the end of z[] is ignored.
*/
static int testcase_glob(const char *zGlob, const char *z){
int c, c2;
int invert;
int seen;
while( (c = (*(zGlob++)))!=0 ){
if( IsSpace(c) ){
if( !IsSpace(*z) ) return 0;
while( IsSpace(*zGlob) ) zGlob++;
while( IsSpace(*z) ) z++;
}else if( c=='*' ){
while( (c=(*(zGlob++))) == '*' || c=='?' ){
if( c=='?' && (*(z++))==0 ) return 0;
}
if( c==0 ){
return 1;
}else if( c=='[' ){
while( *z && testcase_glob(zGlob-1,z)==0 ){
z++;
}
return (*z)!=0;
}
while( (c2 = (*(z++)))!=0 ){
while( c2!=c ){
c2 = *(z++);
if( c2==0 ) return 0;
}
if( testcase_glob(zGlob,z) ) return 1;
}
return 0;
}else if( c=='?' ){
if( (*(z++))==0 ) return 0;
}else if( c=='[' ){
int prior_c = 0;
seen = 0;
invert = 0;
c = *(z++);
if( c==0 ) return 0;
c2 = *(zGlob++);
if( c2=='^' ){
invert = 1;
c2 = *(zGlob++);
}
if( c2==']' ){
if( c==']' ) seen = 1;
c2 = *(zGlob++);
}
while( c2 && c2!=']' ){
if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){
c2 = *(zGlob++);
if( c>=prior_c && c<=c2 ) seen = 1;
prior_c = 0;
}else{
if( c==c2 ){
seen = 1;
}
prior_c = c2;
}
c2 = *(zGlob++);
}
if( c2==0 || (seen ^ invert)==0 ) return 0;
}else if( c=='#' ){
if( (z[0]=='-' || z[0]=='+') && IsDigit(z[1]) ) z++;
if( !IsDigit(z[0]) ) return 0;
z++;
while( IsDigit(z[0]) ){ z++; }
}else{
if( c!=(*(z++)) ) return 0;
}
}
while( IsSpace(*z) ){ z++; }
return *z==0;
}
#endif /* defined(SQLITE_DEBUG) */
/* /*
** Compare the string as a command-line option with either one or two ** Compare the string as a command-line option with either one or two
** initial "-" characters. ** initial "-" characters.
@@ -3225,6 +3344,29 @@ static int do_meta_command(char *zLine, ShellState *p){
} }
}else }else
#ifdef SQLITE_DEBUG
/* Cancel output redirection, if it is currently set (by .testcase)
** Then read the content of the testcase-out.txt file and compare against
** azArg[1]. If there are differences, report an error and exit.
*/
if( c=='c' && n>=3 && strncmp(azArg[0], "check", n)==0 ){
char *zRes = 0;
output_reset(p);
if( nArg!=2 ){
raw_printf(stderr, "Usage: .check GLOB-PATTERN\n");
rc = 1;
}else if( (zRes = readFile("testcase-out.txt"))==0 ){
raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n");
rc = 2;
}else if( testcase_glob(azArg[1],zRes)==0 ){
raw_printf(stderr, ".check failed\n Expected: [%s]\n Got: [%s]\n",
azArg[1], zRes);
rc = 2;
}
sqlite3_free(zRes);
}else
#endif
if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){ if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){
if( nArg==2 ){ if( nArg==2 ){
tryToClone(p, azArg[1]); tryToClone(p, azArg[1]);
@@ -4495,6 +4637,17 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_free(azResult); sqlite3_free(azResult);
}else }else
#ifdef SQLITE_DEBUG
/* Begin redirecting output to the file "testcase-out.txt" */
if( c=='t' && strcmp(azArg[0],"testcase")==0 ){
output_reset(p);
p->out = output_file_open("testcase-out.txt");
if( p->out==0 ){
utf8_printf(stderr, "Error: cannot open 'testcase-out.txt'\n");
}
}else
#endif
if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){ if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){
static const struct { static const struct {
const char *zCtrlName; /* Name of a test-control option */ const char *zCtrlName; /* Name of a test-control option */