###############################################################################
#
# authorizer.eagle --
#
# Written by Joe Mistachkin.
# Released to the public domain, use at your own risk!
#
###############################################################################

package require Eagle
package require Eagle.Library
package require Eagle.Test

runTestPrologue

###############################################################################

package require System.Data.SQLite.Test
runSQLiteTestPrologue

###############################################################################

runTest {test authorizer-1.1 {SQLiteConnection Authorize event} -setup {
  proc onAuthorize { sender e } {
    #
    # NOTE: Filter out the "noise" by allowing all standard
    #       events on the "sqlite_*" tables.
    #
    set noiseActionCodes [list \
        CreateTable CreateIndex Read Insert Update Delete]

    if {[$e ActionCode] in $noiseActionCodes && \
        [string match sqlite_* [$e Argument1]]} then {
      return
    }

    #
    # NOTE: Filter out all "non-primary" events to make the test
    #       results more deterministic in the face of different
    #       query plans.
    #
    if {[$e ActionCode] ne $::filter} then {
      return
    }

    #
    # NOTE: Record the authorizer arguments exactly as we received
    #       them.
    #
    lappend ::data [list \
        [$e UserData] [$e ActionCode] [$e Argument1] \
        [$e Argument2] [$e Database] [$e Context]]

    #
    # NOTE: Deny all attempts to create a table named "tDeny".
    #
    if {[$e ActionCode] eq "CreateTable" && \
        [$e Argument1] eq "tDeny"} then {
      $e ReturnCode Deny
    }
  }

  setupDb [set fileName authorizer-1.1.db]
} -body {
  set connection [getDbConnection]

  set callback onAuthorize
  object invoke $connection add_Authorize $callback

  set results [list]

  set sql [list \
    CreateTable       {CREATE TABLE t1(x);} \
    CreateIndex       {CREATE INDEX i1 ON t1(x);} \
    CreateTrigger     {CREATE TRIGGER tr1 BEFORE INSERT ON t1
                       BEGIN
                         SELECT RAISE(IGNORE);
                       END;} \
    CreateView        {CREATE VIEW v1 AS SELECT * FROM t1;} \
    CreateTempTable   {CREATE TEMPORARY TABLE t2(x);} \
    CreateTempIndex   {CREATE INDEX i2 ON t2(x);} \
    CreateTempTrigger {CREATE TEMPORARY TRIGGER tr2 BEFORE INSERT ON t2
                       BEGIN
                         SELECT RAISE(IGNORE);
                       END;} \
    CreateTempView    {CREATE TEMPORARY VIEW v2 AS SELECT * FROM t2;} \
    Pragma            {PRAGMA journal_mode=WAL;} \
    Function          {SELECT julianday('now');} \
    Read              {SELECT x FROM t1;} \
    Select            {SELECT * FROM t1;} \
    Insert            {INSERT INTO t1(x) VALUES(1);} \
    Update            {UPDATE t1 SET x = x - 1;} \
    Delete            {DELETE FROM t1;} \
    AlterTable        {ALTER TABLE t1 ADD COLUMN y;} \
    Reindex           {REINDEX t1;} \
    Analyze           {ANALYZE t1;} \
    DropTempView      {DROP VIEW v2;} \
    DropTempTrigger   {DROP TRIGGER tr2;} \
    DropTempIndex     {DROP INDEX i2;} \
    DropTempTable     {DROP TABLE t2;} \
    DropView          {DROP VIEW v1;} \
    DropTrigger       {DROP TRIGGER tr1;} \
    DropIndex         {DROP INDEX i1;} \
    Recursive         {WITH t4(x) AS (
                         VALUES(1)
                         UNION ALL
                         SELECT t1.x FROM t1, t4 WHERE t1.x = t4.x
                       )
                       SELECT x FROM t4;} \
    DropTable         {DROP TABLE t1;} \
    Transaction       {BEGIN; SELECT 0; COMMIT;} \
    Savepoint         {SAVEPOINT s1; RELEASE SAVEPOINT s1;} \
    Attach            {ATTACH DATABASE ':memory:' AS d1;} \
    Detach            {DETACH DATABASE d1;} \
    CreateVtable      {CREATE VIRTUAL TABLE t3 USING fts4(x TEXT);} \
    DropVtable        {DROP TABLE t3;} \
    CreateTable       {CREATE TABLE tDeny(x);}]

  foreach {name value} $sql {
    set filter $name; set data [list]
    set code [catch {sql execute $db $value} result]
    set result [lindex [split [string map [list \r\n \n] $result] \n] 0]
    lappend results [list $name $data $code $result]
  }
  lappend results [isTableInDb tDeny]

  set results
} -cleanup {
  catch {object invoke $connection remove_Authorize $callback}
  catch {object removecallback $callback}

  cleanupDb $fileName

  freeDbConnection

  unset -nocomplain result code data filter value name sql results callback \
      connection db fileName

  rename onAuthorize ""
} -constraints \
{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \
{{CreateTable {{0 CreateTable t1 {} main {}}} 0 0} {CreateIndex {{0 CreateIndex\
i1 t1 main {}}} 0 0} {CreateTrigger {{0 CreateTrigger tr1 t1 main {}}} 0 0}\
{CreateView {{0 CreateView v1 {} main {}}} 0 0} {CreateTempTable {{0\
CreateTempTable t2 {} temp {}}} 0 0} {CreateTempIndex {{0 CreateTempIndex i2 t2\
temp {}}} 0 0} {CreateTempTrigger {{0 CreateTempTrigger tr2 t2 temp {}}} 0 0}\
{CreateTempView {{0 CreateTempView v2 {} temp {}}} 0 0} {Pragma {{0 Pragma\
journal_mode WAL {} {}}} 0 0} {Function {{0 Function {} julianday {} {}}} 0 0}\
{Read {{0 Read t1 x main {}}} 0 0} {Select {{0 Select {} {} {} {}}} 0 0}\
{Insert {{0 Insert t1 {} main {}}} 0 0} {Update {{0 Update t1 x main {}}} 0 0}\
{Delete {{0 Delete t1 {} main {}}} 0 0} {AlterTable {{0 AlterTable main t1 {}\
{}}} 0 0} {Reindex {{0 Reindex i1 {} main {}}} 0 0} {Analyze {{0 Analyze t1 {}\
main {}}} 0 0} {DropTempView {{0 DropTempView v2 {} temp {}}} 0 0}\
{DropTempTrigger {{0 DropTempTrigger tr2 t2 temp {}}} 0 0} {DropTempIndex {{0\
DropTempIndex i2 t2 temp {}}} 0 0} {DropTempTable {{0 DropTempTable t2 {} temp\
{}}} 0 0} {DropView {{0 DropView v1 {} main {}}} 0 0} {DropTrigger {{0\
DropTrigger tr1 t1 main {}}} 0 0} {DropIndex {{0 DropIndex i1 t1 main {}}} 0 0}\
{Recursive {{0 Recursive {} {} {} {}}} 0 0} {DropTable {{0 DropTable t1 {} main\
{}}} 0 0} {Transaction {{0 Transaction BEGIN {} {} {}} {0 Transaction COMMIT {}\
{} {}}} 0 0} {Savepoint {{0 Savepoint BEGIN s1 {} {}} {0 Savepoint RELEASE s1\
{} {}}} 0 0} {Attach {{0 Attach :memory: {} {} {}}} 0 0} {Detach {{0 Detach d1\
{} {} {}}} 0 0} {CreateVtable {{0 CreateVtable t3 fts4 main {}}} 0 0}\
{DropVtable {{0 DropVtable t3 fts4 main {}}} 0 0} {CreateTable {{0 CreateTable\
tDeny {} main {}}} 1 {System.Data.SQLite.SQLiteException (0x80004005):\
authorization denied}} False}}

###############################################################################

runSQLiteTestEpilogue
runTestEpilogue
