]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
A number of baby steps for SQLTester.java. It can now handle basic --result cases.
authorstephan <stephan@noemail.net>
Tue, 8 Aug 2023 14:40:47 +0000 (14:40 +0000)
committerstephan <stephan@noemail.net>
Tue, 8 Aug 2023 14:40:47 +0000 (14:40 +0000)
FossilOrigin-Name: 0404f688f6a22b6bbe009de1bee3341ca00e19e2cc32081265cf151876dc032f

ext/jni/GNUmakefile
ext/jni/src/c/sqlite3-jni.c
ext/jni/src/org/sqlite/jni/ResultCode.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/Tester1.java
ext/jni/src/org/sqlite/jni/tester/Outer.java
ext/jni/src/org/sqlite/jni/tester/SQLTester.java
ext/jni/src/org/sqlite/jni/tester/TestScript.java
ext/jni/src/org/sqlite/jni/tester/test-script-interpreter.md
ext/jni/src/tests/000_first.test
manifest
manifest.uuid

index 66df5262258de5612f93399a980ccbd185b9fcfc..d6fc2e6d38bd5045e91eeb6112488fd226560270 100644 (file)
@@ -54,6 +54,7 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/%,\
   NativePointerHolder.java \
   OutputPointer.java \
   ProgressHandler.java \
+  ResultCode.java \
   RollbackHook.java \
   SQLFunction.java \
   sqlite3_context.java \
index 50676c35192e4cc31abfd9745fabf80c1b456cc8..66c62d6053c0174fa626c5ea4c3fb3512876a180 100644 (file)
@@ -2728,6 +2728,11 @@ end:
     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;
diff --git a/ext/jni/src/org/sqlite/jni/ResultCode.java b/ext/jni/src/org/sqlite/jni/ResultCode.java
new file mode 100644 (file)
index 0000000..30626f7
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+** 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);
+  }
+}
index 57df78e9f6734a4d08066d42f834fed0c7c743c6..3c67076469c718ed886d931ff6979d0da85e5e64 100644 (file)
@@ -102,23 +102,27 @@ public class Tester1 {
       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;
   }
 
index f86277d14d1d10d1b0db48de37d627fe52e4051b..e4ea783490c36af4dde622f3f8b3c224328032f4 100644 (file)
@@ -29,8 +29,7 @@ class Outer {
 
   @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")
@@ -41,7 +40,10 @@ class Outer {
 
   @SuppressWarnings("unchecked")
   public Outer verbose(Object... vals){
-    if(verbose) outln(vals);
+    if(verbose){
+      out("VERBOSE: ");
+      outln(vals);
+    }
     return this;
   }
 
index 5fad8a6c0b886574c87f04ed160181d7e871b26c..626e33a52396784782e51c9afbbbbca74516030a 100644 (file)
 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
@@ -40,6 +47,7 @@ public class SQLTester {
   private int nTest;
   private final sqlite3[] aDb = new sqlite3[7];
   private int iCurrentDb = 0;
+  private final String initialDbName = "test.db";
 
   public SQLTester(){
     reset();
@@ -48,6 +56,9 @@ public class SQLTester {
   public void setVerbose(boolean b){
     this.outer.setVerbose(b);
   }
+  public boolean isVerbose(){
+    return this.outer.isVerbose();
+  }
 
   @SuppressWarnings("unchecked")
   public void verbose(Object... vals){
@@ -67,42 +78,51 @@ public class SQLTester {
   //! 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;
   }
 
@@ -152,11 +172,18 @@ public class SQLTester {
     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.
@@ -164,7 +191,7 @@ public class SQLTester {
   void reset(){
     nTest = 0;
     nullView = "nil";
-    resetInputBuffer();
+    clearInputBuffer();
     closeAllDbs();
   }
 
@@ -172,6 +199,89 @@ public class SQLTester {
 
   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){
@@ -189,7 +299,7 @@ public class SQLTester {
       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).");
   }
 }
 
@@ -221,6 +331,7 @@ class Command {
 
   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.");
@@ -254,7 +365,7 @@ class CloseDbCommand extends Command {
     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;
       }
@@ -265,7 +376,7 @@ class CloseDbCommand extends Command {
       id = t.getCurrentDbId();
     }
     t.closeDb(id);
-    t.verbose(argv[0],"db",id);
+    t.verbose(argv[0]," db ",id);
   }
 }
 
@@ -274,7 +385,7 @@ class DbCommand extends Command {
     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);
   }
 }
 
@@ -284,7 +395,7 @@ class GlobCommand extends Command {
     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);
@@ -298,7 +409,7 @@ class NewDbCommand extends Command {
     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);
   }
 }
 
@@ -318,7 +429,7 @@ class NullCommand extends Command {
     argcCheck(argv,1);
     affirmNoContent(content);
     t.setNullValue(argv[1]);
-    //t.verbose(argv[0],argv[1]);
+    //t.verbose(argv[0]," ",argv[1]);
   }
 }
 
@@ -327,9 +438,8 @@ class OpenDbCommand extends Command {
     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);
   }
 }
 
@@ -343,9 +453,37 @@ class PrintCommand extends Command {
 
 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);
+    }
   }
 }
 
@@ -353,9 +491,10 @@ class TestCaseCommand extends Command {
   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);
   }
 }
 
@@ -373,6 +512,7 @@ class CommandDispatcher {
       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;
     }
@@ -382,14 +522,17 @@ class CommandDispatcher {
   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();
+    }
   }
 }
 
@@ -419,5 +562,4 @@ final class Util {
       /* ignore */
     }
   }
-
 }
index c1e26e7a0a23914d9f91b0efa114a709c2453e51..d5af694faa78763edcf2489669e35459d4bcd2dc 100644 (file)
@@ -84,7 +84,7 @@ class TestScript {
      (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;
   }
 
@@ -123,16 +123,16 @@ class TestScript {
         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;
@@ -147,7 +147,7 @@ class TestScript {
       }
       if( !chunk.isEmpty() ){
         ++i;
-        //verbose("CHUNK #"+i,""+ndxPrev,"..",""+pos,chunk);
+        //verbose("CHUNK #",i," ",+ndxPrev,"..",pos,chunk);
         rc.add( chunk );
       }
       ndxPrev = pos + 2;
@@ -157,7 +157,7 @@ class TestScript {
       chunk = tmp.substring(ndxPrev, tmp.length()).trim();
       if( !chunk.isEmpty() ){
         ++i;
-        //verbose("CHUNK #"+(++i),chunk);
+        //verbose("CHUNK #",(++i)," ",chunk);
         rc.add( chunk );
       }
     }
@@ -168,13 +168,14 @@ class TestScript {
      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(
index 345210b1dd2bbe810d0c12afd5c7dff74b50a240..ffaec1b13219766d14940c8e38561479d2d03222 100644 (file)
@@ -76,11 +76,11 @@ commands:
 
 ### 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
 
index 9321576245e59ef5944d1fe988eafdb93d45db60..c838582145ed647be9ee94075ed7ccaf424258b4 100644 (file)
@@ -1,4 +1,8 @@
-/* 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
 
@@ -6,15 +10,19 @@ junk
 
 --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 */
@@ -22,3 +30,6 @@ select 1
 select 'a'
 --notglob #
 --close
+--open SQLTester.db
+--print
+Re-opened db.
index 1616f77eafc6e2c1a63d92974ee37b12d9b6e638..e87960384097ba9ddc67aacd8e4e4c2dc79e0d80 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-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
@@ -230,9 +230,9 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
 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
@@ -249,10 +249,11 @@ F ext/jni/src/org/sqlite/jni/Fts5Tokenizer.java 91489893596b6528c0df5cd7180bd5b5
 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
@@ -264,11 +265,11 @@ F ext/jni/src/org/sqlite/jni/sqlite3.java 62b1b81935ccf3393472d17cb883dc5ff39c38
 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
@@ -2089,8 +2090,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 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.
index 13b058113a037e53e2ffac4ab26ccb709c990a63..19673fabb6a78a947ba482024b085ff790b529b5 100644 (file)
@@ -1 +1 @@
-3aa2b5a5cadb214dc64a3db412b7dfdd805abd8681b61da857b886cba3b937b5
\ No newline at end of file
+0404f688f6a22b6bbe009de1bee3341ca00e19e2cc32081265cf151876dc032f
\ No newline at end of file