NativePointerHolder.java \
OutputPointer.java \
ProgressHandler.java \
+ ResultCode.java \
RollbackHook.java \
SQLFunction.java \
sqlite3_context.java \
UNREF_L(jStmt);
jStmt = 0;
}
+#if 0
+ if( 0!=rc ){
+ MARKER(("prepare rc = %d\n", rc));
+ }
+#endif
OutputPointer_set_sqlite3_stmt(env, jOutStmt, jStmt);
(void)stmt_set_current(jc, pOldStmt);
return (jint)rc;
--- /dev/null
+/*
+** 2023-07-21
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file is part of the JNI bindings for the sqlite3 C API.
+*/
+package org.sqlite.jni;
+
+//! Internal level of indirection requires because we cannot reference
+// static enum members from an enum constructor.
+class ResultCodeMap {
+ private static final java.util.Map<Integer,ResultCode> i2e
+ = new java.util.HashMap<>();
+
+ public static void set(int i, ResultCode src){
+ i2e.put(i, src);
+ }
+ public static ResultCode get(int i){
+ return i2e.get(i);
+ }
+}
+
+/**
+ This enum of sqlite3 result codes is provided not for use with the
+ C-style API (with which it won't work) but for higher-level code which
+ may find it useful to map codes to human-readable names.
+*/
+public enum ResultCode {
+ SQLITE_OK(SQLite3Jni.SQLITE_OK),
+ SQLITE_ERROR(SQLite3Jni.SQLITE_ERROR),
+ SQLITE_INTERNAL(SQLite3Jni.SQLITE_INTERNAL),
+ SQLITE_PERM(SQLite3Jni.SQLITE_PERM),
+ SQLITE_ABORT(SQLite3Jni.SQLITE_ABORT),
+ SQLITE_BUSY(SQLite3Jni.SQLITE_BUSY),
+ SQLITE_LOCKED(SQLite3Jni.SQLITE_LOCKED),
+ SQLITE_NOMEM(SQLite3Jni.SQLITE_NOMEM),
+ SQLITE_READONLY(SQLite3Jni.SQLITE_READONLY),
+ SQLITE_INTERRUPT(SQLite3Jni.SQLITE_INTERRUPT),
+ SQLITE_IOERR(SQLite3Jni.SQLITE_IOERR),
+ SQLITE_CORRUPT(SQLite3Jni.SQLITE_CORRUPT),
+ SQLITE_NOTFOUND(SQLite3Jni.SQLITE_NOTFOUND),
+ SQLITE_FULL(SQLite3Jni.SQLITE_FULL),
+ SQLITE_CANTOPEN(SQLite3Jni.SQLITE_CANTOPEN),
+ SQLITE_PROTOCOL(SQLite3Jni.SQLITE_PROTOCOL),
+ SQLITE_EMPTY(SQLite3Jni.SQLITE_EMPTY),
+ SQLITE_SCHEMA(SQLite3Jni.SQLITE_SCHEMA),
+ SQLITE_TOOBIG(SQLite3Jni.SQLITE_TOOBIG),
+ SQLITE_CONSTRAINT(SQLite3Jni.SQLITE_CONSTRAINT),
+ SQLITE_MISMATCH(SQLite3Jni.SQLITE_MISMATCH),
+ SQLITE_MISUSE(SQLite3Jni.SQLITE_MISUSE),
+ SQLITE_NOLFS(SQLite3Jni.SQLITE_NOLFS),
+ SQLITE_AUTH(SQLite3Jni.SQLITE_AUTH),
+ SQLITE_FORMAT(SQLite3Jni.SQLITE_FORMAT),
+ SQLITE_RANGE(SQLite3Jni.SQLITE_RANGE),
+ SQLITE_NOTADB(SQLite3Jni.SQLITE_NOTADB),
+ SQLITE_NOTICE(SQLite3Jni.SQLITE_NOTICE),
+ SQLITE_WARNING(SQLite3Jni.SQLITE_WARNING),
+ SQLITE_ROW(SQLite3Jni.SQLITE_ROW),
+ SQLITE_DONE(SQLite3Jni.SQLITE_DONE),
+ SQLITE_ERROR_MISSING_COLLSEQ(SQLite3Jni.SQLITE_ERROR_MISSING_COLLSEQ),
+ SQLITE_ERROR_RETRY(SQLite3Jni.SQLITE_ERROR_RETRY),
+ SQLITE_ERROR_SNAPSHOT(SQLite3Jni.SQLITE_ERROR_SNAPSHOT),
+ SQLITE_IOERR_READ(SQLite3Jni.SQLITE_IOERR_READ),
+ SQLITE_IOERR_SHORT_READ(SQLite3Jni.SQLITE_IOERR_SHORT_READ),
+ SQLITE_IOERR_WRITE(SQLite3Jni.SQLITE_IOERR_WRITE),
+ SQLITE_IOERR_FSYNC(SQLite3Jni.SQLITE_IOERR_FSYNC),
+ SQLITE_IOERR_DIR_FSYNC(SQLite3Jni.SQLITE_IOERR_DIR_FSYNC),
+ SQLITE_IOERR_TRUNCATE(SQLite3Jni.SQLITE_IOERR_TRUNCATE),
+ SQLITE_IOERR_FSTAT(SQLite3Jni.SQLITE_IOERR_FSTAT),
+ SQLITE_IOERR_UNLOCK(SQLite3Jni.SQLITE_IOERR_UNLOCK),
+ SQLITE_IOERR_RDLOCK(SQLite3Jni.SQLITE_IOERR_RDLOCK),
+ SQLITE_IOERR_DELETE(SQLite3Jni.SQLITE_IOERR_DELETE),
+ SQLITE_IOERR_BLOCKED(SQLite3Jni.SQLITE_IOERR_BLOCKED),
+ SQLITE_IOERR_NOMEM(SQLite3Jni.SQLITE_IOERR_NOMEM),
+ SQLITE_IOERR_ACCESS(SQLite3Jni.SQLITE_IOERR_ACCESS),
+ SQLITE_IOERR_CHECKRESERVEDLOCK(SQLite3Jni.SQLITE_IOERR_CHECKRESERVEDLOCK),
+ SQLITE_IOERR_LOCK(SQLite3Jni.SQLITE_IOERR_LOCK),
+ SQLITE_IOERR_CLOSE(SQLite3Jni.SQLITE_IOERR_CLOSE),
+ SQLITE_IOERR_DIR_CLOSE(SQLite3Jni.SQLITE_IOERR_DIR_CLOSE),
+ SQLITE_IOERR_SHMOPEN(SQLite3Jni.SQLITE_IOERR_SHMOPEN),
+ SQLITE_IOERR_SHMSIZE(SQLite3Jni.SQLITE_IOERR_SHMSIZE),
+ SQLITE_IOERR_SHMLOCK(SQLite3Jni.SQLITE_IOERR_SHMLOCK),
+ SQLITE_IOERR_SHMMAP(SQLite3Jni.SQLITE_IOERR_SHMMAP),
+ SQLITE_IOERR_SEEK(SQLite3Jni.SQLITE_IOERR_SEEK),
+ SQLITE_IOERR_DELETE_NOENT(SQLite3Jni.SQLITE_IOERR_DELETE_NOENT),
+ SQLITE_IOERR_MMAP(SQLite3Jni.SQLITE_IOERR_MMAP),
+ SQLITE_IOERR_GETTEMPPATH(SQLite3Jni.SQLITE_IOERR_GETTEMPPATH),
+ SQLITE_IOERR_CONVPATH(SQLite3Jni.SQLITE_IOERR_CONVPATH),
+ SQLITE_IOERR_VNODE(SQLite3Jni.SQLITE_IOERR_VNODE),
+ SQLITE_IOERR_AUTH(SQLite3Jni.SQLITE_IOERR_AUTH),
+ SQLITE_IOERR_BEGIN_ATOMIC(SQLite3Jni.SQLITE_IOERR_BEGIN_ATOMIC),
+ SQLITE_IOERR_COMMIT_ATOMIC(SQLite3Jni.SQLITE_IOERR_COMMIT_ATOMIC),
+ SQLITE_IOERR_ROLLBACK_ATOMIC(SQLite3Jni.SQLITE_IOERR_ROLLBACK_ATOMIC),
+ SQLITE_IOERR_DATA(SQLite3Jni.SQLITE_IOERR_DATA),
+ SQLITE_IOERR_CORRUPTFS(SQLite3Jni.SQLITE_IOERR_CORRUPTFS),
+ SQLITE_LOCKED_SHAREDCACHE(SQLite3Jni.SQLITE_LOCKED_SHAREDCACHE),
+ SQLITE_LOCKED_VTAB(SQLite3Jni.SQLITE_LOCKED_VTAB),
+ SQLITE_BUSY_RECOVERY(SQLite3Jni.SQLITE_BUSY_RECOVERY),
+ SQLITE_BUSY_SNAPSHOT(SQLite3Jni.SQLITE_BUSY_SNAPSHOT),
+ SQLITE_BUSY_TIMEOUT(SQLite3Jni.SQLITE_BUSY_TIMEOUT),
+ SQLITE_CANTOPEN_NOTEMPDIR(SQLite3Jni.SQLITE_CANTOPEN_NOTEMPDIR),
+ SQLITE_CANTOPEN_ISDIR(SQLite3Jni.SQLITE_CANTOPEN_ISDIR),
+ SQLITE_CANTOPEN_FULLPATH(SQLite3Jni.SQLITE_CANTOPEN_FULLPATH),
+ SQLITE_CANTOPEN_CONVPATH(SQLite3Jni.SQLITE_CANTOPEN_CONVPATH),
+ SQLITE_CANTOPEN_SYMLINK(SQLite3Jni.SQLITE_CANTOPEN_SYMLINK),
+ SQLITE_CORRUPT_VTAB(SQLite3Jni.SQLITE_CORRUPT_VTAB),
+ SQLITE_CORRUPT_SEQUENCE(SQLite3Jni.SQLITE_CORRUPT_SEQUENCE),
+ SQLITE_CORRUPT_INDEX(SQLite3Jni.SQLITE_CORRUPT_INDEX),
+ SQLITE_READONLY_RECOVERY(SQLite3Jni.SQLITE_READONLY_RECOVERY),
+ SQLITE_READONLY_CANTLOCK(SQLite3Jni.SQLITE_READONLY_CANTLOCK),
+ SQLITE_READONLY_ROLLBACK(SQLite3Jni.SQLITE_READONLY_ROLLBACK),
+ SQLITE_READONLY_DBMOVED(SQLite3Jni.SQLITE_READONLY_DBMOVED),
+ SQLITE_READONLY_CANTINIT(SQLite3Jni.SQLITE_READONLY_CANTINIT),
+ SQLITE_READONLY_DIRECTORY(SQLite3Jni.SQLITE_READONLY_DIRECTORY),
+ SQLITE_ABORT_ROLLBACK(SQLite3Jni.SQLITE_ABORT_ROLLBACK),
+ SQLITE_CONSTRAINT_CHECK(SQLite3Jni.SQLITE_CONSTRAINT_CHECK),
+ SQLITE_CONSTRAINT_COMMITHOOK(SQLite3Jni.SQLITE_CONSTRAINT_COMMITHOOK),
+ SQLITE_CONSTRAINT_FOREIGNKEY(SQLite3Jni.SQLITE_CONSTRAINT_FOREIGNKEY),
+ SQLITE_CONSTRAINT_FUNCTION(SQLite3Jni.SQLITE_CONSTRAINT_FUNCTION),
+ SQLITE_CONSTRAINT_NOTNULL(SQLite3Jni.SQLITE_CONSTRAINT_NOTNULL),
+ SQLITE_CONSTRAINT_PRIMARYKEY(SQLite3Jni.SQLITE_CONSTRAINT_PRIMARYKEY),
+ SQLITE_CONSTRAINT_TRIGGER(SQLite3Jni.SQLITE_CONSTRAINT_TRIGGER),
+ SQLITE_CONSTRAINT_UNIQUE(SQLite3Jni.SQLITE_CONSTRAINT_UNIQUE),
+ SQLITE_CONSTRAINT_VTAB(SQLite3Jni.SQLITE_CONSTRAINT_VTAB),
+ SQLITE_CONSTRAINT_ROWID(SQLite3Jni.SQLITE_CONSTRAINT_ROWID),
+ SQLITE_CONSTRAINT_PINNED(SQLite3Jni.SQLITE_CONSTRAINT_PINNED),
+ SQLITE_CONSTRAINT_DATATYPE(SQLite3Jni.SQLITE_CONSTRAINT_DATATYPE),
+ SQLITE_NOTICE_RECOVER_WAL(SQLite3Jni.SQLITE_NOTICE_RECOVER_WAL),
+ SQLITE_NOTICE_RECOVER_ROLLBACK(SQLite3Jni.SQLITE_NOTICE_RECOVER_ROLLBACK),
+ SQLITE_WARNING_AUTOINDEX(SQLite3Jni.SQLITE_WARNING_AUTOINDEX),
+ SQLITE_AUTH_USER(SQLite3Jni.SQLITE_AUTH_USER),
+ SQLITE_OK_LOAD_PERMANENTLY(SQLite3Jni.SQLITE_OK_LOAD_PERMANENTLY);
+
+ public final int value;
+
+ ResultCode(int v){
+ value = v;
+ ResultCodeMap.set(v, this);
+ }
+
+ public static ResultCode getEntryForInt(int rc){
+ return ResultCodeMap.get(rc);
+ }
+}
rc = sqlite3_prepare_v2(db, sqlChunk, outStmt, oTail);
if(throwOnError) affirm(0 == rc);
else if( 0!=rc ) break;
- stmt = outStmt.getValue();
pos = oTail.getValue();
+ stmt = outStmt.getValue();
+ if( null == stmt ){
+ // empty statement was parsed.
+ continue;
+ }
affirm(0 != stmt.getNativePointer());
while( SQLITE_ROW == (rc = sqlite3_step(stmt)) ){
}
sqlite3_finalize(stmt);
affirm(0 == stmt.getNativePointer());
if(0!=rc && SQLITE_ROW!=rc && SQLITE_DONE!=rc){
- if(throwOnError){
- throw new RuntimeException("db op failed with rc="+rc);
- }else{
- break;
- }
+ break;
}
}
sqlite3_finalize(stmt);
if(SQLITE_ROW==rc || SQLITE_DONE==rc) rc = 0;
+ if( 0!=rc && throwOnError){
+ throw new RuntimeException("db op failed with rc="
+ +rc+": "+sqlite3_errmsg(db));
+ }
return rc;
}
@SuppressWarnings("unchecked")
public static void out(Object... vals){
- int n = 0;
- for(Object v : vals) out((n++>0 ? " " : "")+v);
+ for(Object v : vals) out(v);
}
@SuppressWarnings("unchecked")
@SuppressWarnings("unchecked")
public Outer verbose(Object... vals){
- if(verbose) outln(vals);
+ if(verbose){
+ out("VERBOSE: ");
+ outln(vals);
+ }
return this;
}
package org.sqlite.jni.tester;
import java.util.List;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.nio.charset.StandardCharsets;
import org.sqlite.jni.*;
import static org.sqlite.jni.SQLite3Jni.*;
+class TestFailure extends RuntimeException {
+ public TestFailure(String msg){
+ super(msg);
+ }
+}
/**
This class provides an application which aims to implement the
rudimentary SQL-driven test tool described in the accompanying
private int nTest;
private final sqlite3[] aDb = new sqlite3[7];
private int iCurrentDb = 0;
+ private final String initialDbName = "test.db";
public SQLTester(){
reset();
public void setVerbose(boolean b){
this.outer.setVerbose(b);
}
+ public boolean isVerbose(){
+ return this.outer.isVerbose();
+ }
@SuppressWarnings("unchecked")
public void verbose(Object... vals){
//! Adds the given test script to the to-test list.
public void addTestScript(String filename){
listInFiles.add(filename);
- verbose("Added file",filename);
+ verbose("Added file ",filename);
+ }
+
+ public void setupInitialDb() throws Exception {
+ Util.unlink(initialDbName);
+ openDb(0, initialDbName, true);
}
public void runTests() throws Exception {
// process each input file
- outln("Verbose =",outer.isVerbose());
+ outln("Verbose = ",outer.isVerbose());
for(String f : listInFiles){
reset();
+ setupInitialDb();
++nTestFile;
final TestScript ts = new TestScript(f);
- outln("---------> Test",ts.getName(),"...");
+ outln("---------> Test ",ts.getName()," ...");
ts.run(this);
- outln("<---------",nTest,"test(s) in",f);
+ outln("<--------- ",nTest," test(s) in ",f);
}
+ Util.unlink(initialDbName);
}
- private StringBuilder resetBuffer(StringBuilder b){
+ private StringBuilder clearBuffer(StringBuilder b){
b.delete(0, b.length());
return b;
}
- StringBuilder resetInputBuffer(){
- return resetBuffer(inputBuffer);
+ StringBuilder clearInputBuffer(){
+ return clearBuffer(inputBuffer);
}
- StringBuilder resetResultBuffer(){
- return resetBuffer(resultBuffer);
+ StringBuilder clearResultBuffer(){
+ return clearBuffer(resultBuffer);
}
StringBuilder getInputBuffer(){ return inputBuffer; }
String getInputBufferText(){ return inputBuffer.toString(); }
+ String getResultBufferText(){ return resultBuffer.toString(); }
+
private String takeBuffer(StringBuilder b){
final String rc = b.toString();
- resetBuffer(b);
+ clearBuffer(b);
return rc;
}
if( 0!=rc ){
final String msg = sqlite3_errmsg(db);
sqlite3_close(db);
- Util.toss("db open failed with code",rc,"and message:",msg);
+ Util.toss(TestFailure.class, "db open failed with code",
+ rc,"and message:",msg);
}
return aDb[iCurrentDb] = db;
}
+ sqlite3 openDb(int slot, String name, boolean createIfNeeded) throws Exception {
+ affirmDbId(slot);
+ iCurrentDb = slot;
+ return openDb(name, createIfNeeded);
+ }
+
/**
Resets all tester context state except for that related to
tracking running totals.
void reset(){
nTest = 0;
nullView = "nil";
- resetInputBuffer();
+ clearInputBuffer();
closeAllDbs();
}
void incrementTestCounter(){ ++nTest; ++nTotalTest; }
+ String escapeSqlValue(String v){
+ // TODO: implement the escaping rules
+ return v;
+ }
+
+ private void appendDbErr(sqlite3 db, StringBuilder sb, int rc){
+ sb.append(org.sqlite.jni.ResultCode.getEntryForInt(rc))
+ .append(' ')
+ .append(escapeSqlValue(sqlite3_errmsg(db)));
+ }
+
+ public int execSql(sqlite3 db, boolean throwOnError,
+ boolean appendToResult, String sql) throws Exception {
+ final OutputPointer.Int32 oTail = new OutputPointer.Int32();
+ final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt();
+ final byte[] sqlUtf8 = sql.getBytes(StandardCharsets.UTF_8);
+ if( null==db ) db = getCurrentDb();
+ int pos = 0, n = 1;
+ byte[] sqlChunk = sqlUtf8;
+ int rc = 0;
+ sqlite3_stmt stmt = null;
+ final StringBuilder sb = appendToResult ? resultBuffer : null;
+ //outln("sqlChunk len= = ",sqlChunk.length);
+ while(pos < sqlChunk.length){
+ if(pos > 0){
+ sqlChunk = Arrays.copyOfRange(sqlChunk, pos,
+ sqlChunk.length);
+ }
+ if( 0==sqlChunk.length ) break;
+ rc = sqlite3_prepare_v2(db, sqlChunk, outStmt, oTail);
+ /*outln("PREPARE rc ",rc," oTail=",oTail.getValue(),": ",
+ new String(sqlChunk,StandardCharsets.UTF_8),"\n<EOSQL>");*/
+ if( 0!=rc ){
+ if(throwOnError){
+ Util.toss(RuntimeException.class, "db op failed with rc="
+ +rc+": "+sqlite3_errmsg(db));
+ }else if( null!=sb ){
+ appendDbErr(db, sb, rc);
+ }
+ break;
+ }
+ pos = oTail.getValue();
+ stmt = outStmt.getValue();
+ if( null == stmt ){
+ // empty statement was parsed.
+ continue;
+ }
+ if( null!=sb ){
+ // Add the output to the result buffer...
+ final int nCol = sqlite3_column_count(stmt);
+ int spacing = 0;
+ while( SQLITE_ROW == (rc = sqlite3_step(stmt)) ){
+ for(int i = 0; i < nCol; ++i){
+ if( spacing++ > 0 ) sb.append(' ');
+ String val = sqlite3_column_text16(stmt, i);
+ if( null==val ){
+ sb.append( nullView );
+ continue;
+ }
+ sb.append( escapeSqlValue(val) );
+ }
+ //sb.append('\n');
+ }
+ }else{
+ while( SQLITE_ROW == (rc = sqlite3_step(stmt)) ){}
+ }
+ sqlite3_finalize(stmt);
+ if(SQLITE_ROW==rc || SQLITE_DONE==rc) rc = 0;
+ else if( rc!=0 ){
+ if( null!=sb ){
+ appendDbErr(db, sb, rc);
+ }
+ break;
+ }
+ }
+ sqlite3_finalize(stmt);
+ if( 0!=rc && throwOnError ){
+ Util.toss(RuntimeException.class, "db op failed with rc="
+ +rc+": "+sqlite3_errmsg(db));
+ }
+ return rc;
+ }
+
public static void main(String[] argv) throws Exception{
final SQLTester t = new SQLTester();
for(String a : argv){
t.addTestScript(a);
}
t.runTests();
- t.outer.outln("Processed",t.nTotalTest,"test(s) in",t.nTestFile,"file(s).");
+ t.outer.outln("Processed ",t.nTotalTest," test(s) in ",t.nTestFile," file(s).");
}
}
protected final void argcCheck(String[] argv, int min, int max) throws Exception{
int argc = argv.length-1;
+ if(max<0) max = 99999999;
if(argc<min || argc>max){
if( min==max ) Util.badArg(argv[0],"requires exactly",min,"argument(s)");
else Util.badArg(argv[0],"requires",min,"-",max,"arguments.");
if(argv.length>1){
String arg = argv[1];
if("all".equals(arg)){
- t.verbose(argv[0],"all dbs");
+ t.verbose(argv[0]," all dbs");
t.closeAllDbs();
return;
}
id = t.getCurrentDbId();
}
t.closeDb(id);
- t.verbose(argv[0],"db",id);
+ t.verbose(argv[0]," db ",id);
}
}
argcCheck(argv,1);
affirmNoContent(content);
final sqlite3 db = t.setCurrentDb( Integer.parseInt(argv[1]) );
- t.verbose(argv[0],"set db to",db);
+ t.verbose(argv[0]," set db to ",db);
}
}
argcCheck(argv,1);
affirmNoContent(content);
final String glob = argv[1].replace("#","[0-9]");
- t.verbose(argv[0],"is TODO. Pattern =",glob);
+ t.verbose(argv[0]," is TODO. Pattern = ",glob);
}
public GlobCommand(SQLTester t, String[] argv, String content) throws Exception{
this(false, t, argv, content);
String fname = argv[1];
Util.unlink(fname);
final sqlite3 db = t.openDb(fname, true);
- t.verbose(argv[0],"db",db);
+ t.verbose(argv[0]," db ",db);
}
}
argcCheck(argv,1);
affirmNoContent(content);
t.setNullValue(argv[1]);
- //t.verbose(argv[0],argv[1]);
+ //t.verbose(argv[0]," ",argv[1]);
}
}
argcCheck(argv,1);
affirmNoContent(content);
String fname = argv[1];
- Util.unlink(fname);
final sqlite3 db = t.openDb(fname, false);
- t.verbose(argv[0],"db",db);
+ t.verbose(argv[0]," db ",db);
}
}
class ResultCommand extends Command {
public ResultCommand(SQLTester t, String[] argv, String content) throws Exception{
- argcCheck(argv,0);
- //t.verbose(argv[0],"command is TODO");
+ argcCheck(argv,1,-1);
+ affirmNoContent(content);
t.incrementTestCounter();
+ final String sql = t.takeInputBuffer();
+ //t.verbose(argv[0]," SQL =\n",sql);
+ int rc = t.execSql(null, true, true, sql);
+ final String result = t.getResultBufferText().trim();
+ StringBuilder sbExpect = new StringBuilder();
+ for(int i = 1; i < argv.length; ++i ){
+ if( i>1 ) sbExpect.append(" ");
+ sbExpect.append( argv[i] );
+ }
+ final String sArgs = sbExpect.toString();
+ //t.verbose(argv[0]," rc = ",rc," result buffer:\n", result,"\nargs:\n",sArgs);
+ if( !result.equals(sArgs) ){
+ Util.toss(TestFailure.class, argv[0]," comparison failed.");
+ }
+ }
+}
+
+class RunCommand extends Command {
+ public RunCommand(SQLTester t, String[] argv, String content) throws Exception{
+ argcCheck(argv,0);
+ affirmHasContent(content);
+ int rc = t.execSql(null, false, false, content);
+ if( 0!=rc ){
+ sqlite3 db = t.getCurrentDb();
+ String msg = sqlite3_errmsg(db);
+ t.verbose(argv[0]," non-fatal command error #",rc,": ",
+ msg,"\nfor SQL:\n",content);
+ }
}
}
public TestCaseCommand(SQLTester t, String[] argv, String content) throws Exception{
argcCheck(argv,1);
affirmHasContent(content);
- t.resetInputBuffer();
- t.resetResultBuffer().append(content);
- t.verbose(argv[0],"result buffer:",content);
+ // TODO: do something with the test name
+ t.clearResultBuffer();
+ t.clearInputBuffer().append(content);
+ //t.verbose(argv[0]," input buffer: ",content);
}
}
case "open": return OpenDbCommand.class;
case "print": return PrintCommand.class;
case "result": return ResultCommand.class;
+ case "run": return RunCommand.class;
case "testcase": return TestCaseCommand.class;
default: return null;
}
static void dispatch(SQLTester tester, String[] argv, String content) throws Exception{
final Class cmdClass = getCommandByName(argv[0]);
if(null == cmdClass){
- throw new IllegalArgumentException(
- "No command handler found for '"+argv[0]+"'"
- );
+ Util.toss(IllegalArgumentException.class,
+ "No command handler found for '"+argv[0]+"'");
}
final java.lang.reflect.Constructor<Command> ctor =
cmdClass.getConstructor(SQLTester.class, String[].class, String.class);
- //tester.verbose("Running",argv[0],"...");
- ctor.newInstance(tester, argv, content);
+ try{
+ //tester.verbose("Running ",argv[0]," with:\n", content);
+ ctor.newInstance(tester, argv, content);
+ }catch(java.lang.reflect.InvocationTargetException e){
+ throw (Exception)e.getCause();
+ }
}
}
/* ignore */
}
}
-
}
(because it contains certain content which indicates such).
*/
public static boolean shouldBeIgnored(String content){
- return content.indexOf("SCRIPT_MODULE_NAME")>=0
+ return content.indexOf("SCRIPT_MODULE_NAME")<0
|| content.indexOf("\n|")>=0;
}
s, Pattern.MULTILINE
);
final Matcher m = p.matcher(tmp);
- /*verbose("Pattern {{{",p.pattern(),"}}} with flags",
- ""+p.flags(),"matches:"
+ /*verbose("Pattern {{{ ",p.pattern()," }}} with flags ",
+ p.flags()," matches:"
);*/
int n = 0;
- //while( m.find() ) verbose("#"+(++n)+"\t",m.group(0).trim());
+ //while( m.find() ) verbose("#",(++n),"\t",m.group(0).trim());
tmp = m.replaceAll("");
}
// Chunk the newly-cleaned text into individual commands and their input...
final List<String> rc = new ArrayList<>();
- final Pattern p = Pattern.compile("^--", Pattern.MULTILINE);
+ final Pattern p = Pattern.compile("^--[a-z]", Pattern.MULTILINE);
final Matcher m = p.matcher(tmp);
int ndxPrev = 0, pos = 0, i = 0;
String chunk;
}
if( !chunk.isEmpty() ){
++i;
- //verbose("CHUNK #"+i,""+ndxPrev,"..",""+pos,chunk);
+ //verbose("CHUNK #",i," ",+ndxPrev,"..",pos,chunk);
rc.add( chunk );
}
ndxPrev = pos + 2;
chunk = tmp.substring(ndxPrev, tmp.length()).trim();
if( !chunk.isEmpty() ){
++i;
- //verbose("CHUNK #"+(++i),chunk);
+ //verbose("CHUNK #",(++i)," ",chunk);
rc.add( chunk );
}
}
Runs this test script in the context of the given tester object.
*/
public void run(SQLTester tester) throws Exception {
+ this.setVerbose(tester.isVerbose());
if( null==chunks ){
- verbose("This contains content which forces it to be ignored.");
+ outer.outln("This test contains content which forces it to be skipped.");
}else{
int n = 0;
for(String chunk : chunks){
++n;
- //verbose("#"+n,c).verbose("<EOF>");
+ //outer.verbose("CHUNK #",n," ",chunk,"<EOF>");
final String[] parts = chunk.split("\\n", 2);
final String[] argv = parts[0].split("\\s+");
CommandDispatcher.dispatch(
### The --testcase command
-Every test case starts with a --testcase command. The --testcase command
-resets both the "input buffer" and the "result buffer".
-The argument to the --testcase command is the
-name of the test case. That test case name is used for logging and debugging
-and when printing errors.
+Every test case starts with a --testcase command. The --testcase
+command resets both the "input buffer" and the "result buffer". The
+argument to the --testcase command is the name of the test case. That
+test case name is used for logging and debugging and when printing
+errors. The input buffer is set to the body of the test case.
### The --result command
-/* A script for testing the org.sqlite.jni.tester infrastructure */
+/* A script for testing the org.sqlite.jni.tester infrastructure
+**
+** SCRIPT_MODULE_NAME: 000_first
+**
+*/
# this line is ignored
--new SQLTester.db
--null zilch
+--run
+select 1;
+select 2;
+-- comment
+intentional syntax error
--oom
--print
This is from the print command.
--- also ignored
--testcase first
-input for the first
-command;
---result
-hello world
+select 'a', 'b';
+select 'a', 'b';
+--result a b a b
--testcase second
select 1
--glob # /* ignored */
select 'a'
--notglob #
--close
+--open SQLTester.db
+--print
+Re-opened db.
-C Add\sa\sfew\swords\sof\sclarification\son\show\sthe\sSQLite\sTest\sScript\sInterpreter\nshould\sbe\sinitialized\sto\sstart\seach\stest\sscript.
-D 2023-08-08T14:25:47.658
+C A\snumber\sof\sbaby\ssteps\sfor\sSQLTester.java.\sIt\scan\snow\shandle\sbasic\s--result\scases.
+D 2023-08-08T14:40:47.725
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9
F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
-F ext/jni/GNUmakefile 0d071597509ef4a9ac4b7712dac9ef29ded0db4819721c3b3c15e24d534827f6
+F ext/jni/GNUmakefile ce9587e2a4be50babc2ef4600e5c1016340a1187b9e5770c78000acdd02996bd
F ext/jni/README.md e965674505e105626127ad45e628e4d19fcd379cdafc4d23c814c1ac2c55681d
-F ext/jni/src/c/sqlite3-jni.c d51d930573dc4b13a02a66da9281b3ef814aeabd4c294bf3d7fc499093237224
+F ext/jni/src/c/sqlite3-jni.c ae704d2486e1213ecdc78bbf62d00573d41409d375cc7a3b8e4720f8a764d0cd
F ext/jni/src/c/sqlite3-jni.h bc3ecd3f6e479fd45b80214f6256584cc599336ae222822fa1e603c22ff1fb19
F ext/jni/src/org/sqlite/jni/Authorizer.java 1308988f7f40579ea0e4deeaec3c6be971630566bd021c31367fe3f5140db892
F ext/jni/src/org/sqlite/jni/AutoExtension.java 3409ad8954d6466bf772e6be9379e0e337312b446b668287062845755a16844d
F ext/jni/src/org/sqlite/jni/NativePointerHolder.java 9c5d901cce4f7e57c3d623f4e2476f9f79a8eed6e51b2a603f37866018e040ee
F ext/jni/src/org/sqlite/jni/OutputPointer.java ebdd33d48064c3302d0d4a6dd345562a967f8420edad7c7509403be277d076a0
F ext/jni/src/org/sqlite/jni/ProgressHandler.java 6f62053a828a572de809828b1ee495380677e87daa29a1c57a0e2c06b0a131dc
+F ext/jni/src/org/sqlite/jni/ResultCode.java 7cdf993f2037ab7bd244c9a34dbaef2ace3beb5da5d7e7fda5c6f67634ceb647
F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564
F ext/jni/src/org/sqlite/jni/SQLFunction.java 09ce81c1c637e31c3a830d4c859cce95d65f5e02ff45f8bd1985b3479381bc46
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 3681e6ea94973ce1f7facd6887853a4ae5657a9274dd06279b586dbf77f36c2d
-F ext/jni/src/org/sqlite/jni/Tester1.java 57404879fbea78f0b405b7643abb03dad0a6ce6cea9ec0c4ef55ea40267be565
+F ext/jni/src/org/sqlite/jni/Tester1.java 22dca3ab0d93951382230f71e3cfb65898b80f12704a018c8ab9062df609b4fe
F ext/jni/src/org/sqlite/jni/TesterFts5.java cf2d687baafffdeba219b77cf611fd47a0556248820ea794ae3e8259bfbdc5ee
F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d
F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d
F ext/jni/src/org/sqlite/jni/sqlite3_context.java d26573fc7b309228cb49786e9078597d96232257defa955a3425d10897bca810
F ext/jni/src/org/sqlite/jni/sqlite3_stmt.java 78e6d1b95ac600a9475e9db4623f69449322b0c93d1bd4e1616e76ed547ed9fc
F ext/jni/src/org/sqlite/jni/sqlite3_value.java 3d1d4903e267bc0bc81d57d21f5e85978eff389a1a6ed46726dbe75f85e6914a
-F ext/jni/src/org/sqlite/jni/tester/Outer.java 07b5d68bdc4a01173f2515954a250dce6affcc4efb85b1ac50d24ad05b166bf4
-F ext/jni/src/org/sqlite/jni/tester/SQLTester.java 2261be136c31a432a7416fa86810b97a28a2ad8012463ae68f0975ceac38b42f
-F ext/jni/src/org/sqlite/jni/tester/TestScript.java 38652e01cab9c07b20741829f54ef2f4a5c25a73b2c77213dd9198d4268acc51
-F ext/jni/src/org/sqlite/jni/tester/test-script-interpreter.md a37dd71d1bd24773699b6efaa7ee37e616ae6c2e6554e7d46e0f759dde71f3e3
-F ext/jni/src/tests/000_first.test f58d5f22e2db31b20c6e744a247d14222508c88ed876b03a723c89f540948518
+F ext/jni/src/org/sqlite/jni/tester/Outer.java 3d9c40f8ed58ec0df05ca160986ea06ec84ec1f338b069cfba9604bbba467a01
+F ext/jni/src/org/sqlite/jni/tester/SQLTester.java f16d95e0eb89723010de955197164ea5da58a83852499004ec510f778681a8da
+F ext/jni/src/org/sqlite/jni/tester/TestScript.java 52350fb458d7d2816377a824c18c498c4a97f0026b64278f62ff1c382a92a070
+F ext/jni/src/org/sqlite/jni/tester/test-script-interpreter.md e66ee0de4f6b805afe7486f6826d4e1f26b449066c2ec6550b314950369a4ea2
+F ext/jni/src/tests/000_first.test 752aca36279f9b0ceedaf15a4ce6bc9e0b7f9ca2749287e204d81ca2f7e41e6f
F ext/jni/src/tests/010_ignored.test ce2de6742ff1bf98d8976fda0f260ff3d280e8f8c0a99309fb59fcfef2556fcd
F ext/lsm1/Makefile a553b728bba6c11201b795188c5708915cc4290f02b7df6ba7e8c4c943fd5cd9
F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 94628f88b5cc82832f0ca2b00fd5346bfe99323097c6e659c5ac818c4e31d3e9
-R 9b39d488601a6f92f9f4935ca5c0b938
-U drh
-Z 2b5a8bdcd64c73cfaa2188a49297111d
+P 3aa2b5a5cadb214dc64a3db412b7dfdd805abd8681b61da857b886cba3b937b5
+R 879a6e39ab778945869b54b1f498f7c6
+U stephan
+Z d614dd3e6aa20cfdef1208a3dc72efbf
# Remove this line to create a well-formed Fossil manifest.
-3aa2b5a5cadb214dc64a3db412b7dfdd805abd8681b61da857b886cba3b937b5
\ No newline at end of file
+0404f688f6a22b6bbe009de1bee3341ca00e19e2cc32081265cf151876dc032f
\ No newline at end of file