From: stephan Date: Wed, 9 Aug 2023 13:16:10 +0000 (+0000) Subject: Add SQLTester --tableresult command. X-Git-Tag: version-3.43.0~47^2~50 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ff6b15fbb2e1c78ce99f1555c8bb5b364fcfdec7;p=thirdparty%2Fsqlite.git Add SQLTester --tableresult command. FossilOrigin-Name: 8c5b6d893df4a4e82c6d8e07507fc160b11412ede4bb903ff4e3f5ffa59a9cb9 --- diff --git a/ext/jni/src/org/sqlite/jni/tester/SQLTester.java b/ext/jni/src/org/sqlite/jni/tester/SQLTester.java index 0fd80c7fa6..e4d21f88d0 100644 --- a/ext/jni/src/org/sqlite/jni/tester/SQLTester.java +++ b/ext/jni/src/org/sqlite/jni/tester/SQLTester.java @@ -47,6 +47,13 @@ enum ResultBufferMode { ASIS }; +enum ResultRowMode { + //! Keep all result rows on one line, space-separated. + ONELINE, + //! Add a newline between each result row. + NEWLINE +}; + /** This class provides an application which aims to implement the rudimentary SQL-driven test tool described in the accompanying @@ -159,9 +166,9 @@ public class SQLTester { StringBuilder getInputBuffer(){ return inputBuffer; } - String getInputBufferText(){ return inputBuffer.toString(); } + String getInputText(){ return inputBuffer.toString(); } - String getResultBufferText(){ return resultBuffer.toString(); } + String getResultText(){ return resultBuffer.toString(); } private String takeBuffer(StringBuilder b){ final String rc = b.toString(); @@ -269,7 +276,9 @@ public class SQLTester { } public int execSql(sqlite3 db, boolean throwOnError, - ResultBufferMode appendMode, String sql) throws Exception { + ResultBufferMode appendMode, + ResultRowMode lineMode, + 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); @@ -328,7 +337,10 @@ public class SQLTester { Util.toss(RuntimeException.class, "Unhandled ResultBufferMode."); } } - //sb.append('\n'); + if( ResultRowMode.NEWLINE == lineMode ){ + spacing = 0; + sb.append('\n'); + } } }else{ while( SQLITE_ROW == (rc = sqlite3_step(stmt)) ){} @@ -428,8 +440,9 @@ abstract class Command { protected final void argcCheck(String[] argv, int min, int max) throws Exception{ int argc = argv.length-1; if(argc=0 && argc>max)){ - if( min==max ) Util.badArg(argv[0],"requires exactly",min,"argument(s)"); - else if(max>0){ + if( min==max ){ + Util.badArg(argv[0]," requires exactly ",min," argument(s)"); + }else if(max>0){ Util.badArg(argv[0]," requires ",min,"-",max," arguments."); }else{ Util.badArg(argv[0]," requires at least ",min," arguments."); @@ -447,20 +460,19 @@ abstract class Command { //! Throws if content is not null. protected void affirmNoContent(String content) throws Exception{ if(null != content){ - Util.badArg(this.getClass().getName(),"does not accept content."); + Util.badArg(this.getClass().getName()," does not accept content."); } } //! Throws if content is null. protected void affirmHasContent(String content) throws Exception{ if(null == content){ - Util.badArg(this.getClass().getName(),"requires content."); + Util.badArg(this.getClass().getName()," requires content."); } } } class CloseDbCommand extends Command { - public CloseDbCommand(){} public void process(SQLTester t, String[] argv, String content) throws Exception{ argcCheck(argv,0,1); affirmNoContent(content); @@ -485,7 +497,6 @@ class CloseDbCommand extends Command { //! --db command class DbCommand extends Command { - public DbCommand(){} public void process(SQLTester t, String[] argv, String content) throws Exception{ argcCheck(argv,1); affirmNoContent(content); @@ -500,6 +511,13 @@ class GlobCommand extends Command { public GlobCommand(){} protected GlobCommand(boolean negate){ this.negate = negate; } + public static String globToStrglob(String g){ + /* FIXME: '#' support needs to match 1+ digits, but + sqlite3_strglob() does not support that option. We'll + need a custom glob routine for that. */; + return g.replace("#","[0-9]").trim(); + } + public void process(SQLTester t, String[] argv, String content) throws Exception{ argcCheck(argv,1); affirmNoContent(content); @@ -507,22 +525,22 @@ class GlobCommand extends Command { t.incrementTestCounter(); final String sql = t.takeInputBuffer(); //t.verbose(argv[0]," SQL =\n",sql); - int rc = t.execSql(null, true, ResultBufferMode.ESCAPED, sql); - final String result = t.getResultBufferText().trim(); + int rc = t.execSql(null, true, ResultBufferMode.ESCAPED, + ResultRowMode.ONELINE, sql); + final String result = t.getResultText().trim(); final String sArgs = Util.argvToString(argv); //t.verbose(argv[0]," rc = ",rc," result buffer:\n", result,"\nargs:\n",sArgs); - final String glob = argv[1].replace("#","[0-9]"); + final String glob = globToStrglob(argv[1]); rc = sqlite3_strglob(glob, result); if( (negate && 0==rc) || (!negate && 0!=rc) ){ - Util.toss(TestFailure.class, this.getClass().getSimpleName(), - " glob mismatch: ",glob," vs input: ",result); + Util.toss(TestFailure.class, argv[0], " mismatch: ", + glob," vs input: ",result); } } } //! --new command class NewDbCommand extends Command { - public NewDbCommand(){} public void process(SQLTester t, String[] argv, String content) throws Exception{ argcCheck(argv,1); affirmNoContent(content); @@ -535,7 +553,6 @@ class NewDbCommand extends Command { //! Placeholder dummy/no-op command class NoopCommand extends Command { - public NoopCommand(){} public void process(SQLTester t, String[] argv, String content) throws Exception{ } } @@ -549,7 +566,6 @@ class NotGlobCommand extends GlobCommand { //! --null command class NullCommand extends Command { - public NullCommand(){} public void process(SQLTester t, String[] argv, String content) throws Exception{ argcCheck(argv,1); affirmNoContent(content); @@ -560,7 +576,6 @@ class NullCommand extends Command { //! --open command class OpenDbCommand extends Command { - public OpenDbCommand(){} public void process(SQLTester t, String[] argv, String content) throws Exception{ argcCheck(argv,1); affirmNoContent(content); @@ -572,7 +587,6 @@ class OpenDbCommand extends Command { //! --print command class PrintCommand extends Command { - public PrintCommand(){} public void process(SQLTester t, String[] argv, String content) throws Exception{ if( 1==argv.length && null==content ){ Util.badArg(argv[0]," requires at least 1 argument or body content."); @@ -583,15 +597,15 @@ class PrintCommand extends Command { } class ResultCommand extends Command { - public ResultCommand(){} public void process(SQLTester t, String[] argv, String content) throws Exception{ argcCheck(argv,0,-1); affirmNoContent(content); t.incrementTestCounter(); final String sql = t.takeInputBuffer(); //t.verbose(argv[0]," SQL =\n",sql); - int rc = t.execSql(null, true, ResultBufferMode.ESCAPED, sql); - final String result = t.getResultBufferText().trim(); + int rc = t.execSql(null, true, ResultBufferMode.ESCAPED, + ResultRowMode.ONELINE, sql); + final String result = t.getResultText().trim(); final String sArgs = argv.length>1 ? Util.argvToString(argv) : ""; //t.verbose(argv[0]," rc = ",rc," result buffer:\n", result,"\nargs:\n",sArgs); if( !result.equals(sArgs) ){ @@ -601,14 +615,14 @@ class ResultCommand extends Command { } class RunCommand extends Command { - public RunCommand(){} public void process(SQLTester t, String[] argv, String content) throws Exception{ argcCheck(argv,0,1); affirmHasContent(content); final sqlite3 db = (1==argv.length) ? t.getCurrentDb() : t.getDbById( Integer.parseInt(argv[1]) ); - int rc = t.execSql(db, false, ResultBufferMode.NONE, content); - if( 0!=rc ){ + int rc = t.execSql(db, false, ResultBufferMode.NONE, + ResultRowMode.ONELINE, content); + if( 0!=rc && t.isVerbose() ){ String msg = sqlite3_errmsg(db); t.verbose(argv[0]," non-fatal command error #",rc,": ", msg,"\nfor SQL:\n",content); @@ -616,8 +630,39 @@ class RunCommand extends Command { } } +class TableResultCommand extends Command { + public void process(SQLTester t, String[] argv, String content) throws Exception{ + argcCheck(argv,0); + affirmHasContent(content); + if( !content.endsWith("\n--end") ){ + Util.toss(TestFailure.class, argv[0], " must be terminated with --end."); + }else{ + int n = content.length(); + content = content.substring(0, n-6); + } + final String[] globs = content.split("\s*\n\s*"); + if( globs.length < 1 ){ + Util.toss(TestFailure.class, argv[0], " requires 1 or more globs."); + } + final String sql = t.takeInputBuffer(); + t.execSql(null, true, ResultBufferMode.ESCAPED, ResultRowMode.NEWLINE, sql); + final String rbuf = t.getResultText(); + final String[] res = rbuf.split("\n"); + if( res.length != globs.length ){ + Util.toss(TestFailure.class, argv[0], " failure: input has ", + res.length," row(s) but expecting ",globs.length); + } + for(int i = 0; i < res.length; ++i){ + final String glob = GlobCommand.globToStrglob(globs[i]).replaceAll("\s+"," "); + if( 0 != sqlite3_strglob(glob, res[i]) ){ + Util.toss(TestFailure.class, argv[0], " glob {",glob, + "} does not match: {",res[i],"}"); + } + } + } +} + class TestCaseCommand extends Command { - public TestCaseCommand(){} public void process(SQLTester t, String[] argv, String content) throws Exception{ argcCheck(argv,1); affirmHasContent(content); @@ -650,6 +695,7 @@ class CommandDispatcher { case "print": rv = new PrintCommand(); break; case "result": rv = new ResultCommand(); break; case "run": rv = new RunCommand(); break; + case "tableresult": rv = new TableResultCommand(); break; case "testcase": rv = new TestCaseCommand(); break; default: rv = null; break; } diff --git a/ext/jni/src/org/sqlite/jni/tester/TestScript.java b/ext/jni/src/org/sqlite/jni/tester/TestScript.java index 0bc7b53e77..414ea29bc1 100644 --- a/ext/jni/src/org/sqlite/jni/tester/TestScript.java +++ b/ext/jni/src/org/sqlite/jni/tester/TestScript.java @@ -195,7 +195,7 @@ class TestScript { final String[] parts = block.split("\\n", 2); chunk.argv = parts[0].split("\\s+"); if( parts.length>1 && parts[1].length()>0 ){ - chunk.content = parts[1]; + chunk.content = parts[1].trim(); } rc.add( chunk ); } diff --git a/ext/jni/src/tests/000_first.test b/ext/jni/src/tests/000_first.test index 3f61317b90..742ebfa451 100644 --- a/ext/jni/src/tests/000_first.test +++ b/ext/jni/src/tests/000_first.test @@ -28,11 +28,18 @@ select 'a', 'b'; --result a b a b --testcase second select 123 ---glob #2# ---testcase second +--glob ### +--testcase third select 'a' --notglob # --close --open SQLTester.db --print Re-opened db. +--testcase fourth +SELECT 1, 2; +SELECT 'b', 'c'; +--tableresult + [0-9] # + b c +--end --an-uknown-command diff --git a/manifest b/manifest index 3165e6822e..7f72a5fc63 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Clean\sup\sthe\sSQLTester\soutput\sa\sbit\sby\susing\sthe\smodule\sname,\sinstead\sof\sfilename,\swhere\sappropriate. -D 2023-08-09T12:05:17.196 +C Add\sSQLTester\s--tableresult\scommand. +D 2023-08-09T13:16:10.208 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -266,10 +266,10 @@ 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 3d9c40f8ed58ec0df05ca160986ea06ec84ec1f338b069cfba9604bbba467a01 -F ext/jni/src/org/sqlite/jni/tester/SQLTester.java 42b694da25e20a246140e32d8aa044e65ed60c67f69adcf27c326a1d18b04228 -F ext/jni/src/org/sqlite/jni/tester/TestScript.java 57a5bb63e56324fe20b31142a8704b08cfc0bdff9e936620346fad659fb91759 +F ext/jni/src/org/sqlite/jni/tester/SQLTester.java 59ac50bbc1abc37b34bc4cd47b564d770de2828e045ba59c056f873543de10b3 +F ext/jni/src/org/sqlite/jni/tester/TestScript.java f2a87c88ab23fa4601a985eb69bdc8b4f81cabfab04fdc3544ecefde207e08d4 F ext/jni/src/org/sqlite/jni/tester/test-script-interpreter.md ae1d6706f723517e03a04ab578a539fa3df66fe38adad113f10b61eabc524d09 -F ext/jni/src/tests/000_first.test 954c19705c791023eb5a473de0851d3727406fdef25f4b2521b88972280b4111 +F ext/jni/src/tests/000_first.test 461f465cd1e9c60f19a8fd4231721c1bbd01702d9677696d56087a58f9d2e09e F ext/jni/src/tests/010_ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70 F ext/lsm1/Makefile a553b728bba6c11201b795188c5708915cc4290f02b7df6ba7e8c4c943fd5cd9 F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013 @@ -2090,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 ab9c945bb0b4210b3f47e6341f150f8a7cc45f9e4e4c2247e91d2528ed4772a6 -R 71db74e5804fc1b921164f2085cce4db +P 5323e4fd254274cc527af7536c622b786394599c68eca2da6c7fc641727dbdb2 +R c0ec1fc5e7c5611a47b223974ef77855 U stephan -Z d1b5b5a17f205dc2910f24396b36f01b +Z 3ccc1c720ec01884cd7c12ccaa2f6b70 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 7c80c48420..44b47e7b2a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5323e4fd254274cc527af7536c622b786394599c68eca2da6c7fc641727dbdb2 \ No newline at end of file +8c5b6d893df4a4e82c6d8e07507fc160b11412ede4bb903ff4e3f5ffa59a9cb9 \ No newline at end of file