Port the SQLTester 'v1' commands to the 'v2' evaluation bits. Still TODO is swapping out v1 with these separate impls.

FossilOrigin-Name: 0cf57e5b0f90779e450e9db1ca009610df5e6f4487337d49017636bde3bb02d6
This commit is contained in:
stephan 2023-08-09 23:47:14 +00:00
parent 35af4c5ff1
commit e35a703b76
5 changed files with 302 additions and 40 deletions

View File

@ -234,7 +234,7 @@ public class SQLTester {
sqlite3 getCurrentDb(){ return aDb[iCurrentDb]; }
sqlite3 getDbById(int id) throws Exception{
return affirmDbId(id).aDb[iCurrentDb];
return affirmDbId(id).aDb[id];
}
void closeDb(int id) throws Exception{

View File

@ -12,6 +12,8 @@
** This file contains the TestScript2 part of the SQLTester framework.
*/
package org.sqlite.jni.tester;
import static org.sqlite.jni.SQLite3Jni.*;
import org.sqlite.jni.sqlite3;
import java.util.Arrays;
import java.nio.charset.StandardCharsets;
import java.util.regex.*;
@ -22,6 +24,12 @@ class SQLTestException extends RuntimeException {
}
}
class TestScript2Failed extends SQLTestException {
public TestScript2Failed(TestScript2 ts, String msg){
super(ts.getOutputPrefix()+": "+msg);
}
}
class SkipTestRemainder2 extends SQLTestException {
public SkipTestRemainder2(TestScript2 ts){
super(ts.getOutputPrefix()+": skipping remainder");
@ -73,23 +81,221 @@ abstract class Command2 {
}
}
//! --close command
class CloseDbCommand2 extends Command2 {
public void process(SQLTester t, TestScript2 ts, String[] argv) throws Exception{
argcCheck(argv,0,1);
Integer id;
if(argv.length>1){
String arg = argv[1];
if("all".equals(arg)){
t.closeAllDbs();
return;
}
else{
id = Integer.parseInt(arg);
}
}else{
id = t.getCurrentDbId();
}
t.closeDb(id);
}
}
//! --db command
class DbCommand2 extends Command2 {
public void process(SQLTester t, TestScript2 ts, String[] argv) throws Exception{
argcCheck(argv,1);
t.setCurrentDb( Integer.parseInt(argv[1]) );
}
}
//! --glob command
class GlobCommand2 extends Command2 {
private boolean negate = false;
public GlobCommand2(){}
protected GlobCommand2(boolean negate){ this.negate = negate; }
public void process(SQLTester t, TestScript2 ts, String[] argv) throws Exception{
argcCheck(argv,1);
t.incrementTestCounter();
final String sql = t.takeInputBuffer();
int rc = t.execSql(null, true, ResultBufferMode.ESCAPED,
ResultRowMode.ONELINE, sql);
final String result = t.getResultText();
final String sArgs = Util.argvToString(argv);
//t.verbose(argv[0]," rc = ",rc," result buffer:\n", result,"\nargs:\n",sArgs);
final String glob = argv[1];
rc = SQLTester.strglob(glob, result);
if( (negate && 0==rc) || (!negate && 0!=rc) ){
ts.toss(argv[0], " mismatch: ", glob," vs input: ",result);
}
}
}
//! --json command
class JsonCommand2 extends ResultCommand2 {
public JsonCommand2(){ super(ResultBufferMode.ASIS); }
}
//! --json-block command
class JsonBlockCommand2 extends TableResultCommand2 {
public JsonBlockCommand2(){ super(true); }
}
//! --new command
class NewDbCommand2 extends OpenDbCommand2 {
public NewDbCommand2(){ super(true); }
}
//! Placeholder dummy/no-op commands
class NoopCommand2 extends Command2 {
public void process(SQLTester t, TestScript2 ts, String[] argv) throws Exception{
}
}
//! --notglob command
class NotGlobCommand2 extends GlobCommand2 {
public NotGlobCommand2(){
super(true);
}
}
//! --null command
class NullCommand2 extends Command2 {
public void process(
SQLTester st, TestScript2 ts, String[] argv
) throws Exception{
argcCheck(argv,1);
st.setNullValue( argv[1] );
}
}
//! --open command
class OpenDbCommand2 extends Command2 {
private boolean createIfNeeded = false;
public OpenDbCommand2(){}
protected OpenDbCommand2(boolean c){createIfNeeded = c;}
public void process(SQLTester t, TestScript2 ts, String[] argv) throws Exception{
argcCheck(argv,1);
t.openDb(argv[1], createIfNeeded);
}
}
//! --print command
class PrintCommand2 extends Command2 {
public void process(
SQLTester st, TestScript2 ts, String[] argv
) throws Exception{
st.out(ts.getOutputPrefix(),": ");
if( 1==argv.length ){
st.outln( st.getInputText() );
final String body = ts.fetchCommandBody();
if( 1==argv.length && null==body ){
st.out( st.getInputText() );
}else{
st.outln( Util.argvToString(argv) );
}
final String body = ts.fetchCommandBody();
if( null!=body ){
st.out(body,"\n");
st.out(body);
}
}
}
//! --result command
class ResultCommand2 extends Command2 {
private final ResultBufferMode bufferMode;
protected ResultCommand2(ResultBufferMode bm){ bufferMode = bm; }
public ResultCommand2(){ this(ResultBufferMode.ESCAPED); }
public void process(SQLTester t, TestScript2 ts, String[] argv) throws Exception{
argcCheck(argv,0,-1);
t.incrementTestCounter();
final String sql = t.takeInputBuffer();
//t.verbose(argv[0]," SQL =\n",sql);
int rc = t.execSql(null, false, bufferMode, ResultRowMode.ONELINE, sql);
final String result = t.getResultText().trim();
final String sArgs = argv.length>1 ? Util.argvToString(argv) : "";
if( !result.equals(sArgs) ){
t.outln(argv[0]," FAILED comparison. Result buffer:\n",
result,"\nargs:\n",sArgs);
ts.toss(argv[0]+" comparison failed.");
}
}
}
//! --run command
class RunCommand2 extends Command2 {
public void process(SQLTester t, TestScript2 ts, String[] argv) throws Exception{
argcCheck(argv,0,1);
final sqlite3 db = (1==argv.length)
? t.getCurrentDb() : t.getDbById( Integer.parseInt(argv[1]) );
final String sql = t.takeInputBuffer();
int rc = t.execSql(db, false, ResultBufferMode.NONE,
ResultRowMode.ONELINE, sql);
if( 0!=rc && t.isVerbose() ){
String msg = sqlite3_errmsg(db);
t.verbose(argv[0]," non-fatal command error #",rc,": ",
msg,"\nfor SQL:\n",sql);
}
}
}
//! --tableresult command
class TableResultCommand2 extends Command2 {
private final boolean jsonMode;
protected TableResultCommand2(boolean jsonMode){ this.jsonMode = jsonMode; }
public TableResultCommand2(){ this(false); }
public void process(SQLTester t, TestScript2 ts, String[] argv) throws Exception{
argcCheck(argv,0);
t.incrementTestCounter();
String body = ts.fetchCommandBody();
if( null==body ) ts.toss("Missing ",argv[0]," body.");
body = body.trim();
if( !body.endsWith("\n--end") ){
ts.toss(argv[0], " must be terminated with --end.");
}else{
int n = body.length();
body = body.substring(0, n-6);
}
final String[] globs = body.split("\\s*\\n\\s*");
if( globs.length < 1 ){
ts.toss(argv[0], " requires 1 or more ",
(jsonMode ? "json snippets" : "globs"),".");
}
final String sql = t.takeInputBuffer();
t.execSql(null, true,
jsonMode ? ResultBufferMode.ASIS : ResultBufferMode.ESCAPED,
ResultRowMode.NEWLINE, sql);
final String rbuf = t.getResultText();
final String[] res = rbuf.split("\n");
if( res.length != globs.length ){
ts.toss(argv[0], " failure: input has ", res.length,
" row(s) but expecting ",globs.length);
}
for(int i = 0; i < res.length; ++i){
final String glob = globs[i].replaceAll("\\s+"," ").trim();
//t.verbose(argv[0]," <<",glob,">> vs <<",res[i],">>");
if( jsonMode ){
if( !glob.equals(res[i]) ){
ts.toss(argv[0], " json <<",glob, ">> does not match: <<",
res[i],">>");
}
}else if( 0 != SQLTester.strglob(glob, res[i]) ){
ts.toss(argv[0], " glob <<",glob,">> does not match: <<",res[i],">>");
}
}
}
}
//! --testcase command
class TestCaseCommand2 extends Command2 {
public void process(SQLTester t, TestScript2 ts, String[] argv) throws Exception{
argcCheck(argv,1);
// TODO?: do something with the test name
final String body = ts.fetchCommandBody();
t.clearResultBuffer();
t.clearInputBuffer().append(null==body ? "" : body);
}
}
class CommandDispatcher2 {
private static java.util.Map<String,Command2> commandMap =
@ -103,7 +309,21 @@ class CommandDispatcher2 {
Command2 rv = commandMap.get(name);
if( null!=rv ) return rv;
switch(name){
case "close": rv = new CloseDbCommand2(); break;
case "db": rv = new DbCommand2(); break;
case "glob": rv = new GlobCommand2(); break;
case "json": rv = new JsonCommand2(); break;
case "json-block": rv = new JsonBlockCommand2(); break;
case "new": rv = new NewDbCommand2(); break;
case "notglob": rv = new NotGlobCommand2(); break;
case "null": rv = new NullCommand2(); break;
case "oom": rv = new NoopCommand2(); break;
case "open": rv = new OpenDbCommand2(); break;
case "print": rv = new PrintCommand2(); break;
case "result": rv = new ResultCommand2(); break;
case "run": rv = new RunCommand2(); break;
case "tableresult": rv = new TableResultCommand2(); break;
case "testcase": rv = new TestCaseCommand2(); break;
default: rv = null; break;
}
if( null!=rv ) commandMap.put(name, rv);
@ -187,11 +407,10 @@ class TestScript2 {
return "["+(moduleName==null ? filename : moduleName)+"] line "+
cur.lineNo;
}
@SuppressWarnings("unchecked")
private TestScript2 verbose(Object... vals){
private TestScript2 verboseN(int level, Object... vals){
final int verbosity = outer.getVerbosity();
if(verbosity>0){
if(verbosity>=level){
outer.out("VERBOSE",(verbosity>1 ? "+ " : " "),
getOutputPrefix(),": ");
outer.outln(vals);
@ -199,6 +418,9 @@ class TestScript2 {
return this;
}
private TestScript2 verbose1(Object... vals){return verboseN(1,vals);}
private TestScript2 verbose2(Object... vals){return verboseN(2,vals);}
@SuppressWarnings("unchecked")
public TestScript2 warn(Object... vals){
outer.out("WARNING ", getOutputPrefix(),": ");
@ -355,7 +577,7 @@ class TestScript2 {
if(line.startsWith("#")){
throw new IncompatibleDirective(this, "C-preprocessor input: "+line);
}else if(line.startsWith("---")){
new IncompatibleDirective(this, "Triple-dash: "+line);
new IncompatibleDirective(this, "triple-dash: "+line);
}
Matcher m = patternScriptModuleName.matcher(line);
if( m.find() ){
@ -370,12 +592,19 @@ class TestScript2 {
if( m.find() ){
throw new IncompatibleDirective(this, m.group(1)+": "+m.group(3));
}
if( line.indexOf("\n|")>=0 ){
throw new IncompatibleDirective(this, "newline-pipe combination.");
}
return;
}
public boolean isCommandLine(String line){
public boolean isCommandLine(String line, boolean checkForImpl){
final Matcher m = patternCommand.matcher(line);
return m.find();
boolean rc = m.find();
if( rc && checkForImpl ){
rc = null!=CommandDispatcher2.getCommandByName(m.group(2));
}
return rc;
}
/**
@ -388,33 +617,45 @@ class TestScript2 {
}
/**
Fetches lines until the next command. Throws if
Fetches lines until the next recognized command. Throws if
checkForDirective() does. Returns null if there is no input or
it's only whitespace. The returned string is trim()'d of
leading/trailing whitespace.
it's only whitespace. The returned string retains all whitespace.
Note that "subcommands", --command-like constructs in the body
which do not match a known command name are considered to be
content, not commands.
*/
public String fetchCommandBody(){
final StringBuilder sb = new StringBuilder();
String line;
while( (null != (line = peekLine())) ){
checkForDirective(line);
if( !isCommandLine(line) ){
if( !isCommandLine(line, true) ){
sb.append(line).append("\n");
consumePeeked();
}else{
break;
}
}
line = sb.toString().trim();
return line.isEmpty() ? null : line;
line = sb.toString();
return line.trim().isEmpty() ? null : line;
}
public void processCommand(SQLTester t, String[] argv) throws Exception{
//verbose("got argv: ",argv[0], " ", Util.argvToString(argv));
//verbose("Input buffer = ",t.getInputBuffer());
verbose1("running command: ",argv[0], " ", Util.argvToString(argv));
if(outer.getVerbosity()>1){
final String input = t.getInputText();
if( !input.isEmpty() ) verbose2("Input buffer = ",input);
}
CommandDispatcher2.dispatch(t, this, argv);
}
public void toss(Object... msg) throws TestScript2Failed {
StringBuilder sb = new StringBuilder();
for(Object s : msg) sb.append(s);
throw new TestScript2Failed(this, sb.toString());
}
/**
Runs this test script in the context of the given tester object.
*/

View File

@ -1,4 +1,4 @@
/*
/*
** This is a comment. There are many like it but this one is mine.
**
** SCRIPT_MODULE_NAME: sanity-check
@ -8,14 +8,35 @@
** REQUIRED_PROPERTIES:
**
*/
/*#if foo*/
/*---foo*/
/* --print without flags dumps current input buffer */
--print
non-command/non-directive text after --print is also emitted.
--print 🤩😃
SELECT 1;
SELECT 2;
--print the end
--close all
--oom
--db 0
--new my.db
--null zilch
--testcase 1.0
SELECT 1, null;
--result 1 zilch
--glob *zil*
--notglob *ZIL*
SELECT 1, 2;
intentional error;
--run
--testcase json-1
SELECT json_array(1,2,3)
--json [1,2,3]
--testcase tableresult-1
select 1, 'a';
select 2, 'b';
--tableresult
# [a-z]
2 b
--end
--testcase json-block-1
select json_array(1,2,3);
select json_object('a',1,'b',2);
--json-block
[1,2,3]
{"a":1,"b":2}
--end
--close
--print 🤩😃 the end

View File

@ -1,5 +1,5 @@
C Correct\sREQUIRED_PROPERTIES\shandling\sto\snot\sfail\sif\sthere\sare\sno\sproperties.
D 2023-08-09T22:30:10.275
C Port\sthe\sSQLTester\s'v1'\scommands\sto\sthe\s'v2'\sevaluation\sbits.\sStill\sTODO\sis\sswapping\sout\sv1\swith\sthese\sseparate\simpls.
D 2023-08-09T23:47:14.521
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -266,11 +266,11 @@ F ext/jni/src/org/sqlite/jni/sqlite3_context.java d26573fc7b309228cb49786e907859
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 b06acf9c79e8dbc8fea4a98b00724a6a76e3ee4503eb114671d2885f8fb3df8b
F ext/jni/src/org/sqlite/jni/tester/SQLTester.java 2663dffe3977b73730ba3cbdd6dc0fe053699479759b75bb46c1f966773f0b76
F ext/jni/src/org/sqlite/jni/tester/SQLTester.java 1ae38d872d2cb582e1a1abd67b5e9c276bf2f610cacc918428b63c668131642e
F ext/jni/src/org/sqlite/jni/tester/TestScript.java 463021981a65ffe7147a1bfada557b275b0cba3c33176ac328502ff09d146f28
F ext/jni/src/org/sqlite/jni/tester/TestScript2.java 3fc6700ab92e614f61856eeb87469589e57342cb66f5c4f9de425b45425f278f
F ext/jni/src/org/sqlite/jni/tester/TestScript2.java 25895a534a1e4634268beecd1a689bdfc0aafbfe32071c27b5189ccb8aeec31e
F ext/jni/src/org/sqlite/jni/tester/test-script-interpreter.md ab7169b08566a082ef55c9ef8a553827f99958ed3e076f31eef757563fae51ba
F ext/jni/src/tests/000-000-sanity.test2 dca0364ca25dacdff38355870fee51be7112eade930b3597c808c2f88c44a782
F ext/jni/src/tests/000-000-sanity.test2 dfbcccc7b3548ae56deb2ef8fe17dd9235a81fbd552536ef9202284549c7fcf3
F ext/jni/src/tests/000_first.test cd5fb732520cf36d7a3e5ad94a274c7327a9504b01a1a7f98e1f946df6c539fd
F ext/jni/src/tests/010_ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70
F ext/lsm1/Makefile a553b728bba6c11201b795188c5708915cc4290f02b7df6ba7e8c4c943fd5cd9
@ -2092,8 +2092,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 4fa2ad33edbcef393dd98dbf90586ad8f32ec0beab02f197c8038a44be86c314
R c8b3185b3c963903b037db53ffaa5711
P 7a19bef4f572a90fb7896b9360f9c72b052955ca9b0549be870b2b245c1f1b2b
R eed3d04c8636ba991a620a2a8f5a013d
U stephan
Z f51d1e9a0eee42db59afa92b063b01d4
Z bdeddd00da26b413ab473bf39ad731fc
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
7a19bef4f572a90fb7896b9360f9c72b052955ca9b0549be870b2b245c1f1b2b
0cf57e5b0f90779e450e9db1ca009610df5e6f4487337d49017636bde3bb02d6