From fa32c4233b4a02ae631602dbb0a234ab10df8aaf Mon Sep 17 00:00:00 2001 From: "Kevin M. Rosenberg" Date: Sun, 11 Apr 2004 02:49:49 +0000 Subject: [PATCH] r8936: merged classic-tests into tests --- ChangeLog | 4 + NEWS | 6 +- classic-tests/README | 8 - classic-tests/old-tests/xptest-clsql.lisp | 224 -------- classic-tests/package.lisp | 32 -- classic-tests/tables.lisp | 262 ---------- classic-tests/tests.lisp | 289 ---------- clsql-classic-tests.asd | 37 -- clsql-classic.asd | 3 +- clsql-tests.asd | 4 +- debian/changelog | 6 + doc/clsql.pdf | 608 +++++++++++----------- doc/html.tar.gz | Bin 37415 -> 42467 bytes doc/ref_clsql.xml | 21 +- tests/package.lisp | 2 +- tests/test-basic.lisp | 164 ++++++ tests/test-init.lisp | 39 +- tests/utils.lisp | 68 +++ 18 files changed, 592 insertions(+), 1185 deletions(-) delete mode 100644 classic-tests/README delete mode 100644 classic-tests/old-tests/xptest-clsql.lisp delete mode 100644 classic-tests/package.lisp delete mode 100644 classic-tests/tables.lisp delete mode 100644 classic-tests/tests.lisp delete mode 100644 clsql-classic-tests.asd create mode 100644 tests/test-basic.lisp create mode 100644 tests/utils.lisp diff --git a/ChangeLog b/ChangeLog index 248570e..ebc1347 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +10 Apr 2004 Kevin Rosenberg (kevin@rosenberg.net) + * Version 2.6.1: documentation fixes, merged + classic-tests into tests + 10 Apr 2004 Kevin Rosenberg (kevin@rosenberg.net) * Version 2.6.0 released: New API functions CREATE-DATABASE, DESTORY-DATABASE, PROBE-DATABASE diff --git a/NEWS b/NEWS index 3d158e3..edc7097 100644 --- a/NEWS +++ b/NEWS @@ -1,2 +1,4 @@ -CLSQL now supports the CommonSQL-API with the merge of the orphaned -UncommonSQL package. +Three new API functions added: create-database, destroy-database, +and probe-database. + +CLSQL now supports the CommonSQL-API. diff --git a/classic-tests/README b/classic-tests/README deleted file mode 100644 index 4fb0437..0000000 --- a/classic-tests/README +++ /dev/null @@ -1,8 +0,0 @@ -This test suite looks for a configuration file named -".clsql-test.config" located in the users home directory. This file -contains a single assoc-list that specifies the connection specs for -each database type to be tested. There is an example file in contained -in CLSQL's examples directory. - -These tests require the downloading of the rtest and ptester packages -from http://files.b9.com/. diff --git a/classic-tests/old-tests/xptest-clsql.lisp b/classic-tests/old-tests/xptest-clsql.lisp deleted file mode 100644 index 51fad13..0000000 --- a/classic-tests/old-tests/xptest-clsql.lisp +++ /dev/null @@ -1,224 +0,0 @@ -;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*- -;;;; ************************************************************************* -;;;; FILE IDENTIFICATION -;;;; -;;;; Name: xptest-clsql.cl -;;;; Purpose: Test of CLSQL using XPTest package -;;;; Programmer: Kevin M. Rosenberg -;;;; Date Started: Mar 2002 -;;;; -;;;; $Id$ -;;;; -;;;; The XPTest package can be downloaded from -;;;; http://alpha.onshored.com/lisp-software/ -;;;; -;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg -;;;; -;;;; CLSQL users are granted the rights to distribute and use this software -;;;; as governed by the terms of the Lisp Lesser GNU Public License -;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL. -;;;; ************************************************************************* - - -;;; This test suite looks for a configuration file named "test.config" -;;; This file contains a single a-list that specifies the connection -;;; specs for each database type to be tested. For example, to test all -;;; platforms, a sample "test.config" may look like: -;;; -;;; ((:mysql ("localhost" "a-mysql-db" "user1" "secret")) -;;; (:aodbc ("my-dsn" "a-user" "pass")) -;;; (:paostgresql ("localhost" "another-db" "user2" "dont-tell")) -;;; (:postgresql-socket ("pg-server" "a-db-name" "user" "secret-password"))) - -(declaim (optimize (debug 3) (speed 3) (safety 1) (compilation-speed 0))) -(in-package :cl-user) -(mk:load-system "XPTest") - -(in-package :clsql-user) -(use-package :xptest) - -(def-test-fixture clsql-fixture () - ((aodbc-spec :accessor aodbc-spec) - (mysql-spec :accessor mysql-spec) - (pgsql-spec :accessor pgsql-spec) - (pgsql-socket-spec :accessor pgsql-socket-spec)) - (:documentation "Test fixture for CLSQL testing")) - -(defvar *config-pathname* (make-pathname :name "test" - :type "config" - :defaults *load-truename*)) -(defmethod setup ((fix clsql-fixture)) - (if (probe-file *config-pathname*) - (let (config) - (with-open-file (stream *config-pathname* :direction :input) - (setq config (read stream))) - (setf (aodbc-spec fix) (cadr (assoc :aodbc config))) - (setf (mysql-spec fix) (cadr (assoc :mysql config))) - (setf (pgsql-spec fix) (cadr (assoc :postgresql config))) - (setf (pgsql-socket-spec fix) - (cadr (assoc :postgresql-socket config)))) - (error "XPTest Config file ~S not found" *config-pathname*))) - -(defmethod teardown ((fix clsql-fixture)) - t) - -(defmethod mysql-table-test ((test clsql-fixture)) - (test-table (mysql-spec test) :mysql)) - -(defmethod aodbc-table-test ((test clsql-fixture)) - (test-table (aodbc-spec test) :aodbc)) - -(defmethod pgsql-table-test ((test clsql-fixture)) - (test-table (pgsql-spec test) :postgresql)) - -(defmethod pgsql-socket-table-test ((test clsql-fixture)) - (test-table (pgsql-socket-spec test) :postgresql-socket)) - - -(defmethod test-table (spec type) - (when spec - (let ((db (clsql:connect spec :database-type type :if-exists :new))) - (unwind-protect - (progn - (create-test-table db) - (dolist (row (query "select * from test_clsql" :database db :types :auto)) - (test-table-row row :auto)) - (dolist (row (query "select * from test_clsql" :database db :types nil)) - (test-table-row row nil)) - (loop for row across (map-query 'vector #'list "select * from test_clsql" - :database db :types :auto) - do (test-table-row row :auto)) - (loop for row across (map-query 'vector #'list "select * from test_clsql" - :database db :types nil) - do (test-table-row row nil)) - (loop for row in (map-query 'list #'list "select * from test_clsql" - :database db :types nil) - do (test-table-row row nil)) - (loop for row in (map-query 'list #'list "select * from test_clsql" - :database db :types :auto) - do (test-table-row row :auto)) - (when (map-query nil #'list "select * from test_clsql" - :database db :types :auto) - (failure "Expected NIL result from map-query nil")) - (do-query ((int float bigint str) "select * from test_clsql") - (test-table-row (list int float bigint str) nil)) - (do-query ((int float bigint str) "select * from test_clsql" :types :auto) - (test-table-row (list int float bigint str) :auto)) - (drop-test-table db) - ) - (disconnect :database db))))) - - -(defmethod mysql-low-level ((test clsql-fixture)) - (let ((spec (mysql-spec test))) - (when spec - (let ((db (clsql-mysql::database-connect spec :mysql))) - (clsql-mysql::database-execute-command "DROP TABLE IF EXISTS test_clsql" db) - (clsql-mysql::database-execute-command - "CREATE TABLE test_clsql (i integer, sqrt double, sqrt_str CHAR(20))" db) - (dotimes (i 10) - (clsql-mysql::database-execute-command - (format nil "INSERT INTO test_clsql VALUES (~d,~d,'~a')" - i (number-to-sql-string (sqrt i)) - (number-to-sql-string (sqrt i))) - db)) - (let ((res (clsql-mysql::database-query-result-set "select * from test_clsql" db :full-set t :types nil))) - (unless (= 10 (mysql:mysql-num-rows (clsql-mysql::mysql-result-set-res-ptr res))) - (failure "Error calling mysql-num-rows")) - (clsql-mysql::database-dump-result-set res db)) - (clsql-mysql::database-execute-command "DROP TABLE test_clsql" db) - (clsql-mysql::database-disconnect db))))) - -(defparameter clsql-test-suite - (make-test-suite - "CLSQL Test Suite" - "Basic test suite for database operations." - ("MySQL Low Level Interface" 'clsql-fixture - :test-thunk 'mysql-low-level - :description "A test of MySQL low-level interface") - ("MySQL Table" 'clsql-fixture - :test-thunk 'mysql-table-test - :description "A test of MySQL") - ("PostgreSQL Table" 'clsql-fixture - :test-thunk 'pgsql-table-test - :description "A test of PostgreSQL tables") - ("PostgreSQL Socket Table" 'clsql-fixture - :test-thunk 'pgsql-socket-table-test - :description "A test of PostgreSQL Socket tables") - )) - -#+allegro -(add-test (make-test-case "AODBC table test" 'clsql-fixture - :test-thunk 'aodbc-table-test - :description "Test AODBC table") - clsql-test-suite) - -;;;; Testing functions - -(defun transform-float-1 (i) - (* i (abs (/ i 2)) (expt 10 (* 2 i)))) - -(defun transform-bigint-1 (i) - (* i (expt 10 (* 3 (abs i))))) - -(defun create-test-table (db) - (ignore-errors - (clsql:execute-command - "DROP TABLE test_clsql" :database db)) - (clsql:execute-command - "CREATE TABLE test_clsql (t_int integer, t_float float, t_bigint BIGINT, t_str CHAR(30))" - :database db) - (dotimes (i 11) - (let* ((test-int (- i 5)) - (test-flt (transform-float-1 test-int))) - (clsql:execute-command - (format nil "INSERT INTO test_clsql VALUES (~a,~a,~a,'~a')" - test-int - (number-to-sql-string test-flt) - (transform-bigint-1 test-int) - (number-to-sql-string test-flt) - ) - :database db)))) - -(defun parse-double (num-str) - (let ((*read-default-float-format* 'double-float)) - (coerce (read-from-string num-str) 'double-float))) - -(defun test-table-row (row types) - (unless (and (listp row) - (= 4 (length row))) - (failure "Row ~S is incorrect format" row)) - (destructuring-bind (int float bigint str) row - (cond - ((eq types :auto) - (unless (and (integerp int) - (typep float 'double-float) - (integerp bigint) - (stringp str)) - (failure "Incorrect field type for row ~S" row))) - ((null types) - (unless (and (stringp int) - (stringp float) - (stringp bigint) - (stringp str)) - (failure "Incorrect field type for row ~S" row)) - (setq int (parse-integer int)) - (setq bigint (parse-integer bigint)) - (setq float (parse-double float))) - ((listp types) - (error "NYI") - ) - (t - (failure "Invalid types field (~S) passed to test-table-row" types))) - (unless (= float (transform-float-1 int)) - (failure "Wrong float value ~A for int ~A (row ~S)" float int row)) - (unless (= float (parse-double str)) - (failure "Wrong string value ~A" str)))) - - -(defun drop-test-table (db) - (clsql:execute-command "DROP TABLE test_clsql")) - -(report-result (run-test clsql-test-suite :handle-errors nil) :verbose t) - - diff --git a/classic-tests/package.lisp b/classic-tests/package.lisp deleted file mode 100644 index b8d23bd..0000000 --- a/classic-tests/package.lisp +++ /dev/null @@ -1,32 +0,0 @@ -;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*- -;;;; ************************************************************************* -;;;; FILE IDENTIFICATION -;;;; -;;;; Name: package.lisp -;;;; Purpose: Package file clsql testing suite -;;;; Author: Kevin M. Rosenberg -;;;; Date Started: Apr 2003 -;;;; -;;;; $Id$ -;;;; ************************************************************************* - -(in-package #:cl-user) - -(defpackage #:clsql-classic-tests - (:use #:asdf #:cl #:clsql #:ptester) - (:export - #:*config-pathname* - #:+all-db-types+ - #:conn-specs - #:aodbc-spec - #:mysql-spec - #:postgresql-spec - #:postgresql-socket-spec - #:sqlite-spec - #:read-specs - #:db-type-spec - #:db-type-ensure-system - )) - - - diff --git a/classic-tests/tables.lisp b/classic-tests/tables.lisp deleted file mode 100644 index 44d7ad2..0000000 --- a/classic-tests/tables.lisp +++ /dev/null @@ -1,262 +0,0 @@ -;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*- -;;;; ************************************************************************* -;;;; FILE IDENTIFICATION -;;;; -;;;; Name: tables.lisp -;;;; Purpose: Table creation tests in CLSQL -;;;; Programmer: Kevin M. Rosenberg -;;;; Date Started: Mar 2002 -;;;; -;;;; $Id$ -;;;; -;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg -;;;; -;;;; CLSQL users are granted the rights to distribute and use this software -;;;; as governed by the terms of the Lisp Lesser GNU Public License -;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL. -;;;; ************************************************************************* - -;;; This test suite looks for a configuration file named ".clsql-test.config" -;;; located in the users home directory. -;;; -;;; This file contains a single a-list that specifies the connection -;;; specs for each database type to be tested. For example, to test all -;;; platforms, a sample "test.config" may look like: -;;; -;;; ((:mysql ("localhost" "a-mysql-db" "user1" "secret")) -;;; (:aodbc ("my-dsn" "a-user" "pass")) -;;; (:postgresql ("localhost" "another-db" "user2" "dont-tell")) -;;; (:postgresql-socket ("pg-server" "a-db-name" "user" "secret-password"))) - -(in-package #:clsql-classic-tests) - -(defvar *config-pathname* - (make-pathname :default (user-homedir-pathname) - :name ".clsql-test" - :type ".config")) - -(defclass conn-specs () - ((aodbc-spec :accessor aodbc-spec) - (mysql-spec :accessor mysql-spec) - (pgsql-spec :accessor pgsql-spec) - (pgsql-socket-spec :accessor pgsql-socket-spec)) - (:documentation "Test fixture for CLSQL testing")) - - -(defun read-specs (&optional (path *config-pathname*)) - (if (probe-file path) - (with-open-file (stream path :direction :input) - (let ((config (read stream)) - (specs (make-instance 'conn-specs))) - (setf (aodbc-spec specs) (cadr (assoc :aodbc config))) - (setf (mysql-spec specs) (cadr (assoc :mysql config))) - (setf (pgsql-spec specs) (cadr (assoc :postgresql config))) - (setf (pgsql-socket-spec specs) - (cadr (assoc :postgresql-socket config))) - specs)) - (warn "CLSQL tester config file ~S not found" path))) - -(defvar *conn-specs* (read-specs)) - -(defmethod mysql-table-test ((test conn-specs)) - (test-table (mysql-spec test) :mysql)) - -(defmethod aodbc-table-test ((test conn-specs)) - (test-table (aodbc-spec test) :aodbc)) - -(defmethod pgsql-table-test ((test conn-specs)) - (test-table (pgsql-spec test) :postgresql)) - -(defmethod pgsql-socket-table-test ((test conn-specs)) - (test-table (pgsql-socket-spec test) :postgresql-socket)) - -(defmethod test-table (spec type) - (when spec - (let ((db (clsql:connect spec :database-type type :if-exists :new))) - (unwind-protect - (progn - (create-test-table db) - (dolist (row (query "select * from test_clsql" :database db :result-types :auto)) - (test-table-row row :auto type)) - (dolist (row (query "select * from test_clsql" :database db :result-types nil)) - (test-table-row row nil type)) - (loop for row across (map-query 'vector #'list "select * from test_clsql" - :database db :result-types :auto) - do (test-table-row row :auto type)) - (loop for row across (map-query 'vector #'list "select * from test_clsql" - :database db :result-types nil) - do (test-table-row row nil type)) - (loop for row in (map-query 'list #'list "select * from test_clsql" - :database db :result-types nil) - do (test-table-row row nil type)) - (loop for row in (map-query 'list #'list "select * from test_clsql" - :database db :result-types :auto) - do (test-table-row row :auto type)) - (test (map-query nil #'list "select * from test_clsql" - :database db :result-types :auto) - nil - :fail-info "Expected NIL result from map-query nil") - (do-query ((int float bigint str) "select * from test_clsql") - (test-table-row (list int float bigint str) nil type)) - (do-query ((int float bigint str) "select * from test_clsql" :result-types :auto) - (test-table-row (list int float bigint str) :auto type)) - (drop-test-table db) - ) - (disconnect :database db))))) - - -;;;; Testing functions - -(defun transform-float-1 (i) - (coerce (* i (abs (/ i 2)) (expt 10 (* 2 i))) 'double-float)) - -(defun transform-bigint-1 (i) - (* i (expt 10 (* 3 (abs i))))) - -(defun create-test-table (db) - (ignore-errors - (clsql:execute-command - "DROP TABLE test_clsql" :database db)) - (clsql:execute-command - "CREATE TABLE test_clsql (t_int integer, t_float float, t_bigint BIGINT, t_str CHAR(30))" - :database db) - (dotimes (i 11) - (let* ((test-int (- i 5)) - (test-flt (transform-float-1 test-int))) - (clsql:execute-command - (format nil "INSERT INTO test_clsql VALUES (~a,~a,~a,'~a')" - test-int - (number-to-sql-string test-flt) - (transform-bigint-1 test-int) - (number-to-sql-string test-flt) - ) - :database db)))) - -(defun parse-double (num-str) - (let ((*read-default-float-format* 'double-float)) - (coerce (read-from-string num-str) 'double-float))) - -(defun test-table-row (row types db-type) - (test (and (listp row) - (= 4 (length row))) - t - :fail-info - (format nil "Row ~S is incorrect format" row)) - (destructuring-bind (int float bigint str) row - (cond - ((eq types :auto) - (test (and (integerp int) - (typep float 'double-float) - (or (eq db-type :aodbc) ;; aodbc doesn't handle bigint conversions - (integerp bigint)) - (stringp str)) - t - :fail-info - (format nil "Incorrect field type for row ~S (types :auto)" row))) - ((null types) - (test (and (stringp int) - (stringp float) - (stringp bigint) - (stringp str)) - t - :fail-info - (format nil "Incorrect field type for row ~S (types nil)" row)) - (setq int (parse-integer int)) - (setq bigint (parse-integer bigint)) - (setq float (parse-double float))) - ((listp types) - (error "NYI") - ) - (t - (test t nil - :fail-info - (format nil "Invalid types field (~S) passed to test-table-row" types)))) - (test (transform-float-1 int) - float - :test #'eql - :fail-info - (format nil "Wrong float value ~A for int ~A (row ~S)" float int row)) - (test float - (parse-double str) - :test #'double-float-equal - :fail-info (format nil "Wrong string value ~A for double ~A~%Row: ~S" - str float row)))) - - -(defun double-float-equal (a b) - (if (zerop a) - (if (zerop b) - t - nil) - (let ((diff (abs (/ (- a b) a)))) - (if (> diff (* 10 double-float-epsilon)) - nil - t)))) - -(defun drop-test-table (db) - (clsql:execute-command "DROP TABLE test_clsql" :database db)) - - -(deftest lowlevel.mysql.table.1 - (let ((spec (mysql-spec *conn-specs*)) - (result)) - (when spec - (let ((db (clsql-mysql::database-connect spec :mysql))) - (clsql-mysql::database-execute-command "DROP TABLE IF EXISTS test_clsql" db) - (clsql-mysql::database-execute-command - "CREATE TABLE test_clsql (i integer, sqrt double, sqrt_str CHAR(20))" db) - (dotimes (i 10) - (clsql-mysql::database-execute-command - (format nil "INSERT INTO test_clsql VALUES (~d,~d,'~a')" - i (clsql:number-to-sql-string (sqrt i)) - (clsql:number-to-sql-string (sqrt i))) - db)) - (let ((res (clsql-mysql::database-query-result-set "select * from test_clsql" db :full-set t :result-types nil))) - (setq result (mysql:mysql-num-rows - (clsql-mysql::mysql-result-set-res-ptr res))) - (clsql-mysql::database-dump-result-set res db)) - (clsql-mysql::database-execute-command "DROP TABLE test_clsql" db) - (clsql-mysql::database-disconnect db)))) - 10) - -;(mysql-table-test specs) -;(pgsql-table-test specs) -;(pgsql-socket-table-test specs) -;(aodbc-table-test specs) - - - -(defmacro def-test-table (name spec type) - (deftest ,name - (when ,spec - (let ((db (clsql:connect ,spec :database-type ,type :if-exists :new))) - (unwind-protect - (progn - (create-test-table db) - (dolist (row (query "select * from test_clsql" :database db :result-types :auto)) - (test-table-row row :auto type)) - (dolist (row (query "select * from test_clsql" :database db :result-types nil)) - (test-table-row row nil type)) - (loop for row across (map-query 'vector #'list "select * from test_clsql" - :database db :result-types :auto) - do (test-table-row row :auto type)) - (loop for row across (map-query 'vector #'list "select * from test_clsql" - :database db :result-types nil) - do (test-table-row row nil type)) - (loop for row in (map-query 'list #'list "select * from test_clsql" - :database db :result-types nil) - do (test-table-row row nil type)) - (loop for row in (map-query 'list #'list "select * from test_clsql" - :database db :result-types :auto) - do (test-table-row row :auto type)) - (test (map-query nil #'list "select * from test_clsql" - :database db :result-types :auto) - nil - :fail-info "Expected NIL result from map-query nil") - (do-query ((int float bigint str) "select * from test_clsql") - (test-table-row (list int float bigint str) nil type)) - (do-query ((int float bigint str) "select * from test_clsql" :result-types :auto) - (test-table-row (list int float bigint str) :auto type)) - (drop-test-table db) - ) - (disconnect :database db))))) diff --git a/classic-tests/tests.lisp b/classic-tests/tests.lisp deleted file mode 100644 index d94ed47..0000000 --- a/classic-tests/tests.lisp +++ /dev/null @@ -1,289 +0,0 @@ -;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*- -;;;; ************************************************************************* -;;;; FILE IDENTIFICATION -;;;; -;;;; Name: classic-tests.lisp -;;;; Purpose: Automated test of CLSQL using ACL's tester -;;;; Programmer: Kevin M. Rosenberg -;;;; Date Started: Mar 2002 -;;;; -;;;; $Id$ -;;;; -;;;; This file, part of CLSQL, is Copyright (c) 2002 by Kevin M. Rosenberg -;;;; -;;;; CLSQL users are granted the rights to distribute and use this software -;;;; as governed by the terms of the Lisp Lesser GNU Public License -;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL. -;;;; ************************************************************************* - -;;; This test suite looks for a configuration file named ".clsql-test.config" -;;; located in the users home directory. -;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*- -;;;; ************************************************************************* -;;;; FILE IDENTIFICATION -;;;; -;;;; File: tests.lisp -;;;; Author: Kevin Rosenberg -;;;; $Id$ -;;;; -;;;; This file is part of CLSQL. -;;;; -;;;; CLSQL users are granted the rights to distribute and use this software -;;;; as governed by the terms of the Lisp Lesser GNU Public License -;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL. -;;;; ************************************************************************* - -;;; You need a file named "~/.clsql-tests.config" - -;;; This file contains a single a-list that specifies the connection -;;; specs for each database type to be tested. For example, to test all -;;; platforms, a sample "test.config" may look like: -;;; -;;; ((:mysql ("localhost" "a-mysql-db" "user1" "secret")) -;;; (:aodbc ("my-dsn" "a-user" "pass")) -;;; (:postgresql ("localhost" "another-db" "user2" "dont-tell")) -;;; (:postgresql-socket ("pg-server" "a-db-name" "user" "secret-password")) -;;; (:sqlite ("path-to-sqlite-db"))) - -(in-package #:clsql-classic-tests) - -(defvar *config-pathname* - (make-pathname :defaults (user-homedir-pathname) - :name ".clsql-test" - :type "config")) - -(defvar +all-db-types+ - #-clisp '(:postgresql :postgresql-socket :sqlite :aodbc :mysql) - #+clisp '(:sqlite)) - -(defclass conn-specs () - ((aodbc-spec :accessor aodbc-spec :initform nil) - (mysql-spec :accessor mysql-spec :initform nil) - (pgsql-spec :accessor postgresql-spec :initform nil) - (pgsql-socket-spec :accessor postgresql-socket-spec :initform nil) - (sqlite-spec :accessor sqlite-spec :initform nil)) - (:documentation "Connection specs for CLSQL testing")) - - -(defun read-specs (&optional (path *config-pathname*)) - (if (probe-file path) - (with-open-file (stream path :direction :input) - (let ((config (read stream)) - (specs (make-instance 'conn-specs))) - (setf (aodbc-spec specs) (cadr (assoc :aodbc config))) - (setf (mysql-spec specs) (cadr (assoc :mysql config))) - (setf (postgresql-spec specs) (cadr (assoc :postgresql config))) - (setf (postgresql-socket-spec specs) - (cadr (assoc :postgresql-socket config))) - (setf (sqlite-spec specs) (cadr (assoc :sqlite config))) - specs)) - (progn - (warn "CLSQL test config file ~S not found" path) - nil))) - -(defgeneric test-table (spec type)) - -(defmethod test-table (spec type) - (when spec - (let ((db (clsql:connect spec :database-type type :if-exists :new))) - (unwind-protect - (progn - (create-test-table db) - (dolist (row (query "select * from test_clsql" :database db :result-types :auto)) - (test-table-row row :auto type)) - (dolist (row (query "select * from test_clsql" :database db :result-types nil)) - (test-table-row row nil type)) - (loop for row across (map-query 'vector #'list "select * from test_clsql" - :database db :result-types :auto) - do (test-table-row row :auto type)) - (loop for row across (map-query 'vector #'list "select * from test_clsql" - :database db :result-types nil) - do (test-table-row row nil type)) - (loop for row in (map-query 'list #'list "select * from test_clsql" - :database db :result-types nil) - do (test-table-row row nil type)) - (loop for row in (map-query 'list #'list "select * from test_clsql" - :database db :result-types :auto) - do (test-table-row row :auto type)) - (test (map-query nil #'list "select * from test_clsql" - :database db :result-types :auto) - nil - :fail-info "Expected NIL result from map-query nil") - (do-query ((int float bigint str) "select * from test_clsql") - (test-table-row (list int float bigint str) nil type)) - (do-query ((int float bigint str) "select * from test_clsql" :result-types :auto) - (test-table-row (list int float bigint str) :auto type)) - (drop-test-table db) - ) - (disconnect :database db))))) - -;;; -;;; SQLite is typeless: execute untyped tests only. -;;; -(defmethod test-table (spec (type (eql :sqlite))) - (when spec - (let ((db (clsql:connect spec :database-type type :if-exists :new))) - (unwind-protect - (progn - (create-test-table db) - (dolist (row (query "select * from test_clsql" :database db :result-types nil)) - (test-table-row row nil type)) - (loop for row across (map-query 'vector #'list "select * from test_clsql" - :database db :result-types nil) - do (test-table-row row nil type)) - (loop for row in (map-query 'list #'list "select * from test_clsql" - :database db :result-types nil) - do (test-table-row row nil type)) - - (do-query ((int float bigint str) "select * from test_clsql") - (test-table-row (list int float bigint str) nil type)) - (drop-test-table db) - ) - (disconnect :database db))))) - -(defun mysql-low-level (specs) - #-clisp - (let ((spec (mysql-spec specs))) - (when spec - (let ((db (clsql-mysql::database-connect spec :mysql))) - (clsql-mysql::database-execute-command "DROP TABLE IF EXISTS test_clsql" db) - (clsql-mysql::database-execute-command - "CREATE TABLE test_clsql (i integer, sqrt double, sqrt_str CHAR(20))" db) - (dotimes (i 10) - (clsql-mysql::database-execute-command - (format nil "INSERT INTO test_clsql VALUES (~d,~d,'~a')" - i (clsql-base:number-to-sql-string (sqrt i)) - (clsql-base:number-to-sql-string (sqrt i))) - db)) - (let ((res (clsql-mysql::database-query-result-set "select * from test_clsql" db :full-set t :result-types nil))) - (test (mysql:mysql-num-rows - (clsql-mysql::mysql-result-set-res-ptr res)) - 10 - :test #'eql - :fail-info "Error calling mysql-num-rows") - (clsql-mysql::database-dump-result-set res db)) - (clsql-mysql::database-execute-command "DROP TABLE test_clsql" db) - (clsql-mysql::database-disconnect db))))) - - - -;;;; Testing functions - -(defun transform-float-1 (i) - (coerce (* i (abs (/ i 2)) (expt 10 (* 2 i))) 'double-float)) - -(defun transform-bigint-1 (i) - (* i (expt 10 (* 3 (abs i))))) - -(defun create-test-table (db) - (ignore-errors - (clsql:execute-command - "DROP TABLE test_clsql" :database db)) - (clsql:execute-command - "CREATE TABLE test_clsql (t_int integer, t_float float, t_bigint BIGINT, t_str CHAR(30))" - :database db) - (dotimes (i 11) - (let* ((test-int (- i 5)) - (test-flt (transform-float-1 test-int))) - (clsql:execute-command - (format nil "INSERT INTO test_clsql VALUES (~a,~a,~a,'~a')" - test-int - (clsql-base:number-to-sql-string test-flt) - (transform-bigint-1 test-int) - (clsql-base:number-to-sql-string test-flt) - ) - :database db)))) - -(defun parse-double (num-str) - (let ((*read-default-float-format* 'double-float)) - (coerce (read-from-string num-str) 'double-float))) - -(defun test-table-row (row types db-type) - (test (and (listp row) - (= 4 (length row))) - t - :fail-info - (format nil "Row ~S is incorrect format" row)) - (destructuring-bind (int float bigint str) row - (cond - ((eq types :auto) - (test (and (integerp int) - (typep float 'double-float) - (or (eq db-type :aodbc) ;; aodbc doesn't handle bigint conversions - (integerp bigint)) - (stringp str)) - t - :fail-info - (format nil "Incorrect field type for row ~S (types :auto)" row))) - ((null types) - (test (and (stringp int) - (stringp float) - (stringp bigint) - (stringp str)) - t - :fail-info - (format nil "Incorrect field type for row ~S (types nil)" row)) - (setq int (parse-integer int)) - (setq bigint (parse-integer bigint)) - (setq float (parse-double float))) - ((listp types) - (error "NYI") - ) - (t - (test t nil - :fail-info - (format nil "Invalid types field (~S) passed to test-table-row" types)))) - (unless (eq db-type :sqlite) ; SQLite is typeless. - (test (transform-float-1 int) - float - :test #'eql - :fail-info - (format nil "Wrong float value ~A for int ~A (row ~S)" float int row))) - (test float - (parse-double str) - :test #'double-float-equal - :fail-info (format nil "Wrong string value ~A for double ~A~%Row: ~S" - str float row)))) - - -(defun double-float-equal (a b) - (if (zerop a) - (if (zerop b) - t - nil) - (let ((diff (abs (/ (- a b) a)))) - (if (> diff (* 10 double-float-epsilon)) - nil - t)))) - -(defun drop-test-table (db) - (clsql:execute-command "DROP TABLE test_clsql" :database db)) - -(defun db-type-spec (db-type specs) - (let ((accessor (intern (concatenate 'string (symbol-name db-type) - (symbol-name '#:-spec)) - (find-package '#:clsql-classic-tests)))) - (funcall accessor specs))) - -(defun db-type-ensure-system (db-type) - (unless (find-package (symbol-name db-type)) - (asdf:operate 'asdf:load-op - (intern (concatenate 'string - (symbol-name '#:clsql-) - (symbol-name db-type)))))) - -(defun run-tests () - (let ((specs (read-specs))) - (unless specs - (warn "Not running test because test configuration file is missing") - (return-from run-tests :skipped)) - (mysql-low-level specs) - (with-tests (:name "CLSQL") - (dolist (db-type +all-db-types+) - (let ((spec (db-type-spec db-type specs))) - (when spec - (db-type-ensure-system db-type) - (ignore-errors (destroy-database spec db-type)) - (ignore-errors (create-database spec db-type)) - (test-table spec db-type)))))) - t) diff --git a/clsql-classic-tests.asd b/clsql-classic-tests.asd deleted file mode 100644 index 3d2961f..0000000 --- a/clsql-classic-tests.asd +++ /dev/null @@ -1,37 +0,0 @@ -;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*- -;;;; ************************************************************************* -;;;; FILE IDENTIFICATION -;;;; -;;;; Name: clsql-classic-tests.asd -;;;; Purpose: ASDF system definitionf for clsql testing package -;;;; Author: Kevin M. Rosenberg -;;;; Date Started: Apr 2003 -;;;; -;;;; $Id$ -;;;; ************************************************************************* - -(in-package #:cl-user) -(defpackage #:clsql-classic-tests-system (:use #:asdf #:cl)) -(in-package #:clsql-classic-tests-system) - -(defsystem clsql-classic-tests - :name "clsql-classic-tests" - :author "Kevin Rosenberg " - :maintainer "Kevin M. Rosenberg " - :licence "Lessor Lisp General Public License" - :description "Testing suite for CLSQL" - - :depends-on (clsql ptester #-clisp clsql-mysql) - :components - ((:module :classic-tests - :components - ((:file "package") -;; (:file "tables" :depends-on ("package"))) - (:file "tests" :depends-on ("package"))) - ))) - -(defmethod perform ((o test-op) (c (eql (find-system 'clsql-classic-tests)))) - (unless (funcall (intern (symbol-name '#:run-tests) - (find-package '#:clsql-classic-tests))) - (error "test-op failed"))) - diff --git a/clsql-classic.asd b/clsql-classic.asd index a700cfd..73734df 100644 --- a/clsql-classic.asd +++ b/clsql-classic.asd @@ -39,5 +39,4 @@ #+(or allegro lispworks cmu sbcl openmcl mcl scl) (defmethod perform ((o test-op) (c (eql (find-system 'clsql-classic)))) - (operate 'load-op 'clsql-classic-tests) - (operate 'test-op 'clsql-classic-tests)) + (warn "Testing is provided by the CLSQL-TESTS system")) diff --git a/clsql-tests.asd b/clsql-tests.asd index b4cbdb9..eeca182 100644 --- a/clsql-tests.asd +++ b/clsql-tests.asd @@ -25,12 +25,14 @@ :version "" :licence "" :description "A regression test suite for CLSQL." - :depends-on (clsql clsql-classic-tests rt) + :depends-on (clsql ptester rt) :components ((:module tests :serial t :components ((:file "package") + (:file "utils") (:file "test-init") + (:file "test-basic") (:file "test-connection") (:file "test-fddl") (:file "test-fdml") diff --git a/debian/changelog b/debian/changelog index 5d749ae..7669196 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +cl-sql (2.6.1-1) unstable; urgency=low + + * New upstream + + -- Kevin M. Rosenberg Sat, 10 Apr 2004 19:49:58 -0600 + cl-sql (2.6.0-1) unstable; urgency=low * New upstream diff --git a/doc/clsql.pdf b/doc/clsql.pdf index c63b94c..8595497 100644 --- a/doc/clsql.pdf +++ b/doc/clsql.pdf @@ -2049,10 +2049,10 @@ endobj >> endobj 313 0 obj -<< /Length 1446 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 1455 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -Gau0C997gc&AJ$C#^`M`_29b"e8'UNofoi(B4c6l$e?NoPUr8tn`=iQ%XG0:^EP^DY>Dcb\]4*RlVB\BrWTG[b?UM5_BjB5/c+)k,g?^js-7m'P*F%sUV4[4b_Q44gerZP;>$4UoF7*^[9Siak+\QMT?]0Ro[tQM6hcfqm%hfB#$:#qh%0YrkLc^os+_?@/9*EP[hE'5FBP/8le/'*>efCj!l-r1d9_cfA^8#4Ra\ldTA/]au:CRDqMH17`tSbq]nI$-dS#-fG6\d'WYl5CFiU9E$%PW&.rJ`G&+#GXL%)e=V6L"`]L$+RBYoKX'k4g,9"uW6IH^*-NSX=BSbX"hngt?KNg(d!t*J5hMp?KOr=0VVtd7ES-i5:jK59?u&:'8qT^*KXbW$NJf%2RN@7]CfIEL)3sT7^fK4)iRI!.8jl5@#K]U=!Kt=jaF!&?o18ZoC_N[*,;DBXKu,:;Eo&9p^R(d[,`R0FZd&o'^]rAhdUj@*_&Xt7ZM!MWSng3;%[Ym8CLLegm*#lG)$Xi"3rUd/D_!Tk/k?dMs"\+10i`sDQP=ega%9gH>R!/_lh5@L6F$SF\eMBALCN?h;CJZ8?'Yk1$8'>D0N=sojT)r*9c5Z3V3^[*NPK5rkQ-oWm%8[HN>X;j_%_NPiS'rgbIOYTc#COdPijNg@b,4lCT0#LY-MFP[7oAG)I+%'(g!G[.7h:207a=?,X"?X;lrIcELddJgLXXm`1JYWG$&RL?@=8pE0$%s]d?GYcZJH`u\RcQ(ml&JMXiQks'8@I]pj?CrkdbLK3l^:aC>o&]_@ZM:KI0q`d*-5#LTV3Z,FX*SJUelGJYU64IHp>j;$9@?e-gWC>;cQn.7>7iUYNrDqLnJU;kQ8]4ge$1mbW#=52WAZ"s4)h9ai_[>JDEn?qU'k)dAKoK@JZI$d@p6/@,_E$=&a*Vme"\+T`9K9M:r-:R>'q4p>-2C&A[IO%:/cI<^6.I&YbG@Xm#b[er6@\r$%Qcb"\="c$IJlF\>8]ng.b'Z7tLDFK>NUD3e#sk9Dl!i5`>>QYm_u:lG)5AR#Cb*L&Vr>cNZVq7#NE7-dP(ccp7Ylb)LO'1sGO:"p@IZLla"?rsP8kg3s~> +Gau0C95iiK&AJ$C#WX``,%aB&H3ItZ-gLq>Cq&&!D6_a[JWZm5=BT`6.:3&O;A(9R%mLOUI,U%Iq9\O<:$VIip])LVUrRUXOlZ+,"n9!Pso,M4B\db;'tO$-VIY9>`!W/S#?VJ,2q7a8B(bUsauX0D8Ur`#CU)U&OtJ.#7ukK((N(.HdVf[;?=G=dqkZ;Jp/Kn>`^q$[`n%;]H4XI5Sc]"]bBJkfKncBO$>HH,dc/_FucYYG6hD^^d6I\nXf;*:U[rC4>_[FFFiJ^NM(g5rRIsRn8D/Jq_/TK3k>G1u8Z.oXoR_\k#spdP^((L#QHqVUERW%*K7]FKINH!uO)uB$Xi58oeBJ>*]C9p;TH_Qki15Yg!,#WFli\$0Sqa5KF7Z5[8S;[6/*tS^RFKSYV^J,2Xd$MafLF-??])oJkMVd9DahD3`O'+KJ\ZVXFP`D2=AL*$.Z?O"[Q[+7H)/M)"=*4hV/;h()+s&JL:MUu>,P8>8hABhZ)3VW$GiJ"rGcU<-\a86cXQ:6rtC4lCT@#79mEEc<0W&<&dZTJ+]M=qb?EB:&E+SolPUB%D1X&fNs(cdDBC%=Q[/_i<)5Im(KhH^C#Xh6r)MQ@o7J&KSPV_o(0i<_fE/R0-;;9I/J/6:mphGVNV(0*N+-Q=R,XD$tqUHLWBf9.u@k-juEgh2M\%]tOhFN8>LYkW`fnFr,G'=Th$6;5#6Sa>Y'[38<.2hi!6`Cup6 endstream endobj 314 0 obj @@ -2064,10 +2064,10 @@ endobj >> endobj 315 0 obj -<< /Length 483 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 390 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -GasbW:N(h=(rl#lMB6&t[4P@n)fD$SVu>jsfqC[]7KK@)`,@k.K!m^QH>.lnqn2ChUn'5Q4Jr0(L]CX=#V6u):pVjkj9U0%+SGiZ_=rJ^Uj<(e69RjN65U+HFcgEA(+.<%_$%'rQYU"b]s9o6'c#?+=IN>4PSX':I2+S!>LdJ%eX*hs.-$aD>_r^^>WJe%Y*RTi.mJQt=kQM9gh4[6>S^6%UW#,E(EnUP0FTShQro^;3>(DAn%%6CA7K%^WLndV!,5_=U;5A%PBhp-u1&Rs(1d@qp`cArF[4!dDG1! +Gasakb>,r/&A70VHn5mfI`-*Y>67*H'+`t3#:FMK7?^Wi6/q?QdO:@i.`dt4dI,6FaI.jeDAg4q+s?.VJSg&@EXr7G#&oP-`+pJ6n?S-UUKcPW,H]h3(LTfHJs^VNJ48;'ja_M endstream endobj 316 0 obj @@ -2079,10 +2079,10 @@ endobj >> endobj 317 0 obj -<< /Length 1497 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 1540 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -Gb!;d95iiK&AJ$C#W]96,%;s_H3Is_-gN?f/2gdTL`$56l$e8g;O$*PXLqhe*aK^Keq]sB>,74*9YUSgjDGW$%[_Fc&WZ;HX7O-jF;nrE&H-]f)cM/R_R=c?%**'j@]!q)o0G&Z1ti_q!3]boT)XpH+2S1Xu+tAWa1t&0%U]W$UtZ;e-*q7TEq-@]KNcK(l!*eM,9=H35BW+@Pn_$g?^_QX9d[D7c$O^Q3VtrXi"*#50!Nh5ctXJCXX#)9lrrZe5_,(#\`>pF7TlO7oX@Dp*(Jq\9FF9f:h@=?cM^V*8r>Inh9[K!m!:Ff&&Q$:60?(!=L%6c0E(U6!jlI5Pkg0aPQXU_%7,"[%p?4,FQ4&MA*6WE][[Am0JIlnQnWJcfK=0M77P8G,nrH7lGVc7&;0OV<$>q69C=>H]ql5MqL5jL"5\29QSu(W5k>:%JRmf#TA*UoD5)b*T\K.`',`.Lb)Um$QD1:XM"jfNe+G)>%W&*;"FD>J5ffI]r#PP(7A3U9(8m1GId_XP6'><=SJu)HEO"Tu_"AW:'dHnppq"!,q\sA\d-/4(/.%=$V\T>9%"f=[8,`l11*%G~> +Gb!;d>Ap;q'RlZ]Jb%/7X5F!?)QAuKg"C5CeRgam>#h&?E56!\!)F"KR=AQGp=NW)RF`oA5%f7\h`:[PEYC(.5!dFKJ-T@39GWBVZnO@irL'+re;!,^%PV:`Kt6p;r%#q[L%\FQs'g/3Ai:Tqe\K$ZJT';6`Q-Li]YF>Fs0rK(2p:mZ6IRNaflaI`EZO2GU1@=t%8qXC'm`9E#WrB))fri?W_bK7@/1JHRLhHQ](N5)d/2ZJ3)H4\(a-&RcA#u7&!FU%A/Z\6bHclb&Le&,<@KBhEf6]\f[08G`kOXrh-<'UO%_s1HF;MeR:nJuV>As8Xu/@d0It\\aia.%i2?lGBKC?(iYc3O.`c,f;;PG,g"ttG#d4E+KP@Sh^S*iS\bh)bI]^KQ-eE]rfQOf`8s;mMB)YNMp]3%'[EB:Q'kn*fZ`R5NoQPHu#JV;j;H$FWA*S.P1:=rtK,o7?B%U,PV_5bb3S<:]:hc4,:I`qK_Mh;aa+TBJAS?7G+3$c?7WhVPEdCV?k\MHNnt^!a6X9%Oqo<1oks.oRUP&-%WF3tnI/XlNPuRO'j*_HjN]D@"YV-=#@.0fg,A+.(dB9ZDMc]J.q`6I^HNi)3b,2EiAjtNur]o6Oo_%1?/h[J',Td0S!BM<8B:lgl8=ud48uoHHZTYFPr_9YZ.td>uZ76[q5=>kc:$"cqujJ0[9.LO_EABN]e'\Q([=Y[pPV^P!^`hEYU35\po,!ZE`.A)e+e9/QmI.gk endstream endobj 318 0 obj @@ -2094,10 +2094,10 @@ endobj >> endobj 319 0 obj -<< /Length 392 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 280 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -Gasakb>,r/&A70VHn5mfFr]\m>G;&/L"pZZ[:Z91"F>sIPTYq^Qr^pDo)pkMp;0LW1B>,csP'c2gl0QMBq1nHLAJ,3WPY8(Gd;D?\C<(_\pHh&pMF87YC+f8j,T#oRZL-7c6/Cu=DZZME2c5d+N>bi^fS-CBm_8K":RHYXp?+.K~> +Gas2D]+2\3$q9o2^a7;CFf33gL0'K1A.PdfH3n7ALt9-cI9bP]LjYPT%A/,RC9k(Kg2h2C?T_$dA20Fic,'W2Nk`)bZ:![,oMkJ3u1n\qIjB^d)!<8=HCgU*1(G2#6#"h_fj=76&=*=[UGQ~> endstream endobj 320 0 obj @@ -2109,10 +2109,10 @@ endobj >> endobj 321 0 obj -<< /Length 1126 /Filter [ /ASCII85Decode /FlateDecode ] +<< /Length 1123 /Filter [ /ASCII85Decode /FlateDecode ] >> stream -Gatm:95iQE&AJ$C#W]7`;)+k;]aF*-%cRQ%L[?r+(dI'+,$3/[I;kVKN>OI/41$O(a7q*/X7hR![Kr+t`gKO1"]i'0N#[rTfb/.Ith2")dK)fgS'0K/&a@J<-FUbl47I@R"aNo+.3#X9]q[^-ur)#LQ0k'p!]7r,ufJq2Ar`%J]iSAX`RllJ7]j0AIA15e`1Mr^A/#`>_Lgu[(KW.VI(C0RC?>Z>uQ^5'"&4CJZ^5V))%`ZXigLf#sj`LdNU>bAPi3]UtN=e@B/(@B<*d(86RQ8Ll7Ke/(82;!-2d@EVQaGO;k?Gb>kisdq=UD2*(kiHH\I'p*sgcMoi3_W=hdVD"+QB)(1pQ*p-Q,n6Y'Wo$Rr2U`B>]QP-GXOdQ=O*fFK^JSNAb`6Up/fe$+0/c\,Ku>@o#NH8-:fh"$.V\Z>en15Qkb;Vl#YmgXb8F'be.g]%<$3e`XA96`9]@:h/MoL_#HbN2nNqrL(Mkc:A(th]7-[#ESSfu2JlSI^7Bm&jg#IOcL8&Xs#G\Vj_N.j>)\-u)TtsbOHsQ&L[s-Gjbm,AX-mk8'THJ91K;ZGNUg=I]aN68CF +Gatm:a_oie&A@rkKH/\kL_s$c[K8&=+:ca>\jbhZl%,-jYu"SF,WU_]^6D'T[,`Ng65Rp\G0[bZ9es;oUQ1+,8-:6]7bDu+&I6L?3(1'W'1>%$1j5%9oDAG9?bhBea%=!94l7EbJCNju"9_/PFW0.eI_2#X\)V"H1VTJd33MGR1?YfUc4/8tD9,CML4ImgDP0\>YXE*Kg`0t>iDX(Kpj+YLHoNI<%s:F!]P()-KHacii-nrir,o%S+"2^_@h^`6dof^\$>qN4lT9\'arVEKVkP^cD/rLbob,[tSgb0Gb4#>HqNsK>#:_c.[okBCLc769oA_3D*&l\7)]Ytpb"jDq[rs5M!)l=4NWb8rqP#KP"Ilsan34>q%glkj&E0[KGnFQPEV,)#7(n8\ZQ:u!%%cb,'KB)PEcH#5QoN3A,Yi\\M5cRloXm8Y%0*Sm:Nm':(tCpLWOk1uTN>b3Pu$R0)WhgU=f\t`eAo2LMI\95hp_&nd_5?f7p>Zk/eLOG8k"(rD#jlMt3la6l4"ZeeCN(U1hUeBqflEn^#4,nLk\/>cR&;6UK\oNNSOs?5;TD*;(,sPd'(9o"8D3t)@&b(`:O\^qAO:^8K,O'#$rZAH0'rq@H$(:e^IuRN2'/6@Bb,95ehe.5:].EMn,dU1W)F-iPd-V&s!:i_hI&skX!je^QaHp/#](t*35@l[jt5:%Y[.;X`s(H_Wbo4GD`#&ac5DXCP#laZ>+.NO<3gaLX+[G^@"(p]Q2il1bbBD+P_d(4VDfhRHk&8bokWYCF9.S(_4[WM=]OdC*c/)H*)/`7KRlfUld/fV2+dGAXdZ+nOc_2JS$"#GfZ;`7#MRrR#(.Eo=(DZ?u(e-`ZX6OWEuESsjm^Q=i(jUts.G?4mE]7DXXZ&k?-e8?VTkc&p#Dra5Sj?i7j?s'!ME3dlPd7r%*$lG^cjijcfZk!P$O:%A&ca`lX/7dWI~> endstream endobj 322 0 obj @@ -4225,9 +4225,9 @@ endobj xref 0 522 0000000000 65535 f -0000154820 00000 n -0000155491 00000 n -0000155584 00000 n +0000154664 00000 n +0000155335 00000 n +0000155428 00000 n 0000000015 00000 n 0000000071 00000 n 0000000427 00000 n @@ -4239,179 +4239,179 @@ xref 0000003670 00000 n 0000003793 00000 n 0000004194 00000 n -0000155749 00000 n +0000155593 00000 n 0000004330 00000 n -0000155815 00000 n +0000155659 00000 n 0000004466 00000 n -0000155881 00000 n +0000155725 00000 n 0000004602 00000 n -0000155949 00000 n +0000155793 00000 n 0000004737 00000 n -0000156017 00000 n +0000155861 00000 n 0000004873 00000 n -0000156085 00000 n +0000155929 00000 n 0000005009 00000 n -0000156153 00000 n +0000155997 00000 n 0000005145 00000 n -0000156221 00000 n +0000156065 00000 n 0000005281 00000 n -0000156289 00000 n +0000156133 00000 n 0000005417 00000 n -0000156355 00000 n +0000156199 00000 n 0000005553 00000 n -0000156423 00000 n +0000156267 00000 n 0000005688 00000 n -0000156491 00000 n +0000156335 00000 n 0000005824 00000 n -0000156559 00000 n +0000156403 00000 n 0000005960 00000 n -0000156627 00000 n +0000156471 00000 n 0000006096 00000 n -0000156695 00000 n +0000156539 00000 n 0000006232 00000 n -0000156763 00000 n +0000156607 00000 n 0000006368 00000 n -0000156831 00000 n +0000156675 00000 n 0000006504 00000 n -0000156899 00000 n +0000156743 00000 n 0000006640 00000 n -0000156965 00000 n +0000156809 00000 n 0000006776 00000 n -0000157032 00000 n +0000156876 00000 n 0000006912 00000 n -0000157100 00000 n +0000156944 00000 n 0000007048 00000 n -0000157167 00000 n +0000157011 00000 n 0000007183 00000 n -0000157234 00000 n +0000157078 00000 n 0000007319 00000 n -0000157301 00000 n +0000157145 00000 n 0000007455 00000 n -0000157368 00000 n +0000157212 00000 n 0000007591 00000 n -0000157434 00000 n +0000157278 00000 n 0000007726 00000 n -0000157493 00000 n +0000157337 00000 n 0000007862 00000 n -0000157559 00000 n +0000157403 00000 n 0000007998 00000 n -0000157625 00000 n +0000157469 00000 n 0000008134 00000 n -0000157691 00000 n +0000157535 00000 n 0000008270 00000 n -0000157757 00000 n +0000157601 00000 n 0000008406 00000 n -0000157823 00000 n +0000157667 00000 n 0000008542 00000 n -0000157889 00000 n +0000157733 00000 n 0000008678 00000 n -0000157955 00000 n +0000157799 00000 n 0000008814 00000 n -0000158021 00000 n +0000157865 00000 n 0000008950 00000 n -0000158087 00000 n +0000157931 00000 n 0000009086 00000 n -0000158153 00000 n +0000157997 00000 n 0000009222 00000 n -0000158219 00000 n +0000158063 00000 n 0000009358 00000 n -0000158285 00000 n +0000158129 00000 n 0000009494 00000 n -0000158351 00000 n +0000158195 00000 n 0000009630 00000 n -0000158417 00000 n +0000158261 00000 n 0000009766 00000 n -0000158483 00000 n +0000158327 00000 n 0000009902 00000 n -0000158549 00000 n +0000158393 00000 n 0000010038 00000 n -0000158615 00000 n +0000158459 00000 n 0000010176 00000 n -0000158682 00000 n +0000158526 00000 n 0000010314 00000 n -0000158749 00000 n +0000158593 00000 n 0000010452 00000 n -0000158816 00000 n +0000158660 00000 n 0000010589 00000 n -0000158883 00000 n +0000158727 00000 n 0000010727 00000 n -0000158950 00000 n +0000158794 00000 n 0000010865 00000 n -0000159017 00000 n +0000158861 00000 n 0000011003 00000 n -0000159084 00000 n +0000158928 00000 n 0000011139 00000 n -0000159151 00000 n +0000158995 00000 n 0000011275 00000 n -0000159218 00000 n +0000159062 00000 n 0000011411 00000 n 0000012490 00000 n 0000012616 00000 n 0000012853 00000 n -0000159285 00000 n +0000159129 00000 n 0000012987 00000 n -0000159352 00000 n +0000159196 00000 n 0000013120 00000 n -0000159419 00000 n +0000159263 00000 n 0000013254 00000 n -0000159486 00000 n +0000159330 00000 n 0000013388 00000 n -0000159553 00000 n +0000159397 00000 n 0000013522 00000 n -0000159620 00000 n +0000159464 00000 n 0000013656 00000 n -0000159687 00000 n +0000159531 00000 n 0000013789 00000 n -0000159754 00000 n +0000159598 00000 n 0000013923 00000 n -0000159814 00000 n +0000159658 00000 n 0000014057 00000 n -0000159881 00000 n +0000159725 00000 n 0000014191 00000 n -0000159948 00000 n +0000159792 00000 n 0000014325 00000 n -0000160017 00000 n +0000159861 00000 n 0000014458 00000 n -0000160086 00000 n +0000159930 00000 n 0000014592 00000 n -0000160155 00000 n +0000159999 00000 n 0000014726 00000 n -0000160224 00000 n +0000160068 00000 n 0000014860 00000 n -0000160293 00000 n +0000160137 00000 n 0000014993 00000 n -0000160362 00000 n +0000160206 00000 n 0000015127 00000 n -0000160429 00000 n +0000160273 00000 n 0000015261 00000 n -0000160498 00000 n +0000160342 00000 n 0000015395 00000 n -0000160567 00000 n +0000160411 00000 n 0000015528 00000 n -0000160636 00000 n +0000160480 00000 n 0000015662 00000 n -0000160703 00000 n +0000160547 00000 n 0000015796 00000 n -0000160772 00000 n +0000160616 00000 n 0000015929 00000 n -0000160841 00000 n +0000160685 00000 n 0000016062 00000 n -0000160910 00000 n +0000160754 00000 n 0000016196 00000 n -0000160977 00000 n +0000160821 00000 n 0000016330 00000 n -0000161046 00000 n +0000160890 00000 n 0000016464 00000 n 0000017073 00000 n 0000017183 00000 n 0000019379 00000 n 0000019505 00000 n 0000019558 00000 n -0000161113 00000 n +0000160957 00000 n 0000019699 00000 n 0000019882 00000 n 0000020056 00000 n -0000161182 00000 n +0000161026 00000 n 0000020197 00000 n 0000021986 00000 n 0000022112 00000 n @@ -4538,214 +4538,214 @@ xref 0000093159 00000 n 0000093296 00000 n 0000093433 00000 n -0000094973 00000 n -0000095083 00000 n -0000095659 00000 n -0000095769 00000 n -0000097360 00000 n -0000097470 00000 n -0000097955 00000 n -0000098065 00000 n -0000099285 00000 n -0000099395 00000 n -0000101005 00000 n -0000101115 00000 n -0000101931 00000 n -0000102057 00000 n -0000102086 00000 n -0000102223 00000 n -0000103822 00000 n -0000103948 00000 n -0000103985 00000 n -0000161251 00000 n -0000104124 00000 n -0000161320 00000 n -0000104263 00000 n -0000104877 00000 n -0000105003 00000 n -0000105032 00000 n -0000105169 00000 n -0000107553 00000 n -0000107679 00000 n -0000107724 00000 n -0000107865 00000 n -0000108004 00000 n -0000161389 00000 n -0000108142 00000 n -0000109239 00000 n -0000109365 00000 n -0000109394 00000 n -0000109531 00000 n -0000112088 00000 n -0000112214 00000 n -0000112267 00000 n -0000112408 00000 n -0000112547 00000 n -0000112688 00000 n -0000112829 00000 n -0000114374 00000 n -0000114500 00000 n -0000114537 00000 n -0000114674 00000 n -0000114811 00000 n -0000117117 00000 n -0000117243 00000 n -0000117296 00000 n -0000117437 00000 n -0000117576 00000 n -0000117717 00000 n -0000117858 00000 n -0000118643 00000 n -0000118769 00000 n -0000118806 00000 n -0000118943 00000 n -0000119080 00000 n -0000121295 00000 n -0000121421 00000 n -0000121458 00000 n -0000121599 00000 n -0000121737 00000 n -0000122959 00000 n -0000123085 00000 n -0000123130 00000 n -0000123267 00000 n -0000123404 00000 n -0000123541 00000 n -0000124097 00000 n -0000124207 00000 n -0000125932 00000 n -0000126058 00000 n -0000126095 00000 n -0000126233 00000 n -0000126367 00000 n -0000126737 00000 n -0000126863 00000 n -0000126892 00000 n -0000127024 00000 n -0000128784 00000 n -0000128894 00000 n -0000130819 00000 n -0000130929 00000 n -0000132750 00000 n -0000132860 00000 n -0000133651 00000 n -0000133761 00000 n -0000135235 00000 n -0000135361 00000 n -0000135390 00000 n -0000161458 00000 n -0000161512 00000 n -0000135528 00000 n -0000161578 00000 n -0000135719 00000 n -0000135920 00000 n -0000136062 00000 n -0000136341 00000 n -0000136468 00000 n -0000136610 00000 n -0000136830 00000 n -0000136939 00000 n -0000137063 00000 n -0000137180 00000 n -0000137493 00000 n -0000137744 00000 n -0000137943 00000 n -0000138151 00000 n -0000161644 00000 n -0000138434 00000 n -0000161713 00000 n -0000138621 00000 n -0000138731 00000 n -0000138884 00000 n -0000139071 00000 n -0000139277 00000 n -0000139444 00000 n -0000139757 00000 n -0000139914 00000 n -0000140155 00000 n -0000140344 00000 n -0000140533 00000 n -0000140722 00000 n -0000140917 00000 n -0000141062 00000 n -0000141235 00000 n -0000141409 00000 n -0000141574 00000 n -0000141780 00000 n -0000141957 00000 n -0000142175 00000 n -0000142416 00000 n -0000142628 00000 n -0000142816 00000 n -0000143046 00000 n -0000143264 00000 n -0000143470 00000 n -0000143676 00000 n -0000143910 00000 n -0000144174 00000 n -0000144416 00000 n -0000144626 00000 n -0000144839 00000 n -0000145045 00000 n -0000145194 00000 n -0000145384 00000 n -0000145562 00000 n -0000145740 00000 n -0000145883 00000 n -0000146044 00000 n -0000146246 00000 n -0000146436 00000 n -0000146632 00000 n -0000146816 00000 n -0000147052 00000 n -0000147242 00000 n -0000147373 00000 n -0000147527 00000 n -0000147675 00000 n -0000147866 00000 n -0000148068 00000 n -0000148334 00000 n -0000148655 00000 n -0000148813 00000 n -0000148953 00000 n -0000149138 00000 n -0000161780 00000 n -0000149409 00000 n -0000161849 00000 n -0000149642 00000 n -0000149905 00000 n -0000150108 00000 n -0000150248 00000 n -0000150433 00000 n -0000161918 00000 n -0000150704 00000 n -0000161987 00000 n -0000150937 00000 n -0000151200 00000 n -0000151444 00000 n -0000151584 00000 n -0000151769 00000 n -0000162056 00000 n -0000152040 00000 n -0000162125 00000 n -0000152273 00000 n -0000152536 00000 n -0000152694 00000 n -0000152834 00000 n -0000153019 00000 n -0000162194 00000 n -0000153290 00000 n -0000162263 00000 n -0000153523 00000 n -0000153786 00000 n -0000153920 00000 n -0000154034 00000 n -0000154145 00000 n -0000154261 00000 n -0000154370 00000 n -0000154482 00000 n -0000154603 00000 n -0000154710 00000 n +0000094982 00000 n +0000095092 00000 n +0000095575 00000 n +0000095685 00000 n +0000097319 00000 n +0000097429 00000 n +0000097802 00000 n +0000097912 00000 n +0000099129 00000 n +0000099239 00000 n +0000100849 00000 n +0000100959 00000 n +0000101775 00000 n +0000101901 00000 n +0000101930 00000 n +0000102067 00000 n +0000103666 00000 n +0000103792 00000 n +0000103829 00000 n +0000161095 00000 n +0000103968 00000 n +0000161164 00000 n +0000104107 00000 n +0000104721 00000 n +0000104847 00000 n +0000104876 00000 n +0000105013 00000 n +0000107397 00000 n +0000107523 00000 n +0000107568 00000 n +0000107709 00000 n +0000107848 00000 n +0000161233 00000 n +0000107986 00000 n +0000109083 00000 n +0000109209 00000 n +0000109238 00000 n +0000109375 00000 n +0000111932 00000 n +0000112058 00000 n +0000112111 00000 n +0000112252 00000 n +0000112391 00000 n +0000112532 00000 n +0000112673 00000 n +0000114218 00000 n +0000114344 00000 n +0000114381 00000 n +0000114518 00000 n +0000114655 00000 n +0000116961 00000 n +0000117087 00000 n +0000117140 00000 n +0000117281 00000 n +0000117420 00000 n +0000117561 00000 n +0000117702 00000 n +0000118487 00000 n +0000118613 00000 n +0000118650 00000 n +0000118787 00000 n +0000118924 00000 n +0000121139 00000 n +0000121265 00000 n +0000121302 00000 n +0000121443 00000 n +0000121581 00000 n +0000122803 00000 n +0000122929 00000 n +0000122974 00000 n +0000123111 00000 n +0000123248 00000 n +0000123385 00000 n +0000123941 00000 n +0000124051 00000 n +0000125776 00000 n +0000125902 00000 n +0000125939 00000 n +0000126077 00000 n +0000126211 00000 n +0000126581 00000 n +0000126707 00000 n +0000126736 00000 n +0000126868 00000 n +0000128628 00000 n +0000128738 00000 n +0000130663 00000 n +0000130773 00000 n +0000132594 00000 n +0000132704 00000 n +0000133495 00000 n +0000133605 00000 n +0000135079 00000 n +0000135205 00000 n +0000135234 00000 n +0000161302 00000 n +0000161356 00000 n +0000135372 00000 n +0000161422 00000 n +0000135563 00000 n +0000135764 00000 n +0000135906 00000 n +0000136185 00000 n +0000136312 00000 n +0000136454 00000 n +0000136674 00000 n +0000136783 00000 n +0000136907 00000 n +0000137024 00000 n +0000137337 00000 n +0000137588 00000 n +0000137787 00000 n +0000137995 00000 n +0000161488 00000 n +0000138278 00000 n +0000161557 00000 n +0000138465 00000 n +0000138575 00000 n +0000138728 00000 n +0000138915 00000 n +0000139121 00000 n +0000139288 00000 n +0000139601 00000 n +0000139758 00000 n +0000139999 00000 n +0000140188 00000 n +0000140377 00000 n +0000140566 00000 n +0000140761 00000 n +0000140906 00000 n +0000141079 00000 n +0000141253 00000 n +0000141418 00000 n +0000141624 00000 n +0000141801 00000 n +0000142019 00000 n +0000142260 00000 n +0000142472 00000 n +0000142660 00000 n +0000142890 00000 n +0000143108 00000 n +0000143314 00000 n +0000143520 00000 n +0000143754 00000 n +0000144018 00000 n +0000144260 00000 n +0000144470 00000 n +0000144683 00000 n +0000144889 00000 n +0000145038 00000 n +0000145228 00000 n +0000145406 00000 n +0000145584 00000 n +0000145727 00000 n +0000145888 00000 n +0000146090 00000 n +0000146280 00000 n +0000146476 00000 n +0000146660 00000 n +0000146896 00000 n +0000147086 00000 n +0000147217 00000 n +0000147371 00000 n +0000147519 00000 n +0000147710 00000 n +0000147912 00000 n +0000148178 00000 n +0000148499 00000 n +0000148657 00000 n +0000148797 00000 n +0000148982 00000 n +0000161624 00000 n +0000149253 00000 n +0000161693 00000 n +0000149486 00000 n +0000149749 00000 n +0000149952 00000 n +0000150092 00000 n +0000150277 00000 n +0000161762 00000 n +0000150548 00000 n +0000161831 00000 n +0000150781 00000 n +0000151044 00000 n +0000151288 00000 n +0000151428 00000 n +0000151613 00000 n +0000161900 00000 n +0000151884 00000 n +0000161969 00000 n +0000152117 00000 n +0000152380 00000 n +0000152538 00000 n +0000152678 00000 n +0000152863 00000 n +0000162038 00000 n +0000153134 00000 n +0000162107 00000 n +0000153367 00000 n +0000153630 00000 n +0000153764 00000 n +0000153878 00000 n +0000153989 00000 n +0000154105 00000 n +0000154214 00000 n +0000154326 00000 n +0000154447 00000 n +0000154554 00000 n trailer << /Size 522 @@ -4753,5 +4753,5 @@ trailer /Info 4 0 R >> startxref -162332 +162176 %%EOF diff --git a/doc/html.tar.gz b/doc/html.tar.gz index 09cc776910c1c6c2a9e6eb0e4974b531ba07dc49..891eec545e3de20853221d561177020389c1570d 100644 GIT binary patch literal 42467 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 success - A boolean flag. If &t;, a new database wa + A boolean flag. If &t;, a new database was successfully created. @@ -1700,6 +1700,7 @@ The default is &nil;. => T (create-database '("localhost" "new" "dent" "badpasswd") :database-type :mysql) +=> Error: While trying to access database localhost/new/dent using database-type MYSQL: Error database-create failed: mysqladmin: connect to server at 'localhost' failed @@ -1716,8 +1717,7 @@ error: 'Access denied for user: 'root@localhost' (Using password: YES)' Exceptional Situations An exception will be thrown if the database system does not allow new databases to be created or if database creation - fails. Currently, only the :postgresql-socket - does not allow new databases to be created. + fails. Notes @@ -1762,7 +1762,7 @@ error: 'Access denied for user: 'root@localhost' (Using password: YES)' success - A boolean flag. If &t;, a new database wa + A boolean flag. If &t;, the database was successfully destroyed. @@ -1782,6 +1782,7 @@ error: 'Access denied for user: 'root@localhost' (Using password: YES)' => T (destroy-database '("localhost" "new" "dent" "dent") :database-type :postgresql) +=> Error: While trying to access database localhost/test2/root using database-type POSTGRESQL: Error database-destory failed: dropdb: database removal failed: ERROR: database "test2" does not exist @@ -1797,9 +1798,7 @@ Error: While trying to access database localhost/test2/root Exceptional Situations An exception will be thrown if the database system does not allow databases to be removed, the database does not exist, or - if database removal fails. Currently, only the - :postgresql-socket does not allow - databases to be destroyed. + if database removal fails. Notes @@ -1817,7 +1816,7 @@ Error: While trying to access database localhost/test2/root PROBE-DATABASE - tests for existance of a database + tests for existence of a database Function @@ -1853,7 +1852,7 @@ Error: While trying to access database localhost/test2/root Description - This function tests for the existance of a database in + This function tests for the existence of a database in the database system specified by database-type. @@ -1872,8 +1871,8 @@ Error: While trying to access database localhost/test2/root Exceptional Situations An exception maybe thrown if the database system does - not receive administrator-level authentication. This function - may need to read the administrative table of the database + not receive administrator-level authentication since function + may need to read the administrative database of the database system. diff --git a/tests/package.lisp b/tests/package.lisp index a4333f1..df38db1 100644 --- a/tests/package.lisp +++ b/tests/package.lisp @@ -17,6 +17,6 @@ (in-package #:cl-user) (defpackage #:clsql-tests - (:use #:clsql #:common-lisp #:rtest #:clsql-classic-tests) + (:use #:clsql #:common-lisp #:rtest #:ptester) (:export #:run-tests #:test-initialise-database #:test-connect-to-database) (:documentation "Regression tests for CLSQL.")) diff --git a/tests/test-basic.lisp b/tests/test-basic.lisp new file mode 100644 index 0000000..7664720 --- /dev/null +++ b/tests/test-basic.lisp @@ -0,0 +1,164 @@ +;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*- +;;;; ************************************************************************* +;;;; FILE IDENTIFICATION +;;;; +;;;; Name: test-basic.lisp +;;;; Purpose: Tests for clsql-base and result types +;;;; Author: Kevin M. Rosenberg +;;;; Created: Mar 2002 +;;;; +;;;; $Id: tests.lisp 8926 2004-04-10 21:12:52Z kevin $ +;;;; +;;;; This file, part of CLSQL, is Copyright (c) 2002-2004 by Kevin M. Rosenberg +;;;; +;;;; CLSQL users are granted the rights to distribute and use this software +;;;; as governed by the terms of the Lisp Lesser GNU Public License +;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL. +;;;; ************************************************************************* + +(in-package #:clsql-tests) + + +(defun test-basic (spec type) + (let ((db (clsql:connect spec :database-type type :if-exists :new))) + (unwind-protect + (if (eq type :sqlite) + (%test-basic-untyped db type) + (%test-basic db type)) + (disconnect :database db)))) + +(defun %test-basic (db type) + (create-test-table db) + (dolist (row (query "select * from test_clsql" :database db :result-types :auto)) + (test-table-row row :auto type)) + (dolist (row (query "select * from test_clsql" :database db :result-types nil)) + (test-table-row row nil type)) + (loop for row across (map-query 'vector #'list "select * from test_clsql" + :database db :result-types :auto) + do (test-table-row row :auto type)) + (loop for row across (map-query 'vector #'list "select * from test_clsql" + :database db :result-types nil) + do (test-table-row row nil type)) + (loop for row in (map-query 'list #'list "select * from test_clsql" + :database db :result-types nil) + do (test-table-row row nil type)) + (loop for row in (map-query 'list #'list "select * from test_clsql" + :database db :result-types :auto) + do (test-table-row row :auto type)) + (test (map-query nil #'list "select * from test_clsql" + :database db :result-types :auto) + nil + :fail-info "Expected NIL result from map-query nil") + (do-query ((int float bigint str) "select * from test_clsql") + (test-table-row (list int float bigint str) nil type)) + (do-query ((int float bigint str) "select * from test_clsql" :result-types :auto) + (test-table-row (list int float bigint str) :auto type)) + (drop-test-table db)) + + +(defun %test-basic-untyped (db type) + (create-test-table db) + (dolist (row (query "select * from test_clsql" :database db :result-types nil)) + (test-table-row row nil type)) + (loop for row across (map-query 'vector #'list "select * from test_clsql" + :database db :result-types nil) + do (test-table-row row nil type)) + (loop for row in (map-query 'list #'list "select * from test_clsql" + :database db :result-types nil) + do (test-table-row row nil type)) + + (do-query ((int float bigint str) "select * from test_clsql") + (test-table-row (list int float bigint str) nil type)) + (drop-test-table db)) + +;;;; Testing functions + +(defun transform-float-1 (i) + (coerce (* i (abs (/ i 2)) (expt 10 (* 2 i))) 'double-float)) + +(defun transform-bigint-1 (i) + (* i (expt 10 (* 3 (abs i))))) + +(defun create-test-table (db) + (ignore-errors + (clsql:execute-command + "DROP TABLE test_clsql" :database db)) + (clsql:execute-command + "CREATE TABLE test_clsql (t_int integer, t_float float, t_bigint BIGINT, t_str CHAR(30))" + :database db) + (dotimes (i 11) + (let* ((test-int (- i 5)) + (test-flt (transform-float-1 test-int))) + (clsql:execute-command + (format nil "INSERT INTO test_clsql VALUES (~a,~a,~a,'~a')" + test-int + (clsql-base:number-to-sql-string test-flt) + (transform-bigint-1 test-int) + (clsql-base:number-to-sql-string test-flt) + ) + :database db)))) + +(defun parse-double (num-str) + (let ((*read-default-float-format* 'double-float)) + (coerce (read-from-string num-str) 'double-float))) + +(defun test-table-row (row types db-type) + (test (and (listp row) + (= 4 (length row))) + t + :fail-info + (format nil "Row ~S is incorrect format" row)) + (destructuring-bind (int float bigint str) row + (cond + ((eq types :auto) + (test (and (integerp int) + (typep float 'double-float) + (or (eq db-type :aodbc) ;; aodbc doesn't handle bigint conversions + (integerp bigint)) + (stringp str)) + t + :fail-info + (format nil "Incorrect field type for row ~S (types :auto)" row))) + ((null types) + (test (and (stringp int) + (stringp float) + (stringp bigint) + (stringp str)) + t + :fail-info + (format nil "Incorrect field type for row ~S (types nil)" row)) + (setq int (parse-integer int)) + (setq bigint (parse-integer bigint)) + (setq float (parse-double float))) + ((listp types) + (error "NYI") + ) + (t + (test t nil + :fail-info + (format nil "Invalid types field (~S) passed to test-table-row" types)))) + (unless (eq db-type :sqlite) ; SQLite is typeless. + (test (transform-float-1 int) + float + :test #'eql + :fail-info + (format nil "Wrong float value ~A for int ~A (row ~S)" float int row))) + (test float + (parse-double str) + :test #'double-float-equal + :fail-info (format nil "Wrong string value ~A for double ~A~%Row: ~S" + str float row)))) + + +(defun double-float-equal (a b) + (if (zerop a) + (if (zerop b) + t + nil) + (let ((diff (abs (/ (- a b) a)))) + (if (> diff (* 10 double-float-epsilon)) + nil + t)))) + +(defun drop-test-table (db) + (clsql:execute-command "DROP TABLE test_clsql" :database db)) diff --git a/tests/test-init.lisp b/tests/test-init.lisp index 1a274d9..db217ec 100644 --- a/tests/test-init.lisp +++ b/tests/test-init.lisp @@ -294,23 +294,38 @@ (unless specs (warn "Not running tests because test configuration file is missing") (return-from run-tests :skipped)) + (load-necessary-systems specs) (dolist (db-type +all-db-types+) (let ((spec (db-type-spec db-type specs))) (when spec - (format t -"~& + (do-tests-for-backend spec db-type)))))) + +(defun load-necessary-systems (specs) + (dolist (db-type +all-db-types+) + (when (db-type-spec db-type specs) + (db-type-ensure-system db-type)))) + +(defun do-tests-for-backend (spec db-type) + (format t + "~& ******************************************************************* *** Running CLSQL tests with ~A backend. ******************************************************************* " db-type) - (db-type-ensure-system db-type) - (regression-test:rem-all-tests) - (ignore-errors (destroy-database spec :database-type db-type)) - (ignore-errors (create-database spec :database-type db-type)) - (dolist (test (append *rt-connection* *rt-fddl* *rt-fdml* - *rt-ooddl* *rt-oodml* *rt-syntax*)) - (eval test)) - (test-connect-to-database db-type spec) - (test-initialise-database) - (rtest:do-tests)))))) + (regression-test:rem-all-tests) + + ;; Tests of clsql-base + (ignore-errors (destroy-database spec :database-type db-type)) + (ignore-errors (create-database spec :database-type db-type)) + (with-tests (:name "CLSQL") + (test-basic spec db-type)) + + (ignore-errors (destroy-database spec :database-type db-type)) + (ignore-errors (create-database spec :database-type db-type)) + (dolist (test (append *rt-connection* *rt-fddl* *rt-fdml* + *rt-ooddl* *rt-oodml* *rt-syntax*)) + (eval test)) + (test-connect-to-database db-type spec) + (test-initialise-database) + (rtest:do-tests)) diff --git a/tests/utils.lisp b/tests/utils.lisp new file mode 100644 index 0000000..27cbf94 --- /dev/null +++ b/tests/utils.lisp @@ -0,0 +1,68 @@ +;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*- +;;;; ************************************************************************* +;;;; FILE IDENTIFICATION +;;;; +;;;; Name: utils.lisp +;;;; Purpose: Classes and utilities for testing +;;;; Author: Kevin M. Rosenberg +;;;; Created: Mar 2002 +;;;; +;;;; $Id: tests.lisp 8926 2004-04-10 21:12:52Z kevin $ +;;;; +;;;; This file, part of CLSQL, is Copyright (c) 2002-2004 by Kevin M. Rosenberg +;;;; +;;;; CLSQL users are granted the rights to distribute and use this software +;;;; as governed by the terms of the Lisp Lesser GNU Public License +;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL. +;;;; ************************************************************************* + +(in-package #:clsql-tests) + +(defvar *config-pathname* + (make-pathname :defaults (user-homedir-pathname) + :name ".clsql-test" + :type "config")) + +(defvar +all-db-types+ + #-clisp '(:postgresql :postgresql-socket :sqlite :aodbc :mysql) + #+clisp '(:sqlite)) + +(defclass conn-specs () + ((aodbc-spec :accessor aodbc-spec :initform nil) + (mysql-spec :accessor mysql-spec :initform nil) + (pgsql-spec :accessor postgresql-spec :initform nil) + (pgsql-socket-spec :accessor postgresql-socket-spec :initform nil) + (sqlite-spec :accessor sqlite-spec :initform nil)) + (:documentation "Connection specs for CLSQL testing")) + + +(defun read-specs (&optional (path *config-pathname*)) + (if (probe-file path) + (with-open-file (stream path :direction :input) + (let ((config (read stream)) + (specs (make-instance 'conn-specs))) + (setf (aodbc-spec specs) (cadr (assoc :aodbc config))) + (setf (mysql-spec specs) (cadr (assoc :mysql config))) + (setf (postgresql-spec specs) (cadr (assoc :postgresql config))) + (setf (postgresql-socket-spec specs) + (cadr (assoc :postgresql-socket config))) + (setf (sqlite-spec specs) (cadr (assoc :sqlite config))) + specs)) + (progn + (warn "CLSQL test config file ~S not found" path) + nil))) + +(defun db-type-spec (db-type specs) + (let ((accessor (intern (concatenate 'string (symbol-name db-type) + (symbol-name '#:-spec)) + (find-package '#:clsql-tests)))) + (funcall accessor specs))) + +(defun db-type-ensure-system (db-type) + (unless (find-package (symbol-name db-type)) + (asdf:operate 'asdf:load-op + (intern (concatenate 'string + (symbol-name '#:clsql-) + (symbol-name db-type)))))) + + -- 2.34.1