1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-30 19:03:16 +03:00

Initial skeleton for adding an SQL-driven test script interpreter for the JNI bindings.

FossilOrigin-Name: 2aa8f0edecd3fc30eec28987cdbf1003ace154ddc1447b6f8715ecf38d3b06fb
This commit is contained in:
stephan
2023-08-07 21:04:13 +00:00
parent c7f7b45a15
commit 3897a882f7
7 changed files with 358 additions and 10 deletions

View File

@ -24,6 +24,7 @@ dir.src.c := $(dir.src)/c
dir.bld := $(dir.jni)/bld dir.bld := $(dir.jni)/bld
dir.bld.c := $(dir.bld) dir.bld.c := $(dir.bld)
dir.src.jni := $(dir.src)/org/sqlite/jni dir.src.jni := $(dir.src)/org/sqlite/jni
dir.src.jni.tester := $(dir.src.jni)/tester
$(dir.bld.c): $(dir.bld.c):
mkdir -p $@ mkdir -p $@
@ -34,7 +35,9 @@ DISTCLEAN_FILES := $(dir.jni)/*~ $(dir.src.c)/*~ $(dir.src.jni)/*~
sqlite3-jni.h := $(dir.src.c)/sqlite3-jni.h sqlite3-jni.h := $(dir.src.c)/sqlite3-jni.h
.NOTPARALLEL: $(sqlite3-jni.h) .NOTPARALLEL: $(sqlite3-jni.h)
SQLite3Jni.java := src/org/sqlite/jni/SQLite3Jni.java SQLite3Jni.java := src/org/sqlite/jni/SQLite3Jni.java
SQLite3Jni.class := $(subst .java,.class,$(SQLite3Jni.java)) SQLTester.java := src/org/sqlite/jni/tester/SQLTester.java
SQLite3Jni.class := $(SQLite3Jni.java:.java=.class)
SQLTester.class := $(SQLTester.java:.java=.class)
######################################################################## ########################################################################
# The future of FTS5 customization in this API is as yet unclear. # The future of FTS5 customization in this API is as yet unclear.
@ -43,7 +46,7 @@ enable.fts5 ?= 1
# Be explicit about which Java files to compile so that we can work on # Be explicit about which Java files to compile so that we can work on
# in-progress files without requiring them to be in a compilable statae. # in-progress files without requiring them to be in a compilable statae.
JAVA_FILES := $(patsubst %,$(dir.src.jni)/%,\ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/%,\
BusyHandler.java \ BusyHandler.java \
Collation.java \ Collation.java \
CollationNeeded.java \ CollationNeeded.java \
@ -64,7 +67,7 @@ JAVA_FILES := $(patsubst %,$(dir.src.jni)/%,\
ValueHolder.java \ ValueHolder.java \
) )
ifeq (1,$(enable.fts5)) ifeq (1,$(enable.fts5))
JAVA_FILES += $(patsubst %,$(dir.src.jni)/%,\ JAVA_FILES.main += $(patsubst %,$(dir.src.jni)/%,\
fts5_api.java \ fts5_api.java \
fts5_extension_function.java \ fts5_extension_function.java \
fts5_tokenizer.java \ fts5_tokenizer.java \
@ -77,6 +80,16 @@ ifeq (1,$(enable.fts5))
TesterFts5.java \ TesterFts5.java \
) )
endif endif
JAVA_FILES.tester := $(patsubst %,$(dir.src.jni.tester)/%,\
SQLTester.java \
TestScript.java \
)
CLASS_FILES.main := $(JAVA_FILES.main:.java=.class)
CLASS_FILES.tester := $(JAVA_FILES.tester:.java=.class)
JAVA_FILES += $(JAVA_FILES.main) $(JAVA_FILES.tester)
CLASS_FILES := CLASS_FILES :=
define DOTCLASS_DEPS define DOTCLASS_DEPS
$(1).class: $(1).java $(MAKEFILE) $(1).class: $(1).java $(MAKEFILE)
@ -84,6 +97,7 @@ all: $(1).class
CLASS_FILES += $(1).class CLASS_FILES += $(1).class
endef endef
$(foreach B,$(basename $(JAVA_FILES)),$(eval $(call DOTCLASS_DEPS,$(B)))) $(foreach B,$(basename $(JAVA_FILES)),$(eval $(call DOTCLASS_DEPS,$(B))))
$(CLASS_FILES.tester): $(CLASS_FILES.main)
javac.flags ?= -Xlint:unchecked -Xlint:deprecation javac.flags ?= -Xlint:unchecked -Xlint:deprecation
java.flags ?= java.flags ?=
jnicheck ?= 1 jnicheck ?= 1
@ -193,12 +207,21 @@ $(sqlite3-jni.dll): $(dir.bld.c) $(sqlite3-jni.c) $(SQLite3Jni.java) $(MAKEFILE)
$(sqlite3-jni.c) -shared -o $@ $(sqlite3-jni.c) -shared -o $@
all: $(sqlite3-jni.dll) all: $(sqlite3-jni.dll)
.PHONY: test
test.flags ?= -v test.flags ?= -v
test: $(SQLite3Jni.class) $(sqlite3-jni.dll) test: $(SQLite3Jni.class) $(sqlite3-jni.dll)
$(bin.java) -ea -Djava.library.path=$(dir.bld.c) \ $(bin.java) -ea -Djava.library.path=$(dir.bld.c) \
$(java.flags) -cp $(classpath) \ $(java.flags) -cp $(classpath) \
org.sqlite.jni.Tester1 $(if $(test.flags),-- $(test.flags),) org.sqlite.jni.Tester1 $(if $(test.flags),-- $(test.flags),)
tester.scripts := $(sort $(wildcard $(dir.src)/tests/*.test))
.PHONY: tester
tester: $(CLASS_FILES.tester) $(sqlite3-jni.dll)
$(bin.java) -ea -Djava.library.path=$(dir.bld.c) \
$(java.flags) -cp $(classpath) \
org.sqlite.jni.tester.SQLTester $(tester.scripts)
$(package.jar): $(CLASS_FILES) $(MAKEFILE) $(package.jar): $(CLASS_FILES) $(MAKEFILE)
rm -f $(dir.src)/c/*~ $(dir.src.jni)/*~ rm -f $(dir.src)/c/*~ $(dir.src.jni)/*~
$(bin.jar) -cfe $@ org.sqlite.Tester1 -C src org -C src c $(bin.jar) -cfe $@ org.sqlite.Tester1 -C src org -C src c

View File

@ -0,0 +1,81 @@
package org.sqlite.jni.tester;
import java.util.List;
import java.util.ArrayList;
import static org.sqlite.jni.SQLite3Jni.*;
/**
This class provides an application which aims to implement the
rudimentary SQL-driven test tool described in the accompanying
test-script-interpreter.md.
This is a work in progress.
*/
public class SQLTester {
//! List of input script files.
private java.util.List<String> listInFiles = new ArrayList<>();
private boolean isVerbose = true;
public SQLTester(){
}
public void setVerbose(boolean b){
isVerbose = b;
}
public static <T> void out(T val){
System.out.print(val);
}
public static <T> void outln(T val){
System.out.println(val);
}
@SuppressWarnings("unchecked")
public static <T> void out(T... vals){
int n = 0;
for(T v : vals) out((n++>0 ? " " : "")+v);
}
@SuppressWarnings("unchecked")
public static <T> void outln(T... vals){
out(vals);
out("\n");
}
@SuppressWarnings("unchecked")
private <T> void verbose(T... vals){
if(isVerbose) outln(vals);
}
//! Adds the given test script to the to-test list.
public void addTestScript(String filename){
listInFiles.add(filename);
verbose("Added file",filename);
}
public void runTests() throws Exception {
// process each input file
for(String f : listInFiles){
verbose("Running test script",f);
final TestScript ts = new TestScript(f);
}
}
public static void main(String[] argv) throws Exception{
final SQLTester t = new SQLTester();
for(String a : argv){
if(a.startsWith("-")){
final String flag = a.replaceFirst("-+","");
if( flag.equals("verbose") ){
t.setVerbose(true);
}else if( flag.equals("quiet") ) {
t.setVerbose(false);
}else{
throw new IllegalArgumentException("Unhandled flag: "+flag);
}
}
t.addTestScript(a);
}
t.runTests();
}
}

View File

@ -0,0 +1,36 @@
package org.sqlite.jni.tester;
import java.io.*;
import java.nio.charset.StandardCharsets;
//import java.util.List;
//import java.util.ArrayList;
/**
This class represents a single test script. It handles (or delegates)
its input and parsing. Iteration and evalution are deferred to other,
as-yet-non-existent, classes.
*/
public class TestScript {
//! Test script content.
private String content;
private byte[] readFile(String filename) throws IOException {
return java.nio.file.Files.readAllBytes(java.nio.file.Paths.get(filename));
}
/**
Initializes the script with the content of the given file.
*/
public TestScript(String filename) throws IOException{
this.content = new String(readFile(filename),
StandardCharsets.UTF_8);
}
/**
Initializes the script with the given content, copied
at construction-time.
*/
public TestScript(StringBuffer content){
this.content = content.toString();
}
}

View File

@ -0,0 +1,200 @@
# Specifications For A Rudimentary SQLite Test Script Interpreter
## Overview
The purpose of the Test Script Interpreter is to read and interpret
script files that contain SQL commands and desired results. The
interpreter will check results and report an discrepencies found.
The test script files are ASCII text files. The filename always ends with
".test". Each script is evaluated independently; context does not carry
forward from one script to the next. So, for example, the --null command
run in one test script does not cause any changes in the behavior of
subsequent test scripts. All open database connections are closed
at the end of each test script. All database files created by a test
script are deleted when the script finishes.
## Parsing Rules:
1. Ignore the entire script if the script does not contain the
string "SCRIPT_MODULE_NAME:".
2. Ignore any script that contains the character sequence "\\n\|"
(0x0a, 0x7c). In other words, ignore scripts that contain the
pipe character at the beginning of a line. Such lines represent
test database file content in the "dbtotxt" format. We might add
support for this later, but omit it for the first version.
3. Ignore individual lines that begin with '#' (C-preprocessor lines).
4. If a line begins with exactly two minus signs followed by a
lowercase letter, that is a command. Process commands as described
below.
5. All other lines should be accumulated into the "input buffer".
The various commands will have access to this input buffer.
Some commands will reset the buffer.
## Commands:
Each command looks like an SQL comment. The command begins at the left
margin (no leading space) and starts with exactly 2 minus signs ("-").
The command name consists of lowercase letters and maybe a "-" or two.
Some commands have arguments.
The arguments are separated from the command name by one or more spaces.
Commands have access to the input buffer and might reset the input buffer.
The command can also optionally read (and consume) additional text from
script that comes after the command.
Unknown or unrecognized commands should cause an error message to be
printed and execution to stop.
The initial implemention will only recognize a few commands. Other
commands may be added later. The following is the initial set of
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.
### The --result command
The --result command tries to execute the text in the input buffer as SQL.
For each row of result coming out of this SQL, the text of that result is
appended to the "result buffer". If a result row contains multiple columns,
the columns are processed from left to right. For each column, text is
appended to the result buffer according to the following rules:
* If the result buffer already contains some text, append a space.
(In this way, all column values and all row values are separated from
each other by a single space.)
* If the sqlite3_column_text() returns NULL, then append "nil" - or
some other text that is specified by the --null command - and skip
all subsequent rules.
* If sqlite3_column_text() does not contain any special characters,
append it to the result buffer without any formatting and skip all
subsequent rules.
* If sqlite3_column_text() does not contains curly braces, then put
the text inside of `{...}` and append it and skip all subsequent rules.
* Append the text within double-quotes (`"..."`) and within the text
escape '"' and '\\' by prepending a single '\\' and escape any
control characters (characters less than 0x20) using octal notation:
'\\NNN'.
If an error is encountered while running the SQL, then append the
symbolic C-preprocessor name for the error
code (ex: "SQLITE_CONSTRAINT") as if it were a column value. Then append
the error message text as if it where a column value. Then stop processing.
After the SQL text has been run, compare the content of the result buffer
against the argument to the --result command and report a testing error if
there are any differences.
The --result command resets the input buffer, but it does not reset
the result buffer. This distinction does not matter for the --result
command itself, but it is important for related commands like --glob
and --notglob. Sometimes test cases will contains a bunch of SQL
followed by multiple --glob and/or --notglob statements. All of the
globs should be evaluted agains the result buffer correct, but the SQL
should only be run once. This is accomplished by resetting the input
buffer but not the result buffer.
### The --glob command
The --glob command works just like --result except that the argument to
--glob is interpreted as a TEST-GLOB pattern and the results are compared
using that glob pattern rather than using strcmp(). Other than that,
the two operate the same.
The TEST-GLOB pattern is slightly different for a standard GLOB:
* The '*' character matches zero or more characters.
* The '?' character matches any single character
* The '[...]' character sequence machines a single character
in between the brackets.
* The '#' character matches one or more digits (This is the main
difference between standard unix-glob and TEST-GLOB. unix-glob
does not have this feature. It was added to because it comes
up a lot during SQLite testing.)
### The --notglob command
The --notglob command works just like --glob except that it reports an
error if the GLOB does match, rather than if the GLOB does not matches.
### The --oom command
This command is to be used for out-of-memory testing. It means that
OOM errors should be simulated to ensure that SQLite is able to deal with
them. This command can be silently ignored for now. We might add support
for this later.
### The --tableresult command
The --tableresult command works like --glob except that the GLOB pattern
to be matched is taken from subsequent lines of the input script up to
the next --end. Every span of one or more whitespace characters in this
pattern text is collapsed into a single space (0x20).
Leading and trailing whitespace are removed from the pattern.
The --end that ends the GLOB pattern is not part of the GLOB pattern, but
the --end is consumed from the script input.
### The --new and --open commands
The --new and --open commands cause a database file to be opened.
The name of the file is the argument to the command. The --new command
opens an initially empty database (it deletes the file before opening it)
whereas the --open command opens an existing database if it already
exists.
### The --db command
The script interpreter can have up to 7 different SQLite database
connections open at a time. The --db command is used to switch between
them. The argument to --db is an integer between 0 and 6 that selects
which database connection to use moving forward.
### The --close command
The --close command causes an existing database connetion to close.
This command is a no-op if the database connection is not currently
open. There can be up to 7 different database connections, numbered
0 through 6. The number of the database connection to close is an argument
to the --close command. Or if the argument to --close is "all" then all
open database connections are closed.
### The --null command
The NULL command changes the text that is used to represent SQL NULL
values in the result buffer.
### The --run command
The --run command executes text in the input buffer as if it where SQL.
However, nothing is added to the result buffer. Any output from the SQL
is silently ignored. Errors in the SQL are silently ignored.
The --run command normally executes the SQL in the current database
connection. However, if --run has an argument that is an integer between
0 and 6 then the SQL is run in the alternative database connection specified
by that argument.
### The --json and --json-block commands
The --json and --json-block commands work like --result and --tableresult,
respectively. The difference is that column values are appended to the
result buffer literally, without every enclosing the values in `{...}` or
`"..."` and without escaping any characters in the column value and comparison
is always an exact strcmp() not a GLOB.

View File

@ -0,0 +1,4 @@
/* A script for testing the org.sqlite.jni.tester infrastructure */
# this line is ignored

View File

@ -1,5 +1,5 @@
C When\sconverting\sa\sJava\sexception\sto\sa\sdb\serror\smessage,\suse\sThrowable.toString()\sinstead\sof\sgetMessage()\sso\sthat\sthe\sexception\stype's\sname\sis\sincluded.\sMore\sinternal\sAPI\srenaming\sfor\sconsistency. C Initial\sskeleton\sfor\sadding\san\sSQL-driven\stest\sscript\sinterpreter\sfor\sthe\sJNI\sbindings.
D 2023-08-07T11:18:44.649 D 2023-08-07T21:04:13.706
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -230,7 +230,7 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9 F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9
F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282 F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
F ext/jni/GNUmakefile 61d9bbc179a49523a142928455b3297779b9c40f25783ecf1538279e426cbc99 F ext/jni/GNUmakefile e492513ab2fc6da4f01d6745c852d3ef0afa336994e91a513b523ae8ececcde8
F ext/jni/README.md e965674505e105626127ad45e628e4d19fcd379cdafc4d23c814c1ac2c55681d F ext/jni/README.md e965674505e105626127ad45e628e4d19fcd379cdafc4d23c814c1ac2c55681d
F ext/jni/src/c/sqlite3-jni.c e6463b3fc8ef000d9a5dd1649fe96a4cfc5aac21a43276424cf28d72548c5921 F ext/jni/src/c/sqlite3-jni.c e6463b3fc8ef000d9a5dd1649fe96a4cfc5aac21a43276424cf28d72548c5921
F ext/jni/src/c/sqlite3-jni.h 6c06cdb1e43ce56544dfbe3335a46174dae15d03337d06e55aa7256f85d2ce1b F ext/jni/src/c/sqlite3-jni.h 6c06cdb1e43ce56544dfbe3335a46174dae15d03337d06e55aa7256f85d2ce1b
@ -264,6 +264,10 @@ F ext/jni/src/org/sqlite/jni/sqlite3.java ff3729426704626a6019d97bfee512a83f253c
F ext/jni/src/org/sqlite/jni/sqlite3_context.java d26573fc7b309228cb49786e9078597d96232257defa955a3425d10897bca810 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_stmt.java 78e6d1b95ac600a9475e9db4623f69449322b0c93d1bd4e1616e76ed547ed9fc
F ext/jni/src/org/sqlite/jni/sqlite3_value.java 3d1d4903e267bc0bc81d57d21f5e85978eff389a1a6ed46726dbe75f85e6914a F ext/jni/src/org/sqlite/jni/sqlite3_value.java 3d1d4903e267bc0bc81d57d21f5e85978eff389a1a6ed46726dbe75f85e6914a
F ext/jni/src/org/sqlite/jni/tester/SQLTester.java d51db80b241ba90dea253b453cd7bb44648fdf0bb84370225f63ac541e727e4a
F ext/jni/src/org/sqlite/jni/tester/TestScript.java 67721f78f753c719e465db07abd928fa3c96ebc3917c797b42d21d89aa671a82
F ext/jni/src/org/sqlite/jni/tester/test-script-interpreter.md ba3cf6584783939c8797a67203e63ec588430fdc0b7719f24873e6731c6d0445
F ext/jni/src/tests/000_first.test 9d20eef5d8985ce32dc039004f186a973ca629afee9ab2134f4ec18d1748e426
F ext/lsm1/Makefile a553b728bba6c11201b795188c5708915cc4290f02b7df6ba7e8c4c943fd5cd9 F ext/lsm1/Makefile a553b728bba6c11201b795188c5708915cc4290f02b7df6ba7e8c4c943fd5cd9
F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013 F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013
F ext/lsm1/lsm-test/README 87ea529d2abe615e856d4714bfe8bb185e6c2771b8612aa6298588b7b43e6f86 F ext/lsm1/lsm-test/README 87ea529d2abe615e856d4714bfe8bb185e6c2771b8612aa6298588b7b43e6f86
@ -2083,8 +2087,8 @@ 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 9a494394b9eb28cf88dc5e7075a4b8c682c8e14fdd6837b595bec8011d7e9e72 P 2d44720d06d9e50cb037e92981d2473a3ad0b7560f2f5923d428f59de6fd6aaa
R 482519d6e278134ac56541913ad9c20f R 85efb1bd754dc306bbc436950f6f48cb
U stephan U stephan
Z 5c40003605167b9b55a6a352144a1fa7 Z 24f4287e10d577104a22d65944b7f529
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
2d44720d06d9e50cb037e92981d2473a3ad0b7560f2f5923d428f59de6fd6aaa 2aa8f0edecd3fc30eec28987cdbf1003ace154ddc1447b6f8715ecf38d3b06fb