From f89a67bf6078e1b321ecf493f8be588fa804cf3b Mon Sep 17 00:00:00 2001 From: root Date: Tue, 6 Jun 2000 20:05:44 +0000 Subject: [PATCH 001/143] initial checkin --- CVSROOT/checkoutlist | 13 +++++++++++++ CVSROOT/commitinfo | 15 +++++++++++++++ 2 files changed, 28 insertions(+) create mode 100755 CVSROOT/checkoutlist create mode 100755 CVSROOT/commitinfo diff --git a/CVSROOT/checkoutlist b/CVSROOT/checkoutlist new file mode 100755 index 000000000..b04b3501f --- /dev/null +++ b/CVSROOT/checkoutlist @@ -0,0 +1,13 @@ +# The "checkoutlist" file is used to support additional version controlled +# administrative files in $CVSROOT/CVSROOT, such as template files. +# +# The first entry on a line is a filename which will be checked out from +# the corresponding RCS file in the $CVSROOT/CVSROOT directory. +# The remainder of the line is an error message to use if the file cannot +# be checked out. +# +# File format: +# +# [] +# +# comment lines begin with '#' diff --git a/CVSROOT/commitinfo b/CVSROOT/commitinfo new file mode 100755 index 000000000..b19e7b7a6 --- /dev/null +++ b/CVSROOT/commitinfo @@ -0,0 +1,15 @@ +# The "commitinfo" file is used to control pre-commit checks. +# The filter on the right is invoked with the repository and a list +# of files to check. A non-zero exit of the filter program will +# cause the commit to be aborted. +# +# The first entry on a line is a regular expression which is tested +# against the directory that the change is being committed to, relative +# to the $CVSROOT. For the first match that is found, then the remainder +# of the line is the name of the filter to run. +# +# If the repository name does not match any of the regular expressions in this +# file, the "DEFAULT" line is used, if it is specified. +# +# If the name "ALL" appears as a regular expression it is always used +# in addition to the first matching regex or "DEFAULT". From 1d7bcf2f279eb522961d0472003a0f569aebe968 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 6 Jun 2000 20:05:45 +0000 Subject: [PATCH 002/143] initial checkin --- CVSROOT/config | 11 +++++++++++ CVSROOT/cvswrappers | 23 +++++++++++++++++++++++ CVSROOT/editinfo | 21 +++++++++++++++++++++ CVSROOT/loginfo | 26 ++++++++++++++++++++++++++ CVSROOT/modules | 26 ++++++++++++++++++++++++++ CVSROOT/notify | 12 ++++++++++++ CVSROOT/rcsinfo | 13 +++++++++++++ CVSROOT/taginfo | 20 ++++++++++++++++++++ CVSROOT/verifymsg | 21 +++++++++++++++++++++ 9 files changed, 173 insertions(+) create mode 100755 CVSROOT/config create mode 100755 CVSROOT/cvswrappers create mode 100755 CVSROOT/editinfo create mode 100755 CVSROOT/loginfo create mode 100755 CVSROOT/modules create mode 100755 CVSROOT/notify create mode 100755 CVSROOT/rcsinfo create mode 100755 CVSROOT/taginfo create mode 100755 CVSROOT/verifymsg diff --git a/CVSROOT/config b/CVSROOT/config new file mode 100755 index 000000000..8069cad5d --- /dev/null +++ b/CVSROOT/config @@ -0,0 +1,11 @@ +# Set this to "no" if pserver shouldn't check system users/passwords +#SystemAuth=no + +# Set `PreservePermissions' to `yes' to save file status information +# in the repository. +#PreservePermissions=no + +# Set `TopLevelAdmin' to `yes' to create a CVS directory at the top +# level of the new working directory when using the `cvs checkout' +# command. +#TopLevelAdmin=no diff --git a/CVSROOT/cvswrappers b/CVSROOT/cvswrappers new file mode 100755 index 000000000..0accaf1b1 --- /dev/null +++ b/CVSROOT/cvswrappers @@ -0,0 +1,23 @@ +# This file affects handling of files based on their names. +# +# The -t/-f options allow one to treat directories of files +# as a single file, or to transform a file in other ways on +# its way in and out of CVS. +# +# The -m option specifies whether CVS attempts to merge files. +# +# The -k option specifies keyword expansion (e.g. -kb for binary). +# +# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers) +# +# wildcard [option value][option value]... +# +# where option is one of +# -f from cvs filter value: path to filter +# -t to cvs filter value: path to filter +# -m update methodology value: MERGE or COPY +# -k expansion mode value: b, o, kkv, &c +# +# and value is a single-quote delimited value. +# For example: +#*.gif -k 'b' diff --git a/CVSROOT/editinfo b/CVSROOT/editinfo new file mode 100755 index 000000000..d78886c15 --- /dev/null +++ b/CVSROOT/editinfo @@ -0,0 +1,21 @@ +# The "editinfo" file is used to allow verification of logging +# information. It works best when a template (as specified in the +# rcsinfo file) is provided for the logging procedure. Given a +# template with locations for, a bug-id number, a list of people who +# reviewed the code before it can be checked in, and an external +# process to catalog the differences that were code reviewed, the +# following test can be applied to the code: +# +# Making sure that the entered bug-id number is correct. +# Validating that the code that was reviewed is indeed the code being +# checked in (using the bug-id number or a seperate review +# number to identify this particular code set.). +# +# If any of the above test failed, then the commit would be aborted. +# +# Actions such as mailing a copy of the report to each reviewer are +# better handled by an entry in the loginfo file. +# +# One thing that should be noted is the the ALL keyword is not +# supported. There can be only one entry that matches a given +# repository. diff --git a/CVSROOT/loginfo b/CVSROOT/loginfo new file mode 100755 index 000000000..5a59f0a54 --- /dev/null +++ b/CVSROOT/loginfo @@ -0,0 +1,26 @@ +# The "loginfo" file controls where "cvs commit" log information +# is sent. The first entry on a line is a regular expression which must match +# the directory that the change is being made to, relative to the +# $CVSROOT. If a match is found, then the remainder of the line is a filter +# program that should expect log information on its standard input. +# +# If the repository name does not match any of the regular expressions in this +# file, the "DEFAULT" line is used, if it is specified. +# +# If the name ALL appears as a regular expression it is always used +# in addition to the first matching regex or DEFAULT. +# +# You may specify a format string as part of the +# filter. The string is composed of a `%' followed +# by a single format character, or followed by a set of format +# characters surrounded by `{' and `}' as separators. The format +# characters are: +# +# s = file name +# V = old version number (pre-checkin) +# v = new version number (post-checkin) +# +# For example: +#DEFAULT (echo ""; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog +# or +#DEFAULT (echo ""; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog diff --git a/CVSROOT/modules b/CVSROOT/modules new file mode 100755 index 000000000..cb9e9efc9 --- /dev/null +++ b/CVSROOT/modules @@ -0,0 +1,26 @@ +# Three different line formats are valid: +# key -a aliases... +# key [options] directory +# key [options] directory files... +# +# Where "options" are composed of: +# -i prog Run "prog" on "cvs commit" from top-level of module. +# -o prog Run "prog" on "cvs checkout" of module. +# -e prog Run "prog" on "cvs export" of module. +# -t prog Run "prog" on "cvs rtag" of module. +# -u prog Run "prog" on "cvs update" of module. +# -d dir Place module in directory "dir" instead of module name. +# -l Top-level directory only -- do not recurse. +# +# NOTE: If you change any of the "Run" options above, you'll have to +# release and re-checkout any working directories of these modules. +# +# And "directory" is a path to a directory relative to $CVSROOT. +# +# The "-a" option specifies an alias. An alias is interpreted as if +# everything on the right of the "-a" had been typed on the command line. +# +# You can encode a module within a module by using the special '&' +# character to interpose another module into the current module. This +# can be useful for creating a module that consists of many directories +# spread out over the entire source repository. diff --git a/CVSROOT/notify b/CVSROOT/notify new file mode 100755 index 000000000..34f0bc288 --- /dev/null +++ b/CVSROOT/notify @@ -0,0 +1,12 @@ +# The "notify" file controls where notifications from watches set by +# "cvs watch add" or "cvs edit" are sent. The first entry on a line is +# a regular expression which is tested against the directory that the +# change is being made to, relative to the $CVSROOT. If it matches, +# then the remainder of the line is a filter program that should contain +# one occurrence of %s for the user to notify, and information on its +# standard input. +# +# "ALL" or "DEFAULT" can be used in place of the regular expression. +# +# For example: +#ALL mail %s -s "CVS notification" diff --git a/CVSROOT/rcsinfo b/CVSROOT/rcsinfo new file mode 100755 index 000000000..49e59f4d0 --- /dev/null +++ b/CVSROOT/rcsinfo @@ -0,0 +1,13 @@ +# The "rcsinfo" file is used to control templates with which the editor +# is invoked on commit and import. +# +# The first entry on a line is a regular expression which is tested +# against the directory that the change is being made to, relative to the +# $CVSROOT. For the first match that is found, then the remainder of the +# line is the name of the file that contains the template. +# +# If the repository name does not match any of the regular expressions in this +# file, the "DEFAULT" line is used, if it is specified. +# +# If the name "ALL" appears as a regular expression it is always used +# in addition to the first matching regex or "DEFAULT". diff --git a/CVSROOT/taginfo b/CVSROOT/taginfo new file mode 100755 index 000000000..274a46dd5 --- /dev/null +++ b/CVSROOT/taginfo @@ -0,0 +1,20 @@ +# The "taginfo" file is used to control pre-tag checks. +# The filter on the right is invoked with the following arguments: +# +# $1 -- tagname +# $2 -- operation "add" for tag, "mov" for tag -F, and "del" for tag -d +# $3 -- repository +# $4-> file revision [file revision ...] +# +# A non-zero exit of the filter program will cause the tag to be aborted. +# +# The first entry on a line is a regular expression which is tested +# against the directory that the change is being committed to, relative +# to the $CVSROOT. For the first match that is found, then the remainder +# of the line is the name of the filter to run. +# +# If the repository name does not match any of the regular expressions in this +# file, the "DEFAULT" line is used, if it is specified. +# +# If the name "ALL" appears as a regular expression it is always used +# in addition to the first matching regex or "DEFAULT". diff --git a/CVSROOT/verifymsg b/CVSROOT/verifymsg new file mode 100755 index 000000000..86f747ce2 --- /dev/null +++ b/CVSROOT/verifymsg @@ -0,0 +1,21 @@ +# The "verifymsg" file is used to allow verification of logging +# information. It works best when a template (as specified in the +# rcsinfo file) is provided for the logging procedure. Given a +# template with locations for, a bug-id number, a list of people who +# reviewed the code before it can be checked in, and an external +# process to catalog the differences that were code reviewed, the +# following test can be applied to the code: +# +# Making sure that the entered bug-id number is correct. +# Validating that the code that was reviewed is indeed the code being +# checked in (using the bug-id number or a seperate review +# number to identify this particular code set.). +# +# If any of the above test failed, then the commit would be aborted. +# +# Actions such as mailing a copy of the report to each reviewer are +# better handled by an entry in the loginfo file. +# +# One thing that should be noted is the the ALL keyword is not +# supported. There can be only one entry that matches a given +# repository. From e595f2b40e4e941d8aca123805e0f2b0713ca179 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 8 Mar 2002 13:54:53 +0000 Subject: [PATCH 003/143] Initial Load --- documentation/src/admin.html | 428 +++++++++++ documentation/src/advanced.html | 44 ++ documentation/src/authors.txt | 5 + documentation/src/build_docs.pl | 132 ++++ documentation/src/buildpack.html | 64 ++ documentation/src/clean_html.pl | 56 ++ documentation/src/defsuite.html | 142 ++++ documentation/src/examples.html | 65 ++ documentation/src/fourstep.html | 463 +++++++++++ documentation/src/glossreq.html | 131 ++++ documentation/src/howto.html | 503 ++++++++++++ documentation/src/index.html | 90 +++ documentation/src/map.txt | 33 + documentation/src/prefix.html | 59 ++ documentation/src/release.html | 634 +++++++++++++++ documentation/src/samepack.html | 191 +++++ documentation/src/started.html | 95 +++ documentation/src/suite.html | 84 ++ documentation/src/testapi.html | 295 +++++++ documentation/src/testfunc.html | 125 +++ documentation/src/testproc.html | 282 +++++++ documentation/src/testrun.html | 409 ++++++++++ documentation/src/userguide.html | 66 ++ documentation/src/utassert.html | 1235 ++++++++++++++++++++++++++++++ documentation/src/utconfig.html | 364 +++++++++ documentation/src/utgen.html | 563 ++++++++++++++ documentation/src/utplsql.html | 352 +++++++++ documentation/src/utresult.html | 136 ++++ documentation/src/xref.html | 52 ++ documentation/utplsql.css | 38 + documentation/utplsql.jpg | Bin 0 -> 9388 bytes 31 files changed, 7136 insertions(+) create mode 100644 documentation/src/admin.html create mode 100644 documentation/src/advanced.html create mode 100644 documentation/src/authors.txt create mode 100755 documentation/src/build_docs.pl create mode 100644 documentation/src/buildpack.html create mode 100755 documentation/src/clean_html.pl create mode 100644 documentation/src/defsuite.html create mode 100644 documentation/src/examples.html create mode 100644 documentation/src/fourstep.html create mode 100644 documentation/src/glossreq.html create mode 100644 documentation/src/howto.html create mode 100644 documentation/src/index.html create mode 100644 documentation/src/map.txt create mode 100644 documentation/src/prefix.html create mode 100644 documentation/src/release.html create mode 100644 documentation/src/samepack.html create mode 100644 documentation/src/started.html create mode 100644 documentation/src/suite.html create mode 100644 documentation/src/testapi.html create mode 100644 documentation/src/testfunc.html create mode 100644 documentation/src/testproc.html create mode 100644 documentation/src/testrun.html create mode 100644 documentation/src/userguide.html create mode 100644 documentation/src/utassert.html create mode 100644 documentation/src/utconfig.html create mode 100644 documentation/src/utgen.html create mode 100644 documentation/src/utplsql.html create mode 100644 documentation/src/utresult.html create mode 100644 documentation/src/xref.html create mode 100644 documentation/utplsql.css create mode 100644 documentation/utplsql.jpg diff --git a/documentation/src/admin.html b/documentation/src/admin.html new file mode 100644 index 000000000..faa6c9123 --- /dev/null +++ b/documentation/src/admin.html @@ -0,0 +1,428 @@ + + + + + + + utPLSQL - Administrative Topics + + + + + + + +
+ +
+Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
+[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

< Previous Section: The Four Step Program +to Using utPLSQL | Next Section: +Build Test Packages > +
+ + +

+Administrative Topics

+ +

+Configuring UTL_FILE

+ +

+Join the Project Team

+ +

+Reporting Bugs and Enhancement Requests

+ +

+Components

+ +

+File Descriptions

+ +

+Administrative Topics

+ +

+Configuring UTL_FILE

+If you want utPLSQL to automatically recompile your test packages, you +will need to make sure that UTL_FILE is enabled in your database (this +allows you to read/write operating system files). The database initialization +parameter file (aka, the "init.ora" file) must have at least one utl_file_dir +parameter in it for this to work. Here is some background and guidelines +for working with UTL_FILE: +

UTL_FILE lets you read and write files accessible from the server on +which your database is running. So, theoretically, you could use UTL_FILE +to write right over your tablespace data files, control files and so on. +That is, of course, a very bad idea. Server security requires the ability +to place restrictions on where you can read and write your files. +

UTL_FILE implements this security by limiting access to files that reside +in one of the directories specified in the init.ora file (parameter initialization +file) for the database instance on which UTL_FILE is running. +

When you call UTL_FILE.FOPEN to open a file, you must specify both the +location and the name of the file, in separate arguments. This file location +is then checked against the list of accessible directories. +

The format of the parameter for file access in the init.ora file is: + +utl_file_dir = <directory> + +Include a parameter for utl_file_dir for each directory you want to make +accessible for UTL_FILE operations. The following entries, for example, +enable four different directories in Unix: + +utl_file_dir = /tmp +
utl_file_dir = /ora_apps/hr/time_reporting +
utl_file_dir = /ora_apps/hr/time_reporting/log +
utl_file_dir = /users/test_area + +To bypass server security and allow read/write access to all directories, +you can use this special syntax: + +utl_file_dir = * + +You should not use this option on production systems. In a development +system, this entry certainly makes it easier for developers to get up and +running on UTL_FILE and test their code. You should, however, only allow +access to a few specific directories when you move the application to production. +

Some observations on working with and setting up accessible directories +with UTL_FILE: +

Access is not recursive through subdirectories. If the following lines +were in your init.ora file, for example, + +utl_file_dir = c:\group\dev1 +
utl_file_dir = c:\group\prod\oe +
utl_file_dir = c:\group\prod\ar + +then you would not be able to open a file in the c:\group\prod\oe\reports +subdirectory. +

Do not include the following entry in Unix systems: + +utl_file_dir = . + +This would allow you to read/write on the current directory in the operating +system. +

Do not enclose the directory names within single or double quotes. +

In the UNIX environment, a file created by UTL_FILE.FOPEN has as its +owner the shadow process running the Oracle instance. This is usually the +oracle owner. If you try to access these files outside of UTL_FILE, you +will need to have the correct privileges (or be logged in as oracle) to +access or change these files. +

You should not end your directory name with a delimiter, such as the +forward slash in Unix. The following specification of a directory will +result in problems when trying to read from or write to the directory: + +utl_file_dir = /tmp/orafiles/ + +After you modify your parameter initialization file, you will need to stop +and then restart your database instance. +

Test UTL_FILE Access +

If you have never before used or relied on UTL_FILE, you should write +a simple test to verify that UTL_FILE is now working. You can use the code +shown below (after changing your directory names and names for existing +and new files) to make sure you've got it running properly. +

 
+ +
SET SERVEROUTPUT ON
+ +
DECLARE
+   fid UTL_FILE.FILE_TYPE;
+   v VARCHAR2(32767);
+   PROCEDURE recNgo (str IN VARCHAR2)
+   IS
+   BEGIN
+      DBMS_OUTPUT.PUT_LINE ('UTL_FILE error ' || str);
+
+ +
      UTL_FILE.FCLOSE (fid);
+   END;
+BEGIN
+   /* Change the directory name to one to which you at least 
+   || THINK you have read/write access.
+   */
+   fid := UTL_FILE.FOPEN ('e:\demo', 'existing_file', 'R');
+   UTL_FILE.GET_LINE (fid, v);
+   dbms_output.put_line (v);
+ +
   UTL_FILE.FCLOSE (fid);
+
+ +
   fid := UTL_FILE.FOPEN ('e:\demo', 'new_file', 'W');
+ +
   UTL_FILE.PUT_LINE (fid, v);
+ +
   UTL_FILE.FCLOSE (fid);
+EXCEPTION
+   WHEN UTL_FILE.INVALID_PATH
+    THEN recNgo ('invalid_path');
+   WHEN UTL_FILE.INVALID_MODE
+    THEN recNgo ('invalid_mode');
+   WHEN UTL_FILE.INVALID_FILEHANDLE
+    THEN recNgo ('invalid_filehandle');
+   WHEN UTL_FILE.INVALID_OPERATION
+    THEN recNgo ('invalid_operation');
+   WHEN UTL_FILE.READ_ERROR
+    THEN recNgo ('read_error');
+   WHEN UTL_FILE.WRITE_ERROR
+    THEN recNgo ('write_error');
+   WHEN UTL_FILE.INTERNAL_ERROR
+    THEN recNgo ('internal_error');
+END;
+/
+If an error occurs, it will be displayed on your screen (note: the "set +serveroutput on" is not required for UTL_FILE to work, but simply to display +any errors which might occur). +
+

+Join the utPLSQL Project Team

+ +To take part in the utPLSQL project, please join +our email distribution group. Go to www.egroups.com, +join, and subscribe to the utPLSQL list. You will be including in ongoing +communication about utPLSQL via eGroups. + +

+Reporting Bugs and Enhancement Requests

+ +To identify the version of utPLSQL you are running, +you can execute the following program in SQL*Plus: + +
SQL> set serveroutput on
+ +
SQL> exec dbms_output.put_line (utPLSQL.version)
+ +You can also look inside the utPLSQL package (utPLSQL.pkb) +and check the value of the g_version private variable. + +

+Components

+ +Here are the various components of utPLSQL: + +

+Tables

+All tables are created by the tables.sql (or updated by the tablesupg.sql) +file. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ut_suite + +table + +Persistent storage of test suites defined. +
+ut_package + +table + +Persistent storage of packages to be run within +a suite. +
+ut_test + +table + +Definition of an individual unit test. +
+ut_testcase + +table + +Definition of a test case within a unit test. +
ut_config table Holds +configuration information for each user
ut_assertion table Contains +the definitions of the various assertion routines in the utAssert package. +This table will be used (potentially) by GUI front ends to utPLSQL.
+ +

+Packages

+All packages are created the code.sql file. +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+utPLSQL + +package + +Main test package. +
utConfigpackageAPI to ut_config table
+utSuite + +package + +API to ut_suite table. +
+utPackage + +package + +API to ut_ package table. +
+utTest + +package + +API to ut_test table. +
+utTestcase + +package + +API to ut_testcase table. +
+utAssert + +package + +Collection of assertion routines available to test +the results of your programs. +
+utResult + +package + +API to the results array that is populated by calls +to the utAssert assertions. +
+utGen + +package + +Generates a starting point for test packages for +your own package. +
+ +

+File Descriptions

+ + + + diff --git a/documentation/src/advanced.html b/documentation/src/advanced.html new file mode 100644 index 000000000..11a36b06c --- /dev/null +++ b/documentation/src/advanced.html @@ -0,0 +1,44 @@ + + + + + + + utPLSQL - Advanced Topics + + + + + + + +
+ +
+Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
+[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

< Previous Section: A "Test Run" with utPLSQL +| Next Section: Examples > +
+ + +

+Advanced Topics

+ +

+Building Your Own Test Engine

+ +

+Analyze Test Statistics

+ + + diff --git a/documentation/src/authors.txt b/documentation/src/authors.txt new file mode 100644 index 000000000..1e7fded7a --- /dev/null +++ b/documentation/src/authors.txt @@ -0,0 +1,5 @@ +# This contains a list of authors and their +# email address, separated by a comma +# +Steven Feuerstein,steven@stevenfeuerstein.com +Chris Rimmer,c@24.org.uk diff --git a/documentation/src/build_docs.pl b/documentation/src/build_docs.pl new file mode 100755 index 000000000..1d3055e34 --- /dev/null +++ b/documentation/src/build_docs.pl @@ -0,0 +1,132 @@ +#!/usr/bin/perl -w +# +# This perl script builds the documentation for utPLSQL +# $Id$ +# + +use strict; + +#The directory the output goes into +my $OUTDIR = ".."; + +#Holds the map +my @map; + +#Holds the top navigation string +my $nav = ""; + +#Read the map file +open MAP, "map.txt" or die "Cannot open map.txt"; +my ($filename,$desc,$section); +while (){ + + #Ignore lines starting with #, or empty + if (not /^#/ and /\S/){ + chomp; + + #Split on comma + ($filename, $desc) = split /,/; + + $section = 0; + + #Add entries ending in * to navigation bar + if ($desc =~ s/\*$//){ + $nav .= " | " if $nav; + $nav .= "$desc\n"; + $section = 1; + } + push @map, [$filename, $desc, $section]; + } +} +close MAP; + +#Add the document map +push @map, ["map.html", "Document Map", 1]; +$nav = "[ $nav | Document Map ]"; + +#Holds the copyright string +my $copyright; + +#Read the authors file +open AUTHORS, "authors.txt" or die "Cannot open authors.txt"; +my ($name, $email); +while (){ + + #Ignore lines starting with #, or empty + if (not /^#/ and /\S/){ + chomp; + ($name, $email) = split /,/; + $copyright .= ', ' if $copyright; + $copyright .= "$name"; + } +} +close AUTHORS; + +#Put together the rest of the copyright notice +$copyright = "Copyright (C) 2000-".(((gmtime(time))[5])+1900)." $copyright All rights reserved"; + +my $logo = '
'; + +#Now build the documentation +my $index; +my $body; +my $nextprev; +foreach $index (0..$#map){ + + if ($index != 0){ + $nextprev = '< Previous Section: '.($map[$index-1]->[1]).''; + } else { + $nextprev = ''; + } + if ($index != $#map){ + $nextprev .= ' | ' if $nextprev; + $nextprev .= 'Next Section: '.($map[$index+1]->[1]).' >'; + } + + $body = 0; + open OUTPUT, ">$OUTDIR/$map[$index]->[0]" or die "Cannot open $OUTDIR/$map[$index]->[0]"; + + if ($index != $#map){ + system("./clean_html.pl $map[$index]->[0] > $map[$index]->[0].clean"); + open INPUT, "$map[$index]->[0].clean" or die "Cannot open $map[$index]->[0].clean"; + } + + print OUTPUT "\n"; + print OUTPUT "\n"; + print OUTPUT "$map[$index]->[1]\n"; + print OUTPUT ""; + print OUTPUT "\n"; + print OUTPUT "$logo\n"; + print OUTPUT "

$nav

\n"; + print OUTPUT "

$nextprev

\n"; + + #Either print the body, or construct it for the document map + if ($index != $#map){ + while (){ + $body = 1 if /^\s*\s*$/; + print OUTPUT $_ if $body; + $body = 0 if /^\s*\s*$/i; + } + close INPUT; + unlink("$map[$index]->[0].clean"); + } else { + print OUTPUT "

Document Map

\n"; + foreach (@map){ + if ($_->[2]){ + print OUTPUT ""; + } else { + print OUTPUT "  "; + } + print OUTPUT "[0]\">$_->[1]
"; + print OUTPUT "
" if $_->[2]; + print OUTPUT "\n"; + } + } + + print OUTPUT "

$nextprev

\n"; + print OUTPUT "$logo\n"; + print OUTPUT "

$copyright

\n"; + print OUTPUT ""; + close OUTPUT; +} + diff --git a/documentation/src/buildpack.html b/documentation/src/buildpack.html new file mode 100644 index 000000000..b43b5d610 --- /dev/null +++ b/documentation/src/buildpack.html @@ -0,0 +1,64 @@ + + + + + + + utPLSQL - Build Test Packages + + + + + + + +
+ +
+Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
+[ Home | Getting +Started | Build Test Packages | Examples +| User Guide | Release +Notes | Document Map ] +

< Previous Section: Administrative Topics +| Next Section: How to Build a Test Package > +
+ +

+Build Test Packages

+ +

We learn best by following the examples of those who have gone before +us. So you will find in this document sample test packages and different +approaches to using utPLSQL to test your PL/SQL code like it has never +been tested before! +

Spend some time in the general How to Build a Test +Package so that you are comfortable with the basic steps necessary +to integrate your test code into the utPLSQL framework. The Test Run section +offers a narrative presentation of building a test package; it makes a +nice follow-up to the How To section if you still feel any uncertainty. +Then you will be more than ready to explore the Examples. +

+How to Build a Test Package

+ +

+A "Test Run" with utPLSQL

+ +

+Advanced Topics

+ +
+

+Build Your Own Test Engine

+ +

+Analyze Test Run Statistics

+
+ + + + diff --git a/documentation/src/clean_html.pl b/documentation/src/clean_html.pl new file mode 100755 index 000000000..9fdec3cba --- /dev/null +++ b/documentation/src/clean_html.pl @@ -0,0 +1,56 @@ +#!/usr/bin/perl -w + +# This Perl script cleans HTML for inclusion +# in the documentation +# +# $Id$ +# + +use HTML::TagFilter; +use strict; + +#Make a tag filter object + +my $tf = HTML::TagFilter->new( + strip_comments => 0); + +#Allow these tags +$tf->allow_tags({ title => {none=>[]}, + body => {none=>[]}, + head => {none=>[]}, + html => {none=>[]}, + table => {any=>[]}, + tr => {any=>[]}, + td => {any=>[]}}); + +#...but get rid of style attributes +$tf->deny_tags({ table => {style=>[]}, + tr => {style=>[]}, + td => {style=>[]}}); + +#Build up a string consisting of the +#whole file +my $dirty; +while (<>){ + $dirty .= $_; +} + +#Scrub it +my $clean = $tf->filter($dirty); + +#Now I do my own special cleaning... + +#Remove nbsp - use
instead! +$clean =~ s/ / /gs; + +#Strip those tags out +$clean =~ s/]*>//gs; + +#Remove everything from head but the title +$clean =~ s/.*/<head><title>/gs; +$clean =~ s/<\/title>.*<\/head>/<\/title><\/head>/gs; + +#Remove </pre><pre> pairs with just whitespace between +$clean =~s/<\/pre>\s*<pre>/\n/gs; + +print $clean; diff --git a/documentation/src/defsuite.html b/documentation/src/defsuite.html new file mode 100644 index 000000000..1eda1d99c --- /dev/null +++ b/documentation/src/defsuite.html @@ -0,0 +1,142 @@ +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> +<html> +<head> + + + + <title>utPLSQL - Define Test Suites + + + + + + + +
+ +
+Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
+[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

< Previous Section: utGen Package | Next +Section: Release Notes > +
+ +

+Define Test Suites

+ +If you define test suites and register packages +within those suites, then utPLSQL will both run an unlimited number of +tests with a single command and also track information about your tests +(number of executions, number of failures, start and end date/times for +the last test run). + +FINISH: put these notes with the appropriate program +doc. + +Notes on these programs: + +
    +
  • +All suite names are stored in upper case.
  • + +If you do not specify a directory (dir_in), +you will need to call utConfig.setdir if you want automatic compilation +of your packages to occur. + +If you supply a value for seq_in, packages +will be compiled and tested in ascending numeric sequence order. + +When you call utSuite.rem, it will remove all +packages for that suite by calling utPackage.rem. +
+ +

+utSuite - Define Test Suites

+ +To define a test suite, call this program: + +
   PROCEDURE utSuite.add (
+ +
      name_in IN VARCHAR2,
+ +
      desc_in IN VARCHAR2 := NULL,
+ +
      rem_if_exists_in IN BOOLEAN := TRUE
+ +
      );
+ +
   PROCEDURE utSuite.rem (name_in IN VARCHAR2);
+ +These programs manipulate the contents of the ut_suite +table. See the tables.sql file for the DDL creating this table. + +

+ utPackage - Define Test Packages for a Suite

+ +To register a package in a suite, call one +of the following: + +
   PROCEDURE utPackage.add (
+ +
      suite_in IN VARCHAR2,
+ +
      package_in IN VARCHAR2,
+ +
      samepackage_in IN BOOLEAN := FALSE,
+ +
      prefix_in IN VARCHAR2 := NULL,
+ +
      dir_in IN VARCHAR2 := NULL,
+ +
      seq_in IN PLS_INTEGER := NULL,
+ +
      owner_in IN VARCHAR2 := NULL,
+ +
      add_tests_in IN BOOLEAN := FALSE,
+ +
      test_overloads_in IN BOOLEAN := FALSE
+ +
   );
+ +These programs manipulate the contents of the ut_package +table. See the tables.sql file for the DDL creating this table. + +Here is a sample script that defines a very small +portion of the PL/Vision test suite: + +
BEGIN
+ +
   utSuite.add ('PLVision');
+ +
  
+ +
   utPackage.add
+ +
      'PLVision', 'PLVstr', dir_in => 'e:\utplsql\test');
+ +
  
+ +
   utPackage.add (
+ +
      'PLVision', 'PLVdate', dir_in => 'e:\utplsql\test'');
+ +
  
+ +
   utPLSQL.testsuite ('PLVision', recompile_in => TRUE);
+ +
END;
+ +
/
+ + + + diff --git a/documentation/src/examples.html b/documentation/src/examples.html new file mode 100644 index 000000000..69a3bbebd --- /dev/null +++ b/documentation/src/examples.html @@ -0,0 +1,65 @@ + + + + + + + utPLSQL - Examples + + + + + + + +
+ +
+Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
+[ Home | Getting +Started | Build Test Packages +| Examples | User Guide | +Release +Notes | Document Map ] +

< Previous Section: Advanced Topics | +Next +Section: Cross-Reference by Assertion Type > +
+ +

+Examples

+ +

We learn best by following the examples of those who have gone before +us. So you will find in this document sample test packages and different +approaches to using utPLSQL to test your PL/SQL code like it has never +been tested before! The Cross-reference allows you to easily find the example +that demonstrates the use of a particular kind of utAssertion assertion +routine (compare pipes or tables or files or...). +

+Cross-Reference by Assertion Type

+ +

+Test a Procedure

+ +

+Test a Function

+ +

+Test an Entire Package API

+ +

+Put Test Code in Same Package

+ +

+Use Non-Default Prefix

+ +

+Create and Run a Test Suite

+ + + diff --git a/documentation/src/fourstep.html b/documentation/src/fourstep.html new file mode 100644 index 000000000..91ab8fc23 --- /dev/null +++ b/documentation/src/fourstep.html @@ -0,0 +1,463 @@ + + + + + +utPLSQL - The Four Step Program to using utPLSQL + + + + + + + + + +
+

+
+ +

Authors: Steven Feuerstein, Chris Rimmer

+ +

Copyright 2000-2001, all rights reserved

+ +

[ Home | Getting Started | Build Test Packages | Examples | User Guide | Release Notes | Document Map ]

+ +

< Previous Section: Glossary and Requirements +| Next Section: Administrative Topics >
+

+ + +

The Four Step Program to Using utPLSQL

+ +

Step 1. Install utPLSQL.

+ +

Step 2. Choose a program to test and identify the test +cases.

+ +

Step 3. Build a test package.

+ +

Step 4. Run your test.

+ +

Where To Go From Here

+ +

Step 1. Install (and Upgrade) utPLSQL.

+ +

Note: if you have already installed a previous version of +utPLSQL, you will use these same steps to perform your install. The +installation procedure does not remove any objects, such as tables, +prior to installation. If you wish to install a fresh copy of utPLSQL, and not upgrade +over the existing installation, please follow the steps below for removing +utPLSQL.

+ +

+ +

Connect via SQL*Plus to the session that will own the +utPLSQL components. If you do not already have a schema defined, then you must +create it. The utPLSQL schema must have the authority to:

+ +

+ +

Create tables

+ +

Create packages

+ +

+ +

Once you have connected to the schema, run the utplsql_install.sql +file to install all utPLSQL objects. If the working directory of your SQL*Plus +session is the directory holding the utPLSQL files, you can issue this command:

+ +

+ +
SQL> @utplsql_install
 
+ +

If the working directory of your SQL*Plus session is not +the directory holding the utPLSQL files, you can issue this command:

+ +

+ +
SQL> @<directory>utplsql_install
 
+ +

as in:

+ +

+ +
SQL> @c:\utplsql\utplsql_install
 
+ +

or

+ +

+ +
SQL> @/orautils/utplsql/utplsql_install
 
+ +

This file will remove the existing installation of utPLSQL +and then create all tables and packages needed.

+ +

+ +

To check the installation of utPLSQL, examine the +utplsql_install.log file.

+ +

Removing utPLSQL

+ +

To de-install the product, run the utplsql_uninstall.sql +script, as in:

+ +

+ +
SQL> @utplsql_uninstall
 
+ +

or

+ +

+ +
SQL> @<directory>utplsql_uninstall
+ +

Step 2. Choose a program to test and identify the test +cases.

+ +

You may want to test a single stand-alone procedure or +function, or a set of programs in a package. Pick the program and then come up +with the set of different cases you want to test. This data will determine what +kind of and how many tests you run for your program.

+ +

Suppose, for example, that I have created a stand alone function called +betwnStr (a variation on SUBSTR that returns a sub-string based on a starting +and ending location) that is stored in betwnstr.sf: +

+ +
CREATE OR REPLACE FUNCTION betwnStr (
   string_in IN VARCHAR2,
   start_in IN INTEGER,
   end_in IN INTEGER
   )
   RETURN VARCHAR2
IS
BEGIN
   RETURN (
      SUBSTR (
         string_in,
         start_in,
         end_in – start_in + 1
         )
      );
END;
+ +

To test this function, I will want to pass in a variety of +inputs, as shown in this table:
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Start

+
+

End

+
+

Result

+
+

NULL

+
+

NOT NULL

+
+

NULL

+
+

NOT NULL

+
+

NULL

+
+

NULL

+
+

NULL

+
+

NULL

+
+

NULL

+
+

3 (positive number)

+
+

1 (smaller positive number)

+
+

NULL

+
+

3 (positive number)

+
+

100 (larger than length of string)

+
+

Remainder of string from 3

+
+ +

So now I know what I want to test and how I want to test it.
+

+ +

Step 3. Build a test package.

+ +

utPLSQL offers an easy, automated way to run your tests. To +work automatically, though, you have to follow some rules so that utPLSQL can +find and execute your test code. Here are the rules:

+ +

+ +The test code must be placed inside a +test package. + +

+ +

+ +The test package specification should +be stored in a file named ut_<program>.pks and the body must be stored in +a file named ut_<program>.pkb (by following this naming convention, +utPLSQL can be set to automatically recompile your test package before each +test). + +

+ +

+ +The test package must contain a setup procedure called ut_setup and a teardown procedure called ut_teardown, neither of +which take any arguments. + +

+ +

+ +The test package should have a +separate procedure for each program to be tested in this package. + +

+ +

Now, you should know that there are a number of bells and +whistles in utPLSQL that allow you to change many default values (such as the +prefixes used for the setup, teardown and test procedures) and behavior of the +utPLSQL packages. While you are "Getting Started", however, we will +rely completely on the defaults and get you up and testing ASAP.

+ +

So if I am going to test the stand-alone procedure, betwnstr, my test +package specification, saved in ut_betwnstr.pks, +will look like this:

+ +
CREATE OR REPLACE PACKAGE ut_betwnstr
IS
   PROCEDURE ut_setup;
   PROCEDURE ut_teardown;
 
   PROCEDURE ut_betwnstr;
END ut_betwnstr;
/
+ +

Now let's build the package body, saved in ut_betwnstr.pkb. In this very simple +case, I don't have to set up any data structures and I do not, therefore, have +to tear anything down. My teardown procedure can be empty (but it must +be present). So I have:

+ +
CREATE OR REPLACE PACKAGE BODY ut_betwnstr
IS
   PROCEDURE ut_setup IS
   BEGIN
      NULL;
   END;
 
   PROCEDURE ut_teardown
   IS
   BEGIN
      NULL;
   END;
+ +

Time to build the unit test procedure. To do this, I need to +go back to my grid of test cases and translate those sets of data inputs and +results into calls to programs in the utAssert +package.

+ +

utAssert offers a number of "assertion routines" that test the +values or expression you pass to them and then record the results in utPLSQL. +You can, with utAssert, test for equality between two strings or files or +tables or collections. You can test to see if an expression evaluates to NULL. +I can use both of these types of assertions (equality and IS NULL) for my test +cases, which I repeat below:
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Start

+
+

End

+
+

Result

+
+

NULL

+
+

NOT NULL

+
+

NULL

+
+

NOT NULL

+
+

NULL

+
+

NULL

+
+

NULL

+
+

NULL

+
+

NULL

+
+

3 (positive number)

+
+

1 (smaller positive number)

+
+

NULL

+
+

3 (positive number)

+
+

100 (larger than length of string)

+
+

Remainder of string

+
+ +

Here's how it works: for each test case, I provide a string description of +the case, then the expression I want to evaluate. Let's start with +"typical valid usage". I pass a string "abcdefg", a start +location of 3 and end location of 5, and betwnstr should return +"cde". I express that in my unit test procedure as follows:

+ +
   PROCEDURE ut_betwnstr IS
   BEGIN
      utAssert.eq (
         'Typical valid usage',
         BETWNSTR(
            STRING_IN => 'abcdefg'
            ,
            START_IN => 3
            ,
            END_IN => 5
            ),
         'cde'
         );
+ +

Notice that I call utAssert.eq because I want to compare the +value returned by betwnstr with the string "cde". They should +be equal.

+ +

I can now write another call to a utAssert program for each of my cases. In +this very next example, I call utAssert.isnull, because I am expecting betwnstr +to return a NULL value.

+ +
      utAssert.isnull (
         'NULL start',
         BETWNSTR(
            STRING_IN => 'abcdefg'
            ,
            START_IN => NULL
            ,
            END_IN => 5
            )
         );
 
      utAssert.isnull (
         'NULL end',
         BETWNSTR(
            STRING_IN => 'abcdefg'
            ,
            START_IN => 2
            ,
            END_IN => NULL
            )
         );
         
      utAssert.isnull (
         'End smaller than start',
         BETWNSTR(
            STRING_IN => 'abcdefg'
            ,
            START_IN => 5
            ,
            END_IN => 2
            )
         );
         
      utAssert.eq (
         'End larger than string length',
         BETWNSTR(
            STRING_IN => 'abcdefg'
            ,
            START_IN => 3
            ,
            END_IN => 200
            ),
         'cdefg'
         );
         
   END ut_BETWNSTR;
 
END ut_betwnstr;
/
+ +

I have now created my unit test program for the betwnstr +function. I will compile both these files to make sure there are no compile +errors:

+ +
SQL> @ut_betwnstr.pks
 
Package created.
 
SQL> @ut_betwnstr.pkb
 
Package body created.
+ +

Note: when you run your test, utPLSQL will automatically +attempt to recompile your test package to ensure that the latest changes are +incorporated into the test. It is still worth doing an initial compile to make +sure you built your test properly. You will also need to make sure that UTL_FILE is installed and configured so that your +test package files can be read and compiled by utPLSQL.

+ +

So with the test package in place and compiling, now let's +see how we go about running the test.
+

+ +

Step 4. Run your test.

+ +

You've built your code, you've built your test package, +you've compiled that test package. Now it's time to run the test. Start up +SQL*Plus and connect to the schema owning the code you want to test.

+ +

Then run your test package within the utPLSQL testing framework by calling utPLSQL.test:

+ +
SQL> exec utplsql.test ('betwnstr', recompile_in => FALSE)
+ +

That second parameter in the call to utplsql.test, +"recompile_in => FALSE", tells utPLSQL that you have already +compiled your test package. You can also have utPLSQL automatically recompile your test package +each time you run a test.

+ +

If the test does not find any errors (which means that the assertion +programs did not detect any conflicts), you will see this output:

+ +
SQL> exec utplsql.test ('betwnstr', recompile_in => FALSE)
SUCCESS: "betwnstr"
+ +

If the test detected a failure, you will see output along +these lines:

+ +
SQL> exec utplsql.test ('betwnstr', recompile_in => FALSE)
FAILURE: "betwnstr"
BETWNSTR: IS NULL: NULL start
BETWNSTR: End larger than string length; expected "cdeg", got "cdefg"
+ +

As you can see, utPLSQL tells you the description of the +test case that failed, and also shows you as much as it can about what caused +the failure.

+ +

You have now successfully installed utPLSQL, written a test package and run +your test!

+ +

Automatic Recompilation of Test Package

+ +

utPLSQL will, by default, recompile your test package code +(which must be put in two files <name>.pks for the package specification +and <name>.pkb for the package body). In order to do this, utPLSQL uses +the UTL_FILE package provided by Oracle to read the source code files and then +compile the code found in those files. Before using UTL_FILE you must configure it for use from within PL/SQL.

+ +

Once you have confirmed that UTL_FILE works in your database instance, you +must tell utPLSQL where the test package is located by calling utPLSQL.setdir. +If you do not do this, then utPLSQL will not be able to recompile your test +package before each run, and instead will display an error message.

+ +

Call the utConfig.setdir program to tell +utPLSQL the location of your source code. Suppose that I stored all my code in e:\utplsql\testall. Then I would make this +call in SQL*Plus:

+ +
SQL> exec utplsql.setdir ('e:\utplsql\testall')
+ +

You could also put this program call in your login.sql file +(see the login_sample.sql file) so that you don't have to type that code every +time you start up SQL*Plus (or connect to another session within SQL*Plus).

+ +

Where To Go From Here

+ +

If you proceeded through all four steps, you should now have +used utPLSQL successfully to test a very simple function (betwnstr) or your own +functionality. This will undoubtedly leave you very excited about using utPLSQL +to handle much more complex code and elaborate testing requirements.

+ +

To find out more about the different features and +functionality available in utPLSQL, visit the User +Guide.

+ +

To read through a more thorough presentation of how to build +test packages in utPLSQL, visit How to +Build Test Packages.

+ +

To see a wide array of examples of building test cases and +different kinds of test packages, visit the Examples +document.

+ + + + + diff --git a/documentation/src/glossreq.html b/documentation/src/glossreq.html new file mode 100644 index 000000000..0d1604896 --- /dev/null +++ b/documentation/src/glossreq.html @@ -0,0 +1,131 @@ + + + + + + + utPLSQL - Glossary & Requirements + + + + + + + +
+ +
+Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
+[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

< Previous Section: Getting Started +| Next Section: The Four Step Program to Using utPLSQL +> +
+ +

+Glossary and Requirements

+ +

+Glossary

+ +Before diving into the details, let's make sure +we have a common vocabulary. + +

+Unit Test

+ +A test of a single unit or program. Suppose you +have built product.total_sales, a function to calculate and return total +sales of the specified product for a given date period. You will then build +a single procedure to perform the test for that function. + +

+Test Case

+ +Individual cases or test scenarios for a unit test. +You will want to try out different scenarios (valid and invalid product +Ids, various date ranges, etc.). Each different combination of inputs (parameter +values) is a different test case. These are bundled up and executed within +the single unit test procedure. + +

+Package Test

+ +A set of unit tests which test the functionality +of all programs in a single PL/SQL package (or a single stand-alone program +unit – procedure or function). + +The way utPLSQL works today, you must define +your various tests cases and unit tests within a test package (though it +could +be the same package containing the functionality). + +

+Test Suite

+ +A series of package tests. Obviously, any application +of non-trivial complexity will consist of multiple packages, each covering +their own area of functionality. A test suite contains a series of packages +that can then be tested in sequence by executing the test suite as a whole. + +

+Requirements

+ +If you are using Oracle8i, utPLSQL takes advantage +of a number of Oracle8i features, including autonomous transactions, invoker +rights and native dynamic SQL. You can also, however, use utPLSQL on Oracle7 +(7.3.4 and above) and Oracle8. + +Requirements for using utPLSQL include: +

+·The +schema owning utPLSQL objects must have EXECUTE authority on the DBMS_PIPE +package, as well as the ability to create tables and packages. +

+·If +you want utPLSQL to automatically recompile test packages for you, you +will need to have UTL_FILE installed and +configured to read from the directory or directories in which your package +source files are located. +

Optional: +ability to create public synonyms. The installation script will attempt +to create public synonyms. If your schema does not hae the authority to +do so, these commands will fail, but utPLSQL will still be available for +use in the owning schema. +

+

+Requirements for Executing Test Code

+

+ +If you install and use utPLSQL from within a single schema (ie, the same schema that owns utPLSQL code and tables owns the code +you want to test, as well as the test packages), then no additional privileges are needed. +

+If, however, you install utPLSQL in a shared schema and then access it from other schemas, you may need to grant additional +privileges to the utPLSQL schema. utPLSQL uses dynamic PL/SQL to run the test code. It therefore requires directly granted +EXECUTE privileges on those code elements (both the code to be tested and the test packages) -- or the AUTHID CURRENT_USER +capability of Oracle8i. +

+FOR ORACLE8i AND ABOVE +

+You do not need to grant any additional privileges, unless you want to test code owned by one schema from another schema. +In that case, you will need to grant EXECUTE to the schema from which you run your tests on both the code to be tested and the test package. +

+FOR ORACLE7 AND ORACLE8 +

+You must grant EXECUTE to the utPLSQL schema on both the code to be tested and the test package. +These grants must be made directly and not through roles. + + + + + diff --git a/documentation/src/howto.html b/documentation/src/howto.html new file mode 100644 index 000000000..69531ce56 --- /dev/null +++ b/documentation/src/howto.html @@ -0,0 +1,503 @@ + + + + + + + utPLSQL - How to build a test package + + + + + + + +
+ +

+Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
+[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

< Previous Section: Build Test +Packages | Next Section: A "Test Run" with utPLSQL +> +
+ +

+How to build a test package

+ +

+Instructions

+To use utPLSQL, you will build a test package containing your unit tests. +This test package must conform to the API (application programmatic interface) +rules of utPLSQL, so that utPLSQL can run your tests automatically. +

Every test package must have: +

+

+A setup procedure - register your unit test and set +up any data structures needed for testing.

+ +

+A teardown procedure - remove any data structures +created for testing.

+ +

+One or more unit test procedures - perform the +unit tests.

+
+The names you give to your test package, setup, teardown and unit test +proceedures must also follow the utPLSQL Naming Conventions. +

+Setup Procedure

+ +The utPLSQL.test and utPLSQL.testsuite programs +will call the setup procedure of your test package before it runs any unit +tests. Use this procedure to define your unit tests and also initialize +any data structures needed for your units. The package specification header +for this procedure must be of this form: + +
CREATE OR REPLACE PACKAGE <prefix><package>
+ +
IS
+ +
   PROCEDURE <prefix>setup;
+ +where <prefix> is the unit test prefix and <package> +is the name of the package (or stand alone program) to be tested. The default +naming convention is that your test package and all utPLSQL programs, including +the setup procedure, have a prefix of "ut_", as in: + +
CREATE OR REPLACE PACKAGE ut_<program>
+ +
IS
+ +
   PROCEDURE ut_setup;
+ +Note: if you are using manual +registration of unit tests (which is not the default setting +and is not recommeded), see Naming Conventions +for details on when and how to apply prefixes to your package and procedure +names. + +Now let's take a look at the body/implementation +of the setup procedure and how you can use it to define test data structures +and, optionally, register unit tests. + +

+Define test data structures

+You should use the setup procedure to define data structures you +need in one or more of your tests. You might, for example, want to create +a temporary table to hold information for comparison. You might populate +a collection or a record a scalar global variable. +

Here is an example of such a procedure (see Examples\ut_te_employee.pkb +for the full implementation): +

PROCEDURE ut_setup
+IS
+BEGIN
+   ut_teardown;
+ +
   EXECUTE IMMEDIATE 'CREATE TABLE ut_employee AS
+         SELECT * FROM employee';
+
+   EXECUTE IMMEDIATE 'CREATE TABLE ut_DEL1 AS
+         SELECT * FROM employee';
+
+   EXECUTE IMMEDIATE 'CREATE TABLE ut_DELBY_EMP_DEPT_LOOKUP AS
+         SELECT * FROM employee';
+END;
+For each of my tests, I create a separate table to modify and then use +in my utAssert comparison. +

You could place these statements in each of the individual unit test +procedures. The advantage of storing them all in the single setup procedure +is that they are easier to manage -- and also easier to tear down or destroy +when you are done. +

+Manual registration of unit tests

+ +If you have decided to choose manual +registration of your unit test procedures, then you will need to register +each procedure with a call to utPLSQL.registertest +in the setup procedure. This is not recommended. But if you insist... + +Here is an example of a setup procedure for the +PLVdate package: + +
CREATE OR REPLACE PACKAGE BODY ut_plvdate
+ +
IS
+ +
   PROCEDURE ut_setup
+ +
   IS
+ +
   BEGIN
+ +
      utplsql.addtest ('ut_to_date');
+ +
      utplsql.addtest ('ut_to_char');
+ +
   END;
+ +The names passed to the utPLSQL.addtest procedure +must match the interface of the defined unit test procedures +with the following interface. So the above two calls to addtest tell utPLSQL +to look for two unit test procedures named ut_to_date and ut_to_char. + +

+Teardown Procedure

+ +The utPLSQL.test and utPLSQL.testsuite programs +will call the teardown procedure of your test package after it runs all +unit tests. Use this procedure to destroy or remove any data structures +that were needed for your units. The contents of this procedure should, +in general, be the logical reverse of the contents of the setup +procedure. The package specification header for this procedure must +be of this form: + +
CREATE OR REPLACE PACKAGE <prefix><package>
+ +
IS
+ +
   PROCEDURE <prefix>teardown;
+ +where <prefix> is the unit test prefix and <package> +is the name of the package (or stand alone program) to be tested. + +The default naming convention is that your test +package and all utPLSQL programs, including the teardown procedure, have +a prefix of "ut_", as in: + +
CREATE OR REPLACE PACKAGE ut_<program>
+ +
IS
+ +
   PROCEDURE ut_teardown;
+ +Note: if you are using manual +registration of unit tests (which is not the default setting +and is not recommeded), see Naming Conventions +for details on when and how to apply prefixes to your package and procedure +names. + +Now let's take a look at the body/implementation +of the teardown procedure and how you can use it to remove test data structures. + +Here is an example of the most common type of teardown +procedure -- it does nothing: + +
CREATE OR REPLACE PACKAGE ut_sales_pkg
+ +
IS
+ +
   PROCEDURE teardown
+ +
   IS
+ +
   BEGIN
+ +
      NULL;
+ +
   END;
+ +This is what your teardown procedure will look like +when you do not need to create any special data structures for your tests. +If I were testing a simple string utility, for example, I do not need a +database table or collection to run my tests. Note that even if your teardown +procedure does nothing, it still must be present in the package specification +and body. utPLSQL will look for and try to execute the procedure as +part of its S.O.P. (standard operating procedure). + +Now, if your setup procedure creates something, +you should probably destroy it in teardown. You might drop or truncate +tables, do a ROLLBACK or simply make sure files and cursors are closed. +Here is an example of such a procedure: + +
PROCEDURE teardown
+ +
IS
+ +
BEGIN
+ +
   mycollection.DELETE;
+ +
   EXECUTE IMMEDIATE 'TRUNCATE TABLE ' || workspace_tab;
+ +
   DBMS_SESSION.FREE_UNUSED_USER_MEMORY;
+ +
END;
+ +

+The Unit Test Procedure

+ +The unit test procedure is, of course, where it +gets really interesting and very application specific. + +The general format for a test procedure is as follows: + +
CREATE OR REPLACE PACKAGE <prefix><package>
+IS
+   PROCEDURE <prefix><program>;
+ +where <prefix> is the unit test prefix and <package> +is the name of the package (or stand alone program) to be tested. The default +naming convention is that your test package and the unit test procedure +each have a prefix of "ut_". You can override that prefix with another +of your own choosing in your call to utPLSQL.test +or utPLSQL.testsuite. Under some circumstances, you can drop +the prefix on the unit test procedure, but this is not recommended. see +Naming +Conventions. for details. + +Here is a very generic version of a unit test package +specification and a single unit test procedure: + +
-- Test package for stand alone program
+ +
CREATE OR REPLACE PACKAGE ut_<package>
+ +
IS
+ +
   PROCEDURE ut_setup;
+ +
   PROCEDURE ut_teardown;
+ +
   PROCEDURE ut_<program>;
+ +
END;
+ +The body of your unit test procedure is, well, mostly +yours to figure out, since we don't know what you are testing and how you +need to test it. The basic format of this test procedure, however, should +be: + +
PROCEDURE <myprogram>
+IS
+BEGIN
+   <run package.myprogram or set up for test>
+
+   -- call a utAssert assertion to check results:
+   utAssert.<assertion> (...);
+
+   <repeat of the above for different test cases>
+EXCEPTION
+   WHEN OTHERS
+   THEN
+      utAssert.this (
+         'Unknown failure of <package.myprogram>: ' || SQLERRM,
+         FALSE);
+END;
+You should include a call to a utAssert assertion program in the exception +section to trap unexpected errors and register a test failure (I pass FALSE +for the second argument, which guarantees a failure!). You might, of course, +have other handlers to trap specific exceptions like NO_DATA_FOUND and +either register a failure or ignore the exception, since it might not be +an actual test failure. +

Here is an example of a unit test procedure that contains multiple calls +to assertion programs for different test cases. +

PROCEDURE ut_BETWNSTR IS
+BEGIN
+   utAssert.eq (
+      'Typical valid usage',
+      BETWNSTR(
+         STRING_IN => 'abcdefg'
+         ,
+         START_IN => 3
+         ,
+         END_IN => 5
+         ),
+      'cde'
+      );
+      
+   utAssert.isnull (
+      'NULL start',
+      BETWNSTR(
+         STRING_IN => 'abcdefg'
+         ,
+         START_IN => NULL
+         ,
+         END_IN => 5
+         )
+      );
+
+   utAssert.isnull (
+      'NULL end',
+      BETWNSTR(
+         STRING_IN => 'abcdefg'
+         ,
+         START_IN => 2
+         ,
+         END_IN => NULL
+         )
+      );
+      
+   utAssert.isnull (
+      'End smaller than start',
+      BETWNSTR(
+         STRING_IN => 'abcdefg'
+         ,
+         START_IN => 5
+         ,
+         END_IN => 2
+         )
+      );
+      
+   utAssert.eq (
+      'End larger than string length',
+      BETWNSTR(
+         STRING_IN => 'abcdefg'
+         ,
+         START_IN => 3
+         ,
+         END_IN => 200
+         ),
+      'cdefg'
+      );
+      
+END ut_BETWNSTR;
+In the above case, I am testing a function, so I call the function "in +line" with the assertion program. When testing a procedure, you will call +the procedure first and then call the appropriate assertion program to +test the outcome. +

Explore the Examples to learn about different +ways to write unit test procedures. +

+Naming Conventions

+When you execute a test or test suite, utPLSQL looks for a test package, +based on the name of the program you are testing. It then attempts to execute +specific programs within that package. utPLSQL allows you to test stand-alone +programs (procedure or function) or package-based programs. When testing +the contents of a package, you can place your unit test procedures in the +same +package or a separate test package. That's a lot of flexibility, and +flexibility generally leads to confusion. +

To make things as simple as possible, the default mode of utPLSQL follows +this simple rule: + +

Your unit test package and each utPLSQL-related program in that package +(setup, teardown and unit tests) must all use the same prefix. + +

The default prefix is "ut_", but you can override that with your own. +If you follow this rule (and you can follow it very easily by using the +utGen +package to generate a starting point for your test packages), utPLSQL +

If you are following the utPLSQL defaults and letting the utility automatically +detect and execute unit tests, do not read any further! +

If you choose to perform manual +registration of your unit tests, then read the following sections carefully, +as there is a scenario in which you should not apply the utPLSQL +prefix to your unit test procedures. +

This section describes the conventions or rules that utPLSQL follows +to locate and execute your unit tests. There are three different "scenarios" +to consider: +

Separate test package to test package-based programs +

Separate test package to test a stand-alone program +

Single package containing both source to be tested and +unit test programs +

While these rules might seem confusing at first glance, you will find +over time that they are designed to make the issue of what things are named +as transparent as possible when you run your tests. In other words, you +simply ask to test "mypackage"; you don't have to run some oddly-named +program with a prefix in front of it. +

In addition, you can use the utGen package to +generate a starting point for your test packages. utGen will automatically +follow the rules; you only need to "fill in the blanks" of your unit test +procedures within the established headers. +

+Separate test package to test package-based programs

+If you are placing your unit test code in a package separate from your +source code (the default setting), then the name of that test package must +be of the form: +
<prefix><package>
+where <prefix> is the utPLSQL prefix and <package> is the name of +the package containing the programs to be tested. +

You specify the prefix in one of the following ways: +

    +
  • +When you call utPLSQL.test or utPLSQL.testsuite, you can pass a value for +the prefix_in parameter (the default is "ut_").
  • + +When you call utPackage.add to add a package +to a suite, you can pass a value for the prefix_in parameter (the default +is "ut_"). This prefix is then stored in the ut_package table. +
+The names of the test package programs, on the other hand, should not +have a prefix before them. These prefixes are not necessary to distinguish +the test procedure with the program being tested, since they are defined +in different packages. +

+Separate test package to test a stand-alone program

+If you are placing your unit test code in a package separate from your +source code (the default setting), then the name of that test package must +be of the form: +
<prefix><program>
+where <prefix> is the utPLSQL prefix and <program> is the name of +the stand-alone program you plan to test. +

You specify the prefix in one of the following ways: +

    +
  • +When you call utPLSQL.test or utPLSQL.testsuite, you can pass a value for +the prefix_in parameter (the default is "ut_").
  • + +When you call utPackage.add to add a package +to a suite, you can pass a value for the prefix_in parameter (the default +is "ut_"). This prefix is then stored in the ut_package table. +
+The names of the test package programs, on the other hand, also must have +the same prefix. This is necessary to avoid confusing naming conflicts +between the program you are testing and the name of the unit test procedure +for that program, as in the following package that tests the betwnstr function: +
CREATE OR REPLACE PACKAGE ut_betwnstr
+IS
+   PROCEDURE ut_setup;
+   PROCEDURE ut_teardown;
+   PROCEDURE ut_betwnstr;
+END ut_betwnstr;
+/
+I suppose that looks odd; I have created a function named ut_betwnstr.ut_betwnstr +and it would be very strange to write code like that. But that is the whole +point of utPLSQL: I don't have to write code like that. I just run +my test with nothing more than this: +
SQL> exec utPLSQL.test ('betwnstr')
+ +

+Single package containing both source to be tested and +unit test programs

+Finally, there is the scenario in which a developer places all of her test +programs (setup, teardown and unit tests) in the same package as the code +to be tested. In this case, there is no separate test package, so all of +the test programs must use the utPLSQL prefix, as in: +
CREATE OR REPLACE PACKAGE str
+IS
+   FUNCTION betwn (
+      string_in IN VARCHAR2,
+      start_in IN PLS_INTEGER,
+      end_in IN PLS_INTEGER
+   )
+      RETURN VARCHAR2;
+      
+   PROCEDURE ut_setup;
+   PROCEDURE ut_teardown;
+   PROCEDURE ut_betwn;
+      
+END str;
+/
+You specify the prefix in one of the following ways: +
+
  • +When you call utPLSQL.test or utPLSQL.testsuite, you can pass a value for +the prefix_in parameter (the default is "ut_"). When you call utPackage.add +to add a package to a suite, you can pass a value for the prefix_in parameter +(the default is "ut_"). This prefix is then stored in the ut_package table.
  • +
    + + + + diff --git a/documentation/src/index.html b/documentation/src/index.html new file mode 100644 index 000000000..0db16e26d --- /dev/null +++ b/documentation/src/index.html @@ -0,0 +1,90 @@ + + + + + + + + Welcome to utPLSQL + + + + + + + +
    + +
    +Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
    +[ Home | Getting Started +| Build Test Packages | Examples +| User Guide | Release +Notes | Document Map ] +

    Next Section: Getting Started > +
    + +

    +Table of Contents

    + +

    +Welcome to utPLSQL

    + +

    +a unit testing framework for the Oracle +PL/SQL Language

    + +

    +Getting Started

    + +
    This document tells you the minimum you need +to know in order to get started with utPLSQL: how to install the software, +build simple test packages, and run your tests.
    + +

    +Build Test Packages

    + +
    utPLSQL provides with you a framework in which +to run your tests. You still have to write your test code, and that code +must follow some rules if utPLSQL is going to know how to run those tests.
    + +

    +Examples

    + +
    There is no better way to learn how to build +and run utPLSQL test packages than to work from the many examples found +here.
    + +

    +User Guide

    + +
    Once you are familiar with utPLSQL basics, have +run some tests, and are ready to learn and use more of the many utPLSQL +features, the User Guide will tell you all you need to know about the different +features and programs of utPLSQL.
    + +

    +Release Notes

    + +
    Well, you know what these are: a description +of fixes and enhancements in the latest release!
    + +

    +Document Map

    + +
    The full list of the pages in the documentation
    +Lots of information about utPLSQL is also available on the +Internet at the the utPLSQL +site of the O'Reilly and Associates Oracle Resource Center, including a +Webboard +that will allow you to ask questions, see what others have done with utPLSQL, +and post your own contributions. + + + + diff --git a/documentation/src/map.txt b/documentation/src/map.txt new file mode 100644 index 000000000..b1e6a8c95 --- /dev/null +++ b/documentation/src/map.txt @@ -0,0 +1,33 @@ +# This file contains a list of files and titles to +# make up the documentation. The filename and title +# should be separated by a comma. An asterisk after +# the title means that that file gets added to the +# Navigation Bar and is highlighted in the document +# Map. Note that the document map is not in this list +# but is added automatically at the end. +# +index.html,Home* +started.html,Getting Started* +glossreq.html,Glossary and Requirements +fourstep.html,The Four Step Program to using utPLSQL +admin.html,Administrative Topics +buildpack.html,Build Test Packages* +howto.html,How to build a test package +testrun.html,A "Test Run" with utPLSQL +advanced.html,Advanced Topics +examples.html,Examples* +xref.html,Cross-reference by Assertion Type +testproc.html,Test a Procedure +testfunc.html,Test a Function +testapi.html,Test an Entire Package API +samepack.html,Put Test Code in Same Package +prefix.html,Use Non-Default Prefix +suite.html,Create and Run a Test Suite +userguide.html,User Guide* +utplsql.html,utPLSQL Package +utconfig.html,utConfig Package +utresult.html,utResult Package +utassert.html,utAssert Package +utgen.html,utGen Package +defsuite.html,Define Test Suites +release.html,Release Notes* diff --git a/documentation/src/prefix.html b/documentation/src/prefix.html new file mode 100644 index 000000000..b9307aea7 --- /dev/null +++ b/documentation/src/prefix.html @@ -0,0 +1,59 @@ + + + + + + + utPLSQL - Use Non-Default Prefix + + + + + + + +
    + +
    +Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
    +[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

    < Previous Section: +Put Test Code in Same Package | Next Section: Create +and Run a Test Suite > +
    + +

    +Use Non-Default Prefix

    + +

    The default prefix for utPLSQL is "ut_", but you don't have to use that +prefix. There are some situations where you absolutely will not want to +use the default prefix. Suppose, for example, that you have written a package +with ten procedures, each of which already have "ut_" as a prefix +(it might stand for "Unified Technologies" or "Underside Treatment: or...well, +you get the picture). +

    Since this prefix is not hard-coded into utPLSQL, you can very easily +specify your own prefix. You can do this when you run a test, as in: +

    SQL> utPLSQL.test ('te_employee', prefix_in => 'test_');
    +You can also specify a prefix when you add a package to a test suite, as +in: +
    SQL> utPackage.add ('mysuite', 'mypackage' prefix_in => 'test_');
    +Of course, when you specify a non-default prefix, you must also build your +test package using that prefix. If you plan to generate a starting point +for your package with utGen, be sure to specify your prefix at that point, +as in: +
    SQL> utGen.testpkg('mypackage' prefix_in => 'test_');
    +For an example of a package with a non-default prefix, check out test_te_employee.pks +and test_te_employee.pkb. + + + + diff --git a/documentation/src/release.html b/documentation/src/release.html new file mode 100644 index 000000000..bf13f66da --- /dev/null +++ b/documentation/src/release.html @@ -0,0 +1,634 @@ + + + + + utPLSQL - Release Notes + + + + + +

    +

    + + + + + + + + +
    + +

    + +

    +
    + +


    +Authors: Steven Feuerstein, Chris Rimmer

    + +

    Copyright +2000-2001, all rights reserved
    +
    +

    + +

    [ Home + | Getting Started + | Build Test Packages + | Examples + | User Guide + | Release Notes | Document Map + ]

    + +

    < Previous Section: Define Test Suites + | Next Section: Document Map > +
    +

    + + +

    Release Notes

    + +

    Known Issues

    +

    utPLSQL version 2.x

    +
      +
    • There is an issue surrounding the use of utPLSQL on Oracle 8.1.7 where +the tests use database links. This is because Oracle will consider +the transaction to be distributed and utPLSQL v2 uses autonomous transactions +while the tests are running. This situation causes ORA-00164 in 8.1.7 +(and apparently should not have been allowed in 8.1.5 or 8.1.6 either). It +is possible to work around this problem by turning off autonomous transactions +, but this can cause other problems if the tests themselves have rollbacks +within them.
      +
    • +
    +

    Change History
    +

    +

    utPLSQL version 2.0.9.1

    + +
      + +
    • +Add ut_reqeq table and utreceq package to support the creation of "record +equal" functions (contributed by Dan Spencer).
    • + +
    • +Modify utPLSQL.test so that the record comparison functions are generated +and recompiled whenever the source code is recompiled. + Call utreceq.add to register a package-table combination. +
    • + +
    • +Modified utpackage.id_from_name to take an owner_in parameter with a +NULL default value. v_owner is set to nvl(owner_in,user). added +owner = v_owner and suite_id is null to the WHERE clause.
    • + +
    • +Modified utpackage.add to add in a record with suite_id NULL if one +doesn't exist.
    • + +
    • +Modified utpackage.upd - changed parameter suite_in to suite_id_in (the +type was INTEGER). Changed the UPDATE WHERE clause first line +to VL(suite_id,0) = NVL(suite_id_in,0).
    • + +
    • +Modified utplsql.testsuite - v_suite (the suite id) was in the +call to utplsql.test while the utplsql.test parameter list was expecting +the suite name. The results of a test run are now logged to the +appropriate record in ut_package [the record for the suite if run from +testsuite, the record with suite_id NULL if run via an EXEC UTPLSQL.TEST('packagename')].
    • + +
    • +Add objExists and objNotExists assertion programs
    • + +
    • +Changes to utPLSQL.test engine so that you can test programs define +in one schema from another schema.
    • + +
    • +Add previous_passed and previous_failed to utAssert and utAssert2
    • + +
    • +Set order in which test case results are displayed to the order in which +they are run by adding the tc_run_id to the utr_outcome table.
    • + +
    + +

    utPLSQL version 2.0.8.2

    + +
      + +
    • +Change ut_utp LOB column to VARCHAR2 for the time being.
    • + +
    • +Fixed ALTER TBLE statement in ut_config.tab.
    • + +
    • +Change utplsql.test to allow for compilation of test package before +extracting list of test procedures from that package (avoids the " +Warning...no tests were identified for execution!" message).
    • + +
    • +Add utAssert2.eval generic comparison program, and also utAssert.eval, +with an overloading for just two values, to make it really easy to use.
    • + +
    • +Add utGen.receq_package procedure. It currently ONLY writes the code +out to the screen via DBMS_OUTPUT.PUT_LINE. It does not, in other words, +support the multiple outputs of utGen.testpkg.
    • + +
    • +Update the utplsql_install.sql script to recognize Oracle9.0 and Oracle9.1 + versions and install all 8i features for those versions (there is nothing + specific to 9i at this time).
    • + +
    + +

    utPLSQL version 2.0.8.1

    + +
      + +
    • +Fixes to a number of minor installation errors.
    • + +
    • +Offers option in utPLSQL.test to request that setup and teardown is +executed with each test procedure and not the test package level. +Implements a new features in utPLSQL.test that allows you to specify +that you want to run the setup and teardown procedures before and after +EACH unit test procedure, as opposed to running them once for the unit +test package as a whole. To utilize this feature, simply pass a value +of TRUE to the new per_method_setup_in parameter of utPLSQL.test as +shown below:
    • + +
    + +

    +

    + +

    +SQL> exec utplsql.test ('str', per_method_setup_in => true)

    + +

    utPLSQL version 2.0.7

    + +

    +· + Revamp +utAssert2.define_message implement to simplify creation of new assertion +programs

    + +

    +· + Modify +implementation if ieqminus to avoid duplicate column

    + +

    +· + Change +naming conventions for utPLSQL2 from prefix to delimiter driven (utconfig.delimiter): +QU##NNN. This affects only those test packages which use the utPLSQL2.test +program to run the tests (ie for version 1 utPLSQL test packages and utPLSQL.test, +you can still use your prefix-based approaches).

    + +

    +· + Add +utAssert2.fileExists

    + +

    +· + Compile +utAssert2 with AUTHID CURRENT_USER for Oracle8i and above.

    + +

    +· + 2.0.7.2 +Fix index creation for ut_assertion table.

    + +

    +· + 2.0.7.2 +Fix foreign key definition in ut_argument.

    + +

    +· + 2.0.7.2 +Fix foreign key definition in uta_eq.

    + +

    utPLSQL version 2.0.6

    + +

    +· + Fix +to utgen.pkb to allow generation of procedure bodies when no grid is used.

    + +

    +· + Allow +developers to turn off display of successful results (utResult.include_successes)

    + +

    utPLSQL version 2.0.5

    + +

    +· + Allow +user to specify individual program or programs (via wildcard) to be tested +from a whole package.

    + +

    +· + Add +ut_deterministic and ut_deterministic_arg tables to facilitate generate of +test packages for deterministic functions.

    + +

    +· + Add +ut_deterministic.fmx Oracle Forms GUI to allow easy generation of test packages +for deterministic functions.

    + +

    utPLSQL version 2.0.4

    + +

    +· + Implement +test suite execution in utPLSQL2.

    + +

    +· + Implement +ut_suite_utp table (and the corresponding utsuiteutp package) as an intersection +of ut_suite and ut_utp, defining all those UTPs in a given suite.

    + +

    +· + Improved +error handling with utrerror assertions and general reporting mechanisms. +Assertion and error handling logic applied to define-time packages like utsuite +and utsuiteutp.

    + +

    +· + Revamp +installation process; no longer use OraShare, remove testcase2 entirely. +

    + +

    +· + Create +stand alone utverify procedure.

    + +

    utPLSQL version 2.0.3

    + +

    +· + Add +utr_error table and utrerror package; now all errors are logged to the table +for viewing afterwards. utPLSQL NEVER passes back an unhandled exception +to the console.

    + +

    +· + utAssert.eqfile +now flags problems when opening files.

    + +

    utPLSQL version 2.0.2

    + +

    +· + +clarify how that null_ok_in is supposed to work. For utAssert.this, it should +mean that if the value of the Boolean expression coming in is null, then +that means "success". For eq, it shoudl mean that if BOTH values coming in +are NULL, that is "success". For eqfile, if both files are empty...etc.

    + +

    +· + +add null_ok_in to eqqueryvalue assertions.

    + +

    +· + +add utassert.eqqueryvalue for NUMBER

    + +

    +· + +Enhance utgen to properly generate code for overloaded programs in packages

    + +

    utPLSQL version 2.0.1

    + +

    +· + +store results in utr_outcome tables

    + +

    +· + +support results reporting compatibility with V1

    + +

    +· + +display results of all test, success and failure.

    + +

    utPLSQL version 1.5.6

    + +
      + +
    • +New version of documentation courtesy of Chris Rimmer. Thanks, Chris!
    • + +
    • +utAssert fix in eqcoll to check for both values being null.
    • + +
    • +Enhancements to utGen to generate more self-explanatory code; comments +are now inserted to show the different sections in a standard test case +sequence.
    • + +
    • +Revamped installation procedure based on OraShare utility.
    • + +
    • +Add utGen.testpkg overloadings and new programs to support passing of +argument grids via collection, file or string (this feature is currently +undocumented outside of the release notes).
    • + +
    + +

    utPLSQL version 1.5.5

    + +

    Bug Fixes

    + +
      + +
    • +Change calls from DBMS_OUTPUT.PUT_LINE to utPLSQL.pl to avoid output +errors.
    • + +
    • +Avoid use of DBMS_SQL to obtain sequence values for Oracle7 and Oracle8 +installations of utPLSQL.
    • + +
    + +

    Enhancements

    + +
      + +
    • +Addition of utConfig package (created and integrated by Chris Rimmer) +to isolate all tester configuration information.
    • + +
    + +

    utPLSQL version 1.5.4

    + +

    Bug Fixes

    + +

    +· + utPLSQL.setconfig now sets the user information properly when +the package is first initialized (bug introduced in 1.5.3). +

    + +

    utPLSQL version 1.5.3

    + + +

    Documentation and Usage Changes

    + +
      + +
    • +If you choose to manually register your tests with calls to utPLSQL.addtest +in your setup procedure, you must now INCLUDE the unit test prefix, +as in:
    • + +
    + +
    utPLSQL.addtest ('ut_betwnstr');
    + +

    utPLSQL +will no longer add the prefix for you. This means that you may need to change +your calls to addtest -- or remove them entirely and rely on auto-registration.

    + +

    +Bug Fixes

    + +
      + +
    • +Auto-registration (using the ALL_ARGUMENTS data dictionary view) now +correctly ignores the setup and teardown procedures.
    • + +
    + +

    +Enhancements

    + +
      + +
    • +If no tests are run for the specified program, then a warning is displayed, +after which the SUCCESS message is displayed.
    • + +
    + +

    +utPLSQL version 1.5.2

    + +

    +Bug Fixes

    + +
      + +
    • +Fix setting of default prefix value in utPLSQL.pkb.
    • + +
    • +If you request execution of a test suite that does not exist, that failure +will be reported.
    • + +
    • +If you request execution of a test for a program or package that does +not exist, that failure will be reported.
    • + +
    • +Unique index on ut_package changed to allow multiple entries for same +package, in different suites.
    • + +
    + +

    +Known Problems

    + +
      + +
    • +When running a suite of test packages, the SUCCESS and FAILURE headers +will display for each package, and not for the overall suite.
    • + +
    + +

    +Enhancements

    + +
      + +
    • +The utAssert package now offers isnull and isnotnull assertions overloaded +for Boolean values..
    • + +
    + +

    +utPLSQL version 1.5.1

    + +

    +Support for Oracle7.3, Oracle8 and Oracle8i

    + +

    +utPLSQL can now be used on any version of Oracle from 7.3.4 and above! The +installation script automatically detects your Oracle RDBMS version and adjusts +the code accordingly (Using a great SQL*Plus trick, courtesy of Vladimir +Trusevich; check out the references to &start81 and &start73 in the +source code, as well as the queries in code.sql, to get a sense of how we +can maintain a single base of code for all these versions!).

    + +

    +There are some differences in how the code works:

    + +
      + +
    • +In Oracle8i, the autonomous transaction feature is used to immediately +COMMIT any changes to underlying utPLSQL tables (such as defining a +test suite). In earlier versions, no COMMITs are performed by utPLSQL.
    • + +
    + + +

    +In Oracle8i, the Invoker Rights model is used to allow all of utPLSQL code +to run under the authority of the invoker, not the owner/definer. In earlier +versions, the Definer Rights model is followed. So if you define utPLSQL +in a central schema and then share it with others via GRANTs and synonyms, +you may need to grant additional authority to the utPLSQL schema.

    + + +

    +Stores Additional Configuration Information

    + +

    +When you set the directory for your test code (through a call to +utPLSQL.setdir +, utPLSQL.test or utPLSQL.testsuite), that value is stored in the uPLSQL +configuration table (ut_config). It will be used for current and future sessions +as the default, until you change it.

    + +

    +The prefix you specify in calls to utPLSQL.setprefix +, utPLSQL.test or utPLSQL.testsuite will also be saved in the uPLSQL configuration +table. It will be used for current and future sessions as the default, until +you change it.

    + +

    +Shows All Configuration Information

    + +

    +Call the utPLSQL.showconfig + procedure to display all of the stored configuration values for the specified +schema.

    + +

    +utPLSQL version 1.4.1

    + +

    +Automatic Test Registration

    + +

    +You no longer have to manually register +your unit test procedures + in the setup procedure. Instead, utPLSQL will (in default mode) read and +execute the list of public procedures and functions from the ALL_ARGUMENTS +data dictionary view that conform to utPLSQL naming conventions. This enhancement +makes utPLSQL much easier and simpler to use than before. Simply use the +designated prefix (default being "ut_") on your program names, and they will +be executed.

    + +

    +Improved error handling and reporting

    + +

    +Rather than display a small, easily missed test result, as in :

    + +
    SUCCESS: PLVstr
    + +

    +utPLSQL now displays a much more noticeable (though still lacking in +colors, as in red for failure and green for success) display of the "big +picture", as in:

    + +
    SQL> exec utplsql.test ('str', dir_in=>'e:\openoracle\utplsql\utinstall\examples')
    +
    .
    +
    >    SSSS   U     U   CCC     CCC   EEEEEEE   SSSS     SSSS
    +
    >   S    S  U     U  C   C   C   C  E        S    S   S    S
    +
    >  S        U     U C     C C     C E       S        S
    +
    >   S       U     U C       C       E        S        S
    +
    >    SSSS   U     U C       C       EEEE      SSSS     SSSS
    +
    >        S  U     U C       C       E             S        S
    +
    >         S U     U C     C C     C E              S        S
    +
    >   S    S   U   U   C   C   C   C  E        S    S   S    S
    +
    >    SSSS     UUU     CCC     CCC   EEEEEEE   SSSS     SSSS
    +
    .
    +
     SUCCESS: "str"
    + +

    +utPLSQL version 1.3.2

    + +

    +Improved Statistics Recording

    + +

    +utPLSQL will now record the status of the last test run in the ut_package +and ut_suite tables. It also correctly updates those tables with a count +of executions and failures. Finally, it is no longer necessary to define +your package in and run it from a test suite for results to be recorded. +

    + +

    +New Assertions and Assertion Features

    + +

    +utAssert now offers assertion routines that allow you to easily validate +the contents of PL/SQL collections (index-by tables, nested tables and varying +arrays) by running either the utassert.eqcoll +or utassert.ecollAPI + assertions.

    + +

    +You can also now request that utAssert show the +results of a test immediately + after execution. This allows you to build small test scripts without have +to create a test package and run it through the utPLSQL test engine.

    + +

    +Bug Fixes

    + +

    +Generally, error handling is now improved, particularly for compile errors +on test packages and modifications to underlying tables, such as ut_package. +

    + +

    +When a test has been completed, utPLSQL clears out the results information. +

    + + + + diff --git a/documentation/src/samepack.html b/documentation/src/samepack.html new file mode 100644 index 000000000..2d20712f8 --- /dev/null +++ b/documentation/src/samepack.html @@ -0,0 +1,191 @@ + + + + + + + utPLSQL - Put Test Code in Same Package + + + + + + + +
    + +
    +Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
    +[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

    < Previous Section: Test an Entire Package +API | Next Section: Use Non-Default Prefix > +
    + +

    +Put Test Code in Same Package

    + +

    In some cases (usually when your packages are small and the code you +need to write to construct your tests is also constrained), you will not +want to bother with creating a separate package to test your code. To do +this, you will put the setup, teardown and unit test procedures inside +the package specification and body. We look at two examples: +

      +
    • +Testing a simple string function
    • + +Testing the population of a collection +
    + +

    +Testing a simple string function

    +Suppose I have my basic sting package, containing (for now at least) just +a single function: +
    /*file str.pks */
    +CREATE OR REPLACE PACKAGE str
    +IS
    +   FUNCTION betwn (
    +      string_in IN VARCHAR2,
    +      start_in IN PLS_INTEGER,
    +      end_in IN PLS_INTEGER
    +   )
    +      RETURN VARCHAR2;
    +END str;
    +/
    +Now it is time to test the function. I really don't want to bother with +a separate package; let's keep it together. To do this, I change the specification +to: +
    CREATE OR REPLACE PACKAGE str
    +IS
    +   FUNCTION betwn (
    +      string_in IN VARCHAR2,
    +      start_in IN PLS_INTEGER,
    +      end_in IN PLS_INTEGER
    +   )
    +      RETURN VARCHAR2;
    +      
    +   PROCEDURE ut_setup;
    +   PROCEDURE ut_teardown;
    + 
    +   -- For each program to test...
    +   PROCEDURE ut_betwn;
    +      
    +END str;
    +/
    +The package body contains nothing unusual; it is the same test for str.betwn +that you can find in the Testing +a Scalar Function example. But when I execute my test, I need to tell +utPLSQL that my test code is located in the same package: +
    SQL> exec utplsql.showconfig
    +=============================================================
    +utPLSQL Configuration for SCOTT
    +   Directory: e:\openoracle\utplsql\utinstall\examples
    +   Autcompile? Y
    +   Manual test registration? N
    +   Prefix = ut_
    +=============================================================
    +
    +PL/SQL procedure successfully completed.
    +
    +SQL> exec utPLSQL.test ('str', samepackage_in=>TRUE)
    +.
    +>    SSSS   U     U   CCC     CCC   EEEEEEE   SSSS     SSSS
    +>   S    S  U     U  C   C   C   C  E        S    S   S    S
    +>  S        U     U C     C C     C E       S        S
    +>   S       U     U C       C       E        S        S
    +>    SSSS   U     U C       C       EEEE      SSSS     SSSS
    +>        S  U     U C       C       E             S        S
    +>         S U     U C     C C     C E              S        S
    +>   S    S   U   U   C   C   C   C  E        S    S   S    S
    +>    SSSS     UUU     CCC     CCC   EEEEEEE   SSSS     SSSS
    +.
    + SUCCESS: "str"
    + +

    +Testing the population of a collection

    +Collections are very useful structures, but they can be difficult to analyze +and compare. utPLSQL provides the utAssert.eqColl and utAssert.eqCollAPI +programs to help you do this. +

    For this example, consider the fileIO package: it implements a path +feature for the UTL_FILE package. In other words, you request to open a +file and your file-opening program will search through each of the directories +in the path in sequence until it finds the file or exhausts the list. Here +is the specification of this package: +

    /*file filepath1.pkg */
    +CREATE OR REPLACE PACKAGE fileIO
    +IS
    +   c_delim CHAR(1) := ';';
    +   
    +   dirs dirs_tabtype := dirs_tabtype ();
    +   
    +   -- Unit test list
    +   ut_dirs dirs_tabtype := dirs_tabtype ();
    +   
    +   PROCEDURE setpath (str IN VARCHAR2, delim IN VARCHAR2 := c_delim);
    +   FUNCTION path RETURN VARCHAR2;
    +   FUNCTION pathlist RETURN dirs_tabtype;
    +
    +   FUNCTION open (file IN VARCHAR2, loc IN VARCHAR2 := NULL) RETURN UTL_FILE.FILE_TYPE;
    +   
    +   -- Unit test code in same package
    +   PROCEDURE ut_setup;
    +   PROCEDURE ut_teardown;
    +   PROCEDURE ut_setpath;
    +END;
    +/
    +A few things to notice about this package: +
      +
    • +It declares a publicly available collection, fileIO.dirs, in which the +path is deposited. Because it is declared in the package specification, +I can use the utAssert.eqColl procedure (if the collection was hidden in +the package body, I would have to use utAssert.eqCollAPI).
    • + +The test code is in the same package: the setup, +teardown and test pogram for fileIO.setpath. + +I declare a second, publicly available collection, +fileIO.ut_dirs, against which I will compare the path that is populated +by fileIO.setpath. +
    +Given that, let's take a look at the implementation of the test program: +
    PROCEDURE ut_setpath
    +IS
    +BEGIN
    +   /* Populate base collection */
    +   ut_dirs.DELETE;
    +   
    +   ut_dirs.EXTEND(2);
    +   ut_dirs(1) := 'c:\temp';
    +   ut_dirs(2) := 'e:\demo';
    +   
    +   /* Call setpath to do the work */
    +   setpath ('c:\temp;e:\demo');
    +   
    +   utAssert.eqColl (
    +      'Valid double entry',
    +      'fileio.dirs',
    +      'fileio.ut_dirs'
    +      );
    +END;
    +This program consists of three steps: +
    +
  • +Populate the test collection with direct assignments. Call the setPath +program to populate the actual collection (fileIO.dirs). Call the assertion +program to compare the two. Notice that I pass the names of the +collections to the assertion program. utAssert uses dynamic SQL to build +a PL/SQL block "on the fly" that compares values from the collections.
  • +
    + + + + diff --git a/documentation/src/started.html b/documentation/src/started.html new file mode 100644 index 000000000..9522e4ed2 --- /dev/null +++ b/documentation/src/started.html @@ -0,0 +1,95 @@ + + + + + + + utPLSQL - Getting started + + + + + + + +
    + +
    +Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
    +[ Home | Getting Started | Build +Test Packages | Examples | User +Guide | Release Notes | Document +Map ] +

    < Previous Section: Home | Next +Section: Glossary and Requirements > +
    + +

    +Getting Started

    + +

    This document gives you all the information you need to get started +with utPLSQL: how to install the product, build a test package and run +your test. If you are new to unit testing, you should take a few moments +to review the Glossary to familiarize yourself with the terminology. +

    And it is always worthwhile reviewing requirements before installing +the software! +

    +What is utPLSQL and what do I need?

    + +
    +

    +Glossary

    + +

    +Requirements

    +
    + +

    +The Four Step Program to Using utPLSQL

    + +
    +

    +Step 1. Install utPLSQL.

    + +

    +Step 2. Choose a program to test and identify +the test cases.

    + +

    +Step 3. Build a test package.

    + +

    +Step 4. Run your test.

    + +

    +Where +To Go From Here

    +
    + +

    +Administrative Topics

    + +
    +

    +Configuring UTL_FILE

    + +

    +Join the Project Team

    + +

    +Reporting Bugs and Enhancement Requests

    + +

    +Components

    + +

    +File Descriptions

    +
    + + + diff --git a/documentation/src/suite.html b/documentation/src/suite.html new file mode 100644 index 000000000..17b616393 --- /dev/null +++ b/documentation/src/suite.html @@ -0,0 +1,84 @@ + + + + + + + utPLSQL - Create and Run a Test Suite + + + + + + + +
    + +
    +Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
    +[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

    < Previous Section: Use Non-Default Prefix +| Next Section: User Guide > +
    + +

    +Create and Run a Test Suite

    + +

    Usually our applications are composed of multiple packages. To test +our application, we must test all of the packages. utPLSQL makes it easier +for you to do that by offering test suites. +

    Here is an example of a script that defines a (partial) test suite for +PL/Vision, a code library available from RevealNet +as part of its Active PL/SQL Knowledge Base: +

    /*file plvision.tst */
    +BEGIN
    +   -- Define a test suite for PL/Vision
    +   utsuite.add ('PLVision');
    +   
    +   -- Add packages for testing
    +   utpackage.add (
    +      'PLVision', 'PLVstr', dir_in => 'e:\openoracle\utplsql\examples');
    +   utpackage.add (
    +      'PLVision', 'PLVdate', dir_in => 'e:\openoracle\utplsql\examples');
    +END;   
    +/
    +This is a very simple test suite definition. I rely on all defaults, but +I specify a location for my test package code. By doing this, utPLSQL will +be able to find my test packages even if the default/current utPLSQL directory +is set to another location. +

    If I want to, I can also specify the order in which packages are tested +by passing a value for the seq_in argument. I can request that the test +code be looked for in the same package as the source code, and so on. Here +is a rewriting of the above sutie creation script that demonstrates these +options: +

    BEGIN
    +   utsuite.add ('PLVision');
    +
    +   utpackage.add ('PLVision',
    +      'PLVstr',
    +      dir_in => 'e:\openoracle\utplsql\examples',
    +      seq_in => 1,
    +      samepackage_in => TRUE
    +   );
    +
    +   utpackage.add ('PLVision',
    +      'PLVdate',
    +      dir_in => 'e:\openoracle\utplsql\examples',
    +      seq_in => 2,
    +      samepackage_in => TRUE
    +   );
    +END;
    +/
    + + + + diff --git a/documentation/src/testapi.html b/documentation/src/testapi.html new file mode 100644 index 000000000..a856f6847 --- /dev/null +++ b/documentation/src/testapi.html @@ -0,0 +1,295 @@ + + + + + + + utPLSQL - Test an Entire Package API + + + + + + + +
    + +
    +Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
    +[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

    < Previous Section: Test a Function | +Next +Section: Put Test Code in Same Package > +
    + +

    +Test an Entire Package API

    + +

    Most packages consist of lots more than a single program, and you will +generally want to test each and every of the programs listed in the package +specification. When you generate a test package with utGen, +it will produce a template unit test procedure for each program in the +package specification. You will then need to modify each of these programs. +

    One example of this more complex package structure is the table encapsulation +package. This kind of package establishes a layer of code and therefore +control between application requirements and underlying data structures. +While the building of such a layer is uncommon in the world of PL/SQL developers, +it is strongly recommended practice. A variety of tools, in fact, offer +automated table encapsulation package generation, including Oracle +Designer, RevealNet's PL/Generator +and a variety of IDE (integrated development environment) tools. +

    Suppose, then, that I used PL/Generator to generate a table encapsulation +package for the employee table. It would look like the code found in te_employee.pks +and te_employee.pkb (being rather +lengthy, we will not reproduce it in the documentation. If you take a look, +you will see that their are dozens of programs in the API, which means +that you would have lots of work to do in building your unit test cases. +In addition, many of the programs will be performing DML operations (updating, +deleting, inserting). How you can easily and dependably test those programs? +

    When you are dealing with lots of programs that have a uniform structure +and behavior (which should be the case if you are building table +API packages), then you should look for ways to generate, rather +than write manually, your test package. utGen cannot do this generation +work for you, since the logic in your encapsulation package is specific +to your environment. +

    You can, instead, build your own custom generator or use an existing +generator that is sufficiently flexible to meet your needs. The original +creator of utPLSQL, Steven Feuerstein, +has also been working on generator utilities for a number of years. One +of these utilities, currently "code named" GenX, came in very handy for +creating a test package for his PL/Generator-generated encapsulation packages. +

    Using CGML (Code Generation Markup Language), Steven created a template +that reads information from the data dictionary and defines the setup, +teardown and at least a good starting point for the unit test procedures. +Here is the template logic for the setup procedure: +

       PROCEDURE {utprefix}setup
    +   IS
    +   BEGIN
    +      -- Clean start
    +      {utprefix}teardown;
    +[ASIS]   
    +      -- Generic copy of base table for testing 
    +      EXECUTE IMMEDIATE 
    +         'CREATE TABLE {tabprefix}[objname] AS
    +            SELECT * FROM [objname]';
    +            
    +[ENDASIS]   
    +   [FOREACH]prog
    +   [IF]{allprogs}[EQ]Y[OR][progname][LIKE]UPD%[OR][progname][LIKE]INS%[OR][progname][LIKE]DEL%
    +      -- Create copy of base table for this unit test.
    +      EXECUTE IMMEDIATE 
    +         'CREATE TABLE ^{progtab}^ AS
    +[ASIS]   
    +            SELECT * FROM [objname]';
    +[ENDASIS]   
    +            
    +   [ENDIF]
    +   [ENDFOREACH]
    +   END;
    +You are not, of course, expected to understand all the logic and syntax +in this fragment. If you are interested in pursuing these sorts of genreation +opportunities and would like to check out GenX, drop a note to Steven +Feuerstein. +

    Here is a portion of the generated logic (found in ut_te_employee.pks +and ut_te_employee.pkb), the +program that tests the delete operation in the encapsulation package: +

       PROCEDURE ut_del1
    +   IS
    +      fdbk PLS_INTEGER;
    +   BEGIN
    +      /* Delete that finds now rows. */
    +
    +      EXECUTE IMMEDIATE '
    +      DELETE FROM ut_DEL1
    +       WHERE employee_id = -1
    +      ';
    +      te_employee.del (-1, rowcount_out => fdbk);
    +      -- Test results
    +      utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1');
    +      /* Successful delete */
    +
    +      EXECUTE IMMEDIATE '
    +      DELETE FROM ut_DEL1
    +       WHERE employee_id between 7800 and 7899
    +      ';
    +
    +      FOR rec IN (SELECT *
    +                    FROM employee
    +                   WHERE employee_id BETWEEN 7800 AND 7899)
    +      LOOP
    +         te_employee.del (
    +            rec.employee_id,
    +            rowcount_out => fdbk
    +         );
    +      END LOOP;
    +
    +      -- Test results
    +      utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1');
    +      ROLLBACK;
    +   EXCEPTION
    +      WHEN OTHERS
    +      THEN
    +         utassert.this (
    +            'DEL1 exception ' || SQLERRM,
    +            SQLCODE = 0
    +         );
    +   END;
    +In this procedure, I test for two scenarios: a delete that removes zero +rows and a delete that removes a specific set of rows. In both cases, I +perform the explicit (non-encapsulated) DML logic against a copy +of the actual table (this copy is created in the setup +procedure; that is the reason I use dynamic SQL to refer to this table +-- it doesn't exist when the package is compiled!). Then I do the (hopefully) +same operation by using the API program. Finally, I call the appropriate +utAssert assertion program to compare the results -- and at the end of +the procedure issue a ROLLBACK so that my "source" table (employee, in +this case), i set back to the original data state. Notice that I also put +an assertion program in the exception section to trap any errors and flag +it as a failed test. +

    That should give you a good feel for the kind of code you might write +to test a table encapsulation package. The next two sections show you how +I used the setup and teardown procedures to manage the data structures +I use in my tests. +

    +Set Up Data Structures

    +As I contemplated how best to test these large packages, I revisited some +of my testing principles and found one to be of particular importance: + +

    Build isolated tests. + +

    This principle is important because it allows you to run one, all or +a subset of your tests without having to worry about the impact or dependencies +on the other tests. And test isolation is particularly important +when testing DML operations. The way to validate a successful DML operation +is by analyzing the contents of the "source" table against a "test" table. +If all the tests modify the same test table, ti will be very difficult +if not impossible to verify success or notice failure. +

    So I decided that the best way to run my unit tests for DML operations +was to create a separate test table for each unit test. As a consequence, +my setup procedure for the te_employee +package looks like this: +

       PROCEDURE ut_setup
    +   IS
    +   BEGIN
    +      ut_teardown;
    +      EXECUTE IMMEDIATE 'CREATE TABLE ut_employee AS
    +            SELECT * FROM employee';
    +      EXECUTE IMMEDIATE 'CREATE TABLE ut_DEL1 AS
    +            SELECT * FROM employee';
    +      EXECUTE IMMEDIATE 'CREATE TABLE ut_DELBY_EMP_DEPT_LOOKUP AS
    +            SELECT * FROM employee';
    +      EXECUTE IMMEDIATE 'CREATE TABLE ut_DELBY_EMP_JOB_LOOKUP AS
    +            SELECT * FROM employee';
    +      EXECUTE IMMEDIATE 'CREATE TABLE ut_DELBY_EMP_MGR_LOOKUP AS
    +            SELECT * FROM employee';
    +      EXECUTE IMMEDIATE 'CREATE TABLE ut_INS1 AS
    +            SELECT * FROM employee';
    +      EXECUTE IMMEDIATE 'CREATE TABLE ut_UPD1 AS
    +            SELECT * FROM employee';
    +      EXECUTE IMMEDIATE 'CREATE TABLE ut_UPD$HIRE_DATE1 AS   
    +            SELECT * FROM employee';
    +      EXECUTE IMMEDIATE 'CREATE TABLE ut_UPD$SALARY1 AS
    +            SELECT * FROM employee';
    +   END;
    +I first remove all my data structures using the teardown procedure to make +sure I have a clean start. Then I use dynamic SQL (the Oracle8i version) +to create all my tables. I must rely on dynamic SQL because PL/SQL does +not yet support native DDL statements, such as CREATE TABLE. +

    Then I am set to test. +

    +Tear Down Data Structures

    +Well, if I am going to create a whole bunch of data structures to run my +tests, I had better get rid of those structures when I am done. Here is +the teardown program I generated for the te_employee package: +
       PROCEDURE ut_teardown
    +   IS
    +   BEGIN
    +      BEGIN
    +         EXECUTE IMMEDIATE 'DROP TABLE ut_employee';
    +      EXCEPTION
    +         WHEN OTHERS
    +         THEN
    +            NULL;
    +      END;
    +
    +      BEGIN
    +         EXECUTE IMMEDIATE 'DROP TABLE ut_DEL1';
    +      EXCEPTION
    +         WHEN OTHERS
    +         THEN
    +            NULL;
    +      END;
    +
    +      BEGIN
    +         EXECUTE IMMEDIATE 'DROP TABLE ut_DELBY_EMP_DEPT_LOOKUP';
    +      EXCEPTION
    +         WHEN OTHERS
    +         THEN
    +            NULL;
    +      END;
    +
    +      BEGIN
    +         EXECUTE IMMEDIATE 'DROP TABLE ut_DELBY_EMP_JOB_LOOKUP';
    +      EXCEPTION
    +         WHEN OTHERS
    +         THEN
    +            NULL;
    +      END;
    +
    +      BEGIN
    +         EXECUTE IMMEDIATE 'DROP TABLE ut_DELBY_EMP_MGR_LOOKUP';
    +      EXCEPTION
    +         WHEN OTHERS
    +         THEN
    +            NULL;
    +      END;
    +
    +      BEGIN
    +         EXECUTE IMMEDIATE 'DROP TABLE ut_INS1';
    +      EXCEPTION
    +         WHEN OTHERS
    +         THEN
    +            NULL;
    +      END;
    +
    +      BEGIN
    +         EXECUTE IMMEDIATE 'DROP TABLE ut_UPD1';
    +      EXCEPTION
    +         WHEN OTHERS
    +         THEN
    +            NULL;
    +      END;
    +
    +      BEGIN
    +         EXECUTE IMMEDIATE 'DROP TABLE ut_UPD$HIRE_DATE1';
    +      EXCEPTION
    +         WHEN OTHERS
    +         THEN
    +            NULL;
    +      END;
    +
    +      BEGIN
    +         EXECUTE IMMEDIATE 'DROP TABLE ut_UPD$SALARY1';
    +      EXCEPTION
    +         WHEN OTHERS
    +         THEN
    +            NULL;
    +      END;
    +
    +   END;
    +Again, I use dynamic SQL, but enclose each DROP TABLE statement inside +its own exception section so that if for any reason the DROP fails, I continue +on in an attempt to get as much done as possible. + + + + diff --git a/documentation/src/testfunc.html b/documentation/src/testfunc.html new file mode 100644 index 000000000..1107a93d2 --- /dev/null +++ b/documentation/src/testfunc.html @@ -0,0 +1,125 @@ + + + + + + + utPLSQL - Test a Function + + + + + + + +
    + +
    +Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
    +[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

    < Previous Section: Test a Procedure | +Next +Section: Test an Entire Package API > +
    + +

    +Test a Function

    + +

    As with the procedure, there are a couple of scenarios to consider: +

      +
    • +The function returns a scalar value (number, +date, string, Boolean). In this case, you can embed your call to the function +directly inside a call to a uAssert assertion program, making your test +procedure very concise and easy to write.
    • + + +
    • +The function returns a non-scalar value, +such as an object or a collection. In this case, you will need to call +the function and then evaluate the contents of the returned structure.
    • + + + +
    • +A third situation to consider is that your function returns a value, but +it also takes a number of other actions, the success of which is not reflected +in the returned value. Fully testing such a function (one with "side effects") +can be very difficult, since you must test for a variety of conditions.
    • + +
    + +

    +Testing a Scalar Function

    +First, a test of a function returning a scalar value. Consider the following +packaged function: +
    /*file str.pks and str.pkb */
    +CREATE OR REPLACE PACKAGE str
    +IS
    +   FUNCTION betwn (
    +      string_in IN VARCHAR2,
    +      start_in IN PLS_INTEGER,
    +      end_in IN PLS_INTEGER
    +   )
    +      RETURN VARCHAR2;
    +END str;
    +/
    +The str.betwn function returns the sub-string of a string_in that is found +between the start and end locations specified by start_in and end_in. +

    So...time to test! I generate a test package +and then modify the unit test procedure to check for various conditions: +

    /*file ut_str.pkb */
    +CREATE OR REPLACE PACKAGE BODY ut_str
    +IS
    +   PROCEDURE ut_setup
    +   IS
    +   BEGIN
    +      NULL;
    +   END;
    +   
    +   PROCEDURE ut_teardown
    +   IS
    +   BEGIN
    +      NULL;
    +   END;
    +
    +   -- For each program to test...
    +   PROCEDURE ut_betwn IS
    +   BEGIN
    +      utAssert.eq (
    +         'Typical Valid Usage',
    +         str.betwn ('this is a string', 3, 7),
    +         'is is' 
    +         );
    +         
    +      utAssert.eq (
    +         'Test Negative Start',
    +         str.betwn ('this is a string', -3, 7),
    +         'ing'
    +         );
    +         
    +      utAssert.isNULL (
    +         'Start bigger than end',
    +         str.betwn ('this is a string', 3, 1)
    +         );
    +   END ut_betwn;
    +
    +END ut_str;
    +/
    +As you can see, my calls to str.betwn are embedded right within calls to +utAssert.eq and utAssert.isNULL, making my test code +

    +Testing a Composite Function

    + + + + diff --git a/documentation/src/testproc.html b/documentation/src/testproc.html new file mode 100644 index 000000000..3cbf41828 --- /dev/null +++ b/documentation/src/testproc.html @@ -0,0 +1,282 @@ + + + + + + + utPLSQL - Test a Procedure + + + + + + + +
    + +
    +Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
    +[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

    < Previous Section: Cross-Reference by Assertion +Type | Next Section: Test a Function > +
    + +

    +Test a Procedure

    + +

    There are a couple of scenarios to consider: +

      +
    • +The procedure runs some code and then passes back results through the parameter +list. In this case, I can write a unit test that analyzes the OUT and IN +OUT argument values.
    • + +The procedure runs some code, which changes +other elements of the application (such as a database table or a file). +The parameter list does not contain arguments that can be analyzed for +successful execution. So to assert success, I will need to analyze/compare +the data structures that have been modified. +
    + +

    +Test Success Through Parameters

    + +We'll start with a really simple example. I +have built a procedure that accepts two dates and returns the number of +seconds between them. Here it is: + +
    /*file calc_secs_between.sp */
    +CREATE OR REPLACE PROCEDURE calc_secs_between (
    +   date1 IN DATE,
    +   date2 IN DATE,
    +   secs OUT NUMBER)
    +IS
    +BEGIN
    +   -- 24 hours in a day, 
    +   -- 60 minutes in an hour,
    +   -- 60 seconds in a minute...
    +   secs := (date2 - date1) * 24 * 60 * 60;
    +END;
    +/
    + +After compiling my code cleanly, I generate +my test package: + +
    SQL> SET SERVEROUTPUT ON FORMAT WRAPPED
    +SQL> exec utGen.testpkg ('calc_secs_between ')
    +CREATE OR REPLACE PACKAGE ut_calc_secs_between
    +IS
    +   PROCEDURE ut_setup;
    +   PROCEDURE ut_teardown;
    +
    +   -- For each program to test...
    +   PROCEDURE ut_CALC_SECS_BETWEEN;
    +END ut_calc_secs_between;
    +/
    +CREATE OR REPLACE PACKAGE BODY ut_calc_secs_between
    +IS
    +   PROCEDURE ut_setup
    +   IS
    +   BEGIN
    +      NULL;
    +   END;
    +
    +   PROCEDURE ut_teardown
    +   IS
    +   BEGIN
    +      NULL;
    +   END;
    +
    +   -- For each program to test...
    +   PROCEDURE ut_CALC_SECS_BETWEEN IS
    +   BEGIN
    +      CALC_SECS_BETWEEN (
    +            DATE1 => ''
    +            ,
    +            DATE2 => ''
    +            ,
    +            SECS => ''
    +       );
    +
    +      utAssert.this (
    +         'Test of CALC_SECS_BETWEEN',
    +         '<boolean expression>'
    +         );
    +   END ut_CALC_SECS_BETWEEN;
    +
    +END ut_calc_secs_between;
    +/
    + +I generated the output to the screen, but it +is actually easier to deposit the code directly into two separate files +for package spec and body, ut_calc_secs_between.pks and ut_calc_secs_between.pkb, +which I do as follows: + +
    SQL> exec utGen.testpkg ('calc_secs_between ', output_type_in => utGen.c_file)
    + +By conforming to this standard, utPLSQL can +automatically compile this code before each test. I now edit the ut_calc_secs_between +procedure to test for various cases: + +
    PROCEDURE ut_CALC_SECS_BETWEEN 
    +IS
    +   secs PLS_INTEGER;
    +BEGIN
    +   CALC_SECS_BETWEEN (
    +         DATE1 => SYSDATE
    +         ,
    +         DATE2 => SYSDATE
    +         ,
    +         SECS => secs
    +    );
    +
    +   utAssert.eq (
    +      'Same dates',
    +      secs, 
    +      0
    +      );
    +      
    +   CALC_SECS_BETWEEN (
    +         DATE1 => SYSDATE
    +         ,
    +         DATE2 => SYSDATE+1
    +         ,
    +         SECS => secs
    +    );
    +
    +   utAssert.eq (
    +      'Exactly one day',
    +      secs, 
    +      24 * 60 * 60
    +      );
    +      
    +END ut_CALC_SECS_BETWEEN;
    + +and now I can run my test: + +
    SQL> exec utplsql.test ('calc_secs_between')
    +.
    +>    SSSS   U     U   CCC     CCC   EEEEEEE   SSSS     SSSS
    +>   S    S  U     U  C   C   C   C  E        S    S   S    S
    +>  S        U     U C     C C     C E       S        S
    +>   S       U     U C       C       E        S        S
    +>    SSSS   U     U C       C       EEEE      SSSS     SSSS
    +>        S  U     U C       C       E             S        S
    +>         S U     U C     C C     C E              S        S
    +>   S    S   U   U   C   C   C   C  E        S    S   S    S
    +>    SSSS     UUU     CCC     CCC   EEEEEEE   SSSS     SSSS
    +.
    + SUCCESS: "calc_secs_between"
    + +Certainly, there are a variety of other conditions +to test, but this should give you a good idea of how to go about it! + +

    +Test Success by Analyzing Impact

    + +Now let's consider a more complicated situation. +I have a procedure that truncates all the rows in the specified table. +To do this I just use dynamic SQL, as you can see in: + +
    /*file truncit.sp */
    +CREATE OR REPLACE PROCEDURE truncit (
    +   tab IN VARCHAR2,
    +   sch IN VARCHAR2 := NULL
    +)
    +IS
    +BEGIN
    +   EXECUTE IMMEDIATE 'truncate table ' || NVL (sch, USER) || '.' || tab;
    +END;
    +/
    + +After I run this test, I cannot simply check +the value returned by the procedure. Instead, I must check to see how many +rows are left in the table. Fortunately, I have another dynamic SQL utility +to help me out here, one that returns the count of rows in any table: + +
    /*file tabcount.sf */
    +CREATE OR REPLACE FUNCTION tabcount (
    +   sch IN VARCHAR2,
    +   tab IN VARCHAR2)
    +   RETURN INTEGER
    +IS
    +   retval  INTEGER;
    +BEGIN
    +   EXECUTE IMMEDIATE 
    +      'SELECT COUNT(*) FROM ' || sch || '.' || tab
    +      INTO retval; 
    +   RETURN retval;
    +EXCEPTION
    +    WHEN OTHERS 
    +    THEN
    +       RETURN NULL; 
    +END;
    +/
    + +So I will generate a package +to test truncit and then modify the package body: + +
    SQL> SET SERVEROUTPUT ON FORMAT WRAPPED
    +SQL> exec utGen.testpkg ('truncit', output_type_in => utGen.c_file)
    + +To run my test, I need to truncate a table. +That is an irreversible action, so I will create a "temporary" table in +the setup procedure and drop it in the teardown procedure. Then I will +run my code and use tabCount to validate the results: + +
    /*file ut_truncit.pkb */
    +CREATE OR REPLACE PACKAGE BODY ut_truncit
    +IS
    +   PROCEDURE ut_setup
    +   IS
    +   BEGIN
    +      EXECUTE IMMEDIATE 
    +         'CREATE TABLE temp_emp AS SELECT * FROM employee';
    +   END;
    +   
    +   PROCEDURE ut_teardown
    +   IS
    +   BEGIN
    +      EXECUTE IMMEDIATE 
    +         'DROP TABLE temp_emp';
    +   END;
    +
    +   -- For each program to test...
    +   PROCEDURE ut_TRUNCIT IS
    +   BEGIN
    +      TRUNCIT (
    +            TAB => 'temp_emp'
    +            ,
    +            SCH => USER
    +       );
    +
    +      utAssert.eq (
    +         'Test of TRUNCIT',
    +         tabcount (USER, 'temp_emp'),
    +         0
    +         );
    +   END ut_TRUNCIT;
    +
    +END ut_truncit;
    +/
    + +Not quite as straightforward as checking values +returned in OUT or IN OUT arguments, but not too awful, right? Of course, +things can get considerably more complicated as your code (and the results +you must test for) grows more complex. Regardless, you will find it easier +to build and run your tests through utPLSQL than through more ad hoc and +considerably less organized approaches. + + + + + diff --git a/documentation/src/testrun.html b/documentation/src/testrun.html new file mode 100644 index 000000000..b70e8eecc --- /dev/null +++ b/documentation/src/testrun.html @@ -0,0 +1,409 @@ + + + + + + + utPLSQL - A Test Run with utPLSQL + + + + + + + +
    + +
    +Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
    +[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

    < Previous Section: How to build a test package +| Next Section: Advanced Topics > +
    + +

    +A "Test Run" with utPLSQL

    + +

    I will put utPLSQL to work in a small-scale development +effort, to show you how it all hangs together. I've got a "hangnail" in +my PL/SQL development work, called SUBSTR. This function bothers me and +I want to take care of it. What's the problem? SUBSTR is great when you +know the starting location of a string and number of characters you want.In +many situations, though, I have the start and end locations and I need +to figure out the number of characters I then want. Is it: +

    mystring := SUBSTR (full_string, 5, 17); -- start and end? Nah...
    + +
    mystring := SUBSTR (full_string, 5, 12); -- end – start?
    + +
    mystring := SUBSTR (full_string, 5, 13); -- end – start + 1?
    + +
    mystring := SUBSTR (full_string, 5, 11); -- end – start 1 1?
    + +Why should I have to remember stuff like this? I +never do, and so I take out a scrap of paper, write down 'abcdefgh', put +a mark over the "c" and another over the "g", count on my fingers and then +remember that of course the formula is "end – start + 1". + +All right, so I did that a dozen times, I am sick +of it and determined to stop wasting my time in the future. I will write +a function called "str.betwn" (the betwn function defined in the str package) +that does the work and the remembering for me. + +Instead of immediately coding the function, however, +I will first write my unit tests with utPLSQL! Since my source package +is named "str", I will create a test package named "ut_str". I am a lazy +fellow, so I will take the lazy way out and generate the starting point +for my package: + +
    SQL> exec utgen.testpkg ('str', output_type_in => utplsql.c_file)
    + +Note: for the above call to work, I must have already +set my default directory for utPLSQL, which I do via a SQL*Plus login script +that looks like this: + +
    exec utplsql.setdir ('e:\utplsql\test')
    + +
    SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED
    + +Otherwise, I would need to specify the directory +in my call to genpkg, as in: + +
    SQL> exec utgen.testpkg ('str', output_type_in => utplsql.c_file, dir_in => 'e:\utplsql\test')
    + +I then will find this package spec in the ut_str.pks +file: + +
    CREATE OR REPLACE PACKAGE ut_str
    + +
    IS
    + +
       PROCEDURE ut_setup;
    + +
       PROCEDURE ut_teardown;
    + +
      
    + +
       -- For each program to test...
    + +
       PROCEDURE ut_betwn;
    + +
    END ut_str;
    + +
    /
    + +And I don't really have to modify the specification +at all. The body will, on the other hand, require some work, since I haven't +yet figured out a way to automatically generate the test code itself. Here +is the purely generated test package body found +in the ut_str.pkb file: + +
    CREATE OR REPLACE PACKAGE BODY ut_str
    + +
    IS
    + +
       PROCEDURE ut_setup
    + +
       IS
    + +
       BEGIN
    + +
          NULL;
    + +
       END;
    + +
      
    + +
       PROCEDURE ut_teardown
    + +
       IS
    + +
       BEGIN
    + +
          NULL;
    + +
       END;
    + +
      
    + +
       -- For each program to test...
    + +
       PROCEDURE ut_betwn
    + +
       IS
    + +
       BEGIN
    + +
          utAssert.this (
    + +
             'Test of betwn',
    + +
             <boolean expression>,
    + +
             );
    + +
       END;
    + +
    [ENDFOREACH]
    + +
      
    + +
    END ut_str;
    + +
    /
    + +The setup and teardown procedures are fine (I don't +have any special setup and therefore teardown requirements), but the ut_betwn +needs lots of work. It doesn't really test anything yet. + +Before I start writing my test code, however, I +will just sit back and think about what I want to test. Here are some inputs +that I can think of: + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +String + +Start + +End + +Expected Result +
    +"this is a string" + +3 (positive number) + +7 (bigger positive number) + +"is is" +
    +"this is a string" + +-3 (invalid negative number) + +7 (bigger positive number) + +"ing" (consistent with SUBSTR behavior) +
    +"this is a string" + +3 (positive number) + +1 (smaller positive number) + +NULL +
    + + +

    We could easily come up with a whole lot more test +cases – and if this was real life and not product documentation, I would +not move forward until I had identified all interesting tests. So let's +suppose I have done that and now I am ready to do some coding. Since I +am testing a function, I will want to compare the result of the function +call to my expected results. I will therefore change my assertion from +the generic "assert this" procedure to the utAssert.eq program, and put +the call to the function right into the assertion routine. Here, then, +is my first crack at transforming my ut_betwn procedure: +

    PROCEDURE ut_betwn IS
    + +
    BEGIN
    + +
       utAssert.eq (
    + +
          'Test of betwn',
    + +
          str.betwn ('this is a string', 3, 7),
    + +
          'is is'
    + +
          );
    + +
    END;
    + +Following the Extreme Programming philosophy ("code +a little, test a lot"), I will test this test case before I add all the +other test cases. I do this with a very simple call: + +
    SQL> exec utplsql.test ('str')
    +
    +>    SSSS   U     U   CCC     CCC   EEEEEEE   SSSS     SSSS
    +>   S    S  U     U  C   C   C   C  E        S    S   S    S
    +>  S        U     U C     C C     C E       S        S
    +>   S       U     U C       C       E        S        S
    +>    SSSS   U     U C       C       EEEE      SSSS     SSSS
    +>        S  U     U C       C       E             S        S
    +>         S U     U C     C C     C E              S        S
    +>   S    S   U   U   C   C   C   C  E        S    S   S    S
    +>    SSSS     UUU     CCC     CCC   EEEEEEE   SSSS     SSSS
    +
    +>SUCCESS: "str"
    + +Now, you could say: "Great it worked!" Or you could +say: "I have no idea if it worked. Maybe it always says success." +I go for the latter, so let's deliberately cause a failure: + +
    PROCEDURE ut_betwn IS
    + +
    BEGIN
    + +
       utAssert.eq (
    + +
          'Test of betwn',
    + +
          str.betwn ('this is a string', 3, 7),
    + +
          'this is a pipe'
    + +
          );
    + +
    END;
    + +Saving the file (but not bothering to recompile, +since utPLSQL will do it for me automagically), +I then run my test again: + +
    SQL> exec utplsql.test ('str', recompile_in=>false)
    +
    +>  FFFFFFF   AA     III  L      U     U RRRRR   EEEEEEE
    +>  F        A  A     I   L      U     U R    R  E
    +>  F       A    A    I   L      U     U R     R E
    +>  F      A      A   I   L      U     U R     R E
    +>  FFFF   A      A   I   L      U     U RRRRRR  EEEE
    +>  F      AAAAAAAA   I   L      U     U R   R   E
    +>  F      A      A   I   L      U     U R    R  E
    +>  F      A      A   I   L       U   U  R     R E
    +>  F      A      A  III  LLLLLLL  UUU   R     R EEEEEEE
    +
    +FAILURE: "str"
    +
    +BETWN: Typical Valid Usage; expected "is is", got "this is a pipe"
    + +Now I have a higher degree of confidence that I +am getting this right. Excellent! Now I will add the other test cases: + +
    PROCEDURE ut_betwn IS
    + +
    BEGIN
    + +
       utAssert.eq (
    + +
          'Typical Valid Usage',
    + +
          str.betwn ('this is a string', 3, 7),
    + +
          'is is'
    + +
          );
    + +
         
    + +
       utAssert.eq (
    + +
          'Test Negative Start',
    + +
          str.betwn ('this is a string', -3, 7),
    + +
          'ing'
    + +
          );
    + +
         
    + +
       utAssert.isNULL (
    + +
          'Start bigger than end',
    + +
          str.betwn ('this is a string', 3, 1)
    + +
          );
    + +
    END;
    + +I will deliberately cause each of these tests to +fail, to give you a sense of the quality of feedback: + +
    >  FFFFFFF   AA     III  L      U     U RRRRR   EEEEEEE
    +>  F        A  A     I   L      U     U R    R  E
    +>  F       A    A    I   L      U     U R     R E
    +>  F      A      A   I   L      U     U R     R E
    +>  FFFF   A      A   I   L      U     U RRRRRR  EEEE
    +>  F      AAAAAAAA   I   L      U     U R   R   E
    +>  F      A      A   I   L      U     U R    R  E
    +>  F      A      A   I   L       U   U  R     R E
    +>  F      A      A  III  LLLLLLL  UUU   R     R EEEEEEE
    +
    +FAILURE: "str"
    + +
    betwn: Typical Valid Usage; expected "is is", got "this is a pipe"
    + +
    betwn: Test Negative Start; expected "ing", got "BRRRING"
    + +
    betwn: IS NOT NULL: Start bigger than end
    + +Faced with these results, I can zoom in on the code +within str.betwn that is causing these incorrect results. I resist the +temptation to fix the code for all my tests all at once. Instead, I make +one change at a time, then run my test again. I do that over and over again +until the failure for the single test case goes away. Then I move to the +next one. Eventually, I get a green light and am highly confident of my +program – if, of course, I really did come up with an exhaustive list of +tests. + +As I think of another test case, I add a call to +utAssert to run that test. + +As a bug is reported to me, I add a call to utAssert +to reproduce that bug. Then I repair my code. + + + + diff --git a/documentation/src/userguide.html b/documentation/src/userguide.html new file mode 100644 index 000000000..443f555f9 --- /dev/null +++ b/documentation/src/userguide.html @@ -0,0 +1,66 @@ + + + + + + + utPLSQL - User Guide + + + + + + + +
    + +
    +Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
    +[ Home | Getting +Started | Build Test Packages +| Examples | User Guide | Release +Notes | Document Map ] +

    < Previous Section: Create and Run a Test Suite +| Next Section: utPLSQL Package > +
    + +

    +User Guide

    + +

    The utPLSQL unit testing framework consists of several different elements: +

      +
    • +A set of tables to hold information about unit tests and test suites.
    • + +A set of packages that allow you to run tests, +build test packages and access information about tests you have run. +
    +This document tells you how to use those utPLSQL packages: +

    +utPLSQL - Register and run test packages

    + +

    +utConfig - Set how tests are run

    + +

    +utResult - Analyze and display results +of unit tests

    + +

    +utAssert - Assert that code works +properly

    + +

    +utGen - Generate test packages

    + +

    +Define Test Suites

    + + + + diff --git a/documentation/src/utassert.html b/documentation/src/utassert.html new file mode 100644 index 000000000..16c683a74 --- /dev/null +++ b/documentation/src/utassert.html @@ -0,0 +1,1235 @@ + + + + + + + utPLSQL - utAssert Package + + + + + + + +
    + +
    +Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
    +[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

    < Previous Section: utResult Package | +Next +Section: utGen Package > +
    + +

    +utAssert Package

    + +

    This package contains the following procedures and functions: +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    utAssert.showresults +
    utAssert.noshowresults +
    utAssert.showingresults
    Set the showing of results immediately
    utAssert.thisGeneric "Assert This" Procedure
    utAssert.isnull +
    utAssert.isnotnull
    Check for NULL and NOT NULL values
    utAssert.eqCheck Equality of Scalar Values
    utAssert.eqtableCheck Equality of Database Tables
    utAssert.eqtabcountCheck Equality of Table Counts
    utAssert.eqqueryCheck Equality of Queries
    utAssert.eqqueryvalueCheck Equality of Query against single value
    utAssert.eqfileCheck Equality of Files
    utAssert.eqpipeCheck Equality of Database Pipes
    utAssert.eqcoll +
    utAssert.eqcollapi
    Check Equality of Collections
    utAssert.throwsCheck a procedure or function throws an exception
    + + + +The utAssert package provides a set of assertion +routines ("assert that the following condition is true") that you will +use to register the outcome of a test case. You must call a utAssert assertion +program after (or containing) a test case so that the results of that test +can be recorded and then reported. See Build +Test Packages for many examples and more details on this process. Here +is a very simple example, though, to give you an idea of the code you would +write: + +

       PROCEDURE ut_BETWNSTR IS
    +   BEGIN
    +      utAssert.eq (
    +         'Typical valid usage',
    +         BETWNSTR(
    +            STRING_IN => 'abcdefg'
    +            ,
    +            START_IN => 3
    +            ,
    +            END_IN => 5
    +            ),
    +         'cde'
    +         );
    +   END;
    + +utAssert offers a wide (and ever expanding) set +of assertion programs that allow you to efficiently (a) test the outcome +of your unit test and (b) report the results of that test to utPLSQL. You +should review Common Assertion Parameters and +Behavior before using any specific assertion program. It is also possible +to build your own assertion routine. + +Note: all utAssert assertions are defined in the +ut_assertion table, as well as actually coded in the utAssert package. + +

    +Common Assertion Parameters and Behavior

    + +Each type of assertion routine accepts different +kinds of data, but there are lots of similarities between the assertions, +as well. + +Here is an explanation of the common assertion parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +msg_in + +A message +to be displayed if the assertion fails. This is the first argument and +is mandatory, because the tests need to be self documenting. +
    +check_this_in + +The value +to be checked.. If a Boolean expression, this will usually include the +invocation of the method being tested, resulting in a single line of code +for the entire test case. +
    +against_this_in + +For assert_eq, +the assertion routine will check the check_this_in value against the against_this_in +value. This parameter should be the certifiably correct value. +
    +null_ok_in + +TRUE if +a NULL value should be interpreted as a successful test, FALSE if NULL +indicates failure. +
    +raise_exc_in + +TRUE if +it is OK for the assertion routine to allow an exception to be propagated +out unhandled. +
    + +

    +Showing Results Immediately

    +You can request that utPLSQL display results immediately after running +the assertion program. The default behavior is that utAssert will simply +pass the results to utResult for later processing. You might want to see +results immediately if you are building your own small testing script and +are not calling utPLSQL.test. +

    To request results immediately, call the showResults procedure: +

       PROCEDURE utAssert.showresults;
    +This a session-level setting, and must be reset each time you connect to +Oracle. You can turn off showing of results by calling the noShowResults +program: +
       PROCEDURE utAssert.noshowresults;
    +To determine the current status of this setting, you can call the following +function: +
       FUNCTION utAssert.showing_results return boolean;
    +Here is an example of a simple script that calls an assertion routine and +immediately shows the results: +
    set serveroutput on size 1000000
    +BEGIN
    +   utAssert.showresults;
    +   utAssert.eq (
    +      'Test of betwn',      
    +      str.betwn ('this is a string', 3, 7),      
    +      'this is a pipe'      );
    +END;
    +/
    +And here is the result of running this script: +
    FAILURE: "Unnamed Test"
    +: Test of betwn; expected "this is a pipe", got "is is"
    + +

    +Generic "Assert This" Assertion Procedure

    + +This most generic assertion program simply says +"assert this" and passes a Boolean expression. It is used by all the other +assertion routines, which construct a Boolean expression from their +specific values and logic. + +
       PROCEDURE utAssert.this (
    + +
          msg_in IN VARCHAR2,
    + +
          check_this_in IN BOOLEAN,
    + +
          null_ok_in IN BOOLEAN := FALSE,
    + +
          raise_exc_in IN BOOLEAN := FALSE
    + +
       );
    + +Use utAssert.this when you have a Boolean expression +that you want to check, as in:. + +
    BEGIN
    + +
       ...
    + +
       utAssert.this (
    + +
          'Boolean function result',
    + +
          is_valid_account (my_account)
    + +
          );
    + +You can also use this assertion to register a failure, +most usually in an exception section, as in: + +
    EXCEPTION
    + +
       WHEN OTHERS
    + +
       THEN
    +      utAssert.this (
    + +
             SQLERRM,
    + +
             FALSE);
    + +Generally, you should avoid utAssert.this and instead +use a specialized assertion routine, documented below. Most of the assertions +give you the ability check for equality (of scalars, such as strings, or +more complex data structures like tables, pipes and files): does the data +generated by my code match the expected value(s)? + +

    +Check for NULL and NOT NULL Values

    + +You can check to see if a value is NULL or is NOT +NULL with the following assertions: + +
    PROCEDURE utAssert.isnotnull (
    +   msg_in IN VARCHAR2,
    +   check_this_in IN VARCHAR2,
    +   null_ok_in IN BOOLEAN := FALSE,
    +   raise_exc_in IN BOOLEAN := FALSE
    +);
    +
    +PROCEDURE utAssert.isnull (
    +   msg_in IN VARCHAR2,
    +   check_this_in IN VARCHAR2,
    +   null_ok_in IN BOOLEAN := FALSE,
    +   raise_exc_in IN BOOLEAN := FALSE
    +);
    +
    +PROCEDURE utAssert.isnotnull (
    +   msg_in IN VARCHAR2,
    +   check_this_in IN BOOLEAN,
    +   null_ok_in IN BOOLEAN := FALSE,
    +   raise_exc_in IN BOOLEAN := FALSE
    +);
    +
    +PROCEDURE utAssert.isnull (
    +   msg_in IN VARCHAR2,
    +   check_this_in IN BOOLEAN,
    +
    +   null_ok_in IN BOOLEAN := FALSE,
    +   raise_exc_in IN BOOLEAN := FALSE
    +);
    + +Use these assertions when +you simply want to check if a scalar expression (string, date, number and +Boolean are supported) is NULL or NOT NULL, as in: + +
    +
    +
    BEGIN
    + +
       ...
    + +
       utAssert.isNULL (
    + +
          'Should be nothing left',
    + +
          TRANSLATE (digits_in_string, 'A1234567890', 'A')
    + +
          );
    + +

    +Check Equality of Scalar Values

    +If you need to compare two dates or two strings or two numbers or two Booleans, +use the utAssert.eq assertion program. + +

    Here is the header for the scalar equality check assertion: +

    PROCEDURE utAssert.eq (
    + +
       msg_in IN VARCHAR2,
    + +
       check_this_in IN VARCHAR2|BOOLEAN|DATE|NUMBER,
    + +
       against_this_in IN VARCHAR2|BOOLEAN|DATE|NUMBER,
    + +
       null_ok_in IN BOOLEAN := FALSE,
    + +
       raise_exc_in IN BOOLEAN := FALSE
    + +
    );
    + +If the two values are equal, your code gets a green +light. Otherwise, utAssert writes the test results to the utResult package, +resulting in a red light for the test. + +If NULL values are considered value for this test, +pass TRUE for null_ok_in. If you want the assertion to raise an exception +on failure and stop the test from proceeding, pass TRUE for raise_exc_in. + +Here is an example of using the utAssert.eq program: + +
       PROCEDURE ut_emp_dept_lookuprowcount
    +   IS
    + +
          l_rowcount1 PLS_INTEGER;
    +      l_rowcount2 PLS_INTEGER;
    +   BEGIN
    +      -- Run baseline code.
    +      SELECT COUNT (*)
    +        INTO l_rowcount1
    +        FROM employee
    +       WHERE department_id = 30;
    + +
     
    + +
          -- Compare to program call:
    +      l_rowcount2 :=
    +         te_employee.emp_dept_lookuprowcount (30);
    + +
     
    + +
          -- Test results
    +      utassert.eq (
    +         'Successful EMP_DEPT_LOOKUPROWCOUNT',
    +         l_rowcount2,
    +         l_rowcount1
    +      );
    +   END;
    + +

    +Check Equality of DatabaseTables

    + +If your test performs DML operations (update, insert +or delete), you will need to check your results in a database table. You +could do this by querying the results into local variables and then calling +utAssert.eq to check those values against your expected data. That can +be a very laborious process, so utAssert offers the eqtable and equerry +assertion routines to streamline the process. + +Both these procedures use the MINUS SQL operator +to essentially "subtract" the contents of one table (query) from the other. +If anything is left, then the two tables (queries) are not the same and +the test is given a red light. As you can probably see, the structure of +the two tables (queries) must be identical for this assertion to work properly. + +The utAssert.eqtable allows you to compare the contents +of your data table (changed by your code) against another table, which +you can preset with the data you expect to see after the test. Here is +the header for eqtable: + +
    PROCEDURE utAssert.eqtable (
    + +
       msg_in IN VARCHAR2,
    + +
       check_this_in IN VARCHAR2,
    + +
       against_this_in IN VARCHAR2,
    + +
       check_where_in IN VARCHAR2 := NULL,
    + +
       against_where_in IN VARCHAR2 := NULL,
    + +
       raise_exc_in IN BOOLEAN := FALSE
    + +
    );
    + +where check_this_in and against_this_in are the +names of tables or views. You can supply an optional WHERE clause to restrict +the rows you wish to compare. Here is an example that calls eqTable twice, +to test two different conditions. + +
    PROCEDURE ut_del1
    +IS
    +   fdbk PLS_INTEGER;
    +BEGIN
    +   /* Delete that finds now rows. */
    +
    +   EXECUTE IMMEDIATE '
    +   DELETE FROM ut_DEL1
    +    WHERE employee_id = -1
    +   ';
    +   te_employee.del (-1, rowcount_out => fdbk);
    + +
       -- Test results
    +   utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1');
    +   /* Successful delete */
    +
    +   EXECUTE IMMEDIATE '
    +      DELETE FROM ut_DEL1
    +       WHERE employee_id between 7800 and 7899
    +      ';
    +
    +   FOR rec IN (SELECT *
    +                 FROM employee
    +                WHERE employee_id BETWEEN 7800 AND 7899)
    +   LOOP
    +      te_employee.del (
    +         rec.employee_id,
    +         rowcount_out => fdbk
    +      );
    +   END LOOP;
    +
    +   -- Test results
    +   utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1');
    +   ROLLBACK;
    +EXCEPTION
    +   WHEN OTHERS
    +   THEN
    +      utassert.this (
    +         'DEL1 exception ' || SQLERRM,
    +         SQLCODE = 0
    +      );
    +END;
    + +

    +Check Equality of Table Counts

    +If your tests simply produce the right number of rows in a table but not +a fixed set of values, you will not be able to use utAssert.eqtable +above. However, utAssert.eqtabcount allows you to simply test that +the numbers of rows are equal. The declaration of the procedure is +as follows: +
    PROCEDURE utAssert.eqtabcount (
    + +
       msg_in IN VARCHAR2,
    + +
       check_this_in IN VARCHAR2,
    + +
       against_this_in IN VARCHAR2,
    + +
       check_where_in IN VARCHAR2 := NULL,
    + +
       against_where_in IN VARCHAR2 := NULL,
    + +
       raise_exc_in IN BOOLEAN := FALSE
    + +
    );
    + +where check_this_in and against_this_in are the +names of tables or views. As in utAssert.eqtable, you can supply an optional +WHERE clause to restrict the rows you wish to compare. The following test +will compare the number of rows in the CD_COLLECTION and UT_TEST_5_1 tables +where the given condition holds: +
    utassert.eqtabcount('Test 5.1: Insert new rows',
    + +
                        'CD_COLLECTION',
    + +
                        'UT_TEST_5_1',
    + +
                        'ARTIST = ''The Fall''',
    + +
                        'ARTIST = ''The Fall''');
    + + +

    +Asserting Query Equality

    + +The utAssert.eqquery allows you to compare the data +returned by two queries (strings that are contained in the check_this_in +and against_this_in parameters). In this case, you specify the full SELECT +statements for each query as the parameters. By using equery, you may be +able to avoid constructing a separate table with preset data. + +
    PROCEDURE utAssert.eqquery (
    + +
       msg_in IN VARCHAR2,
    + +
       check_this_in IN VARCHAR2,
    + +
       against_this_in IN VARCHAR2,
    + +
       raise_exc_in IN BOOLEAN := FALSE
    + +
    );
    + +If you want the assertion to raise an exception +on failure and stop the test from proceeding, pass TRUE for raise_exc_in. + +Here is an example of using eqQuery: + +
    PROCEDURE ut_upd1
    +IS
    +BEGIN
    +   /* Update 3 columns by ID */
    +
    +   EXECUTE IMMEDIATE '
    +   UPDATE ut_UPD1 SET
    +      FIRST_NAME = ''SILLY'',
    +      HIRE_DATE = trunc (SYSDATE+100),
    +      COMMISSION = 5000
    +    WHERE
    +       EMPLOYEE_ID = 7600
    +   ';
    +   te_employee.upd (
    +      7600,
    +      first_name_in => 'SILLY',
    +      commission_in => 5000,
    +      hire_date_in => TRUNC (SYSDATE + 100),
    +      rowcount_out => fdbk
    +   );
    +   -- Test results (audit fields are different so do a query)
    +   utassert.eqquery (
    +      'Update three columns',
    +      'select first_name, commission, hire_date from EMPLOYEE',
    +      'select first_name, commission, hire_date from ut_upd1'
    +   );
    +   ROLLBACK;
    +END;
    + +

    +Check Query Equality against a Single Value

    +Often we will wish to test the result of a query against a single value +rather than another query as in utAssert.eqquery +above. It is possible to get around this problem by using a trivial +query of the form: +
    SELECT fixed_value
    +FROM DUAL;
    +Unfortunately, if the query returns multiple values or the wrong value +we will only be told that the test has failed with no details. This +is where utAssert.eqqueryvalue comes to the rescue. The procedure +is declared as follows: +
    PROCEDURE utAssert.eqqueryvalue (
    + +
          msg_in IN VARCHAR2,
    + +
          check_query_in IN VARCHAR2,
    + +
          against_value_in IN VARCHAR2|NUMBER|DATE,
    + +
          raise_exc_in IN BOOLEAN := FALSE
    + +
    );
    +Where check_query_in is the query in question and against_value_in is the +value to check it against. If the query returns more than one value, +the resulting error message will tell you this. Similarly, if the +query returns the wrong value, the message will state the expected and +obtained values. The following call compares the maximum value found +in a table against a given number value: +
    utAssert.eqqueryvalue('Maximum value test',
    + +
                          'SELECT MAX(MEMORY)
    + +
                           FROM COMPUTERS
    + +
                           WHERE OS IN (''Linux'', ''Unix'')',
    + +
                           256);
    +Obviously this should only return a single value, but if it returns something +other than 256, we'll know about it. +

    +Check Equality of Files

    + +Many programs generate output to operating system +files; alternatively, you might write data to a file simply to test results. +Use the eqfile assertion for either of these scenarios. This procedure +uses PL/SQL's UTL_FILE package to compare the contents of two different +files. + +Note: If you have not used UTL_FILE in the past, +you must configure it before it can be +used -- by utPLSQL or by your own code. UTL_FILE must be allowed accss +to either or both of the directories you specify (this involves setting +the utl_file_dir database parameter). + +
    PROCEDURE utAssert.eqfile (
    + +
       msg_in IN VARCHAR2,
    + +
       check_this_in IN VARCHAR2,
    + +
       check_this_dir_in IN VARCHAR2,
    + +
       against_this_in IN VARCHAR2,
    + +
       against_this_dir_in IN VARCHAR2 := NULL,
    + +
       raise_exc_in IN BOOLEAN := FALSE
    + +
    );
    + +If you want the assertion to raise an exception +on failure and stop the test from proceeding, pass TRUE for raise_exc_in. + +You must specify the directory containing the "check +this" file; if you do not specify a directory for the "against this" file, +the "check this" directory will be used. + +Here is an example of using eqFile (see ut_DEPARTMENT2file.pkg +in the Examples directory for the full implementation): + +
    PROCEDURE ut_DEPARTMENT2FILE IS
    +BEGIN
    +   DEPARTMENT2FILE (
    +      LOC => 'c:\temp',
    +      FILE => 'department.dat',
    +      DELIM => '***'
    +    );
    +
    +   utAssert.eqfile (
    +      'Test of DEPARTMENT2FILE',
    +      'department.dat',
    +      'c:\temp',
    +      'department.tst',
    +      'c:\temp'
    +      );      
    +END ut_DEPARTMENT2FILE;
    + +

    +Check Equality of Database Pipes

    + +Database pipes offer a handy mechanism for passing +data between different sessions connected to the RDBMS. It is important +to know that pipes are being filled properly; use the eqpipe to check this +condition. + +With the eqpipe procedure, you compare the contents +of two different pipes. + +
    PROCEDURE utAssert.eqpipe (
    + +
       msg_in IN VARCHAR2,
    + +
       check_this_in IN VARCHAR2,
    + +
       against_this_in IN VARCHAR2,
    + +
       raise_exc_in IN BOOLEAN := FALSE
    + +
    );
    + +If you want the assertion to raise an exception +on failure and stop the test from proceeding, pass TRUE for raise_exc_in. + +To check the contents of a pipe based on the execution +of code, you will need to populate a pipe against which to test equality. +The employee_pipe.pkg file in the Examples directory contains a demonstration +of the kind of code you might write to do this. + +This package contains all of the unit test code +within the same package. Here is my unit test program, which relies on +the utAssert.eqpipe program: + +
    PROCEDURE ut_fillpipe IS
    +   stat PLS_INTEGER;
    +BEGIN
    +   emptypipe ('emps');
    +   emptypipe ('emps2');
    +   
    +   fillpipe ('emps');
    +   
    +   /* Direct filling of pipe. */
    +   
    +   FOR rec IN (SELECT *
    +                 FROM employee)
    +   LOOP
    +      DBMS_PIPE.RESET_BUFFER;
    +      DBMS_PIPE.PACK_MESSAGE (rec.EMPLOYEE_ID);
    +      DBMS_PIPE.PACK_MESSAGE (rec.LAST_NAME);
    +      DBMS_PIPE.PACK_MESSAGE (rec.FIRST_NAME);
    +      DBMS_PIPE.PACK_MESSAGE (rec.MIDDLE_INITIAL);
    +      DBMS_PIPE.PACK_MESSAGE (rec.JOB_ID);
    +      DBMS_PIPE.PACK_MESSAGE (rec.MANAGER_ID);
    +      DBMS_PIPE.PACK_MESSAGE (rec.HIRE_DATE);
    +      DBMS_PIPE.PACK_MESSAGE (rec.SALARY);
    +      DBMS_PIPE.PACK_MESSAGE (rec.COMMISSION);
    +      DBMS_PIPE.PACK_MESSAGE (rec.DEPARTMENT_ID);
    +      DBMS_PIPE.PACK_MESSAGE (rec.CHANGED_BY);
    +      DBMS_PIPE.PACK_MESSAGE (rec.CHANGED_ON);
    +
    +      stat := DBMS_PIPE.SEND_MESSAGE ('emps2', 0);
    +   END LOOP;
    +   
    +   /* Compare the two */
    +   utassert.eqpipe (
    +      'Two employee pipes', 'emps', 'emps2');
    +      
    +END ut_fillpipe;
    + +Since I have stored my unit +test logic with my source code package, I would run my test as follows: + +
    SQL> exec utplsql.test ('employee_pipe', samepackage_in=>TRUE)
    +FAILURE: "employee_pipe"
    +fillpipe: Pipes equal? Compared "emps" against "emps2"
    + +

    +Check Equality of Collections

    + +Collections are as close as you come to arrays in +PL/SQL. They are very useful for managing lists of information, but can +be difficult to debug and maintain. + +With the eqcoll and eqcollAPI procedures, you can +compare the contents of two different arrays. Use the eqColl procedure +when you want to compare two collections that are defined in the specification +of a package. Use the eqCollAPI procedure when you want to compare two +collections that are defined in the body of a package, with programs defined +in the specification (an API) to access and manipulate the collections. + +The collection equality check headers are: + +
       /* Direct access to collections */
    + +
       PROCEDURE utAssert.eqcoll (
    + +
          msg_in IN VARCHAR2,
    + +
          check_this_in IN VARCHAR2, /* pkg1.coll */
    + +
          against_this_in IN VARCHAR2, /* pkg2.coll */
    + +
          eqfunc_in IN VARCHAR2 := NULL,
    + +
          check_startrow_in IN PLS_INTEGER := NULL,
    + +
          check_endrow_in IN PLS_INTEGER := NULL,
    + +
          against_startrow_in IN PLS_INTEGER := NULL,
    + +
          against_endrow_in IN PLS_INTEGER := NULL,
    + +
          match_rownum_in IN BOOLEAN := FALSE,
    + +
          null_ok_in IN BOOLEAN := TRUE,
    + +
          raise_exc_in IN BOOLEAN := FALSE
    + +
       );
    + +
      
    + +
       /* API based access to collections */
    + +
       PROCEDURE utAssert.eqcollapi (
    + +
          msg_in IN VARCHAR2,
    + +
          check_this_pkg_in IN VARCHAR2,
    + +
          against_this_pkg_in IN VARCHAR2,
    + +
          eqfunc_in IN VARCHAR2 := NULL,
    + +
          countfunc_in IN VARCHAR2 := 'COUNT',
    + +
          firstrowfunc_in IN VARCHAR2 := 'FIRST',
    + +
          lastrowfunc_in IN VARCHAR2 := 'LAST',
    + +
          nextrowfunc_in IN VARCHAR2 := 'NEXT',
    + +
          getvalfunc_in IN VARCHAR2 := 'NTHVAL',
    + +
          check_startrow_in IN PLS_INTEGER := NULL,
    + +
          check_endrow_in IN PLS_INTEGER := NULL,
    + +
          against_startrow_in IN PLS_INTEGER := NULL,
    + +
          against_endrow_in IN PLS_INTEGER := NULL,
    + +
          match_rownum_in IN BOOLEAN := FALSE,
    + +
          null_ok_in IN BOOLEAN := TRUE,
    + +
          raise_exc_in IN BOOLEAN := FALSE
    + +
       );
    + +where the eqcoll-specific parameters are as follows: + + + + + + + + + + + + + + + + + + + + + + + + + +
    ParameterDescription
    +msg_in + +The message to be displayed if the test failes +
    +check_this_in + +The name of the collection to be checked. Format: +package.collection. In other words, the collection must be defined in a +package specification. Use eqCollAPI (and check_this_pkg_in) if you want +to hide the declaration of your collection in your package body (recommended). +
    +against_this_in + +The name of the collection to be checked against. +Format: package.collection. In other words, the collection must be defined +in a package specification. Use eqCollAPI (and check_this_pkg_in) if you +want to hide the declaration of your collection in your package body (recommended). +
    + + +

    and the eqcollAPI-specific parameters are as follows: +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ParameterDescription
    +msg_in + +The message to be displayed if the test failes +
    +check_this_pkg_in + +The name of the package that contains the collection +to be checked. +
    +against_this_pkg_in + +The name of the package that contains the collection +to be checked against. +
    +countfunc_in + +The name of the function in the package that returns +the number of rows defined in the collection. +
    +firstrowfunc_in + +The name of the function in the package that returns +the first definedrow in the collection. +
    +lastrowfunc_in + +The name of the function in the package that returns +the last definedrow in the collection. +
    +nextrowfunc_in + +The name of the function in the package that returns +the next definedrow in the collection +from the specified row. +
    +getvalfunc_in + +The name of the function in the package that returns +the contents of the specified row. +
    + + +

    The parameters common to both eqColl and eqCollAPI +are as follows +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ParameterDescription
    +eqfunc_in + +The function used to determine if the contents of +each row of the two collections are the same. If you pass NULL for this +argument, then a standard equality check will be used. This is fine for +scalar values, but will not work, for example, with tables of records. +
    +check_startrow_in + +The starting row in the check collection for comparison. +If NULL, then first row is used. +
    +check_endrow_in + +The ending row in the check collection for comparison. +If NULL, then last row is used. +
    +against_startrow_in + +The starting row in the against collection for comparison. +If NULL, then first row is used. +
    +against_endrow_in + +The ending row in the against collection for comparison. +If NULL, then last row is used. +
    +match_rownum_in + +Pass TRUE if you want to make sure that the same +row numbers are used in each collection. If FALSE, then the row numbers +can be different, but the contents of each corresponding row must be the +same. +
    +null_ok_in + +Pass TRUE if the assertion routine should consider +two NULL collections to be equal. +
    +raise_exc_in + +If you want the assertion to raise an exception +on failure and stop the test from proceeding, pass TRUE for raise_exc_in. +
    + + +

    Here is an example of a script that uses utAssert.eqColl +(taken from filepath1.pkg in the Examples directory): +

    PROCEDURE ut_setpath
    +IS
    +BEGIN
    +   /* Populate base collection */
    +   ut_dirs.DELETE;
    +   ut_dirs.EXTEND(2);
    +   ut_dirs(1) := 'c:\temp';
    +   ut_dirs(2) := 'e:\demo';
    +   
    +   /* Call setpath to do the work */
    +   setpath ('c:\temp;e:\demo');
    +   
    +   utAssert.eqColl (
    +      'Valid double entry',
    +      'fileio.dirs',
    +      'fileio.ut_dirs'
    +      );
    +END;
    + +

    +Checking a Procedure or Function throws an exception

    +Sometimes we design a procedure or function to throw an exception under +certain circumstances. This is something we'd like to be able to +test for. Obviously this is not particularly easy due to the way +exceptions propagate through the call stack. If we simply call the +procedure in our test code, the exception will have no chance of being +caught within the utAssert package! Therefore, we need to pass the +tested call in to the package as a string. The procedure utAssert.throws +allows us to do this: +
    PROCEDURE throws (
    + +
          msg_in VARCHAR2,
    + +
          check_call_in IN VARCHAR2,
    + +
          against_exc_in IN VARCHAR2|NUMBER
    + +
       );
    +Where check_call_in is the call to be made, complete with parameters and +terminating semicolon. The argument against_exc_in is the exception +we expect to be thrown. This can be specified either as a named exception, +or a SQLCODE value. +

    The following example shows both usages: +

    /* Test the Except Function */
    +PROCEDURE ut_except
    +IS
    +BEGIN
    +
    +   /* Call the procedure with a negative number */
    +   /* We expect a NO_DATA_FOUND exception       */
    +   utAssert.throws('Negative Number',
    +      'Except(-1);',
    +      'NO_DATA_FOUND'
    +   );
    +   
    +   /* Call the procedure with zero and a string    */
    +   /* over 2 in length - We expect a SQLCODE of -1 */  
    +   utAssert.throws('Zero and String',
    +      'Except(0, ''Hello'');',
    +      -1
    +     );
    +END;
    + +Note how we have to quote +the string parameters to the call and terminate the string with a semicolon. + +

    +Building Your Own Assertion

    + +You may want to build assertion routines that fit +your specific needs. If PL/SQL supported inheritance, you could extend +the utAssert assertion routines and then customize them through polymorphism. +Lacking this feature, however, you will write your own procedures that +follow the same steps as the pre-build assertions. + +In order to integrate the results of your assertion +test into the utResult package, you will want to mimic the utAssert.this +procedure. Here is its current implementation (Release 1.3.2); check the +body of the utAssert package for any changes. + +
    PROCEDURE this (
    +   msg_in IN VARCHAR2,
    +   check_this_in IN BOOLEAN,
    +   null_ok_in IN BOOLEAN := FALSE,
    +   raise_exc_in IN BOOLEAN := FALSE,
    +   register_in IN BOOLEAN := TRUE
    +   )
    +IS
    +BEGIN
    +   IF    NOT check_this_in
    +      OR (    check_this_in IS NULL
    +          AND NOT null_ok_in)
    +   THEN
    +      IF register_in
    +      THEN
    + +
             -- Registers the results in the utResult databank.
    +         utresult.report (msg_in);
    +      ELSE
    +         utplsql.pl (msg_in);
    +      END IF;
    +      
    +      IF showing_results AND register_in
    +      THEN
    + +
             -- Show the results of the test more recently run.
    +         utresult.showlast;
    +      END IF;
    +
    +      IF raise_exc_in
    +      THEN
    +         RAISE test_failure;
    +      END IF;
    +   END IF;
    +END;
    + +The most important statement to include in your +assertion routine is the call to utResult.report, which will log the results +of the test. + + + + diff --git a/documentation/src/utconfig.html b/documentation/src/utconfig.html new file mode 100644 index 000000000..1306330b1 --- /dev/null +++ b/documentation/src/utconfig.html @@ -0,0 +1,364 @@ + + + + + + + utPLSQL - utConfig Package + + + + + + + +
    + +
    +Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
    +[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

    < Previous Section: utPLSQL Package | Next +Section: utResult Package > +
    + +

    +utConfig Package

    + +

    This package contains the following functions and procedures: +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    utConfig.testerReturn whose configuration is used
    utConfig.settesterSet whose configuration is used
    utConfig.showconfigView a schema's configuration
    utConfig.setdirSet the directory containing the test package code
    utConfig.dirReturn the directory containing the test package code
    utConfig.setprefixSet the default unit test prefix for your code
    utConfig.prefixReturn the default unit test prefix for your code
    utConfig.registertestSet the registration mode (manual or automatic)
    utConfig.autocompileSet autocompile feature
    + +

    To make it as easy as possible for you to run your tests, utPLSQL stores +various pieces of configuration data in the ut_config table. This data +is stored by schema name and is automatically loaded into utPLSQL the first +time you use this utility in your session. This configuration information +is also automatically updated whenever you call utPLSQL.test -- or any +of the utPLSQL programs specifically designed to change the configuration +settings. +

    You can at any time view the utPLSQL configuration for the currently-connected +schema or for another schema (there is not at this point any schema-level +security; all utPLSQL users can view the configurations of all other users). +

    The data that is currently maintained for a utPLSQL user are: +

    Test package directory - the location of the test package code +you want to run. You must specify a directory in order to allow utPLSQL +to automatically compile your test packages before each test run. +

    Unit test prefix - the prefix used for test package names and +the program names within the package. If you do not specify a prefix, the +default of "ut_" is automatically applied. +

    Unit test registration mode - This setting determines whether +utPLSQL will automatically identify the unit tests to be run (strongly +recommended) or if you have chosen to manually register your unit tests +in the test package setup procedure. +

    Auto-compilation of test packages - By default, utPLSQL will +recompile your test package before execution. You can turn off this feature +and manually recompile only when you desire (a fine idea if your test package +has gotten very large!). +

    +Return whose configuration is being used

    +By default, the configuration stored for the currently-connected user will +be used. However, it is possible to use configurations stored against +other usernames. To show whose configuration is currently being used +the following function is used: +
    FUNCTION utConfig.tester RETURN VARCHAR2;
    + +

    +Set whose configuration is being used

    +This returns the configuration that will be used whenever a username is +not specified. To set this, the following procedure is used: +
    PROCEDURE utConfig.settester (username_in IN VARCHAR2 := USER);
    + +

    +View a schema's configuration

    +Call the utPLSQL.showconfig procedure to view the configuration for a specified +schema. The header is: +
    PROCEDURE utConfig.showconfig (username_in IN VARCHAR2 := NULL);
    +If you do not specify a schema, then the currently +used configuration is returned. Here is an example of output from this +procedure: +
    SQL> exec utconfig.showconfig
    +=============================================================
    +utPLSQL Configuration for SCOTT
    +   Directory: /apps/utplsql/code
    +   Autcompile? Y
    +   Manual test registration? N
    +   Prefix = test_
    +=============================================================
    +And here is an example of calling showConfig for a different schema: +
    SQL> exec utconfig.showconfig ('COMP')
    +=============================================================
    +utPLSQL Configuration for COMP
    +   Directory: M:\shared_apps\utplsql\comp
    +   Autcompile? N
    +   Manual test registration? N
    +   Prefix = ut_
    +=============================================================
    +You might want to put a call to showConfig in your SQL*Plus login file +so that you are reminded on startup as to what the current settings are. +Here is such a script (to be found in Examples\login_sample.sql): +
    exec utconfig.setdir ('e:\openoracle\utplsql\utinstall\examples')
    +SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED
    +exec utconfig.showconfig
    + +

    +Set the directory containing the test package code

    +If you want utPLSQL to compile your test package, you must tell it the +directory in which your code is found. You can do this either when you +define +your test suite and packages within the suite, or you can call the +utConfig.setdir procedure to set the directory for your current session. +

    Note: as of v1.5.1, the value you pass in any of these programs is saved +in the configuration table and will be used in the future -- until you +change it by passing a different value. +

    The header for this procedure is: +

    PROCEDURE utConfig.setdir (dir_in IN VARCHAR2, username_in IN VARCHAR2 := NULL);
    +where dir_in is the directory and username_in is the name of the schema +to which this directory applies (NULL means the currently +used configuration is set), as in: +
    SQL> exec utconfig.setdir ('e:\demo\utplsql');
    +or, with the specification of a non-current schema: +
    SQL> exec utconfig.setdir ('e:\demo\utplsql', 'ANALYSIS');
    +Note that this directory must be accessible through UTL_FILE. +

    You might consider putting the the call to utConfig.setdir into your +login.sql so that it is run automatically, each time your start up SQL*Plus +-- if you are always working from the same directory. +

    +Return the directory containing the test package code

    +You can obtain the current directory with a call to utConfig.dir: +
    FUNCTION utConfig.dir (username_in IN VARCHAR2 := NULL)
    +      RETURN VARCHAR2;
    + +

    +Set the default unit test prefix for your code.

    +The unit test prefix is very important in utPLSQL; the utility uses the +prefix to associate source code to be tested with the test package. The +prefix also allows utPLSQL to automatically identify the programs within +a test package that are to be executed as unit tests. +

    The default prefix in utPLSQL is "ut_", but you can override this when +you call utPLSQL.test or by calling the utConfig.setprefix procedure: +

    PROCEDURE utConfig.setPrefix (
    +   prefix_in IN VARCHAR2, username_in IN VARCHAR2 := NULL)
    +where prefix_in is the prefix and username_in is the name of the schema +to which this prefix applies (NULL means the currently +used configuration is set), as in: +
    SQL> exec utconfig.setPrefix ('tst#');
    +or, with the specification of a non-current schema: +
    SQL> exec utconfig.setPrefix ('t_', 'ANALYSIS');
    + +

    +Return the default unit test prefix for your code.

    +You can obtain the current prefix with a call to utConfig.prefix: +
    FUNCTION utConfig.prefix (username_in IN VARCHAR2 := NULL)
    +      RETURN VARCHAR2;
    +uPLSQL currently does not support the use of a suffix, or combination of +suffix and prefix, to identify test packages and unit test procedures. +

    +Set the registration mode (manual or automatic).

    +As of utPLSQL v1.5.1, you no longer have to register your unit test procedures +in the setup procedure of your test package. Instead, utPLSQL will scan +the data dictionary (via theALL_ARGUMENTS view) for the names of all the +unit test procedures you have defined, and then run them. utPLSQL identifies +these programs by looking for all programs whose names start with the specified +prefix. +

    If you so choose, you can request that utPLSQL turn off automatic detection +of unit test procedures and only run those programs listed in the setup +procedure. To do this, you call the utConfig.registerTest procedure: +

    PROCEDURE utConfig.registerTest (
    +      onoff_in IN BOOLEAN,
    +      username_in IN VARCHAR2 := NULL
    +   );
    +as in: +
    SQL> exec utConfig.registerTest (TRUE)
    +Note: if you are using automatic unit test detection, any calls to utPLSQL.addtest +in the setup procedure will be ignored. +

    +Set autocompile feature

    + +The default settings for utPLSQL is to re-compile +your base package before each unit test. This guarantees that any recent +changes will be tested. It also saves you the step of doing an explicit +compile. + +In order to perform automatic compilation: + +
      +Your schema will need to +have either CREATE PROCEDURE or CREATE ANY PROCEDURE privileges granted +directly; +you cannot grant these privileges through roles. + +You will need to set or +pass the location of the source code. You can do this by calling utConfig.setdir +or by including the directory location in your call to utPLSQL.test +or utPLSQL.testsuite (the dir_in +parameter). + +The package specification +must be contained in a file named <package>.pks; the body must be stored +in <package>.pkb. + +You must have configured +the +UTL_FILE built-in package for use +on your database instance. +
    + +In general (and the default), you should allow your +test package to be recompiled with each execution. You might want to avoid +recompilation if: + +
      +You have made a copy of the package body with some +temporary changes and already compiled that. If you recompile automatically, +you will wipe out those changes. + +You have not set up UTL_FILE +and you don't want to deal with it. + +You are running the tests +on a server to which you have no access other than via a database connection. +
    + +

    +Turning off Auto-compile

    + +If you are working with products like SQL*Navigator, +you may be always editing from code stored in the database. In this case, +you will never want to have utPLSQL recompile your code for you – it will +already be compiled and you do not need to hassle with UTL_FILE. + +You can avoid auto-recompilation in two ways: + +1. Pass a value of FALSE for the recompile_in argument +to utPLSQL.test or utPLSQL.testsuite. Here is an example: + +
    BEGIN
    + +
       -- Define a test suite for PL/Vision
    + +
       utsuite.add ('PLVision');
    + +
      
    + +
       -- Add two packages for testing
    + +
       utsuite.addpkg (
    + +
          'PLVision', 'PLVstr', dir_in => 'e:\utplsql');
    + +
       utsuite.addpkg (
    + +
          'PLVision', 'PLVdate', dir_in => 'e:\utplsql');
    + +
      
    + +
       -- Run the test suite
    + +
       utplsql.testsuite (
    + +
          'PLVision', recompile_in => FALSE);
    + +
    END;
    + +
    /
    + +If you know that you will never want to recompilation, +however, you can set the default behavior at the schema level by calling +the autocompile procedure + +
       PROCEDURE utConfig.autocompile (
    + +
          onoff_in IN BOOLEAN,
    + +
          username_in IN VARCHAR2 := NULL
    + +
       );
    + +
     
    + +So I can make the following +call to turn off autocompilation for the SCOTT schema: + +
    +
    +
    SQL> exec utconfig.autocompile (FALSE, 'SCOTT') 
    +This program updates the ut_config table with your information and then +commits the setting. + +

    You can determine the current +setting for auto-compilation at any time by calling the following function: +

    
    +
    +
       FUNCTION utConfig.autocompiling (username_in IN VARCHAR2 := NULL)
    + +
          RETURN BOOLEAN;
    + +Note: When you set the schema-level recompilation +value to FALSE, that will override anything you pass in a call to utPLSQL.test +or utPLSQL.testsuite. + + + + diff --git a/documentation/src/utgen.html b/documentation/src/utgen.html new file mode 100644 index 000000000..9faec28d1 --- /dev/null +++ b/documentation/src/utgen.html @@ -0,0 +1,563 @@ + + + + + + + utPLSQL - utGen Package + + + + + + + +
    + +
    +Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
    +[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

    < Previous Section: utAssert Package | +Next +Section: Define Test Suites> +
    + +

    +utGen Package

    + +

    This package contains the following procedures and functions: +
    + + + + + + + + + + + + + + + + + + +
    utGen.testpkgGenerate skeleton test packages
    utGen.pkgstringGet skeleton as a string
    utGen.countRows +
    utGen.firstRow +
    utGen.firstBodyRow +
    utGen.atFirstRow +
    utGen.lastRow +
    utGen.atLastRow +
    utGen.setRow +
    utGen.getRow +
    utGen.nextRow; +
    utGen.prevRow; +
    utGen.showRows +
    utGen.nthRow
    Get rows from generated skeleton test package as array
    + + +

    +Generate Skeleton Test Packages

    +The utGen contains a procedure that allows you to generate a starting point +for a unit test package. This package can be sent to the screen, +a file, a delimited string or +an array (best for interfacing with a front end). +You can generate a stand-alone test package or code "fragments" to be placed +inside an existing source package. + +We strongly recommend that you use utGen.testpkg +as a starting point for all of your utPLSQL unit test construction. By +taking this approach, you will most easily (and transparently) conform +to the most up to date guidelines for utPLSQL test packages. + +Note: While utGen.testpkg goes as far as +possible to generate sensible unit test code, you will need to edit this +code before you can compile and use it. + +Here is the header of the testpkg procedure: + +
       PROCEDURE utGen.testpkg (
    + +
          package_in IN VARCHAR2,
    + +
          program_in IN VARCHAR2 := '%',
    + +
          samepackage_in IN BOOLEAN := FALSE,
    + +
          prefix_in IN VARCHAR2 := NULL,
    + +
          schema_in IN VARCHAR2 := NULL,
    + +
          output_type_in IN PLS_INTEGER := c_screen,
    + +
          dir_in IN VARCHAR2 := NULL,
    + +
          delim_in IN VARCHAR2 := c_delim
    + +
       );
    + +And here is a description of the parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Parameter NameUsage
    +package_in + +The name of the package or stand-alone program for +which a test package is to be generated. +
    +program_in + +The filter to be applied to the list of programs +for which unit test procedures will be generated. So if you only wanted +to generate unit tests for programs that start with "UPD", you would pass +'UPD%' for this argument. +
    +samepackage_in + +TRUE if you plan to insert the generated code into +the source package, FALSE if you want a stand-alone test package. +
    +prefix_in + +The prefix to be used for the test package and/or +unit test procedures. See section " Organizing Your Test Code" for details. +
    +schema_in + +The schema that owns the package or program specified +by package_in. The default is the currently connected schema. +
    +output_type_in + +The type of output that will receive the generated +code. Valid options are defined as packaged constants: + +
    utGen.c_file
    + +
    utGen.c_screen
    + +
    utGen.c_string
    + +
    utGen.c_array
    + +The following sections explain the way you would +work with these constants and the resulting generated code. +
    +dir_in + +The location of the file containing the generated +code. Used only if you specify utGen.c_file for the output type. +
    +delim_in + +The delimiter used to separate lines of generated +code. Used only if you specify utGen.c_string for the output type. +
    + + +

    Before you use utGen.testpkg, you should make a few +decisions about your generated code: +

      +
    • +Do you want the generated test code to be a stand-alone package or to be +inserted into an existing package? The default is stand-alone. Pass TRUE +for samepackage_in if you want to generate code that can be easily cut +and pasted into your source package. Note that utGen.testpkg does not +actually modify your source package.
    • + +Do you want to generate a unit test program +for every procedure and function in your package? If so, then go with the +default for program_in. If, on the other hand, your package has one hundred +programs and you only want to test, say, only those programs that perform +updates, you might want to pass a non-trivial filter, such as "UPD%". + +Where do you want to send your output? You +can display to the screen, which can then be grabbed and put into a file +(or in SQL*Plus spool it directly to a file). You can send the code to +a file. You can deposit the code in a delimited string and then parse it +within your own environment. Finally -- and of most relevance if you are +building a GUI interface to utPLSQL -- you can generate to an internal +array and then retrieve individual rows of the arrays through the utGen +API. +
    + +Here are some examples of using utGen.testpkg: + +
      +
    1. +Generate to the screen a stand-alone test package for the STR package:
    2. +
    + +
    +
    +
    SQL> exec utGen.testpkg ('str')
    +
    +
    + +
      +
    1. +Generate to the screen unit test code to be embedded inside the STR package:
    2. +
    + +
    +
    +
    SQL> exec utGen.testpkg ('str', samepackage_in => TRUE)
    +
    +
    + +
      +
    1. +Generate to the screen unit test code for all programs whose names contain +"STR" to be embedded inside the STR package,.
    2. +
    + +
    +
    +
    SQL> exec utGen.testpkg ('str', '%STR%', samepackage_in => TRUE)
    +
    +
    + +Now let's explore how to direct the generated code +to different types of output. + +

    +Generating to Screen

    + +The default behavior of utGen.testpkg is to generate +code to your screen (via DBMS_OUTPUT.PUT_LINE). So unless you specify some +other value for output_type_in, the code will be displayed on your screen +or within a window of your PL/SQL IDE (such as TOAD or SQL*Programmer and +so on). You can then transfer that content to a file, or move it to another +window for immediate editing and compilation. + +Here is an example of using utGen.testpkg, while +also spooling to a file: + +
    SQL> set serveroutput on size 1000000
    + +
    SQL> spool str.pkg
    + +
    SQL> exec utgen.testpkg ('str')
    + +...out comes the code... + +
    SQL> spool off
    + +If DBMS_OUTPUT is not enabled in your session, then +utGen.testpkg will not generate any output. + +

    +Generating to File

    + +If you are working with utGen in a command line +style (ie, you are not using a utGen-enabled GUI), then you will probably +find it most useful to generate testing code directly to file. You do this +by specifying utGen.c_file for the output type. You must also specify the +directory in which you want the files (one for the package specification +and another for the body)created. + +Here's a generation request that creates two files +named ut_str.pks and ut_str.pkb in the /newcode directory: + +
    SQL> exec utgen.testpkg ('str', output_type_in => utGen.c_file, dir_in => '/newcode')
    + +Notes on generating to file: + + +
      +
    1. +You do not have to specify a directory if you have previously (in your +current session) called utConfig.setdir to set the default directory for +all file-related utPLSQL operations. The following two lines of code are, +in other words, equivalent to the single line shown above:
    2. +
    + + +
    +
    +
    SQL> exec utconfig.setdir ('/newcode')
    + +
    SQL> exec utgen.testpkg ('str', output_type_in => utGen.c_file);
    +
    +
    + +
      +
    1. +You set up the UTL_FILE package (add at least one utl_file_dir entry in +your database parameter initialization file) and make sure your directory +is accessible through UTL_FILE, before this operation can succeed.
    2. +
    + +

    +Generating to String

    + +If you are accessing utPLSQL functionality through +a GUI, you might find it more useful to direct output to a string (or array, +see next section). You probably don't want to hassle with UTL_FILE (server-based +file IO) and grabbing information from DBMS_OUTPUT.PUT_LINE is just a general +hassle. + +If you generate to a string, you can then retrieve +that string value into a local variable and then parse it for display and +manipulation. Here is an example of redirection to string: + +
    BEGIN
    + +
       utgen.testpkg ('str', output_type_in => utGen.c_string);
    + +
    END;
    + +The generated code is composed of multiple lines +of information, so they need to be separated by a delimiter. The default +delimiter is the vertical bar, '|'. You can override that and provide your +own delimiter. In the following example, I have decided to use the carriage +return character as my delimiter: + +
    BEGIN
    + +
       utgen.testpkg (
    + +
          'str',
    + +
          output_type_in => utGen.c_string,
    + +
          delim_in => CHR(10));
    + +
    END;
    + +Great, so the code has been put in a string. How +do you get all that generated code? Call the utGen.pkgstring function: + +
    FUNCTION utGen.pkgString RETURN VARCHAR2;
    + +

    +Generating to Array

    + +If you are accessing utPLSQL functionality through +a GUI, you might find it more useful to direct output to an array. You +probably don't want to hassle with UTL_FILE (server-based file IO) and +grabbing information from DBMS_OUTPUT.PUT_LINE is just a general hassle. + +If you generate to an array, you can then retrieve +the individual lines of code in the array through an API provided by utGen +(the array itself is "hidden"). Here is an example of redirection to the +utGen array: + +
    BEGIN
    + +
       utgen.testpkg ('str', output_type_in => utGen.c_array);
    + +
    END;
    + +Great, so the code has been put in an array. How +do you get all that generated code? Take advantage of the utGen +API to retrieve individual rows in the array, which offers these features: + +Get the number of rows currently in the array: + +
       FUNCTION utGen.countRows RETURN PLS_INTEGER;
    + +Get the absolute index of the first row in the array: + +
       FUNCTION utGen.firstRow RETURN PLS_INTEGER;
    + +Get the absolute index of the last row in the array: + +
       FUNCTION utGen.lastRow RETURN PLS_INTEGER;
    + +The API offers a set of programs to iterate through +the array, by maintaining a "current row" inside the package. You can: + +Find out if you are positioned at the first row +in the set: + +
       FUNCTION utGen.atFirstRow RETURN BOOLEAN;
    + +Find out if you are positioned at the last row in +the set: + +
       FUNCTION utGen.atLastRow RETURN BOOLEAN;
    + +Find the first relative row containing the start +of the package body definition. This is handy when you want to put the +code for the specification and body in separate windows and/or files: + +
       FUNCTION utGen.firstBodyRow RETURN PLS_INTEGER;
    + +Retrieve the text in the Nth row of the array. This +gives you "random access" to the contents of the array. You can even specify +a negative direction to get the Nth row from the end of the array. + +
       FUNCTION utGen.nthRow (nth IN PLS_INTEGER, direction utGen.IN SIGNTYPE := 1) RETURN codeline_t;
    + +Set the pointer in the array to the specified row +number. This allows you then move either forward or backward from that +row in the array (using nextRow and prevRow, respectively): + +
       PROCEDURE utGen.setRow (nth IN PLS_INTEGER);
    + +Retrieve the line of code stored in the current +row in the array (set via setRow, nextRow or prevRow): + +
       FUNCTION utGen.getRow RETURN codeline_t;
    + +Go to the next row in the array: + +
       PROCEDURE utGen.nextRow;
    + +Go to the previous row in the array: + +
       PROCEDURE utGen.prevRow;
    + +Show the contents of the array using DBMS_OUTPUT.PUT_LINE: + +
       PROCEDURE utGen.showRows (
    + +
          startRow IN PLS_INTEGER := NULL,
    + +
          endRow IN PLS_INTEGER := NULL);
    + +Here is the code I would write in PL/SQL using this +API to display the contents of the array (actually, it is the implementation +of showRows): + +
       PROCEDURE showrows (
    + +
          startrow IN PLS_INTEGER := NULL,
    + +
          endrow IN PLS_INTEGER := NULL
    + +
       )
    + +
       IS
    + +
          v_start PLS_INTEGER
    + +
                        := NVL (startrow, 1);
    + +
          v_end PLS_INTEGER
    + +
             := NVL (endrow, utGen.countRows);
    + +
       BEGIN
    + +
          FOR indx IN 1 .. utGen.countRows
    + +
          LOOP
    + +
             DBMS_OUTPUT.put_line (utGen.getRow (indx));
    + +
          END LOOP;
    + +
       END;
    + +Here is the code I would write to separate out the +contents of the specification from the body: + +
       PROCEDURE showrows (
    + +
          startrow IN PLS_INTEGER := NULL,
    + +
          endrow IN PLS_INTEGER := NULL
    + +
       )
    + +
       IS
    + +
          v_start PLS_INTEGER
    + +
                        := NVL (startrow, 1);
    + +
          v_end PLS_INTEGER
    + +
             := NVL (endrow, utGen.countRows);
    + +
       BEGIN
    + +
          FOR indx IN 1 .. utGen.countRows
    + +
          LOOP
    + +
             IF indx = utGen.firstBodyRow
    + +
             THEN
    + +
                -- switch to Body window or file
    + +
             END IF;
    + +
             write_to_target (utGen.getRow (indx));
    + +
          END LOOP;
    + +
       END;
    + + + + + diff --git a/documentation/src/utplsql.html b/documentation/src/utplsql.html new file mode 100644 index 000000000..b6c19bd26 --- /dev/null +++ b/documentation/src/utplsql.html @@ -0,0 +1,352 @@ + + + + + +utPLSQL - utPLSQL Package + + + + + + + +

    + + + + + +
    +

    +
    + +

    Authors: Steven Feuerstein, Chris Rimmer

    + +

    Copyright 2000-2001, all rights reserved

    + +

    [ Home | Getting Started | Build Test Packages | Examples | User Guide +| Release Notes | Document Map +]

    + +

    < Previous Section: User Guide | Next Section: utConfig Package >
    +

    + + +

    utPLSQL Package

    + +

    The utPLSQL package offers the following capabilities:
    +

    + + + + + + + + + + + + + + + + + + +
    +

    utPLSQL.test

    +
    +

    Run a test

    +
    +

    utPLSQL.testsuite

    +
    +

    Run a test suite

    +
    +

    utPLSQL.addtest

    +
    +

    Register a unit test in a test package

    +
    +

    utPLSQL.version

    +
    +

    Get the version of utPLSQL

    +
    + +

    Run a Test or Test Suite

    + +

    With utPLSQL, you can run all the unit tests contained in a +single test package, or run the tests for a series of test packages defined in +a test suite.

    + +

    The utPLSQL package offers two procedures, test and testsuite, to make it +easy for you to run "red light, green light" tests. Before you can +use these programs, however, you must build +your own test package.

    + +

    To run a test for a single package, use the utPLSQL.test procedure:

    + +
    PROCEDURE utPLSQL.test (
       package_in IN VARCHAR2,
       samepackage_in IN BOOLEAN := FALSE,
       prefix_in IN VARCHAR2 := NULL,
       recompile_in IN BOOLEAN := TRUE,
       dir_in IN VARCHAR2 := NULL,
       suite_in in VARCHAR2 := NULL,
       owner_in IN VARCHAR2 := NULL,
       reset_results_in IN BOOLEAN := TRUE ,
       from_suite_in         IN   BOOLEAN := FALSE,
       subprogram_in         IN   VARCHAR2 := '%',
       per_method_setup_in   IN   BOOLEAN := FALSE
    );
    + +

    where the parameters are defined as follows:
    +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    package_in

    +
    +

    The name of the package or stand-alone program to be + tested.

    +
    +

    samepackage_in

    +
    +

    Pass TRUE if your unit test programs are defined in the same + package as the source code to be tested. The default is that you have created + a separate package.

    +
    +

    prefix_in

    +
    +

    The prefix to be appended to package_in to come up with + the name of the test package. If you do not provide a value, the last prefix + you specified (or the default) will be used.

    +
    +

    recompile_in

    +
    +

    Pass FALSE if you do not want utPLSQL to automatically recompile your test package + before running the test.

    +
    +

    dir_in

    +
    +

    The directory containing the test package source code. If + you do not provide a value in your call to utPLSQL.test (the default) and if + you have not turned off automatic recompilation, utPLSQL will look for the + test package source code in the directory specified by a call to utConfig.setdir. If you do not provide a + value, the last directory you specified (if any) will be used.

    +
    +

    suite_in

    +
    +

    The name of the suite that contains the specified test + package. This is an optional value and is used to update statistics + for the test.

    +
    +

    owner_in

    +
    +

    The name of the schema that was specified when the test + suite was defined and the packaged added to the suite. This is an + optional value and is used to update statistics for + the test.

    +
    +

    reset_results_in

    +
    +

    Pass FALSE to tell utPLSQL to not reset the results + information, in which case you will still be able to view results by calling utResult.show . Otherwise, utPLSQL clears the result + data after each test.

    +
    +

    from_suite_in

    +
    +

    Pass TRUE to tell utPLSQL that this test is being run from + within a test suite (for internal use only).

    +
    +

    subprogram_in

    +
    +

    Pass a string to restrict which of the test procedures + will be executed for this run. Default of % means all tests will be run.

    +
    +

    per_method_setup_in

    +
    +

    Pass TRUE to run the setup and teardown procedure before + and after each unit test procedure is executed. Default of FALSE means that + these programs will be run once, at the start and end of the package test + execution as a whole.

    +
    + +

    Here are some examples of using the utPLSQL.test procedure:

    + +

    1. Run the unit test for the betwnstr function (by executing the ut_betwnstr +test package, since the default prefix is used). Do not recompile the test +package.

    + +
    SQL> exec utPLSQL.test ('betwnstr', recompile_in => FALSE)
    + +

    2. Run all of the unit tests for the te_employee package, +stored in a test package called "test_te_employee" in the /tmp +directory. Recompile the test package before execution.

    + +
    SQL> exec utPLSQL.test ('te_employee', prefix_in => 'test_', dir_in => '/tmp')
    + +

    3. Run all the unit tests for the corporate_polluters +package, located in the same package as the source code.

    + +
    SQL> exec utPLSQL.test ('te_employee', samepackage_in => TRUE)
    + +

    Since utPLSQL follows the red light-green light approach on +reporting results, each time you run utPLSQL.test, it will display the results. +If successful, you will see output like this:

    + +
    SUCCESS: "betwnstr"
    + +

    If the test fails at some point, you will see output like +this:

    + +
    FAILURE: "betwnstr"
    BETWNSTR: IS NULL: NULL start
    BETWNSTR: End larger than string length; expected "cdeg", got "cdefg"
    + +

    Running a Test Suite

    + +

    In addition to running a test for a single test package, you +can set up a test suite that consists of one or more test packages. You can +then run an entire suite of tests with a call to utPLSQL.testsuite:

    + +
    PROCEDURE utPLSQL.testsuite (
       suite_in IN VARCHAR2,
       recompile_in IN BOOLEAN := TRUE,
       reset_results_in IN BOOLEAN := TRUE
       );
    + +

    where suite_in is the name of the suite and recompiled_in +determines the auto compilation behavior. +

    + +

    Here is an example of the call I would make to run all my tests for the +PL/Vision library:

    + +
    SQL> exec utplsql.testsuite ('plvision');
    + +

    The parameter list for utPLSQL.testSuite is much shorter +than utPLSQL.test; rather than pass information like directory, owner name and +same-package through a parameter list, you define these characteristics in the +suite itself (stored in a series of utPLSQL tables).

    + +

    Before you can test an entire suite, you must define +the suite.

    + +

    Recording and Accessing Test Statistics

    + +

    If you have defined test suites, and packages within those +test suites, utPLSQL will update those definitions with the follow statistics +after each test is run:

    + +
      +
    • Status of last run: success + or failure?
    • +
    • Start and end times of last + run
    • +
    • Total number of failures
    • +
    • Total number of executions of + the test
    • +
    + +

    All of this is done for you automatically. You can then write queries and reports against the +ut_package and ut_suite tables.

    + +

    Register a Unit Test

    + +

    As of version 1.4.1, you +no longer have to explicitly register a unit test! The default +behavior of utPLSQL is now to extract from the data dictionary (via the +ALL_ARGUMENTS data dictionary view) the names of all the unit test procedures +you have defined, and then run them. utPLSQL identifies these programs by +looking for all programs whose names start with the specified prefix.

    + +

    If you decide that you want to explicitly register your unit +tests, then you will need to turn on manual registration:

    + +
    SQL> exec utConfig.registertest (TRUE)
    + +

    This setting is immediately saved in the database for your +schema. To turn off manual registration:

    + +
    SQL> exec utConfig.registertest (FALSE)
    + +

    So read no further unless you have turned on manual +registration! You might do this, for example, if you have already built a +number of test packages in a version of utPLSQL prior to 1.4.1 and do not want +to make any changes to your test package code.

    + +

    All aspects of manual registration of unit tests for a +program or package actually occur within the Unit Test Package itself, in the setup procedure. No persistent unit test information +is stored between runs of the unit test, unless you define that unit test +within a test suite.

    + +

    Use the utPLSQL.addtest procedure to register a unit test.

    + +
       PROCEDURE utPLSQL.addtest (
          NAME_IN IN VARCHAR2,
          utprefix_in IN VARCHAR2,
          iterations_in IN PLS_INTEGER := 1
       );
     
       PROCEDURE utPLSQL.addtest (
          package_in IN VARCHAR2,
          NAME_IN IN VARCHAR2,
          utprefix_in IN VARCHAR2,
          iterations_in IN PLS_INTEGER := 1
       );
    + +

    where

    + +

    name_in is the name of the program you are +testing. Note that this is the name of the unit test procedure itself, +including the unit test prefix..

    + +

    utprefix_in is the prefix to be applied to +name_in to construct the unit tst procedure. This is currently NOT IN USE; only +the package prefix specified in your call to utPLSQL.test and utPLSQL.testsuite +is used.

    + +

    iterations_in is the number of times you wish to +run the test (currently NOT IN USE).

    + +

    package_in is the name of the package containing +the unit test procedure. If you provide a package name when you call +utPLSQL.addtest, you will override the package name set when you called +utPLSQL.test -- but only for that one test. We recommend that you not change +the package name.

    + +

    Here is a setup procedure that sets up a series of tests for +a query-only encapsulation of the employee table:

    + +
    CREATE OR REPLACE PACKAGE BODY ut_te_employee
    IS
       PROCEDURE ut_setup
       IS
       BEGIN
          utplsql.addtest ('UT_EMP_DEPT_LOOKUPROWCOUNT');
          utplsql.addtest ('UT_EMP_JOB_LOOKUPROWCOUNT');
          utplsql.addtest ('UT_EMP_MGR_LOOKUPROWCOUNT');
          utplsql.addtest ('UT_HIRE_DATE$VAL');
          utplsql.addtest ('UT_I_EMPLOYEE_NAME$ROW');
          utplsql.addtest ('UT_I_EMPLOYEE_NAME$VAL');
          utplsql.addtest ('UT_ONEROW');
          utplsql.addtest ('UT_PKYROWCOUNT');
          utplsql.addtest ('UT_ROWCOUNT');
          utplsql.addtest ('UT_SALARY$VAL');
       END;
    + +

    Once you have placed your addtest programs into your test +package's setup procedure, you are ready to build your own unit tests.

    + +

    Return utPLSQL version

    + +

    Run the utPLSQL.version function to return the version of +utPLSQL you have installed:

    + +
    FUNCTION utPLSQL.version RETURN VARCHAR2
    + + + + + diff --git a/documentation/src/utresult.html b/documentation/src/utresult.html new file mode 100644 index 000000000..3e15baab8 --- /dev/null +++ b/documentation/src/utresult.html @@ -0,0 +1,136 @@ + + + + + + + utPLSQL - utResult Package + + + + + + + +
    + +
    +Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
    +[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

    < Previous Section: utConfig Package | +Next +Section: utAssert Package > +
    + +

    +utResult Package

    + +

    This package contains the following procedures and functions: +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    utResult.initInitialize the results data
    utResult.show +
    utResult.showone +
    utResult.showlast
    Show results
    utResult.success +
    utResult.failure
    Show the success or failure of the last test
    utResult.firstresult +
    utResult.nextresult +
    utResult.nthresult +
    utResult.resultcount
    Iterate through the results array
    + +The utResult package offers an API to the information +sent by the various utAssert assertion routines after a test is run. If +you employ the utPLSQL.test and utPLSQL.testsuite to run your tests, then +the results will be displayed by calling the utResult.show procedure. + +So, generally, you do not have to do anything to +see or evaluate the results of a test (or suite of tests). The information +will be displayed on your screen using DBMS_OUTPUT. You might, however, +want to access this information in another environment (say, Oracle Forms +or Java, etc.). You might also want to build +your own assertion logic or test engine. In either of these cases, +you will want to use the programs in the utResult package. + +

    +Initialize

    +Initialize the utResult data, setting it all back to NULL: +
    PROCEDURE utResult.init;
    + +

    +Show Results

    +Show the results of your test with one of the following three procedures. +
    PROCEDURE utResult.show (reset_in IN BOOLEAN := FALSE);
    +PROCEDURE utResult.showone (indx_in in pls_integer);
    +PROCEDURE utResult.showlast;
    +Use the show procedure to display the full set of results stored +in the utResult array. If you pass TRUE for its single argument, the results +informatino will be initialized. +

    Use the showone procedure to show the Nth result. +

    Use the showlast procedure to show the results of the last test +run. +

    +Retrieve Test Status

    +The success and failure functions return the status of the most recently +executed test. +
    FUNCTION utResult.success RETURN BOOLEAN;
    +FUNCTION utResult.failure RETURN BOOLEAN;
    + +

    +Scan Results Array

    +The utPLSQL.show procedure iterates through the contents of the utResult +array and displays the information found there. You can write the same +kind of logic by calling a combination of the following programs: +
    PROCEDURE utResult.firstresult;
    +
    +FUNCTION utResult.nextresult RETURN utResult.result_rt;
    +
    +PROCEDURE utResult.nextresult (
    +   name_out OUT VARCHAR2,
    +   msg_out OUT VARCHAR2,
    +   case_indx_out OUT PLS_INTEGER
    +);
    +
    +FUNCTION utResult.nthresult (indx_in IN PLS_INTEGER)
    +   RETURN utResult.result_rt;
    +
    +PROCEDURE utResult.nthresult (
    +   indx_in IN PLS_INTEGER,
    +   name_out OUT VARCHAR2,
    +   msg_out OUT VARCHAR2,
    +   case_indx_out OUT PLS_INTEGER
    +);
    +
    +FUNCTION utResult.resultcount RETURN PLS_INTEGER;
    + + + diff --git a/documentation/src/xref.html b/documentation/src/xref.html new file mode 100644 index 000000000..ff91b27eb --- /dev/null +++ b/documentation/src/xref.html @@ -0,0 +1,52 @@ + + + + + + + utPLSQL - Cross-Reference by Assertion Type + + + + + + + +
    + +
    +Authors: Steven Feuerstein, +Chris Rimmer + +Copyright 2000-2001, all rights +reserved +
    +[ Home | Getting +Started | Build Test Packages +| Examples | User +Guide | Release Notes | Document +Map ] +

    < Previous Section: Examples | Next +Section: Test a Procedure > +
    + +

    +Cross-Reference by Assertion Type

    + +

    The examples are organized by the type of program element being tested +-- and from which package. But they also demonstrate other features of +and handy techniques to use with utPLSQL. These examples, in particular, +show how to use the different kinds of assertion programs. These features +are described below. Click on a link to go to the example that highlights +the feature. +

    Check equality of scalars +

    Check equality of database tables +

    Check equality of database pipes +

    Check equality of files +

    Check equality of collections +

    Testing Impact on Objects +

    Set up and Tear Down Test Data Structures + + + + diff --git a/documentation/utplsql.css b/documentation/utplsql.css new file mode 100644 index 000000000..3770da25e --- /dev/null +++ b/documentation/utplsql.css @@ -0,0 +1,38 @@ +/* utPLSQL Stylesheet */ +/*$Id$*/ + +/* For top-level headings and utPLSQL logo, we want a + purple bar across the page */ +H1, .purple_bar {font-family: Arial, Helvetica, Sans-Serif; + color: #ffffff; + background: #800080; + margin-left: 0px; + margin-right: 0px; + padding-left: 10px; + padding-top: 5px; + padding-bottom: 5px} + +/* Second level headings in purple */ +H2 {font-family: Arial, Helvetica, Sans-Serif; + color: #800080} + +/* Other headings in Sans Serif Font */ +H3, H4, H5, H6 {font-family: Arial, Helvetica, Sans-Serif} + +/* Pre formatted code is in a gray box, in monotype */ +Pre {font-family: Courier, Monotype; + font-size: smaller; + color: #000000; + background: #f0f0f0; + margin-left: 20px; + margin-right: 20px; + padding-left: 10px; + padding-top: 5px; + padding-bottom: 5px; + padding-right: 10px} + +/* Code in monotype */ +Code {font-family: Courier, Monotype;} + +/* Copyright notice is tiny */ +.copyright {font-size: xx-small} diff --git a/documentation/utplsql.jpg b/documentation/utplsql.jpg new file mode 100644 index 0000000000000000000000000000000000000000..288ee26221acdeda86f80b235faa70a695ef4c57 GIT binary patch literal 9388 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 N6eYm^e;S;b{{fh-?mz$l literal 0 HcmV?d00001 From 041dfdeb14862ee7268db89868c948e151cdc0bb Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Sun, 10 Mar 2002 17:28:43 +0000 Subject: [PATCH 004/143] Added Meta Tags Made some other minor modifications to functionality --- documentation/src/build_docs.pl | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/documentation/src/build_docs.pl b/documentation/src/build_docs.pl index 1d3055e34..03465e012 100755 --- a/documentation/src/build_docs.pl +++ b/documentation/src/build_docs.pl @@ -44,8 +44,10 @@ push @map, ["map.html", "Document Map", 1]; $nav = "[ $nav | Document Map ]"; -#Holds the copyright string +#Hold the copyright strings my $copyright; +my $copymeta; +my $authormeta; #Read the authors file open AUTHORS, "authors.txt" or die "Cannot open authors.txt"; @@ -58,12 +60,15 @@ ($name, $email) = split /,/; $copyright .= ', ' if $copyright; $copyright .= "$name"; + $authormeta .= ', ' if $authormeta; + $authormeta .= $name; } } close AUTHORS; -#Put together the rest of the copyright notice +#Put together the rest of the copyright notices $copyright = "Copyright (C) 2000-".(((gmtime(time))[5])+1900)." $copyright All rights reserved"; +$copymeta = "(C) 2000-".(((gmtime(time))[5])+1900)." $authormeta"; my $logo = '

    '; @@ -91,10 +96,17 @@ open INPUT, "$map[$index]->[0].clean" or die "Cannot open $map[$index]->[0].clean"; } - print OUTPUT "\n"; + print OUTPUT "\n\n\n"; + print OUTPUT "\n"; + print OUTPUT "\n\n\n"; print OUTPUT "\n"; print OUTPUT "$map[$index]->[1]\n"; - print OUTPUT ""; + print OUTPUT "\n"; + print OUTPUT "\n"; + print OUTPUT "\n"; + print OUTPUT "[1]\"/>\n"; + print OUTPUT "\n"; + print OUTPUT "\n"; print OUTPUT "\n"; print OUTPUT "$logo\n"; print OUTPUT "

    $nav

    \n"; @@ -103,9 +115,15 @@ #Either print the body, or construct it for the document map if ($index != $#map){ while (){ - $body = 1 if /^\s*\s*$/; + if (/(.*)/){ + $_ = "$1\n"; + $body = 1; + } + if (/(.*)/i){ + $body = 0; + print OUTPUT "$1\n"; + } print OUTPUT $_ if $body; - $body = 0 if /^\s*\s*$/i; } close INPUT; unlink("$map[$index]->[0].clean"); From b5141dc6e0d23068d55699f8423b009db6da95f9 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Sun, 10 Mar 2002 17:32:00 +0000 Subject: [PATCH 005/143] Cleaned up files further Add a CVS ID Line Fixed a few documentation inaccuracies Added documentation on utAssert.previous_* functions --- documentation/src/admin.html | 89 +- documentation/src/advanced.html | 33 +- documentation/src/buildpack.html | 31 +- documentation/src/defsuite.html | 32 +- documentation/src/examples.html | 33 +- documentation/src/fourstep.html | 30 +- documentation/src/glossreq.html | 53 +- documentation/src/howto.html | 37 +- documentation/src/index.html | 46 +- documentation/src/prefix.html | 33 +- documentation/src/release.html | 265 ++--- documentation/src/samepack.html | 34 +- documentation/src/started.html | 31 +- documentation/src/suite.html | 32 +- documentation/src/testapi.html | 33 +- documentation/src/testfunc.html | 33 +- documentation/src/testproc.html | 32 +- documentation/src/testrun.html | 32 +- documentation/src/userguide.html | 31 +- documentation/src/utassert.html | 1814 ++++++++++-------------------- documentation/src/utconfig.html | 38 +- documentation/src/utgen.html | 33 +- documentation/src/utplsql.html | 37 +- documentation/src/utresult.html | 33 +- documentation/src/xref.html | 32 +- 25 files changed, 786 insertions(+), 2141 deletions(-) diff --git a/documentation/src/admin.html b/documentation/src/admin.html index faa6c9123..ea95f8e03 100644 --- a/documentation/src/admin.html +++ b/documentation/src/admin.html @@ -1,37 +1,7 @@ - - - - - - utPLSQL - Administrative Topics - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: The Four Step Program -to Using utPLSQL | Next Section: -Build Test Packages > -
    - + +

    Administrative Topics

    @@ -73,42 +43,42 @@

    location and the name of the file, in separate arguments. This file location is then checked against the list of accessible directories.

    The format of the parameter for file access in the init.ora file is: - +

     utl_file_dir = <directory>
    -
    +
    Include a parameter for utl_file_dir for each directory you want to make accessible for UTL_FILE operations. The following entries, for example, enable four different directories in Unix: - +
     utl_file_dir = /tmp
    -
    utl_file_dir = /ora_apps/hr/time_reporting -
    utl_file_dir = /ora_apps/hr/time_reporting/log -
    utl_file_dir = /users/test_area - +utl_file_dir = /ora_apps/hr/time_reporting +utl_file_dir = /ora_apps/hr/time_reporting/log +utl_file_dir = /users/test_area +
    To bypass server security and allow read/write access to all directories, you can use this special syntax: - +
     utl_file_dir = *
    -
    +
    You should not use this option on production systems. In a development system, this entry certainly makes it easier for developers to get up and running on UTL_FILE and test their code. You should, however, only allow access to a few specific directories when you move the application to production. -

    Some observations on working with and setting up accessible directories -with UTL_FILE: +

    Some observations on working with and setting up accessible directories +with UTL_FILE:

    Access is not recursive through subdirectories. If the following lines were in your init.ora file, for example, - +

     utl_file_dir = c:\group\dev1
    -
    utl_file_dir = c:\group\prod\oe -
    utl_file_dir = c:\group\prod\ar - +utl_file_dir = c:\group\prod\oe +utl_file_dir = c:\group\prod\ar +
    then you would not be able to open a file in the c:\group\prod\oe\reports subdirectory.

    Do not include the following entry in Unix systems: - +

     utl_file_dir = .
    -
    +
    This would allow you to read/write on the current directory in the operating system.

    Do not enclose the directory names within single or double quotes. @@ -120,12 +90,12 @@

    You should not end your directory name with a delimiter, such as the forward slash in Unix. The following specification of a directory will result in problems when trying to read from or write to the directory: - +

     utl_file_dir = /tmp/orafiles/
    -
    +
    After you modify your parameter initialization file, you will need to stop and then restart your database instance. -

    Test UTL_FILE Access +

    Test UTL_FILE Access

    If you have never before used or relied on UTL_FILE, you should write a simple test to verify that UTL_FILE is now working. You can use the code shown below (after changing your directory names and names for existing @@ -185,10 +155,13 @@

    Join the utPLSQL Project Team

    -To take part in the utPLSQL project, please join -our email distribution group. Go to www.egroups.com, -join, and subscribe to the utPLSQL list. You will be including in ongoing -communication about utPLSQL via eGroups. +To take part in the utPLSQL project, first please join +our email distribution group. Go to +http://groups.yahoo.com/group/utPLSQL-Info +and subscribe to the utPLSQL-Info list. You will be including in ongoing +communication about utPLSQL. Once you are up to speed on the project, you +can go to the SourceForge site, choose a task and begin +to contribute.

    Reporting Bugs and Enhancement Requests

    @@ -196,9 +169,9 @@

    To identify the version of utPLSQL you are running, you can execute the following program in SQL*Plus: -
    SQL> set serveroutput on
    +
    SQL> set serveroutput on
    -
    SQL> exec dbms_output.put_line (utPLSQL.version)
    +
    SQL> exec dbms_output.put_line (utPLSQL.version)
    You can also look inside the utPLSQL package (utPLSQL.pkb) and check the value of the g_version private variable. diff --git a/documentation/src/advanced.html b/documentation/src/advanced.html index 11a36b06c..a29d5eb28 100644 --- a/documentation/src/advanced.html +++ b/documentation/src/advanced.html @@ -1,36 +1,7 @@ - - - - - - utPLSQL - Advanced Topics - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: A "Test Run" with utPLSQL -| Next Section: Examples > -
    - + +

    Advanced Topics

    diff --git a/documentation/src/buildpack.html b/documentation/src/buildpack.html index b43b5d610..a061f7c89 100644 --- a/documentation/src/buildpack.html +++ b/documentation/src/buildpack.html @@ -1,34 +1,7 @@ - - - - - - utPLSQL - Build Test Packages - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages | Examples -| User Guide | Release -Notes | Document Map ] -

    < Previous Section: Administrative Topics -| Next Section: How to Build a Test Package > -
    + +

    Build Test Packages

    diff --git a/documentation/src/defsuite.html b/documentation/src/defsuite.html index 1eda1d99c..b33277dc9 100644 --- a/documentation/src/defsuite.html +++ b/documentation/src/defsuite.html @@ -1,35 +1,7 @@ - - - - - - utPLSQL - Define Test Suites - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: utGen Package | Next -Section: Release Notes > -
    + +

    Define Test Suites

    diff --git a/documentation/src/examples.html b/documentation/src/examples.html index 69a3bbebd..1cc6b6a8d 100644 --- a/documentation/src/examples.html +++ b/documentation/src/examples.html @@ -1,36 +1,7 @@ - - - - - - utPLSQL - Examples - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User Guide | -Release -Notes | Document Map ] -

    < Previous Section: Advanced Topics | -Next -Section: Cross-Reference by Assertion Type > -
    + +

    Examples

    diff --git a/documentation/src/fourstep.html b/documentation/src/fourstep.html index 91ab8fc23..1991ea578 100644 --- a/documentation/src/fourstep.html +++ b/documentation/src/fourstep.html @@ -1,33 +1,7 @@ - - - - -utPLSQL - The Four Step Program to using utPLSQL - - - - - - - - - -
    -

    -
    - -

    Authors: Steven Feuerstein, Chris Rimmer

    - -

    Copyright 2000-2001, all rights reserved

    - -

    [ Home | Getting Started | Build Test Packages | Examples | User Guide | Release Notes | Document Map ]

    - -

    < Previous Section: Glossary and Requirements -| Next Section: Administrative Topics >
    -

    - + +

    The Four Step Program to Using utPLSQL

    Step 1. Install utPLSQL.

    diff --git a/documentation/src/glossreq.html b/documentation/src/glossreq.html index 0d1604896..4c998a50c 100644 --- a/documentation/src/glossreq.html +++ b/documentation/src/glossreq.html @@ -1,36 +1,7 @@ - - - - - - utPLSQL - Glossary & Requirements - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: Getting Started -| Next Section: The Four Step Program to Using utPLSQL -> -
    + +

    Glossary and Requirements

    @@ -86,23 +57,29 @@

    (7.3.4 and above) and Oracle8. Requirements for using utPLSQL include: +
      +
    • -·The -schema owning utPLSQL objects must have EXECUTE authority on the DBMS_PIPE +The schema owning utPLSQL objects must have EXECUTE authority on the DBMS_PIPE package, as well as the ability to create tables and packages. +

    • +
    • -·If +If you want utPLSQL to automatically recompile test packages for you, you will need to have UTL_FILE installed and configured to read from the directory or directories in which your package source files are located. +

    • +
    • Optional: +Optional: ability to create public synonyms. The installation script will attempt to create public synonyms. If your schema does not hae the authority to do so, these commands will fail, but utPLSQL will still be available for use in the owning schema. -

      +

    • +

    Requirements for Executing Test Code

    @@ -115,12 +92,12 @@

    EXECUTE privileges on those code elements (both the code to be tested and the test packages) -- or the AUTHID CURRENT_USER capability of Oracle8i.

    -FOR ORACLE8i AND ABOVE +

    For Oracle8i and above

    You do not need to grant any additional privileges, unless you want to test code owned by one schema from another schema. In that case, you will need to grant EXECUTE to the schema from which you run your tests on both the code to be tested and the test package.

    -FOR ORACLE7 AND ORACLE8 +

    For Oracle7 and Oracle8

    You must grant EXECUTE to the utPLSQL schema on both the code to be tested and the test package. These grants must be made directly and not through roles. diff --git a/documentation/src/howto.html b/documentation/src/howto.html index 69531ce56..c991ae1e2 100644 --- a/documentation/src/howto.html +++ b/documentation/src/howto.html @@ -1,41 +1,12 @@ - - - - - - utPLSQL - How to build a test package - - - - - - - -
    - -

    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: Build Test -Packages | Next Section: A "Test Run" with utPLSQL -> -
    + +

    How to build a test package

    -

    -Instructions

    +

    +Instructions

    To use utPLSQL, you will build a test package containing your unit tests. This test package must conform to the API (application programmatic interface) rules of utPLSQL, so that utPLSQL can run your tests automatically. diff --git a/documentation/src/index.html b/documentation/src/index.html index 0db16e26d..f96d17001 100644 --- a/documentation/src/index.html +++ b/documentation/src/index.html @@ -1,41 +1,12 @@ - - - - - - - Welcome to utPLSQL - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting Started -| Build Test Packages | Examples -| User Guide | Release -Notes | Document Map ] -

    Next Section: Getting Started > -
    + +

    Table of Contents

    -

    -Welcome to utPLSQL

    -

    +Welcome to utPLSQL - a unit testing framework for the Oracle PL/SQL Language

    @@ -78,12 +49,11 @@

    Document Map

    The full list of the pages in the documentation
    -Lots of information about utPLSQL is also available on the -Internet at the the utPLSQL -site of the O'Reilly and Associates Oracle Resource Center, including a -Webboard -that will allow you to ask questions, see what others have done with utPLSQL, -and post your own contributions. + +

    The utPLSQL project is hosted at Sourceforge - the home page is to be +found at http://utplsql.sourceforge.net. From here, there are links to the various resources available and details on how to get involved in the project. Discussion of utPLSQL takes place at +Yahoo! Groups, so to ask further questions, or for help with problems visit +http://groups.yahoo.com/group/utPLSQL-Info.

    diff --git a/documentation/src/prefix.html b/documentation/src/prefix.html index b9307aea7..62fef785e 100644 --- a/documentation/src/prefix.html +++ b/documentation/src/prefix.html @@ -1,36 +1,7 @@ - - - - - - utPLSQL - Use Non-Default Prefix - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: -Put Test Code in Same Package | Next Section: Create -and Run a Test Suite > -
    + +

    Use Non-Default Prefix

    diff --git a/documentation/src/release.html b/documentation/src/release.html index bf13f66da..856740be3 100644 --- a/documentation/src/release.html +++ b/documentation/src/release.html @@ -1,52 +1,7 @@ - - - - utPLSQL - Release Notes - - - - - -

    -

    - - - - - - - - -
    - -

    - -

    -
    - -


    -Authors: Steven Feuerstein, Chris Rimmer

    - -

    Copyright -2000-2001, all rights reserved
    -
    -

    - -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes | Document Map - ]

    - -

    < Previous Section: Define Test Suites - | Next Section: Document Map > -
    -

    - + +

    Release Notes

    Known Issues

    @@ -90,7 +45,7 @@

    utPLSQL version 2.0.9.1

  • Modified utpackage.upd - changed parameter suite_in to suite_id_in (the type was INTEGER). Changed the UPDATE WHERE clause first line -to VL(suite_id,0) = NVL(suite_id_in,0).
  • +to NVL(suite_id,0) = NVL(suite_id_in,0).
  • Modified utplsql.testsuite - v_suite (the suite id) was in the @@ -123,7 +78,7 @@

    utPLSQL version 2.0.8.2

    Change ut_utp LOB column to VARCHAR2 for the time being.
  • -Fixed ALTER TBLE statement in ut_config.tab.
  • +Fixed ALTER TABLE statement in ut_config.tab.
  • Change utplsql.test to allow for compilation of test package before @@ -165,177 +120,135 @@

    utPLSQL version 2.0.8.1

    -

    -

    - -

    -SQL> exec utplsql.test ('str', per_method_setup_in => true)

    +

    +SQL> exec utplsql.test ('str', per_method_setup_in => true)
    +

    utPLSQL version 2.0.7

    -

    -· - Revamp +

      +
    • Revamp utAssert2.define_message implement to simplify creation of new assertion -programs

      +programs
    • -

      -· - Modify -implementation if ieqminus to avoid duplicate column

      +
    • Modify +implementation if ieqminus to avoid duplicate column
    • -

      -· - Change +

    • Change naming conventions for utPLSQL2 from prefix to delimiter driven (utconfig.delimiter): QU##NNN. This affects only those test packages which use the utPLSQL2.test program to run the tests (ie for version 1 utPLSQL test packages and utPLSQL.test, -you can still use your prefix-based approaches).

      - -

      -· - Add -utAssert2.fileExists

      +you can still use your prefix-based approaches).
    • -

      -· - Compile -utAssert2 with AUTHID CURRENT_USER for Oracle8i and above.

      +
    • Add +utAssert2.fileExists
    • -

      -· - 2.0.7.2 -Fix index creation for ut_assertion table.

      +
    • Compile +utAssert2 with AUTHID CURRENT_USER for Oracle8i and above.
    • -

      -· - 2.0.7.2 -Fix foreign key definition in ut_argument.

      +
    • (2.0.7.2) +Fix index creation for ut_assertion table.
    • -

      -· - 2.0.7.2 -Fix foreign key definition in uta_eq.

      +
    • (2.0.7.2) +Fix foreign key definition in ut_argument.
    • +
    • (2.0.7.2) +Fix foreign key definition in uta_eq.
    • +
    +

    utPLSQL version 2.0.6

    -

    -· - Fix -to utgen.pkb to allow generation of procedure bodies when no grid is used.

    - -

    -· - Allow -developers to turn off display of successful results (utResult.include_successes)

    +
      +
    • Fix +to utgen.pkb to allow generation of procedure bodies when no grid is used.
    • +
    • Allow +developers to turn off display of successful results (utResult.include_successes)
    • +
    +

    utPLSQL version 2.0.5

    -

    -· - Allow +

      +
    • Allow user to specify individual program or programs (via wildcard) to be tested -from a whole package.

      +from a whole package.
    • -

      -· - Add +

    • Add ut_deterministic and ut_deterministic_arg tables to facilitate generate of -test packages for deterministic functions.

      +test packages for deterministic functions.
    • -

      -· - Add +

    • Add ut_deterministic.fmx Oracle Forms GUI to allow easy generation of test packages -for deterministic functions.

      - +for deterministic functions.
    • +
    +

    utPLSQL version 2.0.4

    -

    -· - Implement -test suite execution in utPLSQL2.

    +
      +
    • Implement +test suite execution in utPLSQL2.
    • -

      -· - Implement +

    • Implement ut_suite_utp table (and the corresponding utsuiteutp package) as an intersection -of ut_suite and ut_utp, defining all those UTPs in a given suite.

      +of ut_suite and ut_utp, defining all those UTPs in a given suite.
    • -

      -· - Improved +

    • Improved error handling with utrerror assertions and general reporting mechanisms. Assertion and error handling logic applied to define-time packages like utsuite -and utsuiteutp.

      +and utsuiteutp.
    • -

      -· - Revamp +

    • Revamp installation process; no longer use OraShare, remove testcase2 entirely. -

      +
    • -

      -· - Create -stand alone utverify procedure.

      +
    • Create +stand alone utverify procedure.
    • +

    utPLSQL version 2.0.3

    -

    -· - Add +

      +
    • Add utr_error table and utrerror package; now all errors are logged to the table for viewing afterwards. utPLSQL NEVER passes back an unhandled exception -to the console.

      +to the console.
    • -

      -· - utAssert.eqfile -now flags problems when opening files.

      +
    • utAssert.eqfile +now flags problems when opening files.
    • +

    utPLSQL version 2.0.2

    -

    -· - +
      +
    • clarify how that null_ok_in is supposed to work. For utAssert.this, it should mean that if the value of the Boolean expression coming in is null, then that means "success". For eq, it shoudl mean that if BOTH values coming in -are NULL, that is "success". For eqfile, if both files are empty...etc.

    - -

    -· - -add null_ok_in to eqqueryvalue assertions.

    +are NULL, that is "success". For eqfile, if both files are empty...etc.
  • -

    -· - -add utassert.eqqueryvalue for NUMBER

    +
  • +add null_ok_in to eqqueryvalue assertions.
  • -

    -· - -Enhance utgen to properly generate code for overloaded programs in packages

    +
  • +add utassert.eqqueryvalue for NUMBER
  • +
  • +Enhance utgen to properly generate code for overloaded programs in packages
  • + +

    utPLSQL version 2.0.1

    -

    -· - -store results in utr_outcome tables

    - -

    -· - -support results reporting compatibility with V1

    +
      +
    • +store results in utr_outcome tables
    • -

      -· - -display results of all test, success and failure.

      +
    • +support results reporting compatibility with V1
    • +
    • +display results of all test, success and failure.
    • +
    +

    utPLSQL version 1.5.6

      @@ -391,15 +304,15 @@

      utPLSQL version 1.5.4

      Bug Fixes

      -

      -· +

        +
      • utPLSQL.setconfig now sets the user information properly when the package is first initialized (bug introduced in 1.5.3). -

        - +
      • +
      +

      utPLSQL version 1.5.3

      -

      Documentation and Usage Changes

        @@ -409,14 +322,14 @@

        Documentation and Usage Changes

        in your setup procedure, you must now INCLUDE the unit test prefix, as in: -
      utPLSQL.addtest ('ut_betwnstr');
      -

      utPLSQL +utPLSQL will no longer add the prefix for you. This means that you may need to change -your calls to addtest -- or remove them entirely and rely on auto-registration.

      - +your calls to addtest -- or remove them entirely and rely on auto-registration. +
    +

    Bug Fixes

    diff --git a/documentation/src/samepack.html b/documentation/src/samepack.html index 2d20712f8..0d38a57d6 100644 --- a/documentation/src/samepack.html +++ b/documentation/src/samepack.html @@ -1,35 +1,7 @@ - - - - - - utPLSQL - Put Test Code in Same Package - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: Test an Entire Package -API | Next Section: Use Non-Default Prefix > -
    + +

    Put Test Code in Same Package

    @@ -84,7 +56,7 @@

    that you can find in the Testing a Scalar Function example. But when I execute my test, I need to tell utPLSQL that my test code is located in the same package: -
    SQL> exec utplsql.showconfig
    +
    SQL> exec utconfig.showconfig
     =============================================================
     utPLSQL Configuration for SCOTT
        Directory: e:\openoracle\utplsql\utinstall\examples
    diff --git a/documentation/src/started.html b/documentation/src/started.html
    index 9522e4ed2..4c5299df2 100644
    --- a/documentation/src/started.html
    +++ b/documentation/src/started.html
    @@ -1,34 +1,7 @@
     
    -
    -
    -   
    -   
    -   
    -   utPLSQL - Getting started
    -
    -
    - 
    -
    -
    -
    -
    -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting Started | Build -Test Packages | Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: Home | Next -Section: Glossary and Requirements > -
    + +

    Getting Started

    diff --git a/documentation/src/suite.html b/documentation/src/suite.html index 17b616393..3906abaab 100644 --- a/documentation/src/suite.html +++ b/documentation/src/suite.html @@ -1,35 +1,7 @@ - - - - - - utPLSQL - Create and Run a Test Suite - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: Use Non-Default Prefix -| Next Section: User Guide > -
    + +

    Create and Run a Test Suite

    diff --git a/documentation/src/testapi.html b/documentation/src/testapi.html index a856f6847..fa507efeb 100644 --- a/documentation/src/testapi.html +++ b/documentation/src/testapi.html @@ -1,36 +1,7 @@ - - - - - - utPLSQL - Test an Entire Package API - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: Test a Function | -Next -Section: Put Test Code in Same Package > -
    + +

    Test an Entire Package API

    diff --git a/documentation/src/testfunc.html b/documentation/src/testfunc.html index 1107a93d2..700be0829 100644 --- a/documentation/src/testfunc.html +++ b/documentation/src/testfunc.html @@ -1,36 +1,7 @@ - - - - - - utPLSQL - Test a Function - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: Test a Procedure | -Next -Section: Test an Entire Package API > -
    + +

    Test a Function

    diff --git a/documentation/src/testproc.html b/documentation/src/testproc.html index 3cbf41828..62c1324b2 100644 --- a/documentation/src/testproc.html +++ b/documentation/src/testproc.html @@ -1,35 +1,7 @@ - - - - - - utPLSQL - Test a Procedure - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: Cross-Reference by Assertion -Type | Next Section: Test a Function > -
    + +

    Test a Procedure

    diff --git a/documentation/src/testrun.html b/documentation/src/testrun.html index b70e8eecc..c321baace 100644 --- a/documentation/src/testrun.html +++ b/documentation/src/testrun.html @@ -1,35 +1,7 @@ - - - - - - utPLSQL - A Test Run with utPLSQL - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: How to build a test package -| Next Section: Advanced Topics > -
    + +

    A "Test Run" with utPLSQL

    diff --git a/documentation/src/userguide.html b/documentation/src/userguide.html index 443f555f9..5117090a2 100644 --- a/documentation/src/userguide.html +++ b/documentation/src/userguide.html @@ -1,34 +1,7 @@ - - - - - - utPLSQL - User Guide - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User Guide | Release -Notes | Document Map ] -

    < Previous Section: Create and Run a Test Suite -| Next Section: utPLSQL Package > -
    + +

    User Guide

    diff --git a/documentation/src/utassert.html b/documentation/src/utassert.html index 16c683a74..ca39f634c 100644 --- a/documentation/src/utassert.html +++ b/documentation/src/utassert.html @@ -1,1235 +1,613 @@ - - - - - - - utPLSQL - utAssert Package - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: utResult Package | -Next -Section: utGen Package > -
    - -

    -utAssert Package

    - -

    This package contains the following procedures and functions: -
    + + + + +

    utAssert Package

    + +

    This package contains the following procedures and functions:
    + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    utAssert.showresults -
    utAssert.noshowresults -
    utAssert.showingresults
    Set the showing of results immediately
    utAssert.thisGeneric "Assert This" Procedure
    utAssert.isnull -
    utAssert.isnotnull
    Check for NULL and NOT NULL values
    utAssert.eqCheck Equality of Scalar Values
    utAssert.eqtableCheck Equality of Database Tables
    utAssert.eqtabcountCheck Equality of Table Counts
    utAssert.eqqueryCheck Equality of Queries
    utAssert.eqqueryvalueCheck Equality of Query against single value
    utAssert.eqfileCheck Equality of Files
    utAssert.eqpipeCheck Equality of Database Pipes
    utAssert.eqcoll -
    utAssert.eqcollapi
    Check Equality of Collections
    utAssert.throwsCheck a procedure or function throws an exception
    utAssert.showresults
    + utAssert.noshowresults
    + utAssert.showingresults
    Set the showing of results immediately
    utAssert.thisGeneric "Assert This" Procedure
    utAssert.isnull
    + utAssert.isnotnull
    Check for NULL and NOT NULL values
    utAssert.eqCheck Equality of Scalar Values
    utAssert.eqtableCheck Equality of Database Tables
    utAssert.eqtabcountCheck Equality of Table Counts
    utAssert.eqqueryCheck Equality of Queries
    utAssert.eqqueryvalueCheck Equality of Query against single value
    utAssert.eqfileCheck Equality of Files
    utAssert.eqpipeCheck Equality of Database Pipes
    utAssert.eqcoll
    + utAssert.eqcollapi
    Check Equality of Collections
    utAssert.throwsCheck a procedure or function throws an exception
    utAssert.previous_passed
    +utAssert.previous_failed

    +
    Check if the previous assertion +passed or failed
    +
    - + The utAssert package provides a set of assertion routines ("assert that +the following condition is true") that you will use to register the outcome +of a test case. You must call a utAssert assertion program after (or containing) +a test case so that the results of that test can be recorded and then reported. +See Build Test Packages for many examples and +more details on this process. Here is a very simple example, though, to give +you an idea of the code you would write:

       PROCEDURE ut_BETWNSTR IS
    BEGIN
    utAssert.eq (
    'Typical valid usage',
    BETWNSTR(
    STRING_IN => 'abcdefg'
    ,
    START_IN => 3
    ,
    END_IN => 5
    ),
    'cde'
    );
    END;
    + utAssert offers a wide (and ever expanding) set of assertion programs that +allow you to efficiently (a) test the outcome of your unit test and (b) report +the results of that test to utPLSQL. You should review +Common Assertion Parameters and Behavior before using any specific assertion +program. It is also possible to build your own assertion +routine. Note: all utAssert assertions are defined in the ut_assertion +table, as well as actually coded in the utAssert package.

    +

    Common Assertion Parameters and Behavior

    + Each type of assertion routine accepts different kinds of data, but there +are lots of similarities between the assertions, as well. Here is an explanation +of the common assertion parameters: + + + + + + + + + + + + + + + + + + + + + + - -The utAssert package provides a set of assertion -routines ("assert that the following condition is true") that you will -use to register the outcome of a test case. You must call a utAssert assertion -program after (or containing) a test case so that the results of that test -can be recorded and then reported. See Build -Test Packages for many examples and more details on this process. Here -is a very simple example, though, to give you an idea of the code you would -write: - -
       PROCEDURE ut_BETWNSTR IS
    -   BEGIN
    -      utAssert.eq (
    -         'Typical valid usage',
    -         BETWNSTR(
    -            STRING_IN => 'abcdefg'
    -            ,
    -            START_IN => 3
    -            ,
    -            END_IN => 5
    -            ),
    -         'cde'
    -         );
    -   END;
    - -utAssert offers a wide (and ever expanding) set -of assertion programs that allow you to efficiently (a) test the outcome -of your unit test and (b) report the results of that test to utPLSQL. You -should review Common Assertion Parameters and -Behavior before using any specific assertion program. It is also possible -to build your own assertion routine. - -Note: all utAssert assertions are defined in the -ut_assertion table, as well as actually coded in the utAssert package. - -

    -Common Assertion Parameters and Behavior

    - -Each type of assertion routine accepts different -kinds of data, but there are lots of similarities between the assertions, -as well. - -Here is an explanation of the common assertion parameters: - -
    msg_in A message to be displayed if the assertion +fails. This is the first argument and is mandatory, because the tests need +to be self documenting.
    check_this_in The value to be checked.. If a Boolean expression, +this will usually include the invocation of the method being tested, resulting +in a single line of code for the entire test case.
    against_this_in For assert_eq, the assertion routine will +check the check_this_in value against the against_this_in value. This parameter +should be the certifiably correct value.
    null_ok_in TRUE if a NULL value should be interpreted +as a successful test, FALSE if NULL indicates failure.
    raise_exc_in TRUE if it is OK for the assertion routine +to allow an exception to be propagated out unhandled.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
    -msg_in - -A message -to be displayed if the assertion fails. This is the first argument and -is mandatory, because the tests need to be self documenting. -
    -check_this_in - -The value -to be checked.. If a Boolean expression, this will usually include the -invocation of the method being tested, resulting in a single line of code -for the entire test case. -
    -against_this_in - -For assert_eq, -the assertion routine will check the check_this_in value against the against_this_in -value. This parameter should be the certifiably correct value. -
    -null_ok_in - -TRUE if -a NULL value should be interpreted as a successful test, FALSE if NULL -indicates failure. -
    -raise_exc_in - -TRUE if -it is OK for the assertion routine to allow an exception to be propagated -out unhandled. -
    - -

    -Showing Results Immediately

    -You can request that utPLSQL display results immediately after running -the assertion program. The default behavior is that utAssert will simply -pass the results to utResult for later processing. You might want to see -results immediately if you are building your own small testing script and -are not calling utPLSQL.test. -

    To request results immediately, call the showResults procedure: -

       PROCEDURE utAssert.showresults;
    -This a session-level setting, and must be reset each time you connect to -Oracle. You can turn off showing of results by calling the noShowResults -program: + +

    Showing Results Immediately

    + You can request that utPLSQL display results immediately after running the +assertion program. The default behavior is that utAssert will simply pass +the results to utResult for later processing. You might want to see results +immediately if you are building your own small testing script and are not +calling utPLSQL.test. +

    To request results immediately, call the showResults procedure:

       PROCEDURE utAssert.showresults;
    + This a session-level setting, and must be reset each time you connect to +Oracle. You can turn off showing of results by calling the noShowResults program:
       PROCEDURE utAssert.noshowresults;
    -To determine the current status of this setting, you can call the following -function: -
       FUNCTION utAssert.showing_results return boolean;
    -Here is an example of a simple script that calls an assertion routine and -immediately shows the results: -
    set serveroutput on size 1000000
    -BEGIN
    -   utAssert.showresults;
    -   utAssert.eq (
    -      'Test of betwn',      
    -      str.betwn ('this is a string', 3, 7),      
    -      'this is a pipe'      );
    -END;
    -/
    -And here is the result of running this script: -
    FAILURE: "Unnamed Test"
    -: Test of betwn; expected "this is a pipe", got "is is"
    - -

    -Generic "Assert This" Assertion Procedure

    - -This most generic assertion program simply says -"assert this" and passes a Boolean expression. It is used by all the other -assertion routines, which construct a Boolean expression from their -specific values and logic. - -
       PROCEDURE utAssert.this (
    - -
          msg_in IN VARCHAR2,
    - -
          check_this_in IN BOOLEAN,
    - -
          null_ok_in IN BOOLEAN := FALSE,
    - -
          raise_exc_in IN BOOLEAN := FALSE
    - -
       );
    - -Use utAssert.this when you have a Boolean expression -that you want to check, as in:. - -
    BEGIN
    - -
       ...
    - -
       utAssert.this (
    - -
          'Boolean function result',
    - -
          is_valid_account (my_account)
    - -
          );
    - -You can also use this assertion to register a failure, -most usually in an exception section, as in: - -
    EXCEPTION
    - -
       WHEN OTHERS
    - -
       THEN
    -      utAssert.this (
    - -
             SQLERRM,
    - -
             FALSE);
    - -Generally, you should avoid utAssert.this and instead -use a specialized assertion routine, documented below. Most of the assertions -give you the ability check for equality (of scalars, such as strings, or -more complex data structures like tables, pipes and files): does the data -generated by my code match the expected value(s)? - -

    -Check for NULL and NOT NULL Values

    - -You can check to see if a value is NULL or is NOT -NULL with the following assertions: - -
    PROCEDURE utAssert.isnotnull (
    -   msg_in IN VARCHAR2,
    -   check_this_in IN VARCHAR2,
    -   null_ok_in IN BOOLEAN := FALSE,
    -   raise_exc_in IN BOOLEAN := FALSE
    -);
    -
    -PROCEDURE utAssert.isnull (
    -   msg_in IN VARCHAR2,
    -   check_this_in IN VARCHAR2,
    -   null_ok_in IN BOOLEAN := FALSE,
    -   raise_exc_in IN BOOLEAN := FALSE
    -);
    -
    -PROCEDURE utAssert.isnotnull (
    -   msg_in IN VARCHAR2,
    -   check_this_in IN BOOLEAN,
    -   null_ok_in IN BOOLEAN := FALSE,
    -   raise_exc_in IN BOOLEAN := FALSE
    -);
    -
    -PROCEDURE utAssert.isnull (
    -   msg_in IN VARCHAR2,
    -   check_this_in IN BOOLEAN,
    -
    -   null_ok_in IN BOOLEAN := FALSE,
    -   raise_exc_in IN BOOLEAN := FALSE
    -);
    - -Use these assertions when -you simply want to check if a scalar expression (string, date, number and -Boolean are supported) is NULL or NOT NULL, as in: - -
    -
    -
    BEGIN
    - -
       ...
    - -
       utAssert.isNULL (
    - -
          'Should be nothing left',
    - -
          TRANSLATE (digits_in_string, 'A1234567890', 'A')
    - -
          );
    - -

    -Check Equality of Scalar Values

    -If you need to compare two dates or two strings or two numbers or two Booleans, -use the utAssert.eq assertion program. - -

    Here is the header for the scalar equality check assertion: -

    PROCEDURE utAssert.eq (
    - -
       msg_in IN VARCHAR2,
    - -
       check_this_in IN VARCHAR2|BOOLEAN|DATE|NUMBER,
    - -
       against_this_in IN VARCHAR2|BOOLEAN|DATE|NUMBER,
    - -
       null_ok_in IN BOOLEAN := FALSE,
    - -
       raise_exc_in IN BOOLEAN := FALSE
    - -
    );
    - -If the two values are equal, your code gets a green -light. Otherwise, utAssert writes the test results to the utResult package, -resulting in a red light for the test. - -If NULL values are considered value for this test, -pass TRUE for null_ok_in. If you want the assertion to raise an exception -on failure and stop the test from proceeding, pass TRUE for raise_exc_in. - -Here is an example of using the utAssert.eq program: - -
       PROCEDURE ut_emp_dept_lookuprowcount
    -   IS
    - -
          l_rowcount1 PLS_INTEGER;
    -      l_rowcount2 PLS_INTEGER;
    -   BEGIN
    -      -- Run baseline code.
    -      SELECT COUNT (*)
    -        INTO l_rowcount1
    -        FROM employee
    -       WHERE department_id = 30;
    - -
     
    - -
          -- Compare to program call:
    -      l_rowcount2 :=
    -         te_employee.emp_dept_lookuprowcount (30);
    - -
     
    - -
          -- Test results
    -      utassert.eq (
    -         'Successful EMP_DEPT_LOOKUPROWCOUNT',
    -         l_rowcount2,
    -         l_rowcount1
    -      );
    -   END;
    - -

    -Check Equality of DatabaseTables

    - -If your test performs DML operations (update, insert -or delete), you will need to check your results in a database table. You -could do this by querying the results into local variables and then calling -utAssert.eq to check those values against your expected data. That can -be a very laborious process, so utAssert offers the eqtable and equerry -assertion routines to streamline the process. - -Both these procedures use the MINUS SQL operator -to essentially "subtract" the contents of one table (query) from the other. -If anything is left, then the two tables (queries) are not the same and -the test is given a red light. As you can probably see, the structure of -the two tables (queries) must be identical for this assertion to work properly. - -The utAssert.eqtable allows you to compare the contents -of your data table (changed by your code) against another table, which -you can preset with the data you expect to see after the test. Here is -the header for eqtable: - -
    PROCEDURE utAssert.eqtable (
    - -
       msg_in IN VARCHAR2,
    - -
       check_this_in IN VARCHAR2,
    - -
       against_this_in IN VARCHAR2,
    - -
       check_where_in IN VARCHAR2 := NULL,
    - -
       against_where_in IN VARCHAR2 := NULL,
    - -
       raise_exc_in IN BOOLEAN := FALSE
    - -
    );
    - -where check_this_in and against_this_in are the -names of tables or views. You can supply an optional WHERE clause to restrict -the rows you wish to compare. Here is an example that calls eqTable twice, -to test two different conditions. - -
    PROCEDURE ut_del1
    -IS
    -   fdbk PLS_INTEGER;
    -BEGIN
    -   /* Delete that finds now rows. */
    -
    -   EXECUTE IMMEDIATE '
    -   DELETE FROM ut_DEL1
    -    WHERE employee_id = -1
    -   ';
    -   te_employee.del (-1, rowcount_out => fdbk);
    - -
       -- Test results
    -   utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1');
    -   /* Successful delete */
    -
    -   EXECUTE IMMEDIATE '
    -      DELETE FROM ut_DEL1
    -       WHERE employee_id between 7800 and 7899
    -      ';
    -
    -   FOR rec IN (SELECT *
    -                 FROM employee
    -                WHERE employee_id BETWEEN 7800 AND 7899)
    -   LOOP
    -      te_employee.del (
    -         rec.employee_id,
    -         rowcount_out => fdbk
    -      );
    -   END LOOP;
    -
    -   -- Test results
    -   utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1');
    -   ROLLBACK;
    -EXCEPTION
    -   WHEN OTHERS
    -   THEN
    -      utassert.this (
    -         'DEL1 exception ' || SQLERRM,
    -         SQLCODE = 0
    -      );
    -END;
    - -

    -Check Equality of Table Counts

    -If your tests simply produce the right number of rows in a table but not -a fixed set of values, you will not be able to use utAssert.eqtable -above. However, utAssert.eqtabcount allows you to simply test that -the numbers of rows are equal. The declaration of the procedure is -as follows: -
    PROCEDURE utAssert.eqtabcount (
    - -
       msg_in IN VARCHAR2,
    - -
       check_this_in IN VARCHAR2,
    - -
       against_this_in IN VARCHAR2,
    - -
       check_where_in IN VARCHAR2 := NULL,
    - -
       against_where_in IN VARCHAR2 := NULL,
    - -
       raise_exc_in IN BOOLEAN := FALSE
    - -
    );
    - -where check_this_in and against_this_in are the -names of tables or views. As in utAssert.eqtable, you can supply an optional -WHERE clause to restrict the rows you wish to compare. The following test -will compare the number of rows in the CD_COLLECTION and UT_TEST_5_1 tables -where the given condition holds: -
    utassert.eqtabcount('Test 5.1: Insert new rows',
    - -
                        'CD_COLLECTION',
    - -
                        'UT_TEST_5_1',
    - -
                        'ARTIST = ''The Fall''',
    - -
                        'ARTIST = ''The Fall''');
    - - -

    -Asserting Query Equality

    - -The utAssert.eqquery allows you to compare the data -returned by two queries (strings that are contained in the check_this_in -and against_this_in parameters). In this case, you specify the full SELECT -statements for each query as the parameters. By using equery, you may be -able to avoid constructing a separate table with preset data. - -
    PROCEDURE utAssert.eqquery (
    - -
       msg_in IN VARCHAR2,
    - -
       check_this_in IN VARCHAR2,
    - -
       against_this_in IN VARCHAR2,
    - -
       raise_exc_in IN BOOLEAN := FALSE
    - -
    );
    - -If you want the assertion to raise an exception -on failure and stop the test from proceeding, pass TRUE for raise_exc_in. - -Here is an example of using eqQuery: - -
    PROCEDURE ut_upd1
    -IS
    -BEGIN
    -   /* Update 3 columns by ID */
    -
    -   EXECUTE IMMEDIATE '
    -   UPDATE ut_UPD1 SET
    -      FIRST_NAME = ''SILLY'',
    -      HIRE_DATE = trunc (SYSDATE+100),
    -      COMMISSION = 5000
    -    WHERE
    -       EMPLOYEE_ID = 7600
    -   ';
    -   te_employee.upd (
    -      7600,
    -      first_name_in => 'SILLY',
    -      commission_in => 5000,
    -      hire_date_in => TRUNC (SYSDATE + 100),
    -      rowcount_out => fdbk
    -   );
    -   -- Test results (audit fields are different so do a query)
    -   utassert.eqquery (
    -      'Update three columns',
    -      'select first_name, commission, hire_date from EMPLOYEE',
    -      'select first_name, commission, hire_date from ut_upd1'
    -   );
    -   ROLLBACK;
    -END;
    - -

    -Check Query Equality against a Single Value

    -Often we will wish to test the result of a query against a single value -rather than another query as in utAssert.eqquery -above. It is possible to get around this problem by using a trivial -query of the form: -
    SELECT fixed_value
    -FROM DUAL;
    -Unfortunately, if the query returns multiple values or the wrong value -we will only be told that the test has failed with no details. This -is where utAssert.eqqueryvalue comes to the rescue. The procedure -is declared as follows: -
    PROCEDURE utAssert.eqqueryvalue (
    - -
          msg_in IN VARCHAR2,
    - -
          check_query_in IN VARCHAR2,
    - -
          against_value_in IN VARCHAR2|NUMBER|DATE,
    - -
          raise_exc_in IN BOOLEAN := FALSE
    - -
    );
    -Where check_query_in is the query in question and against_value_in is the -value to check it against. If the query returns more than one value, -the resulting error message will tell you this. Similarly, if the -query returns the wrong value, the message will state the expected and -obtained values. The following call compares the maximum value found -in a table against a given number value: -
    utAssert.eqqueryvalue('Maximum value test',
    - -
                          'SELECT MAX(MEMORY)
    - -
                           FROM COMPUTERS
    - -
                           WHERE OS IN (''Linux'', ''Unix'')',
    - -
                           256);
    -Obviously this should only return a single value, but if it returns something -other than 256, we'll know about it. -

    -Check Equality of Files

    - -Many programs generate output to operating system -files; alternatively, you might write data to a file simply to test results. -Use the eqfile assertion for either of these scenarios. This procedure -uses PL/SQL's UTL_FILE package to compare the contents of two different -files. - -Note: If you have not used UTL_FILE in the past, -you must configure it before it can be -used -- by utPLSQL or by your own code. UTL_FILE must be allowed accss -to either or both of the directories you specify (this involves setting -the utl_file_dir database parameter). - -
    PROCEDURE utAssert.eqfile (
    - -
       msg_in IN VARCHAR2,
    - -
       check_this_in IN VARCHAR2,
    - -
       check_this_dir_in IN VARCHAR2,
    - -
       against_this_in IN VARCHAR2,
    - -
       against_this_dir_in IN VARCHAR2 := NULL,
    - -
       raise_exc_in IN BOOLEAN := FALSE
    - -
    );
    - -If you want the assertion to raise an exception -on failure and stop the test from proceeding, pass TRUE for raise_exc_in. - -You must specify the directory containing the "check -this" file; if you do not specify a directory for the "against this" file, -the "check this" directory will be used. - -Here is an example of using eqFile (see ut_DEPARTMENT2file.pkg -in the Examples directory for the full implementation): - -
    PROCEDURE ut_DEPARTMENT2FILE IS
    -BEGIN
    -   DEPARTMENT2FILE (
    -      LOC => 'c:\temp',
    -      FILE => 'department.dat',
    -      DELIM => '***'
    -    );
    -
    -   utAssert.eqfile (
    -      'Test of DEPARTMENT2FILE',
    -      'department.dat',
    -      'c:\temp',
    -      'department.tst',
    -      'c:\temp'
    -      );      
    -END ut_DEPARTMENT2FILE;
    - -

    -Check Equality of Database Pipes

    - -Database pipes offer a handy mechanism for passing -data between different sessions connected to the RDBMS. It is important -to know that pipes are being filled properly; use the eqpipe to check this -condition. - -With the eqpipe procedure, you compare the contents -of two different pipes. - -
    PROCEDURE utAssert.eqpipe (
    - -
       msg_in IN VARCHAR2,
    - -
       check_this_in IN VARCHAR2,
    - -
       against_this_in IN VARCHAR2,
    - -
       raise_exc_in IN BOOLEAN := FALSE
    - -
    );
    - -If you want the assertion to raise an exception -on failure and stop the test from proceeding, pass TRUE for raise_exc_in. - -To check the contents of a pipe based on the execution -of code, you will need to populate a pipe against which to test equality. -The employee_pipe.pkg file in the Examples directory contains a demonstration -of the kind of code you might write to do this. - -This package contains all of the unit test code -within the same package. Here is my unit test program, which relies on -the utAssert.eqpipe program: - -
    PROCEDURE ut_fillpipe IS
    -   stat PLS_INTEGER;
    -BEGIN
    -   emptypipe ('emps');
    -   emptypipe ('emps2');
    -   
    -   fillpipe ('emps');
    -   
    -   /* Direct filling of pipe. */
    + To determine the current status of this setting, you can call the following 
    +function: 
       FUNCTION utAssert.showing_results return boolean;
    + Here is an example of a simple script that calls an assertion routine and +immediately shows the results:
    set serveroutput on size 1000000
    BEGIN
    utAssert.showresults;
    utAssert.eq (
    'Test of betwn',
    str.betwn ('this is a string', 3, 7),
    'this is a pipe' );
    END;
    /
    + And here is the result of running this script:
    FAILURE: "Unnamed Test"
    : Test of betwn; expected "this is a pipe", got "is is"
    +

    +

    Generic "Assert This" Assertion Procedure

    + This most generic assertion program simply says "assert this" and passes +a Boolean expression. It is used by all the other assertion routines, which +construct a Boolean expression from their specific values and logic. +
       PROCEDURE utAssert.this (
    +
          msg_in IN VARCHAR2,
    +
          check_this_in IN BOOLEAN,
    +
          null_ok_in IN BOOLEAN := FALSE,
    +
          raise_exc_in IN BOOLEAN := FALSE
    +
       );
    + Use utAssert.this when you have a Boolean expression that you want to check, +as in:.
    BEGIN
    +
       ...
    +
       utAssert.this (
    +
          'Boolean function result',
    +
          is_valid_account (my_account)
    +
          );
    + You can also use this assertion to register a failure, most usually in +an exception section, as in:
    EXCEPTION
    +
       WHEN OTHERS
    +
       THEN
    utAssert.this (
    +
             SQLERRM,
    +
             FALSE);
    + Generally, you should avoid utAssert.this and instead use a specialized +assertion routine, documented below. Most of the assertions give you the +ability check for equality (of scalars, such as strings, or more complex +data structures like tables, pipes and files): does the data generated by +my code match the expected value(s)? +

    Check for NULL and NOT NULL Values

    + You can check to see if a value is NULL or is NOT NULL with the following +assertions:
    PROCEDURE utAssert.isnotnull (
    msg_in IN VARCHAR2,
    check_this_in IN VARCHAR2,
    null_ok_in IN BOOLEAN := FALSE,
    raise_exc_in IN BOOLEAN := FALSE
    );

    PROCEDURE utAssert.isnull (
    msg_in IN VARCHAR2,
    check_this_in IN VARCHAR2,
    null_ok_in IN BOOLEAN := FALSE,
    raise_exc_in IN BOOLEAN := FALSE
    );

    PROCEDURE utAssert.isnotnull (
    msg_in IN VARCHAR2,
    check_this_in IN BOOLEAN,
    null_ok_in IN BOOLEAN := FALSE,
    raise_exc_in IN BOOLEAN := FALSE
    );

    PROCEDURE utAssert.isnull (
    msg_in IN VARCHAR2,
    check_this_in IN BOOLEAN,

    null_ok_in IN BOOLEAN := FALSE,
    raise_exc_in IN BOOLEAN := FALSE
    );
    + Use these assertions when you simply want to check if a scalar expression +(string, date, number and Boolean are supported) is NULL or NOT NULL, as +in:
    +
    +
    BEGIN
    +
       ...
    +
       utAssert.isNULL (
    +
          'Should be nothing left',
    +
          TRANSLATE (digits_in_string, 'A1234567890', 'A')
    +
          );
    + +

    Check Equality of Scalar Values

    + If you need to compare two dates or two strings or two numbers or two Booleans, +use the utAssert.eq assertion program. +

    Here is the header for the scalar equality check assertion:

    PROCEDURE utAssert.eq (
    +
       msg_in IN VARCHAR2,
    +
       check_this_in IN VARCHAR2|BOOLEAN|DATE|NUMBER,
    +
       against_this_in IN VARCHAR2|BOOLEAN|DATE|NUMBER,
    +
       null_ok_in IN BOOLEAN := FALSE,
    +
       raise_exc_in IN BOOLEAN := FALSE
    +
    );
    + If the two values are equal, your code gets a green light. Otherwise, utAssert +writes the test results to the utResult package, resulting in a red light +for the test. If NULL values are considered value for this test, pass TRUE +for null_ok_in. If you want the assertion to raise an exception on failure +and stop the test from proceeding, pass TRUE for raise_exc_in. Here is an +example of using the utAssert.eq program:
       PROCEDURE ut_emp_dept_lookuprowcount
    IS
    +
          l_rowcount1 PLS_INTEGER;
    l_rowcount2 PLS_INTEGER;
    BEGIN
    -- Run baseline code.
    SELECT COUNT (*)
    INTO l_rowcount1
    FROM employee
    WHERE department_id = 30;
    +
     
    +
          -- Compare to program call:
    l_rowcount2 :=
    te_employee.emp_dept_lookuprowcount (30);
    +
     
    +
          -- Test results
    utassert.eq (
    'Successful EMP_DEPT_LOOKUPROWCOUNT',
    l_rowcount2,
    l_rowcount1
    );
    END;
    +

    +

    Check Equality of DatabaseTables

    + If your test performs DML operations (update, insert or delete), you will +need to check your results in a database table. You could do this by querying +the results into local variables and then calling utAssert.eq to check those +values against your expected data. That can be a very laborious process, +so utAssert offers the eqtable and equerry assertion routines to streamline +the process. Both these procedures use the MINUS SQL operator to essentially +"subtract" the contents of one table (query) from the other. If anything +is left, then the two tables (queries) are not the same and the test is given +a red light. As you can probably see, the structure of the two tables (queries) +must be identical for this assertion to work properly. The utAssert.eqtable +allows you to compare the contents of your data table (changed by your code) +against another table, which you can preset with the data you expect to see +after the test. Here is the header for eqtable:
    PROCEDURE utAssert.eqtable (
    +
       msg_in IN VARCHAR2,
    +
       check_this_in IN VARCHAR2,
    +
       against_this_in IN VARCHAR2,
    +
       check_where_in IN VARCHAR2 := NULL,
    +
       against_where_in IN VARCHAR2 := NULL,
    +
       raise_exc_in IN BOOLEAN := FALSE
    +
    );
    + where check_this_in and against_this_in are the names of tables or views. +You can supply an optional WHERE clause to restrict the rows you wish to +compare. Here is an example that calls eqTable twice, to test two different +conditions.
    PROCEDURE ut_del1
    IS
    fdbk PLS_INTEGER;
    BEGIN
    /* Delete that finds now rows. */

    EXECUTE IMMEDIATE '
    DELETE FROM ut_DEL1
    WHERE employee_id = -1
    ';
    te_employee.del (-1, rowcount_out => fdbk);
    +
       -- Test results
    utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1');
    /* Successful delete */

    EXECUTE IMMEDIATE '
    DELETE FROM ut_DEL1
    WHERE employee_id between 7800 and 7899
    ';

    FOR rec IN (SELECT *
    FROM employee
    WHERE employee_id BETWEEN 7800 AND 7899)
    LOOP
    te_employee.del (
    rec.employee_id,
    rowcount_out => fdbk
    );
    END LOOP;

    -- Test results
    utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1');
    ROLLBACK;
    EXCEPTION
    WHEN OTHERS
    THEN
    utassert.this (
    'DEL1 exception ' || SQLERRM,
    SQLCODE = 0
    );
    END;
    + +

    Check Equality of Table Counts

    + If your tests simply produce the right number of rows in a table but not +a fixed set of values, you will not be able to use +utAssert.eqtable above. However, utAssert.eqtabcount allows you to simply +test that the numbers of rows are equal. The declaration of the procedure +is as follows:
    PROCEDURE utAssert.eqtabcount (
    +
       msg_in IN VARCHAR2,
    +
       check_this_in IN VARCHAR2,
    +
       against_this_in IN VARCHAR2,
    +
       check_where_in IN VARCHAR2 := NULL,
    +
       against_where_in IN VARCHAR2 := NULL,
    +
       raise_exc_in IN BOOLEAN := FALSE
    +
    );
    + where check_this_in and against_this_in are the names of tables or views. +As in utAssert.eqtable, you can supply an optional WHERE clause to restrict +the rows you wish to compare. The following test will compare the number +of rows in the CD_COLLECTION and UT_TEST_5_1 tables where the given condition +holds:
    utassert.eqtabcount('Test 5.1: Insert new rows',
    +
                        'CD_COLLECTION',
    +
                        'UT_TEST_5_1',
    +
                        'ARTIST = ''The Fall''',
    +
                        'ARTIST = ''The Fall''');
    - FOR rec IN (SELECT * - FROM employee) - LOOP - DBMS_PIPE.RESET_BUFFER; - DBMS_PIPE.PACK_MESSAGE (rec.EMPLOYEE_ID); - DBMS_PIPE.PACK_MESSAGE (rec.LAST_NAME); - DBMS_PIPE.PACK_MESSAGE (rec.FIRST_NAME); - DBMS_PIPE.PACK_MESSAGE (rec.MIDDLE_INITIAL); - DBMS_PIPE.PACK_MESSAGE (rec.JOB_ID); - DBMS_PIPE.PACK_MESSAGE (rec.MANAGER_ID); - DBMS_PIPE.PACK_MESSAGE (rec.HIRE_DATE); - DBMS_PIPE.PACK_MESSAGE (rec.SALARY); - DBMS_PIPE.PACK_MESSAGE (rec.COMMISSION); - DBMS_PIPE.PACK_MESSAGE (rec.DEPARTMENT_ID); - DBMS_PIPE.PACK_MESSAGE (rec.CHANGED_BY); - DBMS_PIPE.PACK_MESSAGE (rec.CHANGED_ON); - - stat := DBMS_PIPE.SEND_MESSAGE ('emps2', 0); - END LOOP; - - /* Compare the two */ - utassert.eqpipe ( - 'Two employee pipes', 'emps', 'emps2'); - -END ut_fillpipe;
    - -Since I have stored my unit -test logic with my source code package, I would run my test as follows: - -
    SQL> exec utplsql.test ('employee_pipe', samepackage_in=>TRUE)
    -FAILURE: "employee_pipe"
    -fillpipe: Pipes equal? Compared "emps" against "emps2"
    - -

    -Check Equality of Collections

    - -Collections are as close as you come to arrays in -PL/SQL. They are very useful for managing lists of information, but can -be difficult to debug and maintain. - -With the eqcoll and eqcollAPI procedures, you can -compare the contents of two different arrays. Use the eqColl procedure -when you want to compare two collections that are defined in the specification -of a package. Use the eqCollAPI procedure when you want to compare two -collections that are defined in the body of a package, with programs defined -in the specification (an API) to access and manipulate the collections. - -The collection equality check headers are: - -
       /* Direct access to collections */
    - -
       PROCEDURE utAssert.eqcoll (
    - -
          msg_in IN VARCHAR2,
    - -
          check_this_in IN VARCHAR2, /* pkg1.coll */
    - -
          against_this_in IN VARCHAR2, /* pkg2.coll */
    - -
          eqfunc_in IN VARCHAR2 := NULL,
    - -
          check_startrow_in IN PLS_INTEGER := NULL,
    - -
          check_endrow_in IN PLS_INTEGER := NULL,
    - -
          against_startrow_in IN PLS_INTEGER := NULL,
    - -
          against_endrow_in IN PLS_INTEGER := NULL,
    - -
          match_rownum_in IN BOOLEAN := FALSE,
    - -
          null_ok_in IN BOOLEAN := TRUE,
    - -
          raise_exc_in IN BOOLEAN := FALSE
    - -
       );
    - -
      
    - -
       /* API based access to collections */
    - -
       PROCEDURE utAssert.eqcollapi (
    - -
          msg_in IN VARCHAR2,
    - -
          check_this_pkg_in IN VARCHAR2,
    - -
          against_this_pkg_in IN VARCHAR2,
    - -
          eqfunc_in IN VARCHAR2 := NULL,
    - -
          countfunc_in IN VARCHAR2 := 'COUNT',
    - -
          firstrowfunc_in IN VARCHAR2 := 'FIRST',
    - -
          lastrowfunc_in IN VARCHAR2 := 'LAST',
    - -
          nextrowfunc_in IN VARCHAR2 := 'NEXT',
    - -
          getvalfunc_in IN VARCHAR2 := 'NTHVAL',
    - -
          check_startrow_in IN PLS_INTEGER := NULL,
    - -
          check_endrow_in IN PLS_INTEGER := NULL,
    - -
          against_startrow_in IN PLS_INTEGER := NULL,
    - -
          against_endrow_in IN PLS_INTEGER := NULL,
    - -
          match_rownum_in IN BOOLEAN := FALSE,
    - -
          null_ok_in IN BOOLEAN := TRUE,
    - -
          raise_exc_in IN BOOLEAN := FALSE
    - -
       );
    - -where the eqcoll-specific parameters are as follows: - - - - - - - - - - - - - - - - - - - - - - - -
    ParameterDescription
    -msg_in - -The message to be displayed if the test failes -
    -check_this_in - -The name of the collection to be checked. Format: -package.collection. In other words, the collection must be defined in a -package specification. Use eqCollAPI (and check_this_pkg_in) if you want -to hide the declaration of your collection in your package body (recommended). -
    -against_this_in - -The name of the collection to be checked against. +

    Asserting Query Equality

    + The utAssert.eqquery allows you to compare the data returned by two queries +(strings that are contained in the check_this_in and against_this_in parameters). +In this case, you specify the full SELECT statements for each query as the +parameters. By using equery, you may be able to avoid constructing a separate +table with preset data.
    PROCEDURE utAssert.eqquery (
    +
       msg_in IN VARCHAR2,
    +
       check_this_in IN VARCHAR2,
    +
       against_this_in IN VARCHAR2,
    +
       raise_exc_in IN BOOLEAN := FALSE
    +
    );
    + If you want the assertion to raise an exception on failure and stop the +test from proceeding, pass TRUE for raise_exc_in. Here is an example of +using eqQuery:
    PROCEDURE ut_upd1
    IS
    BEGIN
    /* Update 3 columns by ID */

    EXECUTE IMMEDIATE '
    UPDATE ut_UPD1 SET
    FIRST_NAME = ''SILLY'',
    HIRE_DATE = trunc (SYSDATE+100),
    COMMISSION = 5000
    WHERE
    EMPLOYEE_ID = 7600
    ';
    te_employee.upd (
    7600,
    first_name_in => 'SILLY',
    commission_in => 5000,
    hire_date_in => TRUNC (SYSDATE + 100),
    rowcount_out => fdbk
    );
    -- Test results (audit fields are different so do a query)
    utassert.eqquery (
    'Update three columns',
    'select first_name, commission, hire_date from EMPLOYEE',
    'select first_name, commission, hire_date from ut_upd1'
    );
    ROLLBACK;
    END;
    + +

    Check Query Equality against a Single Value

    + Often we will wish to test the result of a query against a single value rather +than another query as in utAssert.eqquery above. +It is possible to get around this problem by using a trivial query of the +form:
    SELECT fixed_value
    FROM DUAL;
    + Unfortunately, if the query returns multiple values or the wrong value we +will only be told that the test has failed with no details. This is where +utAssert.eqqueryvalue comes to the rescue. The procedure is declared as +follows:
    PROCEDURE utAssert.eqqueryvalue (
    +
          msg_in IN VARCHAR2,
    +
          check_query_in IN VARCHAR2,
    +
          against_value_in IN VARCHAR2|NUMBER|DATE,
    +
          raise_exc_in IN BOOLEAN := FALSE
    +
    );
    + Where check_query_in is the query in question and against_value_in is the +value to check it against. If the query returns more than one value, the +resulting error message will tell you this. Similarly, if the query returns +the wrong value, the message will state the expected and obtained values. + The following call compares the maximum value found in a table against a +given number value:
    utAssert.eqqueryvalue('Maximum value test',
    +
                          'SELECT MAX(MEMORY)
    +
                           FROM COMPUTERS
    +
                           WHERE OS IN (''Linux'', ''Unix'')',
    +
                           256);
    + Obviously this should only return a single value, but if it returns something +other than 256, we'll know about it. +

    Check Equality of Files

    + Many programs generate output to operating system files; alternatively, +you might write data to a file simply to test results. Use the eqfile assertion +for either of these scenarios. This procedure uses PL/SQL's UTL_FILE package +to compare the contents of two different files. Note: If you have not used +UTL_FILE in the past, you must configure + it before it can be used -- by utPLSQL or by your own code. UTL_FILE must +be allowed accss to either or both of the directories you specify (this involves +setting the utl_file_dir database parameter).
    PROCEDURE utAssert.eqfile (
    +
       msg_in IN VARCHAR2,
    +
       check_this_in IN VARCHAR2,
    +
       check_this_dir_in IN VARCHAR2,
    +
       against_this_in IN VARCHAR2,
    +
       against_this_dir_in IN VARCHAR2 := NULL,
    +
       raise_exc_in IN BOOLEAN := FALSE
    +
    );
    + If you want the assertion to raise an exception on failure and stop the +test from proceeding, pass TRUE for raise_exc_in. You must specify the directory +containing the "check this" file; if you do not specify a directory for the +"against this" file, the "check this" directory will be used. Here is an +example of using eqFile (see ut_DEPARTMENT2file.pkg in the Examples directory +for the full implementation):
    PROCEDURE ut_DEPARTMENT2FILE IS
    BEGIN
    DEPARTMENT2FILE (
    LOC => 'c:\temp',
    FILE => 'department.dat',
    DELIM => '***'
    );

    utAssert.eqfile (
    'Test of DEPARTMENT2FILE',
    'department.dat',
    'c:\temp',
    'department.tst',
    'c:\temp'
    );
    END ut_DEPARTMENT2FILE;
    + +

    Check Equality of Database Pipes

    + Database pipes offer a handy mechanism for passing data between different +sessions connected to the RDBMS. It is important to know that pipes are being +filled properly; use the eqpipe to check this condition. With the eqpipe +procedure, you compare the contents of two different pipes.
    PROCEDURE utAssert.eqpipe (
    +
       msg_in IN VARCHAR2,
    +
       check_this_in IN VARCHAR2,
    +
       against_this_in IN VARCHAR2,
    +
       raise_exc_in IN BOOLEAN := FALSE
    +
    );
    + If you want the assertion to raise an exception on failure and stop the +test from proceeding, pass TRUE for raise_exc_in. To check the contents +of a pipe based on the execution of code, you will need to populate a pipe +against which to test equality. The employee_pipe.pkg file in the Examples +directory contains a demonstration of the kind of code you might write to +do this. This package contains all of the unit test code within the same +package. Here is my unit test program, which relies on the utAssert.eqpipe +program:
    PROCEDURE ut_fillpipe IS
    stat PLS_INTEGER;
    BEGIN
    emptypipe ('emps');
    emptypipe ('emps2');

    fillpipe ('emps');

    /* Direct filling of pipe. */

    FOR rec IN (SELECT *
    FROM employee)
    LOOP
    DBMS_PIPE.RESET_BUFFER;
    DBMS_PIPE.PACK_MESSAGE (rec.EMPLOYEE_ID);
    DBMS_PIPE.PACK_MESSAGE (rec.LAST_NAME);
    DBMS_PIPE.PACK_MESSAGE (rec.FIRST_NAME);
    DBMS_PIPE.PACK_MESSAGE (rec.MIDDLE_INITIAL);
    DBMS_PIPE.PACK_MESSAGE (rec.JOB_ID);
    DBMS_PIPE.PACK_MESSAGE (rec.MANAGER_ID);
    DBMS_PIPE.PACK_MESSAGE (rec.HIRE_DATE);
    DBMS_PIPE.PACK_MESSAGE (rec.SALARY);
    DBMS_PIPE.PACK_MESSAGE (rec.COMMISSION);
    DBMS_PIPE.PACK_MESSAGE (rec.DEPARTMENT_ID);
    DBMS_PIPE.PACK_MESSAGE (rec.CHANGED_BY);
    DBMS_PIPE.PACK_MESSAGE (rec.CHANGED_ON);

    stat := DBMS_PIPE.SEND_MESSAGE ('emps2', 0);
    END LOOP;

    /* Compare the two */
    utassert.eqpipe (
    'Two employee pipes', 'emps', 'emps2');

    END ut_fillpipe;
    + Since I have stored my unit test logic with my source code package, I would +run my test as follows:
    SQL> exec utplsql.test ('employee_pipe', samepackage_in=>TRUE)
    FAILURE: "employee_pipe"
    fillpipe: Pipes equal? Compared "emps" against "emps2"
    + +

    Check Equality of Collections

    + Collections are as close as you come to arrays in PL/SQL. They are very +useful for managing lists of information, but can be difficult to debug and +maintain. With the eqcoll and eqcollAPI procedures, you can compare the +contents of two different arrays. Use the eqColl procedure when you want +to compare two collections that are defined in the specification of a package. +Use the eqCollAPI procedure when you want to compare two collections that +are defined in the body of a package, with programs defined in the specification +(an API) to access and manipulate the collections. The collection equality +check headers are:
       /* Direct access to collections */
    +
       PROCEDURE utAssert.eqcoll (
    +
          msg_in IN VARCHAR2,
    +
          check_this_in IN VARCHAR2, /* pkg1.coll */
    +
          against_this_in IN VARCHAR2, /* pkg2.coll */
    +
          eqfunc_in IN VARCHAR2 := NULL,
    +
          check_startrow_in IN PLS_INTEGER := NULL,
    +
          check_endrow_in IN PLS_INTEGER := NULL,
    +
          against_startrow_in IN PLS_INTEGER := NULL,
    +
          against_endrow_in IN PLS_INTEGER := NULL,
    +
          match_rownum_in IN BOOLEAN := FALSE,
    +
          null_ok_in IN BOOLEAN := TRUE,
    +
          raise_exc_in IN BOOLEAN := FALSE
    +
       );
    +
      
    +
       /* API based access to collections */
    +
       PROCEDURE utAssert.eqcollapi (
    +
          msg_in IN VARCHAR2,
    +
          check_this_pkg_in IN VARCHAR2,
    +
          against_this_pkg_in IN VARCHAR2,
    +
          eqfunc_in IN VARCHAR2 := NULL,
    +
          countfunc_in IN VARCHAR2 := 'COUNT',
    +
          firstrowfunc_in IN VARCHAR2 := 'FIRST',
    +
          lastrowfunc_in IN VARCHAR2 := 'LAST',
    +
          nextrowfunc_in IN VARCHAR2 := 'NEXT',
    +
          getvalfunc_in IN VARCHAR2 := 'NTHVAL',
    +
          check_startrow_in IN PLS_INTEGER := NULL,
    +
          check_endrow_in IN PLS_INTEGER := NULL,
    +
          against_startrow_in IN PLS_INTEGER := NULL,
    +
          against_endrow_in IN PLS_INTEGER := NULL,
    +
          match_rownum_in IN BOOLEAN := FALSE,
    +
          null_ok_in IN BOOLEAN := TRUE,
    +
          raise_exc_in IN BOOLEAN := FALSE
    +
       );
    + where the eqcoll-specific parameters are as follows: + + + + + + + + + + + + + - +want to hide the declaration of your collection in your package body (recommended). + + + + + + + +
    ParameterDescription
    msg_in The message to be displayed if the test failes +
    check_this_in The name of the collection to be checked. Format: package.collection. In other words, the collection must be defined in a package specification. Use eqCollAPI (and check_this_pkg_in) if you -want to hide the declaration of your collection in your package body (recommended). -
    against_this_in The name of the collection to be checked +against. Format: package.collection. In other words, the collection must +be defined in a package specification. Use eqCollAPI (and check_this_pkg_in) +if you want to hide the declaration of your collection in your package body +(recommended).
    - - -

    and the eqcollAPI-specific parameters are as follows: -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +

    and the eqcollAPI-specific parameters are as follows:
    + +

    ParameterDescription
    -msg_in - -The message to be displayed if the test failes -
    -check_this_pkg_in - -The name of the package that contains the collection -to be checked. -
    -against_this_pkg_in - -The name of the package that contains the collection -to be checked against. -
    -countfunc_in - -The name of the function in the package that returns -the number of rows defined in the collection. -
    -firstrowfunc_in - -The name of the function in the package that returns -the first definedrow in the collection. -
    -lastrowfunc_in - -The name of the function in the package that returns -the last definedrow in the collection. -
    -nextrowfunc_in - -The name of the function in the package that returns -the next definedrow in the collection -from the specified row. -
    -getvalfunc_in - -The name of the function in the package that returns -the contents of the specified row. -
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ParameterDescription
    msg_in The message to be displayed if the test failes +
    check_this_pkg_in The name of the package that contains the +collection to be checked.
    against_this_pkg_in The name of the package that contains the +collection to be checked against.
    countfunc_in The name of the function in the package that +returns the number of rows defined in the collection.
    firstrowfunc_in The name of the function in the package that +returns the first definedrow in the collection.
    lastrowfunc_in The name of the function in the package that +returns the last definedrow in the collection.
    nextrowfunc_in The name of the function in the package that +returns the next definedrow in the collection from the specified row.
    getvalfunc_in The name of the function in the package that +returns the contents of the specified row.
    - - -

    The parameters common to both eqColl and eqCollAPI -are as follows -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +

    +

    The parameters common to both eqColl and eqCollAPI are as follows
    + +

    ParameterDescription
    -eqfunc_in - -The function used to determine if the contents of -each row of the two collections are the same. If you pass NULL for this -argument, then a standard equality check will be used. This is fine for -scalar values, but will not work, for example, with tables of records. -
    -check_startrow_in - -The starting row in the check collection for comparison. -If NULL, then first row is used. -
    -check_endrow_in - -The ending row in the check collection for comparison. -If NULL, then last row is used. -
    -against_startrow_in - -The starting row in the against collection for comparison. -If NULL, then first row is used. -
    -against_endrow_in - -The ending row in the against collection for comparison. -If NULL, then last row is used. -
    -match_rownum_in - -Pass TRUE if you want to make sure that the same -row numbers are used in each collection. If FALSE, then the row numbers -can be different, but the contents of each corresponding row must be the -same. -
    -null_ok_in - -Pass TRUE if the assertion routine should consider -two NULL collections to be equal. -
    -raise_exc_in - -If you want the assertion to raise an exception -on failure and stop the test from proceeding, pass TRUE for raise_exc_in. -
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ParameterDescription
    eqfunc_in The function used to determine if the contents +of each row of the two collections are the same. If you pass NULL for this +argument, then a standard equality check will be used. This is fine for scalar +values, but will not work, for example, with tables of records.
    check_startrow_in The starting row in the check collection +for comparison. If NULL, then first row is used.
    check_endrow_in The ending row in the check collection for +comparison. If NULL, then last row is used.
    against_startrow_in The starting row in the against collection +for comparison. If NULL, then first row is used.
    against_endrow_in The ending row in the against collection +for comparison. If NULL, then last row is used.
    match_rownum_in Pass TRUE if you want to make sure that the +same row numbers are used in each collection. If FALSE, then the row numbers +can be different, but the contents of each corresponding row must be the same. +
    null_ok_in Pass TRUE if the assertion routine should +consider two NULL collections to be equal.
    raise_exc_in If you want the assertion to raise an exception +on failure and stop the test from proceeding, pass TRUE for raise_exc_in. +
    - - -

    Here is an example of a script that uses utAssert.eqColl -(taken from filepath1.pkg in the Examples directory): -

    PROCEDURE ut_setpath
    -IS
    +   

    +

    Here is an example of a script that uses utAssert.eqColl (taken from filepath1.pkg +in the Examples directory):

    PROCEDURE ut_setpath
    IS
    BEGIN
    /* Populate base collection */
    ut_dirs.DELETE;
    ut_dirs.EXTEND(2);
    ut_dirs(1) := 'c:\temp';
    ut_dirs(2) := 'e:\demo';

    /* Call setpath to do the work */
    setpath ('c:\temp;e:\demo');

    utAssert.eqColl (
    'Valid double entry',
    'fileio.dirs',
    'fileio.ut_dirs'
    );
    END;
    +

    +

    Checking a Procedure or Function throws an exception

    + Sometimes we design a procedure or function to throw an exception under certain +circumstances. This is something we'd like to be able to test for. Obviously +this is not particularly easy due to the way exceptions propagate through +the call stack. If we simply call the procedure in our test code, the exception +will have no chance of being caught within the utAssert package! Therefore, +we need to pass the tested call in to the package as a string. The procedure +utAssert.throws allows us to do this:
    PROCEDURE throws (
    +
          msg_in VARCHAR2,
    +
          check_call_in IN VARCHAR2,
    +
          against_exc_in IN VARCHAR2|NUMBER
    +
       );
    + Where check_call_in is the call to be made, complete with parameters and +terminating semicolon. The argument against_exc_in is the exception we expect +to be thrown. This can be specified either as a named exception, or a SQLCODE +value. +

    The following example shows both usages:

    /* Test the Except Function */
    PROCEDURE ut_except
    IS
    BEGIN

    /* Call the procedure with a negative number */
    /* We expect a NO_DATA_FOUND exception */
    utAssert.throws('Negative Number',
    'Except(-1);',
    'NO_DATA_FOUND'
    );

    /* Call the procedure with zero and a string */
    /* over 2 in length - We expect a SQLCODE of -1 */
    utAssert.throws('Zero and String',
    'Except(0, ''Hello'');',
    -1
    );
    END;
    + Note how we have to quote the string parameters to the call and terminate +the string with a semicolon.
    +

    +

    Check if the Previous Assertion Passed or Failed

    +Sometimes, a procedure may have a large number of effects that need to be +tested.  For example, it might insert and update data in a series of +tables.  To test all of these changes, it will be necessary to make +a series of calls to utAssert.  This can have the effect that if the +procedure is not behaving as expected, then the user is presented with a +screenful of errors.  To avoid this and just present them with a single +error, the functions previous_passed and previous_failed can be used.  +These return a BOOLEAN argument giving the success or failure of the previously +called assertion. 
    +
    +The following example gives a demonstration:
    +
    /* Test the BookTrips Procedure */
    +PROCEDURE ut_bookTrips
    +IS 
     BEGIN
    -   /* Populate base collection */
    -   ut_dirs.DELETE;
    -   ut_dirs.EXTEND(2);
    -   ut_dirs(1) := 'c:\temp';
    -   ut_dirs(2) := 'e:\demo';
    -   
    -   /* Call setpath to do the work */
    -   setpath ('c:\temp;e:\demo');
    -   
    -   utAssert.eqColl (
    -      'Valid double entry',
    -      'fileio.dirs',
    -      'fileio.ut_dirs'
    -      );
    -END;
    -

    -Checking a Procedure or Function throws an exception

    -Sometimes we design a procedure or function to throw an exception under -certain circumstances. This is something we'd like to be able to -test for. Obviously this is not particularly easy due to the way -exceptions propagate through the call stack. If we simply call the -procedure in our test code, the exception will have no chance of being -caught within the utAssert package! Therefore, we need to pass the -tested call in to the package as a string. The procedure utAssert.throws -allows us to do this: -
    PROCEDURE throws (
    - -
          msg_in VARCHAR2,
    - -
          check_call_in IN VARCHAR2,
    - -
          against_exc_in IN VARCHAR2|NUMBER
    - -
       );
    -Where check_call_in is the call to be made, complete with parameters and -terminating semicolon. The argument against_exc_in is the exception -we expect to be thrown. This can be specified either as a named exception, -or a SQLCODE value. -

    The following example shows both usages: -

    /* Test the Except Function */
    -PROCEDURE ut_except
    -IS
    -BEGIN
    -
    -   /* Call the procedure with a negative number */
    -   /* We expect a NO_DATA_FOUND exception       */
    -   utAssert.throws('Negative Number',
    -      'Except(-1);',
    -      'NO_DATA_FOUND'
    -   );
    +  /* Call the procedure */
    +  Vacation.bookTrips(5, 'Rio de Janeiro');
    +  
    +  /* Did it insert 5 rows into TRIPS table */
    +  utAssert.eqqueryvalue('Insert 5 rows',
    +    'SELECT COUNT(*)
    +    FROM TRIPS
    +    WHERE CITY = 'Rio de Janeiro',
    +    5);
    +    
    +  /* If that worked, look in more detail */
    +  IF utAssert.previous_passed THEN
    +    
    +    /* Do they all have today's date? */
    +    utAssert.eqqueryvalue('All with todays date',
    +      'SELECT COUNT(*)
    +       FROM TRIPS
    +       WHERE CITY = 'Rio de Janeiro'
    +       AND TRUNC(CREATED) = TRUNC(SYSDATE)',
    +       5);
    +     
    +    /* Do they all have a hotel specified? */
    +    utAssert.eqqueryvalue('Hotel Specfied',
    +      'SELECT COUNT(*)
    +       FROM TRIPS T, HOTELS H
    +       WHERE T.CITY = 'Rio de Janeiro'
    +       AND T.HOTEL = H.ID',
    +       5);
    +     
    + END IF;
        
    -   /* Call the procedure with zero and a string    */
    -   /* over 2 in length - We expect a SQLCODE of -1 */  
    -   utAssert.throws('Zero and String',
    -      'Except(0, ''Hello'');',
    -      -1
    -     );
     END;
    - -Note how we have to quote -the string parameters to the call and terminate the string with a semicolon. - -

    -Building Your Own Assertion

    - -You may want to build assertion routines that fit -your specific needs. If PL/SQL supported inheritance, you could extend -the utAssert assertion routines and then customize them through polymorphism. -Lacking this feature, however, you will write your own procedures that -follow the same steps as the pre-build assertions. - -In order to integrate the results of your assertion -test into the utResult package, you will want to mimic the utAssert.this -procedure. Here is its current implementation (Release 1.3.2); check the -body of the utAssert package for any changes. - -
    PROCEDURE this (
    -   msg_in IN VARCHAR2,
    -   check_this_in IN BOOLEAN,
    -   null_ok_in IN BOOLEAN := FALSE,
    -   raise_exc_in IN BOOLEAN := FALSE,
    -   register_in IN BOOLEAN := TRUE
    -   )
    -IS
    -BEGIN
    -   IF    NOT check_this_in
    -      OR (    check_this_in IS NULL
    -          AND NOT null_ok_in)
    -   THEN
    -      IF register_in
    -      THEN
    - -
             -- Registers the results in the utResult databank.
    -         utresult.report (msg_in);
    -      ELSE
    -         utplsql.pl (msg_in);
    -      END IF;
    -      
    -      IF showing_results AND register_in
    -      THEN
    - -
             -- Show the results of the test more recently run.
    -         utresult.showlast;
    -      END IF;
    -
    -      IF raise_exc_in
    -      THEN
    -         RAISE test_failure;
    -      END IF;
    -   END IF;
    -END;
    - -The most important statement to include in your -assertion routine is the call to utResult.report, which will log the results -of the test. - - +

    +

    Building Your Own Assertion

    + You may want to build assertion routines that fit your specific needs. +If PL/SQL supported inheritance, you could extend the utAssert assertion +routines and then customize them through polymorphism. Lacking this feature, +however, you will write your own procedures that follow the same steps as +the pre-build assertions. In order to integrate the results of your assertion +test into the utResult package, you will want to mimic the utAssert.this procedure. +Here is its current implementation (Release 1.3.2); check the body of the +utAssert package for any changes.
    PROCEDURE this (
    msg_in IN VARCHAR2,
    check_this_in IN BOOLEAN,
    null_ok_in IN BOOLEAN := FALSE,
    raise_exc_in IN BOOLEAN := FALSE,
    register_in IN BOOLEAN := TRUE
    )
    IS
    BEGIN
    IF NOT check_this_in
    OR ( check_this_in IS NULL
    AND NOT null_ok_in)
    THEN
    IF register_in
    THEN
    +
             -- Registers the results in the utResult databank.
    utresult.report (msg_in);
    ELSE
    utplsql.pl (msg_in);
    END IF;

    IF showing_results AND register_in
    THEN
    +
             -- Show the results of the test more recently run.
    utresult.showlast;
    END IF;

    IF raise_exc_in
    THEN
    RAISE test_failure;
    END IF;
    END IF;
    END;
    + The most important statement to include in your assertion routine is the +call to utResult.report, which will log the results of the test. + diff --git a/documentation/src/utconfig.html b/documentation/src/utconfig.html index 1306330b1..5f06cd344 100644 --- a/documentation/src/utconfig.html +++ b/documentation/src/utconfig.html @@ -1,35 +1,7 @@ - - - - - - utPLSQL - utConfig Package - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: utPLSQL Package | Next -Section: utResult Package > -
    + +

    utConfig Package

    @@ -132,13 +104,13 @@

    View a schema's configuration

    -Call the utPLSQL.showconfig procedure to view the configuration for a specified +Call the utconfig.showconfig procedure to view the configuration for a specified schema. The header is:
    PROCEDURE utConfig.showconfig (username_in IN VARCHAR2 := NULL);
    If you do not specify a schema, then the currently used configuration is returned. Here is an example of output from this procedure: -
    SQL> exec utconfig.showconfig
    +
    SQL> exec utconfig.showconfig
     =============================================================
     utPLSQL Configuration for SCOTT
        Directory: /apps/utplsql/code
    @@ -147,7 +119,7 @@ 

    Prefix = test_ =============================================================

    And here is an example of calling showConfig for a different schema: -
    SQL> exec utconfig.showconfig ('COMP')
    +
    SQL> exec utconfig.showconfig ('COMP')
     =============================================================
     utPLSQL Configuration for COMP
        Directory: M:\shared_apps\utplsql\comp
    diff --git a/documentation/src/utgen.html b/documentation/src/utgen.html
    index 9faec28d1..33d620182 100644
    --- a/documentation/src/utgen.html
    +++ b/documentation/src/utgen.html
    @@ -1,36 +1,7 @@
     
    -
    -
    -   
    -   
    -   
    -   utPLSQL - utGen Package
    -
    -
    - 
    -
    -
    -
    -
    -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: utAssert Package | -Next -Section: Define Test Suites> -
    + +

    utGen Package

    diff --git a/documentation/src/utplsql.html b/documentation/src/utplsql.html index b6c19bd26..e1a755824 100644 --- a/documentation/src/utplsql.html +++ b/documentation/src/utplsql.html @@ -1,39 +1,8 @@ - - - - -utPLSQL - utPLSQL Package - - - - - - - -

    - - - - - -
    -

    -
    - -

    Authors: Steven Feuerstein, Chris Rimmer

    - -

    Copyright 2000-2001, all rights reserved

    - -

    [ Home | Getting Started | Build Test Packages | Examples | User Guide -| Release Notes | Document Map -]

    - -

    < Previous Section: User Guide | Next Section: utConfig Package >
    -

    - + -

    utPLSQL Package

    + +

    utPLSQL Package

    The utPLSQL package offers the following capabilities:

    diff --git a/documentation/src/utresult.html b/documentation/src/utresult.html index 3e15baab8..2a722edbd 100644 --- a/documentation/src/utresult.html +++ b/documentation/src/utresult.html @@ -1,36 +1,7 @@ - - - - - - utPLSQL - utResult Package - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: utConfig Package | -Next -Section: utAssert Package > -
    + +

    utResult Package

    diff --git a/documentation/src/xref.html b/documentation/src/xref.html index ff91b27eb..fdd1ed643 100644 --- a/documentation/src/xref.html +++ b/documentation/src/xref.html @@ -1,35 +1,7 @@ - - - - - - utPLSQL - Cross-Reference by Assertion Type - - - - - - - -
    - -
    -Authors: Steven Feuerstein, -Chris Rimmer - -Copyright 2000-2001, all rights -reserved -
    -[ Home | Getting -Started | Build Test Packages -| Examples | User -Guide | Release Notes | Document -Map ] -

    < Previous Section: Examples | Next -Section: Test a Procedure > -
    + +

    Cross-Reference by Assertion Type

    From 126d287bbdf30f7c832c81d78f5799cec6131dc0 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 12 Mar 2002 20:26:16 +0000 Subject: [PATCH 006/143] Added Template File Added ReadMe describing document building --- documentation/src/readme.txt | 71 +++++++++++++++++++++++++++++++++ documentation/src/template.html | 31 ++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 documentation/src/readme.txt create mode 100644 documentation/src/template.html diff --git a/documentation/src/readme.txt b/documentation/src/readme.txt new file mode 100644 index 000000000..3c81d826f --- /dev/null +++ b/documentation/src/readme.txt @@ -0,0 +1,71 @@ +================================== +HOW TO BUILD UTPLSQL DOCUMENTATION +================================== +$Id$ +================================== + +The utPLSQL documentation is built from a series of simple HTML files in the +src directory. These files have none of the navigation bars, logos or +next/previous links which appear in the final documentation. They are also +stripped of font, color and style information at compile-time to let the +stylesheet (utplsql.css) determine the overall look-and-feel. + +--------- +THE FILES +--------- + +The files are compiled into a documentation set situated in the top-level +documentation directory using the 2 control files, map.txt and authors.txt. +The first of these is the driving file, giving a list of the files to be +included. The second gives a list of authors to be included in the copyright +notice on each page and referenced in the Meta tags. + +The format of map.txt is as follows: + + # Any line starting with a # is + # considered a comment + # + index.html,Home* + started.html,Getting Started* + another.html,Further Docs + another2.html,Yet more docs + +Each line consists of the filename to be included and the title of the page, +separated with a comma. Any file whose title is followed by an asterisk is +considered the start of a new section. This means a link to the file will +appear in the navigation bar at the top of each page and it will appear in +bold in the document map. Note that the document map itself does not appear +in map.txt, but is always added at the end and is considered a new section. +This page is entirely generated at compile-time. + +The format of authors.txt is as follows: + + # Again, lines starting # are ignored + # + Steven Feuerstein,steven@stevenfeuerstein.com + Chris Rimmer,c@24.org.uk + A N Other,ano@ther.net + +Each line in this file simply gives the name of the author and their email +address, separated with a comma. + +----------- +THE SCRIPTS +----------- + +The 2 Perl scripts used to build the documentation are clean_html.pl and +build_docs.pl. + +The first of these simply strips HTML files down to the basics, removing +everything from the header and removing Javascript, fonts, color etc. It +requires the HTML::TagFilter module which in turn also requires the +HTML::Parser and HTML::Tagset modules (all available from search.cpan.org). + +The second script goes through each file listed in map.txt, cleans it using +the previous script and then adds logos, navigation bars, next/previous links, +copyright information etc. The resulting files are put in the top-level +documentation directory. + +NOTE: Anything within a source file before the +"" comment line and after the +"" comment line is ignored. diff --git a/documentation/src/template.html b/documentation/src/template.html new file mode 100644 index 000000000..d417e748e --- /dev/null +++ b/documentation/src/template.html @@ -0,0 +1,31 @@ + + + + +

    +Heading +

    + +

    +Subheading 1 +

    +Some body text here... +
    +BEGIN
    +  Some.Example(Code);
    +END;
    +
    + +

    +Subheading 2 +

    +Some more body text here... +
      +
    • Point 1
    • +
    • Point 2
    • +
    • Point 3
    • +
    + + + + From 31e6f53a63aab041ca7ea1a907bbbab64489a9e1 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 14 Mar 2002 23:34:02 +0000 Subject: [PATCH 007/143] Initial version --- documentation/src/writedoc.html | 93 +++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 documentation/src/writedoc.html diff --git a/documentation/src/writedoc.html b/documentation/src/writedoc.html new file mode 100644 index 000000000..4ea640123 --- /dev/null +++ b/documentation/src/writedoc.html @@ -0,0 +1,93 @@ + +How to add to the utPLSQL documentation set + + +

    Writing Documentation

    +

    +The utPLSQL documentation is built from a series of simple HTML files in the +src directory. These files have none of the navigation bars, logos or +next/previous links which appear in the final documentation. They are also +stripped of font, color and style information at compile-time to let the +stylesheet (utplsql.css) determine the overall look-and-feel.

    + +

    Unlike the code (at the time of writing), the documentation is held with CVS. So to make changes, you should set yourself up with access to the utPLSQL CVS repository. If you don't have the privileges, mail one of the Project Admins. Check out the latest version and you're ready to go.

    + +

    The HTML Files

    +

    As described above, the base files in the src directory are used to generate the final +product. To add new documentation to one of these files, or to correct errors, +simply edit it. It makes sense to follow the layout that is already present in the +file, adding links at the top of the page where appropriate. The HTML should be +kept simple, so use the relevant header styles (<H1>...<H6>) to label your sections +and subsections, use <pre> to mark sections of code etc. Let the stylesheet +do the work of setting the colors and fonts.

    + +

    If you are adding an entirely new file to the documentation, use the file +template.html as a basis. This contains the relevant comment +lines which tell the scripts which parts of the file to use +(see the note below). Finally, you will need to +edit map.txt to ensure that the file is linked from the other pages in +the documentation. This is described in the next section.

    + +

    The Control Files

    + +

    The files are compiled into a documentation set situated in the top-level +documentation directory using the 2 control files, map.txt and authors.txt. +The first of these is the driving file, giving a list of the files to be +included. The second gives a list of authors to be included in the copyright +notice on each page and referenced in the Meta tags.

    + +

    The format of map.txt is as follows:

    +
    +   # Any line starting with a # is 
    +   # considered a comment
    +   #
    +   index.html,Home*
    +   started.html,Getting Started*
    +   another.html,Further Docs
    +   another2.html,Yet more docs
    + +

    Each line consists of the filename to be included and the title of the page, +separated with a comma. Any file whose title is followed by an asterisk is +considered the start of a new section. This means a link to the file will +appear in the navigation bar at the top of each page and it will appear in +bold in the document map. Note that the document map itself does not appear +in map.txt, but is always added at the end and is considered a new section. +This page is entirely generated at compile-time.

    + +

    To add a new page to the documentation, simply add it to this file in the +correct position. Note that generally you will not be adding a new section!

    + +

    The format of authors.txt is as follows:

    +
    +   # Again, lines starting # are ignored
    +   #
    +   Steven Feuerstein,steven@stevenfeuerstein.com
    +   Chris Rimmer,c@24.org.uk
    +   A N Other,ano@ther.net
    + +

    Each line in this file simply gives the name of the author and their email + address, separated with a comma. So if you've made a contribution and your name + is not listed, add it!

    + +

    The Scripts

    +

    The 2 Perl scripts used to build the documentation are clean_html.pl and + build_docs.pl.

    + +

    The first of these simply strips HTML files down to the basics, removing +everything from the header and removing Javascript, fonts, color etc. It +requires the HTML::TagFilter module which in turn also requires the +HTML::Parser and HTML::Tagset modules (all available from search.cpan.org).

    + +

    The second script goes through each file listed in map.txt, cleans it using +the previous script and then adds logos, navigation bars, next/previous links, +copyright information etc. The resulting files are put in the top-level +documentation directory.

    + +

    NOTE: Anything within a source file before the +<!-- Begin utPLSQL Body --> comment line and after the +<!-- End utPLSQL Body --> comment line is ignored.

    + +Chris Rimmer, c@24.org.uk March 2002 + + + From 617f946ac7e6d2928977d8bdf61f75d93ba81fad Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 19 Jul 2002 14:28:16 +0000 Subject: [PATCH 008/143] Created initial version --- documentation/src/utoutput.html | 166 ++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 documentation/src/utoutput.html diff --git a/documentation/src/utoutput.html b/documentation/src/utoutput.html new file mode 100644 index 000000000..33445b88c --- /dev/null +++ b/documentation/src/utoutput.html @@ -0,0 +1,166 @@ + + + + +

    +utOutput Package

    + +

    This package contains the following procedures and functions: +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    utOutput.saveTurn on the 'save' flag
    utOutput.nosaveTurn off the 'save' flag
    utOutput.savingReturn the 'save' flag
    utOutput.extractPull text from the DBMS_OUTPUT buffer
    utOutput.replaceReplace saved output in the DBMS_OUTPUT buffer
    utOutput.nextLinePull the next line from the DBMS_OUTPUT buffer
    utOutput.countCount the lines in the DBMS_OUTPUT buffer
    + +

    Outline of Usage

    + +

    The problem with attempting to test output in PL/SQL is that there is a single +DBMS_OUTPUT buffer. When your test is run, there may already be output in the +buffer from other tests, or from the tested code. So what state should you +leave it in once you have finished? Perhaps you want all the output created by +your tested code to end up in the buffer as if it had been run normally (i.e. +not from within utPLSQL), or maybe you want only the text that was in the +buffer before you started to be left.

    + +

    This package attempts to allow to do any of these. There is a flag in the +package to determine whether text pulled from the output buffer should be +saved. This is set with 'save' and 'nosave' and returned by +'saving'. Data is pulled from the buffer using 'extract', +while the procedure 'replace' puts any saved data back into the output +buffer.

    + +

    The intent is that it is used like this:

    + +
    +PROCEDURE ut_my_test IS
    +BEGIN
    +
    +  --Pull out any text already in the output buffer
    +  utoutput.save;
    +  utoutput.extract;
    +
    +  --Your testing code here, with saving turned on or off as you see fit
    +
    +  --Put text back in the output buffer 
    +  utoutput.replace;
    +
    +END;
    +
    + +

    So to start with, we save any text already in the buffer. We then carry out +our testing. If we want the output generated by the testing to end up back in +the output buffer, we turn on saving. Finally, we put the saved text back.

    + +

    Saving Output

    + +

    The three routines for handling the save flag are:

    +
    +PROCEDURE save;
    +
    +PROCEDURE nosave;
    +
    +FUNCTION saving RETURN BOOLEAN;
    +
    + +

    Quite simply, 'save' turns the flag on, 'nosave' turns it off and 'saving' +returns its current value.

    + +

    Extracting Output

    + +

    There are 4 versions of the extract routine to get text from the output buffer:

    + +
    +FUNCTION extract (
    +   buffer_out    OUT DBMS_OUTPUT.CHARARR,
    +   max_lines_in  IN INTEGER := NULL,
    +   save_in       IN BOOLEAN := saving
    +) RETURN INTEGER;
    +
    +PROCEDURE extract (
    +   buffer_out    OUT DBMS_OUTPUT.CHARARR,
    +   max_lines_in  IN INTEGER := NULL,
    +   save_in       IN BOOLEAN := saving
    +);
    +
    +FUNCTION extract(
    +   max_lines_in  IN INTEGER := NULL,
    +   save_in       IN BOOLEAN := saving
    +) RETURN INTEGER;
    +
    +PROCEDURE extract(
    +   max_lines_in  IN INTEGER := NULL,
    +   save_in       IN BOOLEAN := saving
    +);
    +
    + +

    The function versions return the number of lines extracted from the +DBMS_OUTPUT buffer. The other parameters are used as follows: +

      +
    • buffer_out - This is a buffer in which to put the extracted text.
    • +
    • max_lines_in - This is the maximum number of lines to be extracted. If NULL is passed in (the default) then all the lines are extracted.
    • +
    • save_in - This specifies if the extracted output should be saved. It overrides the global save flag.
    • +
    +

    + +

    Replacing Output

    + +

    The replace procedure takes no parameters:

    +
    +PROCEDURE replace;   
    +
    +

    It simply puts the saved text back into the DBMS_OUTPUT buffer. Note that the buffer is emptied at this point.

    + +

    Checking Output Line-by-Line

    + +

    The nextLine function makes it easy to check output line-by-line as it +simply extracts and returns the next line of output:

    + +
    +FUNCTION nextLine(
    +  raise_exc_in BOOLEAN := TRUE, 
    +  save_in BOOLEAN := saving
    +) RETURN VARCHAR2;   
    +
    + +

    The raise_exc_in flag determines if the function should throw the exception utOutput.EMPTY_OUTPUT_BUFFER when asked for the next line from an empty buffer. If no exception is thrown, NULL is returned. As with extract, the save_in flag simply overrides the global save flag setting. +

    + +

    Size of Output

    + +

    This function simply counts the number of lines present in the output buffer:

    + +
    +FUNCTION count RETURN INTEGER;   
    +
    + +

    Note that the output itself is left untouched.

    + + + + From d1fb20e54cc4fe6390e32bfeef3c881099d667ee Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 19 Jul 2002 14:29:14 +0000 Subject: [PATCH 009/143] Added utoutput --- documentation/src/map.txt | 1 + documentation/src/userguide.html | 3 +++ 2 files changed, 4 insertions(+) diff --git a/documentation/src/map.txt b/documentation/src/map.txt index b1e6a8c95..b6159124d 100644 --- a/documentation/src/map.txt +++ b/documentation/src/map.txt @@ -29,5 +29,6 @@ utconfig.html,utConfig Package utresult.html,utResult Package utassert.html,utAssert Package utgen.html,utGen Package +utoutput.html,utOutput Package defsuite.html,Define Test Suites release.html,Release Notes* diff --git a/documentation/src/userguide.html b/documentation/src/userguide.html index 5117090a2..7399406ee 100644 --- a/documentation/src/userguide.html +++ b/documentation/src/userguide.html @@ -31,6 +31,9 @@

    utGen - Generate test packages

    +

    + utOutput - Handling DBMS_OUTPUT for testing

    +

    Define Test Suites

    From 6706b17f89d79d74cbcefec4c2196247ee9f550f Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 19 Jul 2002 15:07:37 +0000 Subject: [PATCH 010/143] Fixed to work under Windows --- documentation/src/build_docs.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/src/build_docs.pl b/documentation/src/build_docs.pl index 03465e012..4786a9f8e 100755 --- a/documentation/src/build_docs.pl +++ b/documentation/src/build_docs.pl @@ -92,7 +92,7 @@ open OUTPUT, ">$OUTDIR/$map[$index]->[0]" or die "Cannot open $OUTDIR/$map[$index]->[0]"; if ($index != $#map){ - system("./clean_html.pl $map[$index]->[0] > $map[$index]->[0].clean"); + system("clean_html.pl $map[$index]->[0] > $map[$index]->[0].clean"); open INPUT, "$map[$index]->[0].clean" or die "Cannot open $map[$index]->[0].clean"; } From e742ad8c37a0cdef0104fa64cff60d7a7fba4acb Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 19 Jul 2002 15:08:57 +0000 Subject: [PATCH 011/143] Changed heading sizes to make them more consistent with other pages --- documentation/src/utconfig.html | 40 ++++++++++++++++----------------- documentation/src/utgen.html | 20 ++++++++--------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/documentation/src/utconfig.html b/documentation/src/utconfig.html index 5f06cd344..cd043b6f0 100644 --- a/documentation/src/utconfig.html +++ b/documentation/src/utconfig.html @@ -88,22 +88,22 @@

    recompile your test package before execution. You can turn off this feature and manually recompile only when you desire (a fine idea if your test package has gotten very large!). -

    -Return whose configuration is being used

    +

    +Return whose configuration is being used

    By default, the configuration stored for the currently-connected user will be used. However, it is possible to use configurations stored against other usernames. To show whose configuration is currently being used the following function is used:
    FUNCTION utConfig.tester RETURN VARCHAR2;
    -

    -Set whose configuration is being used

    +

    +Set whose configuration is being used

    This returns the configuration that will be used whenever a username is not specified. To set this, the following procedure is used:
    PROCEDURE utConfig.settester (username_in IN VARCHAR2 := USER);
    -

    -View a schema's configuration

    +

    +View a schema's configuration

    Call the utconfig.showconfig procedure to view the configuration for a specified schema. The header is:
    PROCEDURE utConfig.showconfig (username_in IN VARCHAR2 := NULL);
    @@ -134,8 +134,8 @@

    SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED exec utconfig.showconfig

    -

    -Set the directory containing the test package code

    +

    +Set the directory containing the test package code

    If you want utPLSQL to compile your test package, you must tell it the directory in which your code is found. You can do this either when you define @@ -156,14 +156,14 @@

    You might consider putting the the call to utConfig.setdir into your login.sql so that it is run automatically, each time your start up SQL*Plus -- if you are always working from the same directory. -

    -Return the directory containing the test package code

    +

    +Return the directory containing the test package code

    You can obtain the current directory with a call to utConfig.dir:
    FUNCTION utConfig.dir (username_in IN VARCHAR2 := NULL)
           RETURN VARCHAR2;
    -

    -Set the default unit test prefix for your code.

    +

    +Set the default unit test prefix for your code.

    The unit test prefix is very important in utPLSQL; the utility uses the prefix to associate source code to be tested with the test package. The prefix also allows utPLSQL to automatically identify the programs within @@ -179,15 +179,15 @@

    or, with the specification of a non-current schema:
    SQL> exec utconfig.setPrefix ('t_', 'ANALYSIS');
    -

    -Return the default unit test prefix for your code.

    +

    +Return the default unit test prefix for your code.

    You can obtain the current prefix with a call to utConfig.prefix:
    FUNCTION utConfig.prefix (username_in IN VARCHAR2 := NULL)
           RETURN VARCHAR2;
    uPLSQL currently does not support the use of a suffix, or combination of suffix and prefix, to identify test packages and unit test procedures. -

    -Set the registration mode (manual or automatic).

    +

    +Set the registration mode (manual or automatic).

    As of utPLSQL v1.5.1, you no longer have to register your unit test procedures in the setup procedure of your test package. Instead, utPLSQL will scan the data dictionary (via theALL_ARGUMENTS view) for the names of all the @@ -205,8 +205,8 @@

    SQL> exec utConfig.registerTest (TRUE)
    Note: if you are using automatic unit test detection, any calls to utPLSQL.addtest in the setup procedure will be ignored. -

    -Set autocompile feature

    +

    +Set autocompile feature

    The default settings for utPLSQL is to re-compile your base package before each unit test. This guarantees that any recent @@ -253,8 +253,8 @@

    on a server to which you have no access other than via a database connection. -

    -Turning off Auto-compile

    +

    +Turning off Auto-compile

    If you are working with products like SQL*Navigator, you may be always editing from code stored in the database. In this case, diff --git a/documentation/src/utgen.html b/documentation/src/utgen.html index 33d620182..0e94c5720 100644 --- a/documentation/src/utgen.html +++ b/documentation/src/utgen.html @@ -39,8 +39,8 @@

    -

    -Generate Skeleton Test Packages

    +

    +Generate Skeleton Test Packages

    The utGen contains a procedure that allows you to generate a starting point for a unit test package. This package can be sent to the screen, a file, a delimited string or @@ -256,8 +256,8 @@

    Now let's explore how to direct the generated code to different types of output. -

    -Generating to Screen

    +

    +Generating to Screen

    The default behavior of utGen.testpkg is to generate code to your screen (via DBMS_OUTPUT.PUT_LINE). So unless you specify some @@ -282,8 +282,8 @@

    If DBMS_OUTPUT is not enabled in your session, then utGen.testpkg will not generate any output. -

    -Generating to File

    +

    +Generating to File

    If you are working with utGen in a command line style (ie, you are not using a utGen-enabled GUI), then you will probably @@ -324,8 +324,8 @@

    is accessible through UTL_FILE, before this operation can succeed. -

    -Generating to String

    +

    +Generating to String

    If you are accessing utPLSQL functionality through a GUI, you might find it more useful to direct output to a string (or array, @@ -366,8 +366,8 @@

    FUNCTION utGen.pkgString RETURN VARCHAR2;
    -

    -Generating to Array

    +

    +Generating to Array

    If you are accessing utPLSQL functionality through a GUI, you might find it more useful to direct output to an array. You From fcdf833706d78a7c39992542f63c3ba98e05b1bd Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 19 Jul 2002 16:19:48 +0000 Subject: [PATCH 012/143] Added documentation on eqOutput assertions --- documentation/src/utassert.html | 80 ++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 5 deletions(-) diff --git a/documentation/src/utassert.html b/documentation/src/utassert.html index ca39f634c..cfc9f58c5 100644 --- a/documentation/src/utassert.html +++ b/documentation/src/utassert.html @@ -68,7 +68,11 @@

    utAssert Package

    passed or failed
    - + + utAssert.eqoutput + Check Equality of DBMS_OUTPUT Collections + + The utAssert package provides a set of assertion routines ("assert that @@ -569,7 +573,7 @@

    Check if the Previous Assertion Passed or Failed

    utAssert.eqqueryvalue('Insert 5 rows', 'SELECT COUNT(*) FROM TRIPS - WHERE CITY = 'Rio de Janeiro', + WHERE CITY = ''Rio de Janeiro''', 5); /* If that worked, look in more detail */ @@ -579,7 +583,7 @@

    Check if the Previous Assertion Passed or Failed

    utAssert.eqqueryvalue('All with todays date', 'SELECT COUNT(*) FROM TRIPS - WHERE CITY = 'Rio de Janeiro' + WHERE CITY = ''Rio de Janeiro''' AND TRUNC(CREATED) = TRUNC(SYSDATE)', 5); @@ -587,14 +591,80 @@

    Check if the Previous Assertion Passed or Failed

    utAssert.eqqueryvalue('Hotel Specfied', 'SELECT COUNT(*) FROM TRIPS T, HOTELS H - WHERE T.CITY = 'Rio de Janeiro' + WHERE T.CITY = ''Rio de Janeiro''' AND T.HOTEL = H.ID', 5); END IF; END;
    -

    + +

    Comparing output from DBMS_OUTPUT

    + +

    To complement the utOutput package, these +assertions allow you to easily compare collections of the type +DBMS_OUTPUT.CHARARR. Unlike the eqcoll and + eqcollapi assertions, this allows the comparison of locally defined +collections. The procedures are declared as follows:

    + +
    +PROCEDURE eqoutput (
    +   msg_in                IN   VARCHAR2,
    +   check_this_in         IN   DBMS_OUTPUT.CHARARR,
    +   against_this_in       IN   DBMS_OUTPUT.CHARARR,
    +   ignore_case_in        IN   BOOLEAN := FALSE,
    +   ignore_whitespace_in  IN   BOOLEAN := FALSE,
    +   null_ok_in            IN   BOOLEAN := TRUE,
    +   raise_exc_in          IN   BOOLEAN := FALSE
    +);
    +
    +PROCEDURE eqoutput (
    +   msg_in                IN   VARCHAR2,
    +   check_this_in         IN   DBMS_OUTPUT.CHARARR,
    +   against_this_in       IN   VARCHAR2,
    +   line_delimiter_in     IN   CHAR := NULL,
    +   ignore_case_in        IN   BOOLEAN := FALSE,
    +   ignore_whitespace_in  IN   BOOLEAN := FALSE,
    +   null_ok_in            IN   BOOLEAN := TRUE,
    +   raise_exc_in          IN   BOOLEAN := FALSE
    +);
    +
    + +

    The first version simply compares two collections, whereas the second compares a collection against a delimited string. The delimiter +can be specified by the line_delimiter_in parameter. If NULL is passed in (which is the default) then the lines are delimited by carriage returns. +Thus to test a collection mybuff which should look like:

    + +
    +   mybuff(0) := 'Zidane';
    +   mybuff(1) := 'Ronaldo';
    +   mybuff(2) := 'Kahn';
    +
    + +

    we could pass in parameters:

    + +
    +   check_this_in => 'Zidane|Ronaldo|Kahn';
    +   line_delimiter_in => '|';
    +
    + +

    or:

    + +
    +   check_this_in => 
    +'Zidane
    +Ronaldo
    +Kahn';
    +   line_delimiter_in => NULL;
    +
    + +

    There are also the following flags to modify the way that the line-by-line comparisons are carried out:

    + +
      +
    • ignore_case_in - this specifies that case should be ignored when comparing lines.
    • +
    • ignore_whitespace_in - this specifies that whitespace differences should be ignored when comparing lines.
    • +
    + +

    Finally, note that only the text itself is compared. These assertions do not care about how the records within the collections are numbered.

    Building Your Own Assertion

    You may want to build assertion routines that fit your specific needs. If PL/SQL supported inheritance, you could extend the utAssert assertion From b1d8bada1c1e30ca6c2756de7d186326d7cd7a9b Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 19 Jul 2002 16:31:25 +0000 Subject: [PATCH 013/143] Added warning about tracing --- documentation/src/utoutput.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/documentation/src/utoutput.html b/documentation/src/utoutput.html index 33445b88c..a85d19bb3 100644 --- a/documentation/src/utoutput.html +++ b/documentation/src/utoutput.html @@ -77,6 +77,11 @@

    Outline of Usage

    our testing. If we want the output generated by the testing to end up back in the output buffer, we turn on saving. Finally, we put the saved text back.

    +

    Warning

    +

    In the current version of utPLSQL (2.0.9.1) use of this package is virtually impossible with +utPLSQL tracing turned on. The reason for this is that this facility writes output using +DBMS_OUTPUT every time an assertion is called.

    +

    Saving Output

    The three routines for handling the save flag are:

    From 9ec09b60b5efd6400aff2e5f75828a21ae359e42 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 25 Jul 2002 09:30:47 +0000 Subject: [PATCH 014/143] Removed links to Example files. --- documentation/src/fourstep.html | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/documentation/src/fourstep.html b/documentation/src/fourstep.html index 1991ea578..5945f2f55 100644 --- a/documentation/src/fourstep.html +++ b/documentation/src/fourstep.html @@ -98,7 +98,7 @@

    Step 2. Choose a program to test and identify the test

    Suppose, for example, that I have created a stand alone function called betwnStr (a variation on SUBSTR that returns a sub-string based on a starting -and ending location) that is stored in betwnstr.sf: +and ending location) that is stored in betwnstr.sf(1):

    CREATE OR REPLACE FUNCTION betwnStr (
       string_in IN VARCHAR2,
       start_in IN INTEGER,
       end_in IN INTEGER
       )
       RETURN VARCHAR2
    IS
    BEGIN
       RETURN (
          SUBSTR (
             string_in,
             start_in,
             end_in – start_in + 1
             )
          );
    END;
    @@ -226,12 +226,12 @@

    Step 3. Build a test package.

    rely completely on the defaults and get you up and testing ASAP.

    So if I am going to test the stand-alone procedure, betwnstr, my test -package specification, saved in ut_betwnstr.pks, +package specification, saved in ut_betwnstr.pks(1), will look like this:

    CREATE OR REPLACE PACKAGE ut_betwnstr
    IS
       PROCEDURE ut_setup;
       PROCEDURE ut_teardown;
     
       PROCEDURE ut_betwnstr;
    END ut_betwnstr;
    /
    -

    Now let's build the package body, saved in ut_betwnstr.pkb. In this very simple +

    Now let's build the package body, saved in ut_betwnstr.pkb(1). In this very simple case, I don't have to set up any data structures and I do not, therefore, have to tear anything down. My teardown procedure can be empty (but it must be present). So I have:

    @@ -365,7 +365,7 @@

    Step 4. Run your test.

    Then run your test package within the utPLSQL testing framework by calling utPLSQL.test:

    -
    SQL> exec utplsql.test ('betwnstr', recompile_in => FALSE)
    +
    SQL> exec utplsql.test ('betwnstr', recompile_in => FALSE)

    That second parameter in the call to utplsql.test, "recompile_in => FALSE", tells utPLSQL that you have already @@ -403,10 +403,10 @@

    Automatic Recompilation of Test Package

    package before each run, and instead will display an error message.

    Call the utConfig.setdir program to tell -utPLSQL the location of your source code. Suppose that I stored all my code in e:\utplsql\testall. Then I would make this +utPLSQL the location of your source code. Suppose that I stored all my code in e:\utplsql\testall. Then I would make this call in SQL*Plus:

    -
    SQL> exec utplsql.setdir ('e:\utplsql\testall')
    +
    SQL> exec utplsql.setdir ('e:\utplsql\testall')

    You could also put this program call in your login.sql file (see the login_sample.sql file) so that you don't have to type that code every @@ -431,6 +431,12 @@

    Where To Go From Here

    different kinds of test packages, visit the Examples document.

    +
    + +

    Footnotes

    + +

    1. This file is to be found in the Examples directory of the utPLSQL distribution.

    + From ca9bcff179206e879185a1c00541cb10b0c30c3f Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 25 Jul 2002 09:32:06 +0000 Subject: [PATCH 015/143] Removed components section which is well out of date (and difficult to keep in synch) --- documentation/src/admin.html | 222 +---------------------------------- 1 file changed, 1 insertion(+), 221 deletions(-) diff --git a/documentation/src/admin.html b/documentation/src/admin.html index ea95f8e03..ef1392960 100644 --- a/documentation/src/admin.html +++ b/documentation/src/admin.html @@ -44,7 +44,7 @@

    is then checked against the list of accessible directories.

    The format of the parameter for file access in the init.ora file is:

    -utl_file_dir = <directory>
    +utl_file_dir = <directory>
     
    Include a parameter for utl_file_dir for each directory you want to make accessible for UTL_FILE operations. The following entries, for example, @@ -176,226 +176,6 @@

    You can also look inside the utPLSQL package (utPLSQL.pkb) and check the value of the g_version private variable. -

    -Components

    - -Here are the various components of utPLSQL: - -

    -Tables

    -All tables are created by the tables.sql (or updated by the tablesupg.sql) -file. -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -ut_suite - -table - -Persistent storage of test suites defined. -
    -ut_package - -table - -Persistent storage of packages to be run within -a suite. -
    -ut_test - -table - -Definition of an individual unit test. -
    -ut_testcase - -table - -Definition of a test case within a unit test. -
    ut_config table Holds -configuration information for each user
    ut_assertion table Contains -the definitions of the various assertion routines in the utAssert package. -This table will be used (potentially) by GUI front ends to utPLSQL.
    - -

    -Packages

    -All packages are created the code.sql file. -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -utPLSQL - -package - -Main test package. -
    utConfigpackageAPI to ut_config table
    -utSuite - -package - -API to ut_suite table. -
    -utPackage - -package - -API to ut_ package table. -
    -utTest - -package - -API to ut_test table. -
    -utTestcase - -package - -API to ut_testcase table. -
    -utAssert - -package - -Collection of assertion routines available to test -the results of your programs. -
    -utResult - -package - -API to the results array that is populated by calls -to the utAssert assertions. -
    -utGen - -package - -Generates a starting point for test packages for -your own package. -
    - -

    -File Descriptions

    - From 197bf6380ae5f91d966529c899ff47065fa4c9db Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 25 Jul 2002 09:54:04 +0000 Subject: [PATCH 016/143] Removed references to components and file description sections --- documentation/src/started.html | 5 ----- 1 file changed, 5 deletions(-) diff --git a/documentation/src/started.html b/documentation/src/started.html index 4c5299df2..dade88f1c 100644 --- a/documentation/src/started.html +++ b/documentation/src/started.html @@ -57,11 +57,6 @@

    Reporting Bugs and Enhancement Requests

    -

    -Components

    - -

    -File Descriptions

    From c74c84b40b08198dcb89df42b9bba643662bc517 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 25 Jul 2002 09:54:37 +0000 Subject: [PATCH 017/143] Removed advanced.html and references to it --- documentation/src/advanced.html | 15 --------------- documentation/src/buildpack.html | 11 ----------- documentation/src/map.txt | 1 - 3 files changed, 27 deletions(-) delete mode 100644 documentation/src/advanced.html diff --git a/documentation/src/advanced.html b/documentation/src/advanced.html deleted file mode 100644 index a29d5eb28..000000000 --- a/documentation/src/advanced.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - -

    -Advanced Topics

    - -

    -Building Your Own Test Engine

    - -

    -Analyze Test Statistics

    - - - diff --git a/documentation/src/buildpack.html b/documentation/src/buildpack.html index a061f7c89..be354192a 100644 --- a/documentation/src/buildpack.html +++ b/documentation/src/buildpack.html @@ -21,17 +21,6 @@

    A "Test Run" with utPLSQL

    -

    -Advanced Topics

    - -
    -

    -Build Your Own Test Engine

    - -

    -Analyze Test Run Statistics

    -
    - diff --git a/documentation/src/map.txt b/documentation/src/map.txt index b6159124d..6e8d2b1ca 100644 --- a/documentation/src/map.txt +++ b/documentation/src/map.txt @@ -14,7 +14,6 @@ admin.html,Administrative Topics buildpack.html,Build Test Packages* howto.html,How to build a test package testrun.html,A "Test Run" with utPLSQL -advanced.html,Advanced Topics examples.html,Examples* xref.html,Cross-reference by Assertion Type testproc.html,Test a Procedure From d20339f8ac99080eda01629a19f234e4021e990b Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 25 Jul 2002 10:19:56 +0000 Subject: [PATCH 018/143] Minor tweaks to text and markup --- documentation/src/howto.html | 12 ++++++------ documentation/src/testrun.html | 4 +--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/documentation/src/howto.html b/documentation/src/howto.html index c991ae1e2..b0af806b0 100644 --- a/documentation/src/howto.html +++ b/documentation/src/howto.html @@ -35,18 +35,18 @@

    any data structures needed for your units. The package specification header for this procedure must be of this form: -
    CREATE OR REPLACE PACKAGE <prefix><package>
    +
    CREATE OR REPLACE PACKAGE <prefix><package>
    IS
    -
       PROCEDURE <prefix>setup;
    +
       PROCEDURE <prefix>setup;
    -where <prefix> is the unit test prefix and <package> +where <prefix> is the unit test prefix and <package> is the name of the package (or stand alone program) to be tested. The default naming convention is that your test package and all utPLSQL programs, including the setup procedure, have a prefix of "ut_", as in: -
    CREATE OR REPLACE PACKAGE ut_<program>
    +
    CREATE OR REPLACE PACKAGE ut_<program>
    IS
    @@ -68,8 +68,8 @@

    need in one or more of your tests. You might, for example, want to create a temporary table to hold information for comparison. You might populate a collection or a record a scalar global variable. -

    Here is an example of such a procedure (see Examples\ut_te_employee.pkb -for the full implementation): +

    Here is an example of such a procedure (see the file ut_te_employee.pkb +in the Examples directory of the utPLSQL distribution for the full implementation):

    PROCEDURE ut_setup
     IS
     BEGIN
    diff --git a/documentation/src/testrun.html b/documentation/src/testrun.html
    index c321baace..7cca678bc 100644
    --- a/documentation/src/testrun.html
    +++ b/documentation/src/testrun.html
    @@ -9,7 +9,7 @@ 

    effort, to show you how it all hangs together. I've got a "hangnail" in my PL/SQL development work, called SUBSTR. This function bothers me and I want to take care of it. What's the problem? SUBSTR is great when you -know the starting location of a string and number of characters you want.In +know the starting location of a string and number of characters you want. In many situations, though, I have the start and end locations and I need to figure out the number of characters I then want. Is it:
    mystring := SUBSTR (full_string, 5, 17); -- start and end? Nah...
    @@ -124,8 +124,6 @@

       END;
    -
    [ENDFOREACH]
    -
      
    END ut_str;
    From 6cb147d96a58b1aa0bc4fe1fa7aa8f2b3a65e250 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 25 Jul 2002 10:21:56 +0000 Subject: [PATCH 019/143] Removed Cross-Reference Page (since it only had 2 links) and references to it --- documentation/src/examples.html | 7 +------ documentation/src/map.txt | 1 - documentation/src/xref.html | 24 ------------------------ 3 files changed, 1 insertion(+), 31 deletions(-) delete mode 100644 documentation/src/xref.html diff --git a/documentation/src/examples.html b/documentation/src/examples.html index 1cc6b6a8d..575a06ef1 100644 --- a/documentation/src/examples.html +++ b/documentation/src/examples.html @@ -8,12 +8,7 @@

    We learn best by following the examples of those who have gone before us. So you will find in this document sample test packages and different approaches to using utPLSQL to test your PL/SQL code like it has never -been tested before! The Cross-reference allows you to easily find the example -that demonstrates the use of a particular kind of utAssertion assertion -routine (compare pipes or tables or files or...). -

    -Cross-Reference by Assertion Type

    - +been tested before!

    Test a Procedure

    diff --git a/documentation/src/map.txt b/documentation/src/map.txt index 6e8d2b1ca..9ee6d8661 100644 --- a/documentation/src/map.txt +++ b/documentation/src/map.txt @@ -15,7 +15,6 @@ buildpack.html,Build Test Packages* howto.html,How to build a test package testrun.html,A "Test Run" with utPLSQL examples.html,Examples* -xref.html,Cross-reference by Assertion Type testproc.html,Test a Procedure testfunc.html,Test a Function testapi.html,Test an Entire Package API diff --git a/documentation/src/xref.html b/documentation/src/xref.html deleted file mode 100644 index fdd1ed643..000000000 --- a/documentation/src/xref.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - -

    -Cross-Reference by Assertion Type

    - -

    The examples are organized by the type of program element being tested --- and from which package. But they also demonstrate other features of -and handy techniques to use with utPLSQL. These examples, in particular, -show how to use the different kinds of assertion programs. These features -are described below. Click on a link to go to the example that highlights -the feature. -

    Check equality of scalars -

    Check equality of database tables -

    Check equality of database pipes -

    Check equality of files -

    Check equality of collections -

    Testing Impact on Objects -

    Set up and Tear Down Test Data Structures - - - - From 61e3421ad8a51e173b1a3ec7534212c61971835c Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 25 Jul 2002 10:30:58 +0000 Subject: [PATCH 020/143] Minor tweaks --- documentation/src/testproc.html | 55 +++++++++++++++++---------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/documentation/src/testproc.html b/documentation/src/testproc.html index 62c1324b2..9fb608cf6 100644 --- a/documentation/src/testproc.html +++ b/documentation/src/testproc.html @@ -43,8 +43,8 @@

    After compiling my code cleanly, I generate my test package: -
    SQL> SET SERVEROUTPUT ON FORMAT WRAPPED
    -SQL> exec utGen.testpkg ('calc_secs_between ')
    +
    SQL> SET SERVEROUTPUT ON FORMAT WRAPPED
    +SQL> exec utGen.testpkg ('calc_secs_between ')
     CREATE OR REPLACE PACKAGE ut_calc_secs_between
     IS
        PROCEDURE ut_setup;
    @@ -72,16 +72,16 @@ 

    PROCEDURE ut_CALC_SECS_BETWEEN IS BEGIN CALC_SECS_BETWEEN ( - DATE1 => '' + DATE1 => '' , - DATE2 => '' + DATE2 => '' , - SECS => '' + SECS => '' ); utAssert.this ( 'Test of CALC_SECS_BETWEEN', - '<boolean expression>' + '<boolean expression>' ); END ut_CALC_SECS_BETWEEN; @@ -93,7 +93,7 @@

    for package spec and body, ut_calc_secs_between.pks and ut_calc_secs_between.pkb, which I do as follows: -
    SQL> exec utGen.testpkg ('calc_secs_between ', output_type_in => utGen.c_file)
    +
    SQL> exec utGen.testpkg ('calc_secs_between ', output_type_in => utGen.c_file)
    By conforming to this standard, utPLSQL can automatically compile this code before each test. I now edit the ut_calc_secs_between @@ -104,11 +104,11 @@

    secs PLS_INTEGER; BEGIN CALC_SECS_BETWEEN ( - DATE1 => SYSDATE + DATE1 => SYSDATE , - DATE2 => SYSDATE + DATE2 => SYSDATE , - SECS => secs + SECS => secs ); utAssert.eq ( @@ -118,11 +118,11 @@

    ); CALC_SECS_BETWEEN ( - DATE1 => SYSDATE + DATE1 => SYSDATE , - DATE2 => SYSDATE+1 + DATE2 => SYSDATE+1 , - SECS => secs + SECS => secs ); utAssert.eq ( @@ -135,17 +135,17 @@

    and now I can run my test: -
    SQL> exec utplsql.test ('calc_secs_between')
    +
    SQL> exec utplsql.test ('calc_secs_between')
     .
    ->    SSSS   U     U   CCC     CCC   EEEEEEE   SSSS     SSSS
    ->   S    S  U     U  C   C   C   C  E        S    S   S    S
    ->  S        U     U C     C C     C E       S        S
    ->   S       U     U C       C       E        S        S
    ->    SSSS   U     U C       C       EEEE      SSSS     SSSS
    ->        S  U     U C       C       E             S        S
    ->         S U     U C     C C     C E              S        S
    ->   S    S   U   U   C   C   C   C  E        S    S   S    S
    ->    SSSS     UUU     CCC     CCC   EEEEEEE   SSSS     SSSS
    +>    SSSS   U     U   CCC     CCC   EEEEEEE   SSSS     SSSS
    +>   S    S  U     U  C   C   C   C  E        S    S   S    S
    +>  S        U     U C     C C     C E       S        S
    +>   S       U     U C       C       E        S        S
    +>    SSSS   U     U C       C       EEEE      SSSS     SSSS
    +>        S  U     U C       C       E             S        S
    +>         S U     U C     C C     C E              S        S
    +>   S    S   U   U   C   C   C   C  E        S    S   S    S
    +>    SSSS     UUU     CCC     CCC   EEEEEEE   SSSS     SSSS
     .
      SUCCESS: "calc_secs_between"
    @@ -174,6 +174,7 @@

    the value returned by the procedure. Instead, I must check to see how many rows are left in the table. Fortunately, I have another dynamic SQL utility to help me out here, one that returns the count of rows in any table: +(Note that you could also use utAssert.eqqueryvalue here.)
    /*file tabcount.sf */
     CREATE OR REPLACE FUNCTION tabcount (
    @@ -197,8 +198,8 @@ 

    So I will generate a package to test truncit and then modify the package body: -
    SQL> SET SERVEROUTPUT ON FORMAT WRAPPED
    -SQL> exec utGen.testpkg ('truncit', output_type_in => utGen.c_file)
    +
    SQL> SET SERVEROUTPUT ON FORMAT WRAPPED
    +SQL> exec utGen.testpkg ('truncit', output_type_in => utGen.c_file)
    To run my test, I need to truncate a table. That is an irreversible action, so I will create a "temporary" table in @@ -226,9 +227,9 @@

    PROCEDURE ut_TRUNCIT IS BEGIN TRUNCIT ( - TAB => 'temp_emp' + TAB => 'temp_emp' , - SCH => USER + SCH => USER ); utAssert.eq ( From 3309c73536b0aa4d15a06d0d5eb6da104d5ee859 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 25 Jul 2002 10:54:11 +0000 Subject: [PATCH 021/143] Removed the (empty) composite function section --- documentation/src/testfunc.html | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/documentation/src/testfunc.html b/documentation/src/testfunc.html index 700be0829..d5d9d63fa 100644 --- a/documentation/src/testfunc.html +++ b/documentation/src/testfunc.html @@ -15,7 +15,7 @@

  • -The function returns a non-scalar value, +The function returns a non-scalar value, such as an object or a collection. In this case, you will need to call the function and then evaluate the contents of the returned structure.
  • @@ -87,9 +87,7 @@

    END ut_str; /

    As you can see, my calls to str.betwn are embedded right within calls to -utAssert.eq and utAssert.isNULL, making my test code -

    -Testing a Composite Function

    +utAssert.eq and utAssert.isNULL, making my test code compact. From 5d5fc29955f2fb229de9fa1b89f252dea9c0b495 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 25 Jul 2002 12:16:44 +0000 Subject: [PATCH 022/143] Minor Tweaks --- documentation/src/samepack.html | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/documentation/src/samepack.html b/documentation/src/samepack.html index 0d38a57d6..e354ba8f7 100644 --- a/documentation/src/samepack.html +++ b/documentation/src/samepack.html @@ -12,13 +12,14 @@

    the package specification and body. We look at two examples:

    -Testing a simple string function

    + + Testing a simple string function

    Suppose I have my basic sting package, containing (for now at least) just a single function:
    /*file str.pks */
    @@ -67,22 +68,22 @@ 

    PL/SQL procedure successfully completed. -SQL> exec utPLSQL.test ('str', samepackage_in=>TRUE) +SQL> exec utPLSQL.test ('str', samepackage_in => TRUE) . -> SSSS U U CCC CCC EEEEEEE SSSS SSSS -> S S U U C C C C E S S S S -> S U U C C C C E S S -> S U U C C E S S -> SSSS U U C C EEEE SSSS SSSS -> S U U C C E S S -> S U U C C C C E S S -> S S U U C C C C E S S S S -> SSSS UUU CCC CCC EEEEEEE SSSS SSSS +> SSSS U U CCC CCC EEEEEEE SSSS SSSS +> S S U U C C C C E S S S S +> S U U C C C C E S S +> S U U C C E S S +> SSSS U U C C EEEE SSSS SSSS +> S U U C C E S S +> S U U C C C C E S S +> S S U U C C C C E S S S S +> SSSS UUU CCC CCC EEEEEEE SSSS SSSS . SUCCESS: "str"

    -

    -Testing the population of a collection

    +

    + Testing the population of a collection

    Collections are very useful structures, but they can be difficult to analyze and compare. utPLSQL provides the utAssert.eqColl and utAssert.eqCollAPI programs to help you do this. From 76c4cf2d52994858ab83ef29fb31fecf7c7a38ea Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 25 Jul 2002 12:18:18 +0000 Subject: [PATCH 023/143] Removed links to Example files Misc other tweaks --- documentation/src/testapi.html | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/documentation/src/testapi.html b/documentation/src/testapi.html index fa507efeb..ebea4a8d7 100644 --- a/documentation/src/testapi.html +++ b/documentation/src/testapi.html @@ -19,8 +19,8 @@

    Designer, RevealNet's PL/Generator and a variety of IDE (integrated development environment) tools.

    Suppose, then, that I used PL/Generator to generate a table encapsulation -package for the employee table. It would look like the code found in te_employee.pks -and te_employee.pkb (being rather +package for the employee table. It would look like the code found in te_employee.pks +and te_employee.pkb(1) (being rather lengthy, we will not reproduce it in the documentation. If you take a look, you will see that their are dozens of programs in the API, which means that you would have lots of work to do in building your unit test cases. @@ -38,7 +38,8 @@

    has also been working on generator utilities for a number of years. One of these utilities, currently "code named" GenX, came in very handy for creating a test package for his PL/Generator-generated encapsulation packages. -

    Using CGML (Code Generation Markup Language), Steven created a template +

    Using CGML (Code Generation Markup Language), Steven created a template +(See te_utpkg.gdr in the Examples directory of the utPLSQL distribution) that reads information from the data dictionary and defines the setup, teardown and at least a good starting point for the unit test procedures. Here is the template logic for the setup procedure: @@ -70,8 +71,8 @@

    in this fragment. If you are interested in pursuing these sorts of genreation opportunities and would like to check out GenX, drop a note to Steven Feuerstein. -

    Here is a portion of the generated logic (found in ut_te_employee.pks -and ut_te_employee.pkb), the +

    Here is a portion of the generated logic (found in ut_te_employee.pks +and ut_te_employee.pkb"(1)), the program that tests the delete operation in the encapsulation package:

       PROCEDURE ut_del1
        IS
    @@ -83,7 +84,7 @@ 

    DELETE FROM ut_DEL1 WHERE employee_id = -1 '; - te_employee.del (-1, rowcount_out => fdbk); + te_employee.del (-1, rowcount_out => fdbk); -- Test results utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1'); /* Successful delete */ @@ -99,7 +100,7 @@

    LOOP te_employee.del ( rec.employee_id, - rowcount_out => fdbk + rowcount_out => fdbk ); END LOOP; @@ -146,8 +147,8 @@

    if not impossible to verify success or notice failure.

    So I decided that the best way to run my unit tests for DML operations was to create a separate test table for each unit test. As a consequence, -my setup procedure for the te_employee -package looks like this: +my setup procedure for the te_employee package looks like this: +(See ut_te_employee.pkb in the Examples directory of the utPLSQL distribution)

       PROCEDURE ut_setup
        IS
        BEGIN
    @@ -260,7 +261,9 @@ 

    Again, I use dynamic SQL, but enclose each DROP TABLE statement inside its own exception section so that if for any reason the DROP fails, I continue on in an attempt to get as much done as possible. - +
    +

    Footnotes

    +1. These files are in the Examples directory of the utPLSQL distribution. From 3833a5d9d03524d0ab6b13527cbce7ca5667eb15 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 25 Jul 2002 12:24:57 +0000 Subject: [PATCH 024/143] Minor tweaks --- documentation/src/prefix.html | 10 +++++----- documentation/src/suite.html | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/documentation/src/prefix.html b/documentation/src/prefix.html index 62fef785e..0766380f3 100644 --- a/documentation/src/prefix.html +++ b/documentation/src/prefix.html @@ -13,17 +13,17 @@

    you get the picture).

    Since this prefix is not hard-coded into utPLSQL, you can very easily specify your own prefix. You can do this when you run a test, as in: -

    SQL> utPLSQL.test ('te_employee', prefix_in => 'test_');
    +
    SQL> utPLSQL.test ('te_employee', prefix_in => 'test_');
    You can also specify a prefix when you add a package to a test suite, as in: -
    SQL> utPackage.add ('mysuite', 'mypackage' prefix_in => 'test_');
    +
    SQL> utPackage.add ('mysuite', 'mypackage' prefix_in => 'test_');
    Of course, when you specify a non-default prefix, you must also build your test package using that prefix. If you plan to generate a starting point for your package with utGen, be sure to specify your prefix at that point, as in: -
    SQL> utGen.testpkg('mypackage' prefix_in => 'test_');
    -For an example of a package with a non-default prefix, check out test_te_employee.pks -and test_te_employee.pkb. +
    SQL> utGen.testpkg('mypackage' prefix_in => 'test_');
    +For an example of a package with a non-default prefix, check out test_te_employee.pks +and test_te_employee.pkb (Both to be found in the Examples directory of the utPLSQL distribution). diff --git a/documentation/src/suite.html b/documentation/src/suite.html index 3906abaab..d4f652072 100644 --- a/documentation/src/suite.html +++ b/documentation/src/suite.html @@ -18,9 +18,9 @@

    -- Add packages for testing utpackage.add ( - 'PLVision', 'PLVstr', dir_in => 'e:\openoracle\utplsql\examples'); + 'PLVision', 'PLVstr', dir_in => 'e:\openoracle\utplsql\examples'); utpackage.add ( - 'PLVision', 'PLVdate', dir_in => 'e:\openoracle\utplsql\examples'); + 'PLVision', 'PLVdate', dir_in => 'e:\openoracle\utplsql\examples'); END; /

    This is a very simple test suite definition. I rely on all defaults, but @@ -37,16 +37,16 @@

    utpackage.add ('PLVision', 'PLVstr', - dir_in => 'e:\openoracle\utplsql\examples', - seq_in => 1, - samepackage_in => TRUE + dir_in => 'e:\openoracle\utplsql\examples', + seq_in => 1, + samepackage_in => TRUE ); utpackage.add ('PLVision', 'PLVdate', - dir_in => 'e:\openoracle\utplsql\examples', - seq_in => 2, - samepackage_in => TRUE + dir_in => 'e:\openoracle\utplsql\examples', + seq_in => 2, + samepackage_in => TRUE ); END; /

    From 43eb8d2dcd866a1da34608165db2fe38696e45df Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 25 Jul 2002 14:20:50 +0000 Subject: [PATCH 025/143] Added documentation on utPLSQL trace functionality --- documentation/src/utoutput.html | 2 +- documentation/src/utplsql.html | 136 ++++++++++++++++++++++++++++++-- 2 files changed, 132 insertions(+), 6 deletions(-) diff --git a/documentation/src/utoutput.html b/documentation/src/utoutput.html index a85d19bb3..330e8ba90 100644 --- a/documentation/src/utoutput.html +++ b/documentation/src/utoutput.html @@ -79,7 +79,7 @@

    Outline of Usage

    Warning

    In the current version of utPLSQL (2.0.9.1) use of this package is virtually impossible with -utPLSQL tracing turned on. The reason for this is that this facility writes output using +utPLSQL tracing turned on. The reason for this is that this facility writes output using DBMS_OUTPUT every time an assertion is called.

    Saving Output

    diff --git a/documentation/src/utplsql.html b/documentation/src/utplsql.html index e1a755824..79d3d9473 100644 --- a/documentation/src/utplsql.html +++ b/documentation/src/utplsql.html @@ -40,6 +40,16 @@

    utPLSQL Package

    Get the version of utPLSQL

    + + +

    utPLSQL.trc
    + utPLSQL.notrc
    + utPLSQL.tracing

    + + +

    Control utPLSQL's tracing mechanism

    + +

    Run a Test or Test Suite

    @@ -55,7 +65,19 @@

    Run a Test or Test Suite

    To run a test for a single package, use the utPLSQL.test procedure:

    -
    PROCEDURE utPLSQL.test (
       package_in IN VARCHAR2,
       samepackage_in IN BOOLEAN := FALSE,
       prefix_in IN VARCHAR2 := NULL,
       recompile_in IN BOOLEAN := TRUE,
       dir_in IN VARCHAR2 := NULL,
       suite_in in VARCHAR2 := NULL,
       owner_in IN VARCHAR2 := NULL,
       reset_results_in IN BOOLEAN := TRUE ,
       from_suite_in         IN   BOOLEAN := FALSE,
       subprogram_in         IN   VARCHAR2 := '%',
       per_method_setup_in   IN   BOOLEAN := FALSE
    );
    +
    PROCEDURE utPLSQL.test (
    +   package_in IN VARCHAR2,
    +   samepackage_in IN BOOLEAN := FALSE,
    +   prefix_in IN VARCHAR2 := NULL,
    +   recompile_in IN BOOLEAN := TRUE,
    +   dir_in IN VARCHAR2 := NULL,
    +   suite_in in VARCHAR2 := NULL,
    +   owner_in IN VARCHAR2 := NULL,
    +   reset_results_in IN BOOLEAN := TRUE ,
    +   from_suite_in         IN   BOOLEAN := FALSE,
    +   subprogram_in         IN   VARCHAR2 := '%',
    +   per_method_setup_in   IN   BOOLEAN := FALSE
    +);

    where the parameters are defined as follows:

    @@ -201,7 +223,9 @@

    Run a Test or Test Suite

    If the test fails at some point, you will see output like this:

    -
    FAILURE: "betwnstr"
    BETWNSTR: IS NULL: NULL start
    BETWNSTR: End larger than string length; expected "cdeg", got "cdefg"
    +
    FAILURE: "betwnstr"
    +BETWNSTR: IS NULL: NULL start
    +BETWNSTR: End larger than string length; expected "cdeg", got "cdefg"

    Running a Test Suite

    @@ -209,7 +233,12 @@

    Running a Test Suite

    can set up a test suite that consists of one or more test packages. You can then run an entire suite of tests with a call to utPLSQL.testsuite:

    -
    PROCEDURE utPLSQL.testsuite (
       suite_in IN VARCHAR2,
       recompile_in IN BOOLEAN := TRUE,
       reset_results_in IN BOOLEAN := TRUE
       );
    +
    PROCEDURE utPLSQL.testsuite (
    +   suite_in IN VARCHAR2,
    +   recompile_in IN BOOLEAN := TRUE,
    +   reset_results_in IN BOOLEAN := TRUE
    +   per_method_setup_in in BOOLEAN := FALSE
    +   );

    where suite_in is the name of the suite and recompiled_in determines the auto compilation behavior. @@ -278,7 +307,18 @@

    Register a Unit Test

    Use the utPLSQL.addtest procedure to register a unit test.

    -
       PROCEDURE utPLSQL.addtest (
          NAME_IN IN VARCHAR2,
          utprefix_in IN VARCHAR2,
          iterations_in IN PLS_INTEGER := 1
       );
     
       PROCEDURE utPLSQL.addtest (
          package_in IN VARCHAR2,
          NAME_IN IN VARCHAR2,
          utprefix_in IN VARCHAR2,
          iterations_in IN PLS_INTEGER := 1
       );
    +
       PROCEDURE utPLSQL.addtest (
    +      NAME_IN IN VARCHAR2,
    +      utprefix_in IN VARCHAR2,
    +      iterations_in IN PLS_INTEGER := 1
    +   );
    + 
    +   PROCEDURE utPLSQL.addtest (
    +      package_in IN VARCHAR2,
    +      NAME_IN IN VARCHAR2,
    +      utprefix_in IN VARCHAR2,
    +      iterations_in IN PLS_INTEGER := 1
    +   );

    where

    @@ -303,7 +343,22 @@

    Register a Unit Test

    Here is a setup procedure that sets up a series of tests for a query-only encapsulation of the employee table:

    -
    CREATE OR REPLACE PACKAGE BODY ut_te_employee
    IS
       PROCEDURE ut_setup
       IS
       BEGIN
          utplsql.addtest ('UT_EMP_DEPT_LOOKUPROWCOUNT');
          utplsql.addtest ('UT_EMP_JOB_LOOKUPROWCOUNT');
          utplsql.addtest ('UT_EMP_MGR_LOOKUPROWCOUNT');
          utplsql.addtest ('UT_HIRE_DATE$VAL');
          utplsql.addtest ('UT_I_EMPLOYEE_NAME$ROW');
          utplsql.addtest ('UT_I_EMPLOYEE_NAME$VAL');
          utplsql.addtest ('UT_ONEROW');
          utplsql.addtest ('UT_PKYROWCOUNT');
          utplsql.addtest ('UT_ROWCOUNT');
          utplsql.addtest ('UT_SALARY$VAL');
       END;
    +
    CREATE OR REPLACE PACKAGE BODY ut_te_employee
    +IS
    +   PROCEDURE ut_setup
    +   IS
    +   BEGIN
    +      utplsql.addtest ('UT_EMP_DEPT_LOOKUPROWCOUNT');
    +      utplsql.addtest ('UT_EMP_JOB_LOOKUPROWCOUNT');
    +      utplsql.addtest ('UT_EMP_MGR_LOOKUPROWCOUNT');
    +      utplsql.addtest ('UT_HIRE_DATE$VAL');
    +      utplsql.addtest ('UT_I_EMPLOYEE_NAME$ROW');
    +      utplsql.addtest ('UT_I_EMPLOYEE_NAME$VAL');
    +      utplsql.addtest ('UT_ONEROW');
    +      utplsql.addtest ('UT_PKYROWCOUNT');
    +      utplsql.addtest ('UT_ROWCOUNT');
    +      utplsql.addtest ('UT_SALARY$VAL');
    +   END;

    Once you have placed your addtest programs into your test package's setup procedure, you are ready to build your own unit tests.

    @@ -315,6 +370,77 @@

    Return utPLSQL version

    FUNCTION utPLSQL.version RETURN VARCHAR2
    +

    utPLSQL Trace

    + +

    These routines are very simple and take no arguments:

    + +
    +PROCEDURE trc;
    +
    +PROCEDURE notrc;
    +
    +FUNCTION tracing RETURN BOOLEAN;
    +
    + +

    The procedures trc and notrc are used to turn tracing on and off +respectively. The function tracing returns TRUE if tracing is currently turned +on and FALSE otherwise. This facility is useful when writing code in utPLSQL +(the framework itself, not your test code). An example of the output generated +is:

    + +
    +Initialized utPLSQL session...
    +Setpkg to Lottery
    +Package and program = ut_Lottery
    +Same package? N
    +Is package? Y
    +Prefix = ut_
    +Recompiling ut_Lottery in
    +Runprog of ut_SETUP
    +Package and program = ut_Lottery.ut_SETUP
    +Same package? N
    +Is package? Y
    +Prefix = ut_
    +Addtest
    +Package and program = Lottery.UT_DRAW
    +Same package? N
    +Override? Y
    +Prefix = ut_
    +Runprog of UT_DRAW
    +Package and program = ut_Lottery.UT_DRAW
    +Same package? N
    +Is package? Y
    +Prefix = ut_
    +.
    +>  FFFFFFF   AA     III  L      U     U RRRRR   EEEEEEE
    +>  F        A  A     I   L      U     U R    R  E
    +>  F       A    A    I   L      U     U R     R E
    +>  F      A      A   I   L      U     U R     R E
    +>  FFFF   A      A   I   L      U     U RRRRRR  EEEE
    +>  F      AAAAAAAA   I   L      U     U R   R   E
    +>  F      A      A   I   L      U     U R    R  E
    +>  F      A      A   I   L       U   U  R     R E
    +>  F      A      A  III  LLLLLLL  UUU   R     R EEEEEEE
    +.
    +FAILURE: "Lottery"
    +.
    +> Individual Test Case Results:
    +>
    +FAILURE - EQ "Test of DRAW" Expected "01 02 05 27 43 49" and got "02 04 27 28 31 33"
    +>
    +>
    +> Errors recorded in utPLSQL Error Log:
    +>
    +> NONE FOUND
    +Runprog of ut_TEARDOWN
    +Package and program = ut_Lottery.ut_TEARDOWN
    +Same package? N
    +Is package? Y
    +Prefix = ut_
    +
    +PL/SQL procedure successfully completed.
    +
    + From b994627c112f30d2dcb947047855572c14dd696c Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 26 Jul 2002 15:46:49 +0000 Subject: [PATCH 026/143] Added references to all the routines in the package including the V2-specific delimiter routines --- documentation/src/utconfig.html | 65 +++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/documentation/src/utconfig.html b/documentation/src/utconfig.html index cd043b6f0..d6d69b5f9 100644 --- a/documentation/src/utconfig.html +++ b/documentation/src/utconfig.html @@ -56,11 +56,36 @@

    Set the registration mode (manual or automatic) + + utConfig.registering + +Return the registration mode + + utConfig.autocompile Set autocompile feature + + + utConfig.autocompiling + + Return the autocompile flag + + + +utConfig.setdelimiter + +Set the V2 delimiter + + + + utConfig.delimiter + + Return the V2 delimiter + +

    To make it as easy as possible for you to run your tests, utPLSQL stores @@ -149,9 +174,9 @@

    where dir_in is the directory and username_in is the name of the schema to which this directory applies (NULL means the currently used configuration is set), as in: -
    SQL> exec utconfig.setdir ('e:\demo\utplsql');
    +
    SQL> exec utconfig.setdir ('e:\demo\utplsql');
    or, with the specification of a non-current schema: -
    SQL> exec utconfig.setdir ('e:\demo\utplsql', 'ANALYSIS');
    +
    SQL> exec utconfig.setdir ('e:\demo\utplsql', 'ANALYSIS');
    Note that this directory must be accessible through UTL_FILE.

    You might consider putting the the call to utConfig.setdir into your login.sql so that it is run automatically, each time your start up SQL*Plus @@ -175,9 +200,9 @@

    where prefix_in is the prefix and username_in is the name of the schema to which this prefix applies (NULL means the currently used configuration is set), as in: -
    SQL> exec utconfig.setPrefix ('tst#');
    +
    SQL> exec utconfig.setPrefix ('tst#');
    or, with the specification of a non-current schema: -
    SQL> exec utconfig.setPrefix ('t_', 'ANALYSIS');
    +
    SQL> exec utconfig.setPrefix ('t_', 'ANALYSIS');

    Return the default unit test prefix for your code.

    @@ -202,9 +227,16 @@

    username_in IN VARCHAR2 := NULL );

    as in: -
    SQL> exec utConfig.registerTest (TRUE)
    +
    SQL> exec utConfig.registerTest (TRUE)
    Note: if you are using automatic unit test detection, any calls to utPLSQL.addtest in the setup procedure will be ignored. + +

    You can return the current registration mode using the following function: +

    FUNCTION registeringtest (username_in IN VARCHAR2 := NULL)
    +   RETURN BOOLEAN;
    +This returns TRUE if the registration mode has been set to manual and FALSE otherwise. +

    +

    Set autocompile feature

    @@ -228,8 +260,8 @@

    parameter). The package specification -must be contained in a file named <package>.pks; the body must be stored -in <package>.pkb. +must be contained in a file named <package>.pks; the body must be stored +in <package>.pkb. You must have configured the @@ -278,11 +310,11 @@

       utsuite.addpkg (
    -
          'PLVision', 'PLVstr', dir_in => 'e:\utplsql');
    +
          'PLVision', 'PLVstr', dir_in => 'e:\utplsql');
       utsuite.addpkg (
    -
          'PLVision', 'PLVdate', dir_in => 'e:\utplsql');
    +
          'PLVision', 'PLVdate', dir_in => 'e:\utplsql');
      
    @@ -290,7 +322,7 @@

       utplsql.testsuite (
    -
          'PLVision', recompile_in => FALSE);
    +
          'PLVision', recompile_in => FALSE);
    END;
    @@ -315,7 +347,7 @@



    -
    SQL> exec utconfig.autocompile (FALSE, 'SCOTT') 
    +
    SQL> exec utconfig.autocompile (FALSE, 'SCOTT') 
    This program updates the ut_config table with your information and then commits the setting. @@ -331,6 +363,17 @@

    value to FALSE, that will override anything you pass in a call to utPLSQL.test or utPLSQL.testsuite. +

    + V2 Delimiter

    +

    You can set the delimiter to be used in V2 procedure names using the following procedure: +

    PROCEDURE setdelimiter (
    +  delimiter_in IN VARCHAR2, 
    +  username_in IN VARCHAR2 := NULL
    +); 
    +while the current delimiter can be obtained by the function: +
    FUNCTION delimiter (username_in IN VARCHAR2 := NULL)
    +  RETURN VARCHAR2;
    +

    From d44293ef8f30f8032706966576552757aabecbd6 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 26 Jul 2002 16:13:50 +0000 Subject: [PATCH 027/143] Added the success display routines Removed broken link --- documentation/src/utresult.html | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/documentation/src/utresult.html b/documentation/src/utresult.html index 2a722edbd..ca2b4b8fe 100644 --- a/documentation/src/utresult.html +++ b/documentation/src/utresult.html @@ -37,6 +37,13 @@

    Iterate through the results array + + + utResult.include_successes
    + utResult.ignore_successes + Control the display of passed tests + + The utResult package offers an API to the information @@ -48,8 +55,8 @@

    see or evaluate the results of a test (or suite of tests). The information will be displayed on your screen using DBMS_OUTPUT. You might, however, want to access this information in another environment (say, Oracle Forms -or Java, etc.). You might also want to build -your own assertion logic or test engine. In either of these cases, +or Java, etc.). You might also want to build +your own assertion logic or test engine. In either of these cases, you will want to use the programs in the utResult package.

    @@ -102,6 +109,16 @@

    ); FUNCTION utResult.resultcount RETURN PLS_INTEGER;

    + +

    + Control the Display of Success Messages

    +

    The following procedures turn on or off the display of success messages. In other words, +when turned on (as is the default) a message will be displayed for each successful assertion. +The specifications are as follows: +

    +procedure include_successes;
    +procedure ignore_successes; 

    + From ed51d6a97f499949c5bc5bd0ff8b62cc4d30ce01 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 30 Jul 2002 15:56:55 +0000 Subject: [PATCH 028/143] Changed "code" style to make it look like "pre" --- documentation/utplsql.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/documentation/utplsql.css b/documentation/utplsql.css index 3770da25e..fe4a5d0e5 100644 --- a/documentation/utplsql.css +++ b/documentation/utplsql.css @@ -32,7 +32,8 @@ Pre {font-family: Courier, Monotype; padding-right: 10px} /* Code in monotype */ -Code {font-family: Courier, Monotype;} +Code {font-family: Courier, Monotype; + font-size: smaller;} /* Copyright notice is tiny */ .copyright {font-size: xx-small} From 22678383223355d4a834b7cbdb95db8596b9cd83 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 30 Jul 2002 15:57:52 +0000 Subject: [PATCH 029/143] Added explanation of the testcase generation via grid --- documentation/src/utgen.html | 294 ++++++++++++++++++++++++++++++++--- 1 file changed, 270 insertions(+), 24 deletions(-) diff --git a/documentation/src/utgen.html b/documentation/src/utgen.html index 0e94c5720..3d757492b 100644 --- a/documentation/src/utgen.html +++ b/documentation/src/utgen.html @@ -9,11 +9,22 @@


    - + + + + + + + + @@ -29,8 +40,8 @@


    utGen.atLastRow
    utGen.setRow
    utGen.getRow -
    utGen.nextRow; -
    utGen.prevRow; +
    utGen.nextRow +
    utGen.prevRow
    utGen.showRows
    utGen.nthRow @@ -154,13 +165,15 @@

    The type of output that will receive the generated code. Valid options are defined as packaged constants: -
    utGen.c_file
    +
      +
    • utGen.c_file
    • -
      utGen.c_screen
      +
    • utGen.c_screen
    • -
      utGen.c_string
      +
    • utGen.c_string
    • -
      utGen.c_array
      +
    • utGen.c_array
    • +
    The following sections explain the way you would work with these constants and the resulting generated code. @@ -226,7 +239,7 @@

    -
    SQL> exec utGen.testpkg ('str')
    +
    SQL> exec utGen.testpkg ('str')
    @@ -237,7 +250,7 @@

    -
    SQL> exec utGen.testpkg ('str', samepackage_in => TRUE)
    +
    SQL> exec utGen.testpkg ('str', samepackage_in => TRUE)
    @@ -249,7 +262,7 @@

    -
    SQL> exec utGen.testpkg ('str', '%STR%', samepackage_in => TRUE)
    +
    SQL> exec utGen.testpkg ('str', '%STR%', samepackage_in => TRUE)
    @@ -269,15 +282,15 @@

    Here is an example of using utGen.testpkg, while also spooling to a file: -
    SQL> set serveroutput on size 1000000
    +
    SQL> set serveroutput on size 1000000
    -
    SQL> spool str.pkg
    +
    SQL> spool str.pkg
    -
    SQL> exec utgen.testpkg ('str')
    +
    SQL> exec utgen.testpkg ('str')
    ...out comes the code... -
    SQL> spool off
    +
    SQL> spool off
    If DBMS_OUTPUT is not enabled in your session, then utGen.testpkg will not generate any output. @@ -295,7 +308,7 @@

    Here's a generation request that creates two files named ut_str.pks and ut_str.pkb in the /newcode directory: -
    SQL> exec utgen.testpkg ('str', output_type_in => utGen.c_file, dir_in => '/newcode')
    +
    SQL> exec utgen.testpkg ('str', output_type_in => utGen.c_file, dir_in => '/newcode')
    Notes on generating to file: @@ -311,9 +324,9 @@

    -
    SQL> exec utconfig.setdir ('/newcode')
    +
    SQL> exec utconfig.setdir ('/newcode')
    -
    SQL> exec utgen.testpkg ('str', output_type_in => utGen.c_file);
    +
    SQL> exec utgen.testpkg ('str', output_type_in => utGen.c_file);
    @@ -339,7 +352,7 @@

    BEGIN
    -
       utgen.testpkg ('str', output_type_in => utGen.c_string);
    +
       utgen.testpkg ('str', output_type_in => utGen.c_string);
    END;
    @@ -355,9 +368,9 @@

          'str',
    -
          output_type_in => utGen.c_string,
    +
          output_type_in => utGen.c_string,
    -
          delim_in => CHR(10));
    +
          delim_in => CHR(10));
    END;
    @@ -381,7 +394,7 @@

    BEGIN
    -
       utgen.testpkg ('str', output_type_in => utGen.c_array);
    +
       utgen.testpkg ('str', output_type_in => utGen.c_array);
    END;
    @@ -529,6 +542,239 @@

       END;
    - - - +

    + Generating Test Packages with Test Cases

    + +

    The procedures to generate test packages with test cases are similar to testpkg above, but with a number of extra parameters:

    + +
     PROCEDURE testpkg (
    +      package_in           IN   VARCHAR2,
    +      grid_in              IN   grid_tt,
    +      program_in           IN   VARCHAR2 := '%',
    +      samepackage_in       IN   BOOLEAN := FALSE,
    +      prefix_in            IN   VARCHAR2 := NULL,
    +      schema_in            IN   VARCHAR2 := NULL,
    +      output_type_in       IN   PLS_INTEGER := c_screen,
    +      dir_in               IN   VARCHAR2 := NULL,
    +      delim_in             IN   VARCHAR2 := c_delim,
    +      date_format_in       IN   VARCHAR2 := 'MM/DD/YYYY',
    +      only_if_in_grid_in   IN   BOOLEAN := FALSE
    +   );
    +
    +   PROCEDURE testpkg_from_file (
    +      package_in           IN   VARCHAR2,
    +      gridfile_loc_in      IN   VARCHAR2,
    +      gridfile_in          IN   VARCHAR2,
    +      program_in           IN   VARCHAR2 := '%',
    +      samepackage_in       IN   BOOLEAN := FALSE,
    +      prefix_in            IN   VARCHAR2 := NULL,
    +      schema_in            IN   VARCHAR2 := NULL,
    +      output_type_in       IN   PLS_INTEGER := c_screen,
    +      dir_in               IN   VARCHAR2 := NULL,
    +      field_delim_in       IN   VARCHAR2 := '|',
    +      arg_delim_in         IN   VARCHAR2 := c_delim,
    +      date_format_in       IN   VARCHAR2 := 'MM/DD/YYYY',
    +      only_if_in_grid_in   IN   BOOLEAN := FALSE
    +   );
    +
    +   PROCEDURE testpkg_from_string (
    +      package_in           IN   VARCHAR2,
    +      grid_in              IN   VARCHAR2,
    +      program_in           IN   VARCHAR2 := '%',
    +      samepackage_in       IN   BOOLEAN := FALSE,
    +      prefix_in            IN   VARCHAR2 := NULL,
    +      schema_in            IN   VARCHAR2 := NULL,
    +      output_type_in       IN   PLS_INTEGER := c_screen,
    +      dir_in               IN   VARCHAR2 := NULL,
    +      line_delim_in        IN   VARCHAR := CHR (10),
    +      field_delim_in       IN   VARCHAR2 := '|',
    +      arg_delim_in         IN   VARCHAR2 := c_delim,
    +      date_format_in       IN   VARCHAR2 := 'MM/DD/YYYY',
    +      only_if_in_grid_in   IN   BOOLEAN := FALSE
    +   ); 
    + +

    In each case, the idea is the same. We have to provide not only the +arguments supplied to the basic version of testpkg, but also details of each of +the test cases in a grid. In the first case, this is as a PL/SQL table, in the +second this is as a file and in the final case, this is as a string.

    + +

    The PL/SQL table passed to testpkg is defined as follows:

    + +

     TYPE grid_rt IS RECORD (
    +      progname                      VARCHAR2 (100),
    +      overload                      PLS_INTEGER,
    +      tcname                        VARCHAR2 (100),
    +      message                       VARCHAR2 (2000),
    +      arglist                       VARCHAR2 (2000),
    +      return_value                  VARCHAR2 (2000),
    +      assertion_type                VARCHAR2 (100));
    +
    +   TYPE grid_tt IS TABLE OF grid_rt
    +      INDEX BY BINARY_INTEGER; 
    + +

    Where the definitions of the fields are as follows:

    + +
      + +
    1. progname - This is the name of the subprogram to be tested.
    2. + +
    3. overload - This is the version of the subprogram where + overladed versions exist. (You may have to look in the data dictionary to + work this out).
    4. + +
    5. tcname - The name of the test case.
    6. + +
    7. message - The message to be used in the assertion + code.
    8. + +
    9. arglist - The list of arguments to be passed to the + subprogram.
    10. + +
    11. return_value - The return value to be checked against.
    12. + +
    13. assertion_type - The type of assertion to be used. + Currently this is ignored unless it contains 'EQ' or 'ISNULL'
    14. + +
    + +

    In testpkg_from_file and testpkg_from_string, exactly the same fields need +to be passed (and in the same order). These fields are separated by the +character given by the field_delim_in parameter which defaults to '|', the pipe +symbol. In the case of testpkg_from_string, we can also specify the line +delimiter in the line_delim_in parameter, which defaults to an ASCII linefeed +character.

    + +

    In all cases, the arguments specified in the arglist field are separated +by yet another delimiter, which is passed in the arg_delim_in parameter (or just delim_in in the case of testpkg). This defaults to a semicolon.

    + +

    The remaining arguments passed to these routines are date_format_in and only_if_in_grid_in. The former gives the date format used in dates passed through the arglist and return_values fields. The latter specifies if tests should only be generated for subprograms listed in the grid or not.

    + +

    An Example

    + +

    All of this is probably best explained with an example. Suppose I have a package defined as:

    + +
    +CREATE OR REPLACE PACKAGE lottery AS
    +  FUNCTION Draw (seed_in NUMBER := NULL, when_in DATE := NULL) RETURN VARCHAR2;
    +END;
    +
    + +

    This returns a string describing a lottery draw, given a seed and a date. I +want to test the following conditions: (It doesn't make much sense, but hey, +it's only an example) + +

      + +
    • Passing both parameters as NULL, we should get back '01 02 03 04 05 + 06'.
    • + +
    • Passing in 7 for the seed and 1 January 2001 for the date, we should get back '23 24 27 37 39 48'.
    • + +
    • Passing in 0 for the seed and today's date, we should get back NULL
    • + +
    So to generate the skeleton I require I could run the following through +SQL*Plus:

    + +
    set serveroutput on size 1000000
    +declare
    +  a_grid utgen.grid_tt;
    +begin
    +  
    +  a_grid(0).progname := 'Draw';
    +  a_grid(0).tcname := 'Test Case 1';
    +  a_grid(0).message := 'The First Test';
    +  a_grid(0).return_value := '01 02 03 04 05 06';
    +  a_grid(0).assertion_type := 'EQ';
    +  a_grid(1).progname := 'Draw';
    +  a_grid(1).tcname := 'Test Case 2';
    +  a_grid(1).message := 'The Second Test';
    +  a_grid(1).arglist := '7;2001-01-01';
    +  a_grid(1).return_value := '23 24 27 37 39 48';
    +  a_grid(1).assertion_type := 'EQ';
    +  a_grid(2).progname := 'Draw';
    +  a_grid(2).tcname := 'Test Case 3';
    +  a_grid(2).message := 'The Third Test';
    +  a_grid(2).return_value := NULL;
    +  a_grid(2).arglist := '0;!SYSDATE';
    +  a_grid(2).assertion_type := 'ISNULL';
    +  
    +  utgen.testpkg(
    +    package_in => 'LOTTERY', 
    +    grid_in => a_grid, 
    +    date_format_in => 'YYYY-MM-DD');
    +end;
    +/
    + +

    or the equivalent:

    + +
    set serveroutput on size 1000000
    +begin
    +  utgen.testpkg_from_string (
    +      package_in => 'LOTTERY',
    +      grid_in =>
    +'Draw||Test Case 1|The First Test||01 02 03 04 05 06|EQ
    +Draw||Test Case 2|The Second Test|7;2001-01-01|23 24 27 37 39 48|EQ
    +Draw||Test Case 3|The Third Test|0;!SYSDATE||ISNULL',
    +      date_format_in => 'YYYY-MM-DD'
    +   );
    +end;
    +/ 
    + +

    which generate the following for the body of ut_draw (tidied up a little for compactness):

    + +
    PROCEDURE ut_DRAW
    +IS
    +   -- Verify and complete data types.
    +   against_this VARCHAR2(2000);
    +   check_this VARCHAR2(2000);
    +BEGIN
    +   
    +   -- Define "control" operation for "Test Case 1"
    +   against_this := '01 02 03 04 05 06';
    +    
    +   -- Execute test code for "Test Case 1"
    +   check_this := 
    +   LOTTERY.DRAW (SEED_IN => '', WHEN_IN => '');
    +    
    +   -- Assert success for "Test Case 1"
    +   -- Compare the two values.
    +   utAssert.eq ( 'The First Test', check_this, against_this);
    +
    +   -- End of test for "Test Case 1"
    +   
    +   -- Define "control" operation for "Test Case 2"
    +   against_this := '23 24 27 37 39 48';
    +    
    +   -- Execute test code for "Test Case 2"
    +   check_this := LOTTERY.DRAW (SEED_IN => 7, WHEN_IN => TO_DATE ('2001-01-01', 'YYYY-MM-DD'));
    +    
    +   -- Assert success for "Test Case 2"
    +   -- Compare the two values.
    +   utAssert.eq ( 'The Second Test', check_this, against_this);
    +
    +   -- End of test for "Test Case 2"
    +   
    +   -- Define "control" operation for "Test Case 3"
    +   against_this := NULL;
    +    
    +   -- Execute test code for "Test Case 3"
    +   check_this := 
    +   LOTTERY.DRAW (SEED_IN => 0, WHEN_IN => SYSDATE);
    +    
    +   -- Assert success for "Test Case 3"
    +   -- Check for NULL return value.
    +   utAssert.isNULL ( 'The Third Test', check_this);
    +
    +   -- End of test for "Test Case 3"
    +   
    +END ut_DRAW; 
    + +

    Note that the different data types are handled automatically. So '2001-01-01' is converted to +a date using TO_DATE and the specified date format. However, we wanted to enter SYSDATE for our +argument in one of these cases. How do we stop this being converted into a date? The answer +is that we need to prefix the value with a '!' (an exclamation mark). This causes utGen to +pass this along 'as is' without attempting any conversion. Note that this cannot currently +be overridden, so if your data starts with an exclamation mark, you'll have to work around +this problem.

    + + From 7b9006cafa9b42bd0310eba5464bc1b033c4db97 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 30 Jul 2002 16:08:09 +0000 Subject: [PATCH 030/143] Minor tweaks --- documentation/src/defsuite.html | 52 ++++++++++++++------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/documentation/src/defsuite.html b/documentation/src/defsuite.html index b33277dc9..0b5b71374 100644 --- a/documentation/src/defsuite.html +++ b/documentation/src/defsuite.html @@ -6,47 +6,40 @@

    Define Test Suites

    If you define test suites and register packages -within those suites, then utPLSQL will both run an unlimited number of -tests with a single command and also track information about your tests -(number of executions, number of failures, start and end date/times for -the last test run). +within those suites, then utPLSQL will run an unlimited number of +tests with a single command. -FINISH: put these notes with the appropriate program -doc. - -Notes on these programs: +

    Note

    • All suite names are stored in upper case.
    • +
    • If you do not specify a directory (dir_in), you will need to call utConfig.setdir if you want automatic compilation -of your packages to occur. +of your packages to occur.
    • -If you supply a value for seq_in, packages -will be compiled and tested in ascending numeric sequence order. +
    • If you supply a value for seq_in, packages +will be compiled and tested in ascending numeric sequence order.
    • -When you call utSuite.rem, it will remove all -packages for that suite by calling utPackage.rem. +
    • When you call utSuite.rem, it will remove all +packages for that suite by calling utPackage.rem.

    utSuite - Define Test Suites

    -To define a test suite, call this program: - -
       PROCEDURE utSuite.add (
    - -
          name_in IN VARCHAR2,
    - -
          desc_in IN VARCHAR2 := NULL,
    - -
          rem_if_exists_in IN BOOLEAN := TRUE
    +To create and remove test suites, call these programs: -
          );
    +
    +   PROCEDURE utSuite.add (
    +      name_in IN VARCHAR2,
    +      desc_in IN VARCHAR2 := NULL,
    +      rem_if_exists_in IN BOOLEAN := TRUE
    +      );
     
    -
       PROCEDURE utSuite.rem (name_in IN VARCHAR2);
    + PROCEDURE utSuite.rem (name_in IN VARCHAR2);
    These programs manipulate the contents of the ut_suite table. See the tables.sql file for the DDL creating this table. @@ -54,8 +47,7 @@

    utPackage - Define Test Packages for a Suite

    -To register a package in a suite, call one -of the following: +To register a package in a suite, call the following:
       PROCEDURE utPackage.add (
    @@ -79,7 +71,7 @@

       );
    -These programs manipulate the contents of the ut_package +This manipulates the contents of the ut_package table. See the tables.sql file for the DDL creating this table. Here is a sample script that defines a very small @@ -93,17 +85,17 @@

       utPackage.add
    -
          'PLVision', 'PLVstr', dir_in => 'e:\utplsql\test');
    +
          'PLVision', 'PLVstr', dir_in => 'e:\utplsql\test');
      
       utPackage.add (
    -
          'PLVision', 'PLVdate', dir_in => 'e:\utplsql\test'');
    +
          'PLVision', 'PLVdate', dir_in => 'e:\utplsql\test'');
      
    -
       utPLSQL.testsuite ('PLVision', recompile_in => TRUE);
    +
       utPLSQL.testsuite ('PLVision', recompile_in => TRUE);
    END;
    From 9794aee869d97e50408f2804feabf24608bda90f Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 31 Jul 2002 15:48:37 +0000 Subject: [PATCH 031/143] Added utRecEq Package to User Guide --- documentation/src/map.txt | 1 + documentation/src/userguide.html | 3 ++ documentation/src/utreceq.html | 91 ++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 documentation/src/utreceq.html diff --git a/documentation/src/map.txt b/documentation/src/map.txt index 9ee6d8661..089a6a5e6 100644 --- a/documentation/src/map.txt +++ b/documentation/src/map.txt @@ -28,5 +28,6 @@ utresult.html,utResult Package utassert.html,utAssert Package utgen.html,utGen Package utoutput.html,utOutput Package +utreceq.html,utRecEq Package defsuite.html,Define Test Suites release.html,Release Notes* diff --git a/documentation/src/userguide.html b/documentation/src/userguide.html index 7399406ee..c75f20d16 100644 --- a/documentation/src/userguide.html +++ b/documentation/src/userguide.html @@ -34,6 +34,9 @@

    utOutput - Handling DBMS_OUTPUT for testing

    +

    + utRecEq - Generate functions to compare record types

    +

    Define Test Suites

    diff --git a/documentation/src/utreceq.html b/documentation/src/utreceq.html new file mode 100644 index 000000000..0a01c0a21 --- /dev/null +++ b/documentation/src/utreceq.html @@ -0,0 +1,91 @@ + + + + +

    + utRecEq Package +

    + +

    This package contains the following procedures and functions: +
    +

    utGen.testpkgutGen.testpkg (basic version) Generate skeleton test packages
    + utGen.testpkg (grid version)
    + utGen.testpkg_from_file
    + utGen.testpkg_from_string +
    Generate skeleton test packages with test cases
    utGen.pkgstring
    + + + + + + + + + + + + + +
    utRecEq.addAdd a record type comparison function
    utRecEq.compileCompile a package's record type comparison functions
    utRecEq.remRemove record type comparison functions
    + +

    Generate functions to compare record types

    + +

    This package (created by Dan Spencer) allows the creation of functions to +allow the comparison of record types based on tables or views (%ROWTYPE +records in other words). They are generated by the add procedure: + +

    PROCEDURE add(
    +   pkg_name_in IN ut_package.name%TYPE,
    +   record_in  IN ut_receq.name%TYPE,
    +   rec_owner_in  IN ut_receq.created_by%TYPE := USER
    +);
    + +The pkg_name_in parameter contains the name of a tested package you wish to +associate with this record type. Note that this package name should already +exist in the ut_package table. The record_in parameter contains the name of +the view or table whose record type is to be compared. The final (optional) +parameter contains the name of the schema in which the table or view exists. +It defaults to the current user.

    + +

    The generated function will be named EQ_{Record_Schema_}Record_Name. The +schema is only inserted when the record type is not within the current one. The +function will return TRUE if the two records are identical on a field-by-field +comparison and FALSE otherwise. Note that NULL fields are considered +equal.

    + +

    The details of the EQ_* functions and their association with tested packages held in two tables: +

      + +
    • UT_RECEQ - This table holds a list of the EQ_* functions including the + target table/view and the schema in which it is found.
    • + +
    • UT_RECEQ_PKG - This table cross-references the tested packages against the functions listed in UT_RECEQ.
    • + +

    + +

    Compile a package's record comparison functions

    + +

    This routine recompiles all the EQ_* functions associated with a given package: + +

    PROCEDURE compile(pkg_name_in IN ut_package.name%TYPE);
    + +when autocompiling is turned on, this is called by +utplsql.test or utplsql.testsuite before the test packages themselves are recompiled.

    + +

    Remove record comparison functions

    + +

    To remove record comparison functions, use the following: + +

    PROCEDURE rem(
    +   name_in  IN ut_receq.name%TYPE,
    +   rec_owner_in   IN ut_receq.created_by%TYPE := USER
    +   for_package_in IN BOOLEAN := FALSE
    +);
    + +If for_package_in is FALSE, then name_in is taken to refer to a record type to +remove, with rec_owner_in specifying the schema the record type is in. All package associations for this record type are removed and the EQ_* function is dropped.

    + +

    On the other hand, if for_package_in is TRUE, then name_in is taken to refer +to a package. In this case, all the package's associations are removed. If no +other package is associated with a given record, then the EQ_* function is +dropped. (Note that the rec_owner_in parameter is ignored here).

    + + + + From 2394b97a11939e28c897bd4daf9080cb70811696 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Mon, 5 Aug 2002 19:39:32 +0000 Subject: [PATCH 032/143] Added section on objectExists assertions --- documentation/src/utassert.html | 40 ++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/documentation/src/utassert.html b/documentation/src/utassert.html index cfc9f58c5..5681f4375 100644 --- a/documentation/src/utassert.html +++ b/documentation/src/utassert.html @@ -72,7 +72,11 @@

    utAssert Package

    utAssert.eqoutput Check Equality of DBMS_OUTPUT Collections - + + utAssert.objexists
    + utAssert.objnotexists + Check for existence of database objects + The utAssert package provides a set of assertion routines ("assert that @@ -664,7 +668,35 @@

    Comparing output from DBMS_OUTPUT

  • ignore_whitespace_in - this specifies that whitespace differences should be ignored when comparing lines.
  • -

    Finally, note that only the text itself is compared. These assertions do not care about how the records within the collections are numbered.

    +

    Finally, note that only the text itself is compared. These assertions do +not care about how the records within the collections are numbered.

    + +

    Check for Existence of Database Objects

    + +

    The following assertions (created by Raji) check that a named database +object exists or does not exist: + +

    PROCEDURE objExists (
    +   msg_in            IN   VARCHAR2,
    +   check_this_in     IN   VARCHAR2,
    +   null_ok_in        IN   BOOLEAN := FALSE,
    +   raise_exc_in      IN   BOOLEAN := FALSE
    +);
    +
    +PROCEDURE objnotExists (
    +   msg_in            IN   VARCHAR2,
    +   check_this_in     IN   VARCHAR2,
    +   null_ok_in        IN   BOOLEAN := FALSE,
    +   raise_exc_in      IN   BOOLEAN := FALSE
    +);
    + +In both cases, the check_this_in parameter gives the name of the object to +check for. So passing 'MYTHING' will check if the MYTHING object exists. This +is assumed to be in the current schema. To check for objects in a schema other +than the current one, simply add the name of the schema, separated by a dot. +So passing 'ANOTHER.THATTHING' will check for the existence of the THATTHING +object in the ANOTHER schema.

    +

    Building Your Own Assertion

    You may want to build assertion routines that fit your specific needs. If PL/SQL supported inheritance, you could extend the utAssert assertion @@ -677,7 +709,9 @@

    Building Your Own Assertion

             -- Registers the results in the utResult databank.
    utresult.report (msg_in);
    ELSE
    utplsql.pl (msg_in);
    END IF;

    IF showing_results AND register_in
    THEN
             -- Show the results of the test more recently run.
    utresult.showlast;
    END IF;

    IF raise_exc_in
    THEN
    RAISE test_failure;
    END IF;
    END IF;
    END;
    The most important statement to include in your assertion routine is the -call to utResult.report, which will log the results of the test. + call to utResult.report, which will log the results of the test. + + From 0337aea12bda93a85c57af3e823e34bb680006dd Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 6 Aug 2002 13:21:16 +0000 Subject: [PATCH 033/143] Added Steven's Release Notes for 2.0.9.2 --- documentation/src/release.html | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/documentation/src/release.html b/documentation/src/release.html index 856740be3..7a69ff2b7 100644 --- a/documentation/src/release.html +++ b/documentation/src/release.html @@ -16,9 +16,29 @@

    utPLSQL version 2.x

    , but this can cause other problems if the tests themselves have rollbacks within them.
    +
  • The utAssert.eqtable assertion program will not work with tables that + contain non-scalar datatypes, such as LOBs, XMLType, collections and so on. +
  • Change History

    +

    utPLSQL version 2.0.9.2

    +
      +
    • Surround + AUTHID CURRENT_USER clause of utreceq.pks to allow for installation on + Oracle7 and Oracle8.
    • +
    • Add + override_package_in argument to utPLSQL.test so that you can bypass the + standard ut_<package> naming conventions for testing. This is useful + when your package name's length is 28 or above. By passing in the override + package name, you can avoid the name limitation.
    • +
    • New + assertion programs to validate DBMS_OUTPUT text that is generated from + within a program.
    • +
    • Add + utplsql.run and utplsql.runsuite to run a named test package directly, and + not correlate it via the name of the program being tested.
    • +

    utPLSQL version 2.0.9.1

    Change History

    +

    utPLSQL version 2.0.10.1

    +
      +
    • +Allow user to specify (as part of their individual configuration) that they +only want to show failed tests, and then whether all information or just the +description (request from Heinz of UBS). Supersedes the +utresult.ignore_successes and utresult.include_successes (whose settings do not +persist across sessions). +
    • +
    • +Support for testing contents of REF CURSORs (cursor variables) has been added +(provided by Venky Mangapillai) with the eq_refc_table and eq_refc_query +assertion routines. +
    • +
    • +Adds testpkg_from_table to utgen to allow generation of a test package directly +from the new ut_grid table (provided by Patrick Barel). Patrick has also built +a Windows-based front end, utGen.exe, that allows us to populate this grid very +easily. Thanks, Patrick! +
    • +
    • +Add ut_outcome_seq sequence for ut_outcome table. +
    • +
    • +Add control_info and test_info columns to ut_outcome table. +
    • +
    • +Add ability to direct output from utPLSQL's test run (the test results) to a +file instead of to the screen. This functionality was provided by Rainer +Medert. The documentation for this feature has not yet been integrated into the +documentation set. You will find the "beta" documentation in the +file_output_spec.doc in the doc directory. +
    • +

    utPLSQL version 2.0.9.2

    • Surround From 14d8281daf157f7d48c7e8441ca13aae4f5cfbf2 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Mon, 7 Oct 2002 16:33:19 +0000 Subject: [PATCH 036/143] Removed spurious space --- documentation/src/map.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/src/map.txt b/documentation/src/map.txt index 72ea8cdab..5d2f86047 100644 --- a/documentation/src/map.txt +++ b/documentation/src/map.txt @@ -27,7 +27,7 @@ utconfig.html,utConfig Package utresult.html,utResult Package utassert.html,utAssert Package utgen.html,utGen Package -utgen_frontend.html, utGen Front-End +utgen_frontend.html,utGen Front-End utoutput.html,utOutput Package utreceq.html,utRecEq Package defsuite.html,Define Test Suites From 3d2257e94d74edc56944c12c4b2993b289b39659 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 10 Oct 2002 08:22:59 +0000 Subject: [PATCH 037/143] Removed a couple of references to Yahoo Group and replaced with the forum --- documentation/src/admin.html | 7 +++---- documentation/src/index.html | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/documentation/src/admin.html b/documentation/src/admin.html index ef1392960..fa599833a 100644 --- a/documentation/src/admin.html +++ b/documentation/src/admin.html @@ -156,10 +156,9 @@

      Join the utPLSQL Project Team

      To take part in the utPLSQL project, first please join -our email distribution group. Go to -http://groups.yahoo.com/group/utPLSQL-Info -and subscribe to the utPLSQL-Info list. You will be including in ongoing -communication about utPLSQL. Once you are up to speed on the project, you +the utPLSQL Forum. Go to +http://utplsql.oracledeveloper.nl +and join in the discussions. Once you are up to speed on the project, you can go to the SourceForge site, choose a task and begin to contribute. diff --git a/documentation/src/index.html b/documentation/src/index.html index f96d17001..da46a5eeb 100644 --- a/documentation/src/index.html +++ b/documentation/src/index.html @@ -52,8 +52,8 @@

      The utPLSQL project is hosted at Sourceforge - the home page is to be found at http://utplsql.sourceforge.net. From here, there are links to the various resources available and details on how to get involved in the project. Discussion of utPLSQL takes place at -Yahoo! Groups, so to ask further questions, or for help with problems visit -http://groups.yahoo.com/group/utPLSQL-Info.

      +the utPLSQL Forum, so to ask further questions, or for help with problems visit +http://utplsql.oracledeveloper.nl.

      From 408b5ff3c78f0b8def30bf8041548cfeeacf760f Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Mon, 6 Jan 2003 21:26:17 +0000 Subject: [PATCH 038/143] Added documentation on file output --- documentation/src/fileout.html | 149 ++++++++++++++++++++++++++++++++ documentation/src/map.txt | 1 + documentation/src/utconfig.html | 71 +++++++++++++++ 3 files changed, 221 insertions(+) create mode 100644 documentation/src/fileout.html diff --git a/documentation/src/fileout.html b/documentation/src/fileout.html new file mode 100644 index 000000000..348ac26f0 --- /dev/null +++ b/documentation/src/fileout.html @@ -0,0 +1,149 @@ + + + + +

      +Configuring File Output +

      + +

      +Outline +

      +By default, the results of a test run are written to the screen +(via DBMS_OUTPUT). The subprograms described in this section were created +by Rainer Medert to allow these results to be written to file instead. +They form part of the utConfig package. +Don't forget that you will first need to enable file output from the database +via the UTL_FILE_DIR parameter in order to do this. + +

      +Turning file output on +

      + +

      To turn on file output, use the follow procedure:

      + +
      PROCEDURE setfile (
      +  fileout_in IN BOOLEAN := FALSE, 
      +  username_in IN VARCHAR2 := NULL
      +);
      + +

      the boolean flag specifies whether file output should be turned on or off, +while the username specifies which tester to set the flag for. As usual, +this defaults to the user returned by utConfig.tester.

      + +

      To see if file output is being used, use the following:

      + +
      FUNCTION getfile (username_in IN VARCHAR2 := NULL) RETURN BOOLEAN;
      + +

      this will return the file output flag for the given user.

      + +

      +Setting the directory to be used +

      + +

      Once file output has been turned on, you can specify which directory the +files will be written to using the following procedure:

      + +
      PROCEDURE setfiledir (
      +  dir_in IN VARCHAR2 := NULL, 
      +  username_in IN VARCHAR2 := NULL
      +);
      + +

      the directory given will have to have been specified for output in a +UTL_FILE_DIR database parameter, as mentioned above.

      + +

      To see which directory is being used for output, use the following:

      + +
      FUNCTION filedir (username_in IN VARCHAR2 := NULL) RETURN VARCHAR2;
      + +

      +Formatting the output filenames +

      + +

      The structure of the filenames used for output is as follows:

      + +
      <user-prefix>_[program-name_]<date><extension>
      + +

      Each of these elements can be configured using the following procedures.

      + +

      The user-prefix is an arbitrary string. It defaults to the username of the currently connected user, but can be set (and returned) using the following:

      + +
      -- Set the file prefix for a user
      +PROCEDURE setuserprefix (
      +  userprefix_in IN VARCHAR2 := NULL, 
      +  username_in IN VARCHAR2 := NULL
      +);
      +
      +-- Get the file prefix for a user
      +FUNCTION userprefix (username_in IN VARCHAR2 := NULL) RETURN VARCHAR2;
      + + +

      The program-name is the name of the tested program, or the test suite +being run. By default, this is element is not used in the generated filename. +To turn this on or off (and to determine the current setting), use the +following:

      + +
      -- Set the include program name flag for a user
      +PROCEDURE setincludeprogname (
      +  incname_in IN BOOLEAN := FALSE, 
      +  username_in IN VARCHAR2 := NULL
      +);
      +
      +-- Get the include program name flag for a user
      +FUNCTION includeprogname (username_in IN VARCHAR2 := NULL) RETURN BOOLEAN;
      + + +

      The date element of the filename is simply SYSDATE converted to a string. The default format is 'YYYYDDMMHH24MISS', but this can be set (and returned) using the following:

      + +
      -- Set the date format for a user
      +PROCEDURE setdateformat (
      +  dateformat_in IN VARCHAR2 := 'yyyyddmmhh24miss', 
      +  username_in IN VARCHAR2 := NULL
      +);
      +          
      +-- Get the date format for a user
      +FUNCTION dateformat (username_in IN VARCHAR2 := NULL) RETURN VARCHAR2;
      + + +

      The final element of the filename that can be configured is the extension. +This defaults to ".UTF" but can be set (and returned) using the following:

      + +
      -- Set the file extension for a user
      +PROCEDURE setfileextension (
      +  fileextension_in IN VARCHAR2 := '.UTF', 
      +  username_in IN VARCHAR2 := NULL
      +);
      +
      +-- Get the file extension for a user
      +FUNCTION fileextension (username_in IN VARCHAR2 := NULL) RETURN VARCHAR2;
      + +

      Note The initial dot must be included, otherwise there will be none +in the resulting filename!

      + +

      +Setting all the parameters at once +

      + +

      It is possible to set all the file output parameters at once using the following procedure:

      + +
      PROCEDURE setfileinfo ( 
      +  fileout_in IN BOOLEAN := FALSE,
      +  dir_in IN VARCHAR2 := NULL,
      +  userprefix_in IN VARCHAR2 := NULL, 
      +  incname_in IN BOOLEAN := FALSE,     
      +  dateformat_in IN VARCHAR2 := 'yyyyddmmhh24miss', 
      +  fileextension_in IN VARCHAR2 := '.UTF',
      +  username_in IN VARCHAR2 := NULL
      +);
      + +

      To get back all of the file output parameters simultaneously, use the following function:

      + +

      FUNCTION fileinfo (username_in IN VARCHAR2 := NULL) RETURN rec_fileinfo;
      + +

      The record type rec_fileinfo is defined in the utConfig package and has one field for each of the parameters.

      + +

      + + + + diff --git a/documentation/src/map.txt b/documentation/src/map.txt index 5d2f86047..18bc7d8d4 100644 --- a/documentation/src/map.txt +++ b/documentation/src/map.txt @@ -24,6 +24,7 @@ suite.html,Create and Run a Test Suite userguide.html,User Guide* utplsql.html,utPLSQL Package utconfig.html,utConfig Package +fileout.html,Configuring File Output utresult.html,utResult Package utassert.html,utAssert Package utgen.html,utGen Package diff --git a/documentation/src/utconfig.html b/documentation/src/utconfig.html index d6d69b5f9..a51b01384 100644 --- a/documentation/src/utconfig.html +++ b/documentation/src/utconfig.html @@ -86,6 +86,77 @@

      Return the V2 delimiter + + utConfig.setfile + Sets file output TRUE or FALSE + + + + utConfig.getfile + Return whether file output is being used + + + + + utConfig.setfiledir + Set the directory for the file output + + + + utConfig.filedir + Return which directory is used for file output + + + + utConfig.setuserprefix + Set the user prefix for the output file name + + + + utConfig.userprefix + Return the user prefix for the output file name + + + + utConfig.setincludeprogname + Set whether to include the name of the program being tested in the output file name + + + + utConfig.includeprogname + Return whether to include the name of the program being tested in the output file name + + + + utConfig.setdateformat + Set the date format for the date portion of the output file name + + + + utConfig.dateformat + Return the date format used to construct output file name + + + + utConfig.setfileextension + Set the file extension for the output file name + + + + utConfig.fileextension + Return the file extension used for the output file name + + + + utConfig.setfileinfo + Set all of the above file output related items + + + + utConfig.fileinfo + Return all of the above file output related items + +

      To make it as easy as possible for you to run your tests, utPLSQL stores From 5436dd673713dd4022550da949a2ea383b4e8661 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 8 Jan 2003 14:22:19 +0000 Subject: [PATCH 039/143] Added better installation instructions --- documentation/src/fourstep.html | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/documentation/src/fourstep.html b/documentation/src/fourstep.html index 5945f2f55..2f5ba497c 100644 --- a/documentation/src/fourstep.html +++ b/documentation/src/fourstep.html @@ -24,19 +24,35 @@

      Step 1. Install (and Upgrade) utPLSQL.

      over the existing installation, please follow the steps below for removing utPLSQL.

      -

      Connect via SQL*Plus to the session that will own the utPLSQL components. If you do not already have a schema defined, then you must create it. The utPLSQL schema must have the authority to:

      -

      +
        +
      • Create a session.
      • +
      • Create tables, views, packages and sequences.
      • +
      • Execute the SYS.DBMS_PIPE package.
      • +
      -

      Create tables

      +

      The following is an example script submitted by Bill Pribyl, which creates a user "UTP" with sufficient privileges +to install utPLSQL. Obviously it is only an example and will need to be changed for your environment:

      -

      Create packages

      +
      connect system/manager
      +create user utp identified by utp default tablespace
      +  users temporary tablespace temp;
       
      -

      +grant create session, create table, create procedure, + create sequence, create view, create public synonym, + drop public synonym to utp; + +alter user utp quota unlimited on users; + +connect sys as sysdba +grant execute on dbms_pipe to utp;
      + +

      Note If the schema in question does not have the ability to create and drop public synonyms, you +will get error messages when installing. However, utPLSQL will still function correctly.

      Once you have connected to the schema, run the utplsql_install.sql file to install all utPLSQL objects. If the working directory of your SQL*Plus From b33804fea9137baa440c3c273ec1cabb47f68f8f Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Sun, 18 May 2003 14:25:53 +0000 Subject: [PATCH 040/143] Added docs on showfailuresonly and showingfailuresonly --- documentation/src/utconfig.html | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/documentation/src/utconfig.html b/documentation/src/utconfig.html index a51b01384..d319102b7 100644 --- a/documentation/src/utconfig.html +++ b/documentation/src/utconfig.html @@ -86,6 +86,16 @@

      Return the V2 delimiter + + utConfig.showfailuresonly + Turn off the display of successful tests + + + + utConfig.showfailuresonly + Return whether successful test results are shown or not + + utConfig.setfile Sets file output TRUE or FALSE @@ -445,6 +455,21 @@

      FUNCTION delimiter (username_in IN VARCHAR2 := NULL)
         RETURN VARCHAR2;

      + +

      + Turn off the display of successful test results +

      +

      +By default, the results of all the tests are shown. This includes both successful and unsuccessful +results. The following procedure allows you to limit the tests shown to only those that have failed: +

      PROCEDURE showfailuresonly (
      +     onoff_in      IN   BOOLEAN,
      +     username_in   IN   VARCHAR2 := NULL
      +   );
      +the current setting can be obtained by the function: +
      FUNCTION showingfailuresonly (username_in IN VARCHAR2 := NULL)
      +      RETURN BOOLEAN;
      +

      From bf4cc3c2bd0678337e3bbcebcebf04caebeed170 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 22 May 2003 16:18:54 +0000 Subject: [PATCH 041/143] Removed the "showresults" documentation --- documentation/src/utassert.html | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/documentation/src/utassert.html b/documentation/src/utassert.html index 5681f4375..0228b453f 100644 --- a/documentation/src/utassert.html +++ b/documentation/src/utassert.html @@ -8,12 +8,6 @@

      utAssert Package

      - - - - @@ -131,22 +125,6 @@

      Common Assertion Parameters and Behavior

      utAssert.showresults
      - utAssert.noshowresults
      - utAssert.showingresults
      Set the showing of results immediately
      utAssert.this Generic "Assert This" Procedure
      -

      Showing Results Immediately

      - You can request that utPLSQL display results immediately after running the -assertion program. The default behavior is that utAssert will simply pass -the results to utResult for later processing. You might want to see results -immediately if you are building your own small testing script and are not -calling utPLSQL.test. -

      To request results immediately, call the showResults procedure:

         PROCEDURE utAssert.showresults;
      - This a session-level setting, and must be reset each time you connect to -Oracle. You can turn off showing of results by calling the noShowResults program: -
         PROCEDURE utAssert.noshowresults;
      - To determine the current status of this setting, you can call the following -function:
         FUNCTION utAssert.showing_results return boolean;
      - Here is an example of a simple script that calls an assertion routine and -immediately shows the results:
      set serveroutput on size 1000000
      BEGIN
      utAssert.showresults;
      utAssert.eq (
      'Test of betwn',
      str.betwn ('this is a string', 3, 7),
      'this is a pipe' );
      END;
      /
      - And here is the result of running this script:
      FAILURE: "Unnamed Test"
      : Test of betwn; expected "this is a pipe", got "is is"
      -

      Generic "Assert This" Assertion Procedure

      This most generic assertion program simply says "assert this" and passes a Boolean expression. It is used by all the other assertion routines, which From 23938fc503350865e1e14741b9c7fe5b99a9361c Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 28 May 2003 08:19:02 +0000 Subject: [PATCH 042/143] Initial Upload --- examples/GEN_UT_BETWNSTR.PRC | 19 + examples/TESTIT.PRC | 9 + examples/betwnstr.sf | 18 + examples/bewtnstr.utc | 5 + examples/calc_secs_between.sp | 10 + examples/department.tst | 11 + examples/department2file.sp | 22 + examples/employee_pipe.pkg | 265 ++ examples/filepath1.pkg | 131 + examples/filepath2.pkg | 177 ++ examples/gen_ut_betwnstr.pro | 17 + examples/gen_ut_betwnstr.sql | 20 + examples/gen_ut_betwnstr_to_screen.sql | 16 + examples/gen_ut_plvstr.pro | 19 + examples/login.sql | 7 + examples/login_sample.sql | 4 + examples/mybooks_setup.sql | 77 + examples/plvision.tst | 16 + examples/qu_betwnstr.pkb | 99 + examples/registertests.sql | 5 + examples/showfailures.sql | 39 + examples/str.pkb | 87 + examples/str.pks | 26 + examples/str2list.pkg | 215 ++ examples/str2list.tst | 20 + examples/str_same.pkb | 20 + examples/str_same.pks | 10 + examples/tabcount.sf | 17 + examples/te_employee.pkb | 1710 +++++++++++ examples/te_employee.pks | 691 +++++ examples/te_utpkg.gdr | 199 ++ examples/temp.sql | 53 + examples/tequery_utpkg.gdr | 111 + examples/test_betwnstr.sql | 3 + examples/test_te_employee.pkb | 916 ++++++ examples/test_te_employee.pks | 28 + examples/truncit.sp | 9 + examples/ut_betwnstr.pkb | 122 + examples/ut_betwnstr.pks | 9 + examples/ut_betwnstr_failures.pkb | 79 + examples/ut_betwnstr_gen.pkg | 137 + examples/ut_bstr.pkb | 47 + examples/ut_bstr.pks | 9 + examples/ut_calc_secs_between.pkb | 51 + examples/ut_calc_secs_between.pks | 9 + examples/ut_department2file.pkg | 45 + examples/ut_mybooks_pkg.sql | 337 +++ examples/ut_plvdate.pkb | 38 + examples/ut_plvdate.pks | 12 + examples/ut_plvstr.pkb | 134 + examples/ut_plvstr.pks | 9 + examples/ut_str.pkb | 54 + examples/ut_str.pks | 10 + examples/ut_te_employee.pkb | 916 ++++++ examples/ut_te_employee.pks | 28 + examples/ut_truncit.pkb | 34 + examples/ut_truncit.pks | 9 + examples/ut_vda$strings1.pkg | 1469 ++++++++++ examples/utgen.txt | 147 + source/ut_aeq.pkb | 742 +++++ source/ut_aeq.pks | 251 ++ source/ut_argument.tab | 14 + source/ut_assert.pkb | 666 +++++ source/ut_assert.pks | 324 ++ source/ut_assert2.pkb | 3737 ++++++++++++++++++++++++ source/ut_assert2.pks | 621 ++++ source/ut_assertion.tab | 147 + source/ut_assertion_seq.seq | 1 + source/ut_config.pkb | 758 +++++ source/ut_config.pks | 248 ++ source/ut_config.tab | 30 + source/ut_deterministic.tab | 12 + source/ut_deterministic_arg.tab | 10 + source/ut_eq.tab | 15 + source/ut_gen.pkb | 1383 +++++++++ source/ut_gen.pks | 218 ++ source/ut_grid.tab | 39 + source/ut_i_do.sql | 105 + source/ut_i_grants.sql | 40 + source/ut_i_install.sql | 68 + source/ut_i_packages.sql | 29 + source/ut_i_packages_b.sql | 29 + source/ut_i_recompile.sql | 31 + source/ut_i_run.sql | 12 + source/ut_i_sequences.sql | 14 + source/ut_i_spool_temp.sql | 31 + source/ut_i_synonyms.sql | 35 + source/ut_i_tables.sql | 25 + source/ut_i_uninstall.sql | 111 + source/ut_i_views.sql | 2 + source/ut_outcome.pkb | 107 + source/ut_outcome.pks | 29 + source/ut_outcome.tab | 26 + source/ut_output.pkb | 173 ++ source/ut_output.pks | 67 + source/ut_package.pkb | 372 +++ source/ut_package.pks | 98 + source/ut_package.tab | 31 + source/ut_package_seq.seq | 1 + source/ut_plsql.pkb | 1595 ++++++++++ source/ut_plsql.pks | 253 ++ source/ut_plsql2.pkb | 474 +++ source/ut_plsql2.pks | 98 + source/ut_plsql_runnum_seq.seq | 1 + source/ut_plsql_util.pkb | 1589 ++++++++++ source/ut_plsql_util.pks | 188 ++ source/ut_receq.pkb | 295 ++ source/ut_receq.pks | 45 + source/ut_receq.tab | 30 + source/ut_receq_seq.seq | 1 + source/ut_refcursor_results_seq.seq | 1 + source/ut_rerror.pkb | 308 ++ source/ut_rerror.pks | 84 + source/ut_result.pkb | 352 +++ source/ut_result.pks | 98 + source/ut_result2.pkb | 318 ++ source/ut_result2.pks | 96 + source/ut_routcome.pkb | 205 ++ source/ut_routcome.pks | 32 + source/ut_rsuite.pkb | 114 + source/ut_rsuite.pks | 16 + source/ut_rtestcase.pkb | 108 + source/ut_rtestcase.pks | 16 + source/ut_runittest.pkb | 116 + source/ut_runittest.pks | 16 + source/ut_rutp.pkb | 202 ++ source/ut_rutp.pks | 33 + source/ut_suite.pkb | 238 ++ source/ut_suite.pks | 83 + source/ut_suite.tab | 19 + source/ut_suite_seq.seq | 1 + source/ut_suite_utp.tab | 11 + source/ut_suiteutp.pkb | 182 ++ source/ut_suiteutp.pks | 70 + source/ut_test.pkb | 172 ++ source/ut_test.pks | 69 + source/ut_test.tab | 19 + source/ut_test_seq.seq | 1 + source/ut_testcase.pkb | 171 ++ source/ut_testcase.pks | 72 + source/ut_testcase.tab | 31 + source/ut_testcase_seq.seq | 1 + source/ut_testprep.pkb | 18 + source/ut_testprep.pks | 11 + source/ut_testprep.tab | 13 + source/ut_unittest.pkb | 166 ++ source/ut_unittest.pks | 49 + source/ut_unittest.tab | 19 + source/ut_unittest_seq.seq | 1 + source/ut_utoutput.pkb | 193 ++ source/ut_utoutput.pks | 14 + source/ut_utp.pkb | 382 +++ source/ut_utp.pks | 110 + source/ut_utp.tab | 31 + source/ut_utp_seq.seq | 1 + source/ut_vvalue.pkb | 880 ++++++ source/ut_vvalue.pks | 274 ++ source/uta_eq.tab | 17 + source/uta_eq_seq.seq | 1 + source/utr_error.tab | 28 + source/utr_outcome.tab | 23 + source/utr_suite.tab | 17 + source/utr_testcase.tab | 16 + source/utr_unittest.tab | 16 + source/utr_utp.tab | 17 + source/utv_last_run.sql | 9 + source/utv_result_full.sql | 14 + source/utv_value.tab | 17 + source/utv_value_seq.seq | 1 + 169 files changed, 29620 insertions(+) create mode 100644 examples/GEN_UT_BETWNSTR.PRC create mode 100644 examples/TESTIT.PRC create mode 100644 examples/betwnstr.sf create mode 100644 examples/bewtnstr.utc create mode 100644 examples/calc_secs_between.sp create mode 100644 examples/department.tst create mode 100644 examples/department2file.sp create mode 100644 examples/employee_pipe.pkg create mode 100644 examples/filepath1.pkg create mode 100644 examples/filepath2.pkg create mode 100644 examples/gen_ut_betwnstr.pro create mode 100644 examples/gen_ut_betwnstr.sql create mode 100644 examples/gen_ut_betwnstr_to_screen.sql create mode 100644 examples/gen_ut_plvstr.pro create mode 100644 examples/login.sql create mode 100644 examples/login_sample.sql create mode 100644 examples/mybooks_setup.sql create mode 100644 examples/plvision.tst create mode 100644 examples/qu_betwnstr.pkb create mode 100644 examples/registertests.sql create mode 100644 examples/showfailures.sql create mode 100644 examples/str.pkb create mode 100644 examples/str.pks create mode 100644 examples/str2list.pkg create mode 100644 examples/str2list.tst create mode 100644 examples/str_same.pkb create mode 100644 examples/str_same.pks create mode 100644 examples/tabcount.sf create mode 100644 examples/te_employee.pkb create mode 100644 examples/te_employee.pks create mode 100644 examples/te_utpkg.gdr create mode 100644 examples/temp.sql create mode 100644 examples/tequery_utpkg.gdr create mode 100644 examples/test_betwnstr.sql create mode 100644 examples/test_te_employee.pkb create mode 100644 examples/test_te_employee.pks create mode 100644 examples/truncit.sp create mode 100644 examples/ut_betwnstr.pkb create mode 100644 examples/ut_betwnstr.pks create mode 100644 examples/ut_betwnstr_failures.pkb create mode 100644 examples/ut_betwnstr_gen.pkg create mode 100644 examples/ut_bstr.pkb create mode 100644 examples/ut_bstr.pks create mode 100644 examples/ut_calc_secs_between.pkb create mode 100644 examples/ut_calc_secs_between.pks create mode 100644 examples/ut_department2file.pkg create mode 100644 examples/ut_mybooks_pkg.sql create mode 100644 examples/ut_plvdate.pkb create mode 100644 examples/ut_plvdate.pks create mode 100644 examples/ut_plvstr.pkb create mode 100644 examples/ut_plvstr.pks create mode 100644 examples/ut_str.pkb create mode 100644 examples/ut_str.pks create mode 100644 examples/ut_te_employee.pkb create mode 100644 examples/ut_te_employee.pks create mode 100644 examples/ut_truncit.pkb create mode 100644 examples/ut_truncit.pks create mode 100644 examples/ut_vda$strings1.pkg create mode 100644 examples/utgen.txt create mode 100644 source/ut_aeq.pkb create mode 100644 source/ut_aeq.pks create mode 100644 source/ut_argument.tab create mode 100644 source/ut_assert.pkb create mode 100644 source/ut_assert.pks create mode 100644 source/ut_assert2.pkb create mode 100644 source/ut_assert2.pks create mode 100644 source/ut_assertion.tab create mode 100644 source/ut_assertion_seq.seq create mode 100644 source/ut_config.pkb create mode 100644 source/ut_config.pks create mode 100644 source/ut_config.tab create mode 100644 source/ut_deterministic.tab create mode 100644 source/ut_deterministic_arg.tab create mode 100644 source/ut_eq.tab create mode 100644 source/ut_gen.pkb create mode 100644 source/ut_gen.pks create mode 100644 source/ut_grid.tab create mode 100644 source/ut_i_do.sql create mode 100644 source/ut_i_grants.sql create mode 100644 source/ut_i_install.sql create mode 100644 source/ut_i_packages.sql create mode 100644 source/ut_i_packages_b.sql create mode 100644 source/ut_i_recompile.sql create mode 100644 source/ut_i_run.sql create mode 100644 source/ut_i_sequences.sql create mode 100644 source/ut_i_spool_temp.sql create mode 100644 source/ut_i_synonyms.sql create mode 100644 source/ut_i_tables.sql create mode 100644 source/ut_i_uninstall.sql create mode 100644 source/ut_i_views.sql create mode 100644 source/ut_outcome.pkb create mode 100644 source/ut_outcome.pks create mode 100644 source/ut_outcome.tab create mode 100644 source/ut_output.pkb create mode 100644 source/ut_output.pks create mode 100644 source/ut_package.pkb create mode 100644 source/ut_package.pks create mode 100644 source/ut_package.tab create mode 100644 source/ut_package_seq.seq create mode 100644 source/ut_plsql.pkb create mode 100644 source/ut_plsql.pks create mode 100644 source/ut_plsql2.pkb create mode 100644 source/ut_plsql2.pks create mode 100644 source/ut_plsql_runnum_seq.seq create mode 100644 source/ut_plsql_util.pkb create mode 100644 source/ut_plsql_util.pks create mode 100644 source/ut_receq.pkb create mode 100644 source/ut_receq.pks create mode 100644 source/ut_receq.tab create mode 100644 source/ut_receq_seq.seq create mode 100644 source/ut_refcursor_results_seq.seq create mode 100644 source/ut_rerror.pkb create mode 100644 source/ut_rerror.pks create mode 100644 source/ut_result.pkb create mode 100644 source/ut_result.pks create mode 100644 source/ut_result2.pkb create mode 100644 source/ut_result2.pks create mode 100644 source/ut_routcome.pkb create mode 100644 source/ut_routcome.pks create mode 100644 source/ut_rsuite.pkb create mode 100644 source/ut_rsuite.pks create mode 100644 source/ut_rtestcase.pkb create mode 100644 source/ut_rtestcase.pks create mode 100644 source/ut_runittest.pkb create mode 100644 source/ut_runittest.pks create mode 100644 source/ut_rutp.pkb create mode 100644 source/ut_rutp.pks create mode 100644 source/ut_suite.pkb create mode 100644 source/ut_suite.pks create mode 100644 source/ut_suite.tab create mode 100644 source/ut_suite_seq.seq create mode 100644 source/ut_suite_utp.tab create mode 100644 source/ut_suiteutp.pkb create mode 100644 source/ut_suiteutp.pks create mode 100644 source/ut_test.pkb create mode 100644 source/ut_test.pks create mode 100644 source/ut_test.tab create mode 100644 source/ut_test_seq.seq create mode 100644 source/ut_testcase.pkb create mode 100644 source/ut_testcase.pks create mode 100644 source/ut_testcase.tab create mode 100644 source/ut_testcase_seq.seq create mode 100644 source/ut_testprep.pkb create mode 100644 source/ut_testprep.pks create mode 100644 source/ut_testprep.tab create mode 100644 source/ut_unittest.pkb create mode 100644 source/ut_unittest.pks create mode 100644 source/ut_unittest.tab create mode 100644 source/ut_unittest_seq.seq create mode 100644 source/ut_utoutput.pkb create mode 100644 source/ut_utoutput.pks create mode 100644 source/ut_utp.pkb create mode 100644 source/ut_utp.pks create mode 100644 source/ut_utp.tab create mode 100644 source/ut_utp_seq.seq create mode 100644 source/ut_vvalue.pkb create mode 100644 source/ut_vvalue.pks create mode 100644 source/uta_eq.tab create mode 100644 source/uta_eq_seq.seq create mode 100644 source/utr_error.tab create mode 100644 source/utr_outcome.tab create mode 100644 source/utr_suite.tab create mode 100644 source/utr_testcase.tab create mode 100644 source/utr_unittest.tab create mode 100644 source/utr_utp.tab create mode 100644 source/utv_last_run.sql create mode 100644 source/utv_result_full.sql create mode 100644 source/utv_value.tab create mode 100644 source/utv_value_seq.seq diff --git a/examples/GEN_UT_BETWNSTR.PRC b/examples/GEN_UT_BETWNSTR.PRC new file mode 100644 index 000000000..82a014bff --- /dev/null +++ b/examples/GEN_UT_BETWNSTR.PRC @@ -0,0 +1,19 @@ +CREATE OR REPLACE PROCEDURE gen_ut_betwnstr +IS + utc VARCHAR2 (1000) + := '#program name|test case name|message|arguments|result|assertion type +betwnstr|normal|normal|abcdefgh;3;5|cde|eq +betwnstr|zero start|zero start|abcdefgh;0;2|abc|eq +betwnstr|null start|null start|abcdefgh;!null;2|null|isnull +betwnstr|null end|null end|abcdefgh;!3;!null|null|isnull'; +BEGIN + utconfig.setdir ('d:\openoracle\utplsql\examples'); + utconfig.showconfig; + utgen.testpkg_from_string ('betwnstr', + utc, + output_type_in=> utgen.c_file, + dir_in=> 'd:\openoracle\utplsql\examples' + ); +END; +/ + diff --git a/examples/TESTIT.PRC b/examples/TESTIT.PRC new file mode 100644 index 000000000..da3fb43af --- /dev/null +++ b/examples/TESTIT.PRC @@ -0,0 +1,9 @@ +CREATE OR REPLACE PROCEDURE testit (prog_in IN VARCHAR2, recompile_in in boolean := true) +IS +BEGIN + utconfig.setdir ('d:\openoracle\utplsql\examples'); + utconfig.showconfig; + utplsql.test (prog_in, recompile_in => recompile_in); +END; +/ + diff --git a/examples/betwnstr.sf b/examples/betwnstr.sf new file mode 100644 index 000000000..205f42c86 --- /dev/null +++ b/examples/betwnstr.sf @@ -0,0 +1,18 @@ +CREATE OR REPLACE FUNCTION betwnstr ( + string_in IN VARCHAR2, + start_in IN INTEGER, + end_in IN INTEGER +) + RETURN VARCHAR2 +IS + l_start PLS_INTEGER := start_in; +BEGIN + IF l_start = 0 + THEN + l_start := 1; + END IF; + + RETURN (SUBSTR (string_in, l_start, end_in - l_start + 1)); +END; +/ + diff --git a/examples/bewtnstr.utc b/examples/bewtnstr.utc new file mode 100644 index 000000000..b7349d9c5 --- /dev/null +++ b/examples/bewtnstr.utc @@ -0,0 +1,5 @@ +#program name|test case name|message|arguments|result|assertion type +betwnstr|Normal|Typical valid usage|abcdefg;2;5|bcde|eq +betwnstr|ZeroStart|Zero start value|abcdefg;0;5|abcde|eq +betwnstr|BigEnd|Way big end value|abcdefg;5;500|efg|eq +betwnstr|NULLstart|NULL start value|;5;500|null|isnull diff --git a/examples/calc_secs_between.sp b/examples/calc_secs_between.sp new file mode 100644 index 000000000..3aac1c686 --- /dev/null +++ b/examples/calc_secs_between.sp @@ -0,0 +1,10 @@ +CREATE OR REPLACE PROCEDURE calc_secs_between ( + date1 IN DATE, + date2 IN DATE, + secs OUT NUMBER +) +IS +BEGIN + secs := (date2 - date1) * 24 * 60 * 60; +END; +/ diff --git a/examples/department.tst b/examples/department.tst new file mode 100644 index 000000000..92d1c2c1b --- /dev/null +++ b/examples/department.tst @@ -0,0 +1,11 @@ +10***ACCOUNTING***122 +20***RESEARCH***124 +30***SALES***123 +40***OPERATIONS***167 +12***RESEARCH12***122 +13***SALES13***122 +14***OPERATIONS14***122 +23***SALES23***124 +24***OPERATIONS24***124 +34***OPERATIONS34***123 +43***SALES43***167 diff --git a/examples/department2file.sp b/examples/department2file.sp new file mode 100644 index 000000000..e7b307292 --- /dev/null +++ b/examples/department2file.sp @@ -0,0 +1,22 @@ +CREATE OR REPLACE PROCEDURE DEPARTMENT2file ( + loc IN VARCHAR2, + file IN VARCHAR2 := 'DEPARTMENT.dat', + delim IN VARCHAR2 := '|' + ) +IS + fid UTL_FILE.FILE_TYPE; + line VARCHAR2(32767); +BEGIN + fid := UTL_FILE.FOPEN (loc, file, 'W'); + + FOR rec IN (SELECT * FROM DEPARTMENT) + LOOP + line := + TO_CHAR (rec.DEPARTMENT_ID) || delim || + rec.NAME || delim || + TO_CHAR (rec.LOC_ID); + UTL_FILE.PUT_LINE (fid, line); + END LOOP; + UTL_FILE.FCLOSE (fid); +END; +/ \ No newline at end of file diff --git a/examples/employee_pipe.pkg b/examples/employee_pipe.pkg new file mode 100644 index 000000000..cf99174dd --- /dev/null +++ b/examples/employee_pipe.pkg @@ -0,0 +1,265 @@ +CREATE OR REPLACE PACKAGE EMPLOYEE_pipe +-- Wrapper around pipe based on EMPLOYEE +-- Generated using GenX +-- Author: Steven Feuerstein, steven@stevenfeuerstein.com +IS + PROCEDURE setpipe (pipe_in IN VARCHAR2); + FUNCTION pipe RETURN VARCHAR; + + FUNCTION send ( + EMPLOYEE_ID_in IN number, + LAST_NAME_in IN varchar2, + FIRST_NAME_in IN varchar2, + MIDDLE_INITIAL_in IN varchar2, + JOB_ID_in IN number, + MANAGER_ID_in IN number, + HIRE_DATE_in IN date, + SALARY_in IN number, + COMMISSION_in IN number, + DEPARTMENT_ID_in IN number, + CHANGED_BY_in IN varchar2, + CHANGED_ON_in IN date, + wait IN INTEGER := 0 + ) RETURN PLS_INTEGER; + + FUNCTION send (rec IN EMPLOYEE%ROWTYPE, + wait IN INTEGER := 0 + ) RETURN PLS_INTEGER; + + FUNCTION receive ( + EMPLOYEE_ID_out OUT number, + LAST_NAME_out OUT varchar2, + FIRST_NAME_out OUT varchar2, + MIDDLE_INITIAL_out OUT varchar2, + JOB_ID_out OUT number, + MANAGER_ID_out OUT number, + HIRE_DATE_out OUT date, + SALARY_out OUT number, + COMMISSION_out OUT number, + DEPARTMENT_ID_out OUT number, + CHANGED_BY_out OUT varchar2, + CHANGED_ON_out OUT date, + wait IN INTEGER := 0 + ) RETURN PLS_INTEGER; + + FUNCTION receive (rec OUT EMPLOYEE%ROWTYPE, + wait IN INTEGER := 0 + ) RETURN PLS_INTEGER; + + PROCEDURE fillpipe (pipe_in IN VARCHAR2); + PROCEDURE emptypipe (pipe_in IN VARCHAR2); + + /* Unit Test code in same package */ + + PROCEDURE ut_setup; + + PROCEDURE ut_teardown; + + PROCEDURE ut_fillpipe; +END; +/ +CREATE OR REPLACE PACKAGE BODY EMPLOYEE_pipe +IS + g_name VARCHAR2(200) := 'EMPLOYEE_pipe'; + + PROCEDURE setpipe (pipe_in IN VARCHAR2) IS + BEGIN g_name := pipe_in; END; + + FUNCTION pipe RETURN VARCHAR IS BEGIN RETURN g_name; END; + + FUNCTION send ( + EMPLOYEE_ID_in IN number, + LAST_NAME_in IN varchar2, + FIRST_NAME_in IN varchar2, + MIDDLE_INITIAL_in IN varchar2, + JOB_ID_in IN number, + MANAGER_ID_in IN number, + HIRE_DATE_in IN date, + SALARY_in IN number, + COMMISSION_in IN number, + DEPARTMENT_ID_in IN number, + CHANGED_BY_in IN varchar2, + CHANGED_ON_in IN date, + wait IN INTEGER := 0 + ) RETURN PLS_INTEGER + IS + stat INTEGER; + BEGIN + DBMS_PIPE.RESET_BUFFER; + DBMS_PIPE.PACK_MESSAGE (EMPLOYEE_ID_in); + DBMS_PIPE.PACK_MESSAGE (LAST_NAME_in); + DBMS_PIPE.PACK_MESSAGE (FIRST_NAME_in); + DBMS_PIPE.PACK_MESSAGE (MIDDLE_INITIAL_in); + DBMS_PIPE.PACK_MESSAGE (JOB_ID_in); + DBMS_PIPE.PACK_MESSAGE (MANAGER_ID_in); + DBMS_PIPE.PACK_MESSAGE (HIRE_DATE_in); + DBMS_PIPE.PACK_MESSAGE (SALARY_in); + DBMS_PIPE.PACK_MESSAGE (COMMISSION_in); + DBMS_PIPE.PACK_MESSAGE (DEPARTMENT_ID_in); + DBMS_PIPE.PACK_MESSAGE (CHANGED_BY_in); + DBMS_PIPE.PACK_MESSAGE (CHANGED_ON_in); + + stat := DBMS_PIPE.SEND_MESSAGE (g_name, wait); + + RETURN stat; + END; + + FUNCTION receive ( + EMPLOYEE_ID_out OUT number, + LAST_NAME_out OUT varchar2, + FIRST_NAME_out OUT varchar2, + MIDDLE_INITIAL_out OUT varchar2, + JOB_ID_out OUT number, + MANAGER_ID_out OUT number, + HIRE_DATE_out OUT date, + SALARY_out OUT number, + COMMISSION_out OUT number, + DEPARTMENT_ID_out OUT number, + CHANGED_BY_out OUT varchar2, + CHANGED_ON_out OUT date, + wait IN INTEGER := 0 + ) RETURN PLS_INTEGER + IS + stat INTEGER; + BEGIN + --// Receive next message and unpack for each column. //-- + stat := DBMS_PIPE.RECEIVE_MESSAGE (g_name, wait); + + IF stat = 0 + THEN + DBMS_PIPE.UNPACK_MESSAGE (EMPLOYEE_ID_out); + DBMS_PIPE.UNPACK_MESSAGE (LAST_NAME_out); + DBMS_PIPE.UNPACK_MESSAGE (FIRST_NAME_out); + DBMS_PIPE.UNPACK_MESSAGE (MIDDLE_INITIAL_out); + DBMS_PIPE.UNPACK_MESSAGE (JOB_ID_out); + DBMS_PIPE.UNPACK_MESSAGE (MANAGER_ID_out); + DBMS_PIPE.UNPACK_MESSAGE (HIRE_DATE_out); + DBMS_PIPE.UNPACK_MESSAGE (SALARY_out); + DBMS_PIPE.UNPACK_MESSAGE (COMMISSION_out); + DBMS_PIPE.UNPACK_MESSAGE (DEPARTMENT_ID_out); + DBMS_PIPE.UNPACK_MESSAGE (CHANGED_BY_out); + DBMS_PIPE.UNPACK_MESSAGE (CHANGED_ON_out); + END IF; + + RETURN stat; + END; + + FUNCTION send (rec IN EMPLOYEE%ROWTYPE, + wait IN INTEGER := 0 + ) RETURN PLS_INTEGER + IS + stat PLS_INTEGER; + BEGIN + stat := send ( + rec.EMPLOYEE_ID, + rec.LAST_NAME, + rec.FIRST_NAME, + rec.MIDDLE_INITIAL, + rec.JOB_ID, + rec.MANAGER_ID, + rec.HIRE_DATE, + rec.SALARY, + rec.COMMISSION, + rec.DEPARTMENT_ID, + rec.CHANGED_BY, + rec.CHANGED_ON, + wait); + RETURN stat; + END; + + FUNCTION receive (rec OUT EMPLOYEE%ROWTYPE, + wait IN INTEGER := 0 + ) RETURN PLS_INTEGER + IS + stat PLS_INTEGER; + BEGIN + stat := receive ( + rec.EMPLOYEE_ID, + rec.LAST_NAME, + rec.FIRST_NAME, + rec.MIDDLE_INITIAL, + rec.JOB_ID, + rec.MANAGER_ID, + rec.HIRE_DATE, + rec.SALARY, + rec.COMMISSION, + rec.DEPARTMENT_ID, + rec.CHANGED_BY, + rec.CHANGED_ON, + wait); + RETURN stat; + END; + + PROCEDURE fillpipe (pipe_in IN VARCHAR2) + IS + stat PLS_INTEGER; + BEGIN + employee_pipe.setpipe (pipe_in); + + FOR rec IN (SELECT * + FROM employee) + LOOP + stat := employee_pipe.send (rec); + END LOOP; + END; + + PROCEDURE emptypipe (pipe_in IN VARCHAR2) + IS + stat PLS_INTEGER; + BEGIN + LOOP + stat := DBMS_PIPE.RECEIVE_MESSAGE (pipe_in, 0); + EXIT WHEN stat != 0; + END LOOP; + END; + + /* Unit Test code in same package */ + + PROCEDURE ut_setup IS + BEGIN + NULL; + END; + + PROCEDURE ut_teardown IS + BEGIN + NULL; + END; + + PROCEDURE ut_fillpipe IS + stat PLS_INTEGER; + BEGIN + emptypipe ('emps'); + emptypipe ('emps2'); + + fillpipe ('emps'); + + /* Direct filling of pipe. */ + + FOR rec IN (SELECT * + FROM employee) + LOOP + DBMS_PIPE.RESET_BUFFER; + DBMS_PIPE.PACK_MESSAGE (rec.EMPLOYEE_ID); + DBMS_PIPE.PACK_MESSAGE (rec.LAST_NAME); + DBMS_PIPE.PACK_MESSAGE (rec.FIRST_NAME); + DBMS_PIPE.PACK_MESSAGE (rec.MIDDLE_INITIAL); + DBMS_PIPE.PACK_MESSAGE (rec.JOB_ID); + DBMS_PIPE.PACK_MESSAGE (rec.MANAGER_ID); + DBMS_PIPE.PACK_MESSAGE (rec.HIRE_DATE); + DBMS_PIPE.PACK_MESSAGE (rec.SALARY); + DBMS_PIPE.PACK_MESSAGE (rec.COMMISSION); + DBMS_PIPE.PACK_MESSAGE (rec.DEPARTMENT_ID); + DBMS_PIPE.PACK_MESSAGE (rec.CHANGED_BY); + DBMS_PIPE.PACK_MESSAGE (rec.CHANGED_ON); + + stat := DBMS_PIPE.SEND_MESSAGE ('emps2', 0); + END LOOP; + + /* Compare the two */ + utassert.eqpipe ( + 'Two employee pipes', 'emps', 'emps2'); + + END ut_fillpipe; + +END; +/ \ No newline at end of file diff --git a/examples/filepath1.pkg b/examples/filepath1.pkg new file mode 100644 index 000000000..350b7f74f --- /dev/null +++ b/examples/filepath1.pkg @@ -0,0 +1,131 @@ +CREATE TYPE dirs_tabtype IS TABLE OF VARCHAR2(2000); +/ + +CREATE OR REPLACE PACKAGE fileIO +IS + c_delim CHAR(1) := ';'; + + dirs dirs_tabtype := dirs_tabtype (); + + -- Unit test list + ut_dirs dirs_tabtype := dirs_tabtype (); + + PROCEDURE setpath (str IN VARCHAR2, delim IN VARCHAR2 := c_delim); + FUNCTION path RETURN VARCHAR2; + FUNCTION pathlist RETURN dirs_tabtype; + + FUNCTION open (file IN VARCHAR2, loc IN VARCHAR2 := NULL) RETURN UTL_FILE.FILE_TYPE; + + -- Unit test code in same package + PROCEDURE ut_setup; + PROCEDURE ut_teardown; + PROCEDURE ut_setpath; +END; +/ + +CREATE OR REPLACE PACKAGE BODY fileIO +IS + g_path VARCHAR2(32767); + g_delim CHAR(1) := c_delim; + + PROCEDURE setpath (str IN VARCHAR2, delim IN VARCHAR2 := c_delim) + IS + BEGIN + g_path := str; + g_delim := NVL (delim, c_delim); + str2list.parse (str, g_delim, 'fileIO', 'dirs'); + END; + + FUNCTION path RETURN VARCHAR2 + IS + BEGIN + RETURN g_path; + END; + + FUNCTION pathlist RETURN dirs_tabtype + IS + BEGIN + RETURN dirs; + END; + + FUNCTION open (file IN VARCHAR2, loc IN VARCHAR2 := NULL) RETURN UTL_FILE.FILE_TYPE + IS + indx PLS_INTEGER; + + /* Location of next path separator */ + v_lastsep PLS_INTEGER := 1; + v_sep PLS_INTEGER := INSTR (g_path, c_delim); + v_dir VARCHAR2(500); + retval UTL_FILE.FILE_TYPE; + + PROCEDURE set_next_dir IS + BEGIN + v_sep := INSTR (g_path, c_delim, v_sep+1); + IF v_sep = 0 + THEN + v_dir := SUBSTR (g_path, v_lastsep); + ELSE + v_dir := SUBSTR (g_path, v_lastsep, v_sep - v_lastsep); + END IF; + END; + BEGIN + IF loc IS NOT NULL + THEN + indx := NULL; + v_dir := loc; + ELSE + indx := dirs.FIRST; + v_dir := dirs(indx); + END IF; + + WHILE v_dir IS NOT NULL + LOOP + BEGIN + --DBMS_OUTPUT.PUT_LINE ('...looking in ' || v_dir); + retval := UTL_FILE.FOPEN (v_dir, file, 'R'); + EXIT; + EXCEPTION + WHEN OTHERS + THEN + indx := dirs.NEXT (indx); + IF indx IS NULL + THEN + v_dir := NULL; + ELSE + v_dir := dirs(indx); + END IF; + END; + END LOOP; + RETURN retval; + END; + + PROCEDURE ut_setup IS + BEGIN + NULL: + END; + + PROCEDURE ut_teardown + IS BEGIN NULL; END; + + PROCEDURE ut_setpath + IS + BEGIN + /* Populate base collection */ + ut_dirs.DELETE; + + ut_dirs.EXTEND(2); + ut_dirs(1) := 'c:\temp'; + ut_dirs(2) := 'e:\demo'; + + /* Call setpath to do the work */ + setpath ('c:\temp;e:\demo'); + + utAssert.eqColl ( + 'Valid double entry', + 'fileio.dirs', + 'fileio.ut_dirs' + ); + END; + +END; +/ diff --git a/examples/filepath2.pkg b/examples/filepath2.pkg new file mode 100644 index 000000000..c82ddbf4c --- /dev/null +++ b/examples/filepath2.pkg @@ -0,0 +1,177 @@ +/* Formatted by PL/Formatter v3.1.2.1 on 2000/09/16 06:52 */ + +CREATE OR REPLACE PACKAGE fileio +IS + c_delim CHAR (1) := ';'; + + TYPE dirs_ibtabtype IS TABLE OF VARCHAR2 (2000) + INDEX BY BINARY_INTEGER; + + PROCEDURE setpath (str IN VARCHAR2, delim IN VARCHAR2 := c_delim); + + FUNCTION path + RETURN VARCHAR2; + + FUNCTION pathlist + RETURN dirs_ibtabtype; + + PROCEDURE append (onedir IN VARCHAR2); + + PROCEDURE delete (rowindex IN PLS_INTEGER := NULL); + + FUNCTION COUNT + RETURN PLS_INTEGER; + + FUNCTION FIRST + RETURN PLS_INTEGER; + + FUNCTION LAST + RETURN PLS_INTEGER; + + FUNCTION NEXT (rowindex IN PLS_INTEGER := NULL) + RETURN PLS_INTEGER; + + FUNCTION nthval (rowindex IN PLS_INTEGER := NULL) + RETURN VARCHAR2; + + FUNCTION open (file IN VARCHAR2, loc IN VARCHAR2 := NULL) + RETURN UTL_FILE.file_type; +END; +/ + +CREATE OR REPLACE PACKAGE BODY fileio +IS + g_path VARCHAR2 (32767); + g_delim CHAR (1) := c_delim; + dirs dirs_ibtabtype; + + PROCEDURE setpath (str IN VARCHAR2, delim IN VARCHAR2 := c_delim) + IS + BEGIN + g_path := str; + g_delim := NVL (delim, c_delim); + str2list.parse (str, g_delim, 'fileIO', 'append', 'delete', 'VARCHAR2(32767)'); + END; + + PROCEDURE append (onedir IN VARCHAR2) + IS + BEGIN + dirs (NVL (dirs.LAST, 0) + 1) := onedir; + END; + + PROCEDURE delete (rowindex IN PLS_INTEGER := NULL) + IS + BEGIN + IF rowindex IS NULL + THEN + dirs.delete; + ELSE + dirs.delete (rowindex); + END IF; + END; + + FUNCTION COUNT + RETURN PLS_INTEGER + IS + BEGIN + RETURN dirs.COUNT; + END; + + FUNCTION FIRST + RETURN PLS_INTEGER + IS + BEGIN + RETURN dirs.FIRST; + END; + + FUNCTION LAST + RETURN PLS_INTEGER + IS + BEGIN + RETURN dirs.FIRST; + END; + + FUNCTION NEXT (rowindex IN PLS_INTEGER := NULL) + RETURN PLS_INTEGER + IS + BEGIN + RETURN dirs.NEXT (rowindex); + END; + + FUNCTION nthval (rowindex IN PLS_INTEGER := NULL) + RETURN VARCHAR2 + IS + BEGIN + RETURN dirs (rowindex); + END; + + FUNCTION path + RETURN VARCHAR2 + IS + BEGIN + RETURN g_path; + END; + + FUNCTION pathlist + RETURN dirs_ibtabtype + IS + BEGIN + RETURN dirs; + END; + + FUNCTION open (file IN VARCHAR2, loc IN VARCHAR2 := NULL) + RETURN UTL_FILE.file_type + IS + indx PLS_INTEGER; + /* Location of next path separator */ + v_lastsep PLS_INTEGER := 1; + v_sep PLS_INTEGER := INSTR (g_path, c_delim); + v_dir VARCHAR2 (500); + retval UTL_FILE.file_type; + + PROCEDURE set_next_dir + IS + BEGIN + v_sep := INSTR (g_path, c_delim, v_sep + 1); + + IF v_sep = 0 + THEN + v_dir := SUBSTR (g_path, v_lastsep); + ELSE + v_dir := SUBSTR (g_path, v_lastsep, v_sep - v_lastsep); + END IF; + END; + BEGIN + IF loc IS NOT NULL + THEN + indx := NULL; + v_dir := loc; + ELSE + indx := dirs.FIRST; + v_dir := dirs (indx); + END IF; + + WHILE v_dir IS NOT NULL + LOOP + BEGIN + --DBMS_OUTPUT.PUT_LINE ('...looking in ' || v_dir); + retval := UTL_FILE.fopen (v_dir, file, 'R'); + EXIT; + EXCEPTION + WHEN OTHERS + THEN + indx := dirs.NEXT (indx); + + IF indx IS NULL + THEN + v_dir := NULL; + ELSE + v_dir := dirs (indx); + END IF; + END; + END LOOP; + + RETURN retval; + END; +END; +/ diff --git a/examples/gen_ut_betwnstr.pro b/examples/gen_ut_betwnstr.pro new file mode 100644 index 000000000..e8e5ef26d --- /dev/null +++ b/examples/gen_ut_betwnstr.pro @@ -0,0 +1,17 @@ +CREATE OR REPLACE PROCEDURE gen_ut_betwnstr +IS + utc VARCHAR2 (1000) + := '#program name|overload|test case name|message|arguments|result|assertion type +betwnstr||normal|normal|abcdefgh;3;5|cde|eq +betwnstr||zero start|zero start|abcdefgh;0;2|abc|eq +betwnstr||null start|null start|abcdefgh;!null;2|null|isnull +betwnstr||null end|null end|abcdefgh;!3;!null|null|isnull'; +BEGIN + utconfig.setdir ('d:\openoracle\utplsql\examples'); + utconfig.showconfig; + utgen.testpkg_from_string ('betwnstr', + utc, + output_type_in=> utgen.c_file, + dir_in=> 'c:\temp' + ); +END; diff --git a/examples/gen_ut_betwnstr.sql b/examples/gen_ut_betwnstr.sql new file mode 100644 index 000000000..50e627682 --- /dev/null +++ b/examples/gen_ut_betwnstr.sql @@ -0,0 +1,20 @@ +DECLARE + utc VARCHAR2 (1000) + := '#program name|test case name|message|arguments|result|assertion type +betwnstr|1|normal|normal|abcdefgh;3;5|cde|eq +betwnstr|1|zero start|zero start|abcdefgh;0;2|ab|eq +betwnstr|1|null start|null start|abcdefgh;!null;2|null|isnull +betwnstr|1|big start small end|big start small end|abcdefgh;10;5|null|isnull +betwnstr|1|null end|null end|abcdefgh;!3;!null|null|isnull' +; +BEGIN + utgen.testpkg_from_string ('betwnstr', + utc + /*, + output_type_in=> utgen.c_file, + dir_in=> 'd:\demo-seminar' + */ + ); +END; +/ + diff --git a/examples/gen_ut_betwnstr_to_screen.sql b/examples/gen_ut_betwnstr_to_screen.sql new file mode 100644 index 000000000..d33f8bffc --- /dev/null +++ b/examples/gen_ut_betwnstr_to_screen.sql @@ -0,0 +1,16 @@ +/* Formatted on 2001/08/21 09:10 (RevealNet Formatter v4.4.1) */ +DECLARE + utc VARCHAR2 (1000) + := '#program name|test case name|message|arguments|result|assertion type +betwnstr|1|normal|normal|abcdefgh;3;5|cde|eq +betwnstr|1|zero start|zero start|abcdefgh;0;2|abc|eq +betwnstr|1|null start|null start|abcdefgh;!null;2|null|isnull +betwnstr|1|null end|null end|abcdefgh;!3;!null|null|isnull'; +BEGIN + utgen.testpkg_from_string ( + 'betwnstr', + utc + ); +END; +/ + diff --git a/examples/gen_ut_plvstr.pro b/examples/gen_ut_plvstr.pro new file mode 100644 index 000000000..90758e0cd --- /dev/null +++ b/examples/gen_ut_plvstr.pro @@ -0,0 +1,19 @@ +CREATE OR REPLACE PROCEDURE gen_ut_plvstr +IS + utc VARCHAR2 (1000) + := '#program name|overload#|test case name|message|arguments|result|assertion type +betwn|1|normal|normal|abcdefgh;3;5;TRUE|cde|eq +betwn|1|zero start|zero start|abcdefgh;0;2;TRUE|abc|eq +betwn|1|null start|null start|abcdefgh;!null;2;TRUE|null|isnull +betwn|1|null end|null end|abcdefgh;!3;!null;TRUE|null|isnull'; +BEGIN + utconfig.setdir ('d:\openoracle\utplsql\examples'); + utconfig.showconfig; + utgen.testpkg_from_string ('plvstr', + utc, + output_type_in=> utgen.c_file, + dir_in=> 'd:\openoracle\utplsql\examples', + schema_in => 'PLVPRO', + only_if_in_grid_in => TRUE + ); +END; diff --git a/examples/login.sql b/examples/login.sql new file mode 100644 index 000000000..b163d7576 --- /dev/null +++ b/examples/login.sql @@ -0,0 +1,7 @@ +BEGIN + utconfig.setdir ('d:\openoracle\utplsql\examples'); + utconfig.showconfig; +END; +/ + + diff --git a/examples/login_sample.sql b/examples/login_sample.sql new file mode 100644 index 000000000..4a54f6811 --- /dev/null +++ b/examples/login_sample.sql @@ -0,0 +1,4 @@ +exec utConfig.setdir ('YOUR DIRECTORY HERE') +REM exec utplsql.setdir ('e:\openoracle\utplsql\utinstall\examples') +SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED +exec utConfig.showconfig diff --git a/examples/mybooks_setup.sql b/examples/mybooks_setup.sql new file mode 100644 index 000000000..ce8698b3d --- /dev/null +++ b/examples/mybooks_setup.sql @@ -0,0 +1,77 @@ +/**************************************************************************************** + + Author : Venky Mangapillai + Created : Mar'2002 + Description : This is the Prerequest program for UTPSQL test package called UT_MYBOOKS_PKG + +****************************************************************************************/ + +CREATE TABLE mybooks ( + book_id NUMBER, + book_nm VARCHAR2(30), + publish_dt DATE +) +/ +ALTER TABLE mybooks ADD CONSTRAINT mybooks_pk PRIMARY KEY (book_id) +/ +TRUNCATE TABLE mybooks +/ +INSERT INTO mybooks VALUES (1,'Sports History','01-JAN-2002'); +INSERT INTO mybooks VALUES (2,'World History','02-JAN-2002'); +INSERT INTO mybooks VALUES (3,'Medicine History','03-JAN-2002'); +INSERT INTO mybooks VALUES (4,'Market History','04-JAN-2002'); +INSERT INTO mybooks VALUES (5,'Weather History','05-JAN-2002'); + +CREATE OR REPLACE PACKAGE mybooks_pkg AS +TYPE mybooks_rec IS REF CURSOR RETURN mybooks%ROWTYPE; + +FUNCTION sel_book_func(bookid NUMBER) RETURN mybooks_rec; +PROCEDURE sel_book_proc(bookid NUMBER, rc OUT mybooks_rec); +FUNCTION sel_booknm(bookid NUMBER) RETURN VARCHAR2; +PROCEDURE ins(bookid NUMBER, booknm VARCHAR2,publishdt DATE); +PROCEDURE upd(bookid NUMBER, booknm VARCHAR2,publishdt DATE); +PROCEDURE del(bookid NUMBER); + +END; +/ +CREATE OR REPLACE PACKAGE BODY mybooks_pkg AS +FUNCTION sel_book_func(bookid NUMBER) RETURN mybooks_rec IS + rc mybooks_rec; +BEGIN + OPEN rc FOR SELECT * FROM mybooks WHERE book_id = bookid; + RETURN(rc); +END; + +FUNCTION sel_booknm(bookid NUMBER) RETURN VARCHAR2 IS + booknm VARCHAR2(30); +BEGIN + SELECT book_nm INTO booknm FROM mybooks WHERE book_id = bookid; + RETURN(booknm); +END; + +PROCEDURE ins(bookid NUMBER, booknm VARCHAR2,publishdt DATE) IS +BEGIN + INSERT INTO mybooks VALUES (bookid,booknm,publishdt); + COMMIT; +END; + +PROCEDURE upd(bookid NUMBER, booknm VARCHAR2,publishdt DATE) IS +BEGIN + UPDATE mybooks SET book_nm=booknm, publish_dt=publishdt WHERE book_id = bookid; + COMMIT; +END; + +PROCEDURE del(bookid NUMBER) IS +BEGIN + DELETE FROM mybooks WHERE book_id = bookid; + COMMIT; +END; + +PROCEDURE sel_book_proc(bookid NUMBER, rc OUT mybooks_rec) IS +BEGIN + OPEN rc FOR SELECT * FROM mybooks WHERE book_id = bookid; +END; + +END; +/ +show errors diff --git a/examples/plvision.tst b/examples/plvision.tst new file mode 100644 index 000000000..eb55e9ae3 --- /dev/null +++ b/examples/plvision.tst @@ -0,0 +1,16 @@ +BEGIN + -- Define a test suite for PL/Vision + utsuite.add ('PLVision'); + + -- Add two packages for testing + utpackage.add ( + 'PLVision', 'PLVstr', dir_in => 'e:\openoracle\utplsql\examples'); + utpackage.add ( + 'PLVision', 'PLVdate', dir_in => 'e:\openoracle\utplsql\examples'); + + -- Run the test suite + utplsql.testsuite ( + 'PLVision', recompile_in => TRUE); +END; +/ + diff --git a/examples/qu_betwnstr.pkb b/examples/qu_betwnstr.pkb new file mode 100644 index 000000000..d489db59a --- /dev/null +++ b/examples/qu_betwnstr.pkb @@ -0,0 +1,99 @@ +/* Formatted by PL/Formatter v3.1.2.1 on 2001/04/11 14:05 */ + +CREATE OR REPLACE PACKAGE BODY ut_betwnstr +IS + PROCEDURE ut_setup + IS + BEGIN + NULL; + END; + + PROCEDURE ut_teardown + IS + BEGIN + NULL; + END; + + -- For each program to test... + PROCEDURE ut_betwnstr + IS + -- Verify and complete data types. + against_this VARCHAR2 (2000); + check_this VARCHAR2 (2000); + datapack utpack.datapack_t; + BEGIN + -- Define "control" operation for "normal" + + against_this := 'cde'; + -- Execute test code for "normal" + + check_this := + betwnstr (string_in=> 'abcdefgh', + start_in => 3, + end_in => 5 + ); + -- Assert success for "normal" + + -- Compare the two values. + -- This is generated so record is used to avoid overloading issues. + utassert2.eq (100, 'normal', check_this, against_this); + -- End of test for "normal" + + -- Define "control" operation for "zero start" + + against_this := 'abc'; + -- Execute test code for "zero start" + + check_this := + betwnstr (string_in=> 'abcdefgh', + start_in => 0, + end_in => 2 + ); + -- Assert success for "zero start" + + -- Compare the two values. + --utassert.eq ('zero start', check_this, against_this); + utassert2.eq (101, 'zero start', check_this, against_this); + -- End of test for "zero start" + + -- Define "control" operation for "null start" + + against_this := NULL; + -- Execute test code for "null start" + + check_this := + betwnstr (string_in=> 'abcdefgh', + start_in => NULL, + end_in => 2 + ); + -- Assert success for "null start" + + -- Check for NULL return value. + --utassert.isnull ('null start', against_this); + utassert2.isnull (102, 'null start', against_this); + -- End of test for "null start" + + -- Define "control" operation for "null end" + + against_this := NULL; + -- Execute test code for "null end" + + check_this := + betwnstr (string_in=> 'abcdefgh', + start_in => 3, + end_in => NULL + ); + -- Assert success for "null end" + + -- Check for NULL return value. + --utassert.isnull ('null end', against_this); + utassert2.isnull (103, 'null end', against_this); + -- End of test for "null end" + + utassert2.eqtable (104, 'compare emps', 'emp', 'emp2'); + + END ut_betwnstr; +END ut_betwnstr; +/ + + diff --git a/examples/registertests.sql b/examples/registertests.sql new file mode 100644 index 000000000..5ab6e7354 --- /dev/null +++ b/examples/registertests.sql @@ -0,0 +1,5 @@ +BEGIN + utplsql.trc; + utconfig.registertest (TRUE ); + utplsql.test ('betwnstr'); +END; diff --git a/examples/showfailures.sql b/examples/showfailures.sql new file mode 100644 index 000000000..41e24aec8 --- /dev/null +++ b/examples/showfailures.sql @@ -0,0 +1,39 @@ +COLUMN suite format a42 heading '********* SUITE *********' + +COLUMN package format a16 heading '*** PACKAGE ***' + +COLUMN time_stamp format a18 + +COLUMN test format a80 fold_before heading "" + +COLUMN junk fold_after heading "" + +COLUMN junk2 fold_before heading "" + +SET pagesize 0 + +SET linesize 80 + +BREAK on suite noduplicates on package noduplicates on time_stamp noduplicates on junk noduplicates skip 6 + +SPOOL last_run_failures.txt + +SELECT '********************* SUITE ************ PACKAGE ********* Time +Stamp' + junk, + s.description suite, p.NAME PACKAGE, + TO_CHAR (p.last_end, 'dd-mon-yy hh24:mi:ss') time_stamp, + '-----------------------------' junk2, + DECODE ( + p.last_end, + NULL, 'Unable to Execute', + NVL (o.description, 'Passed all +Tests') + ) test + FROM utr_outcome o, ut_package p, ut_suite s + WHERE o.run_id(+) = p.last_run_id + AND o.status(+) = 'FAILURE' + AND s.id = p.suite_id +ORDER BY s.id, p.seq, p.last_end; + +SPOOL off diff --git a/examples/str.pkb b/examples/str.pkb new file mode 100644 index 000000000..3b572e628 --- /dev/null +++ b/examples/str.pkb @@ -0,0 +1,87 @@ +/* Formatted on 2001/11/19 15:15 (Formatter Plus v4.5.2) */ +CREATE OR REPLACE PACKAGE BODY str +IS + FUNCTION betwn ( + string_in IN VARCHAR2, + start_in IN PLS_INTEGER, + end_in IN PLS_INTEGER + ) + RETURN VARCHAR2 + IS + l_start PLS_INTEGER := start_in; + BEGIN + IF l_start = 0 + THEN + l_start := 1; + END IF; + + RETURN (SUBSTR ( + string_in, + l_start, + end_in + - l_start + + 1 + ) + ); + END; + + FUNCTION betwn2 ( + string_in IN VARCHAR2, + start_in IN PLS_INTEGER, + end_in IN PLS_INTEGER + ) + RETURN VARCHAR2 + IS + BEGIN + -- Handle negative values + IF end_in < 0 + THEN + RETURN betwn (string_in, start_in, end_in); + ELSE + RETURN (SUBSTR ( + string_in, + LENGTH (string_in) + + end_in + + 1, + start_in + - end_in + + 1 + ) + ); + END IF; + END; + + PROCEDURE ut_setup + IS + BEGIN + NULL; + END; + + PROCEDURE ut_teardown + IS + BEGIN + NULL; + END; + + -- For each program to test... + PROCEDURE ut_betwn + IS + BEGIN + utassert.eq ( + 'Typical Valid Usage', + str.betwn ('this is a string', 3, 7), + 'is is' + ); + utassert.eq ( + 'Test Negative Start', + str.betwn ('this is a string', -3, 7), + 'ing' + ); + utassert.isnull ( + 'Start bigger than end', + str.betwn ('this is a string', 3, 1) + ); + END; +END str; +/ + diff --git a/examples/str.pks b/examples/str.pks new file mode 100644 index 000000000..df3144765 --- /dev/null +++ b/examples/str.pks @@ -0,0 +1,26 @@ +/* Formatted on 2001/11/19 15:11 (Formatter Plus v4.5.2) */ +CREATE OR REPLACE PACKAGE str +IS + FUNCTION betwn ( + string_in IN VARCHAR2, + start_in IN PLS_INTEGER, + end_in IN PLS_INTEGER + ) + RETURN VARCHAR2; + + FUNCTION betwn2 ( + string_in IN VARCHAR2, + start_in IN PLS_INTEGER, + end_in IN PLS_INTEGER + ) + RETURN VARCHAR2; + + PROCEDURE ut_setup; + + PROCEDURE ut_teardown; + + -- For each program to test... + PROCEDURE ut_betwn; +END str; +/ + diff --git a/examples/str2list.pkg b/examples/str2list.pkg new file mode 100644 index 000000000..eb47f5402 --- /dev/null +++ b/examples/str2list.pkg @@ -0,0 +1,215 @@ +CREATE OR REPLACE PACKAGE str2list +IS + PROCEDURE parse ( + str IN VARCHAR2, + delim IN VARCHAR2, + pkg IN VARCHAR2, + tab IN VARCHAR2, + datatype IN VARCHAR2 := 'VARCHAR2(32767)', + extend_needed BOOLEAN := FALSE + ); + + PROCEDURE parse ( + str IN VARCHAR2, + delim IN VARCHAR2, + pkg IN VARCHAR2, + appendproc IN VARCHAR2, /* pkg.appendproc (oneval); */ + deleteproc IN VARCHAR2, /* pkg.deleteproc (onerow); or pkg.deleteproc; */ + datatype IN VARCHAR2 + ); + + PROCEDURE showlist ( + pkg IN VARCHAR2, + tab IN VARCHAR2 + ); + + PROCEDURE showlist ( + pkg IN VARCHAR2, + firstrowproc IN VARCHAR2, + nextrowproc IN VARCHAR2, + getvalfunc IN VARCHAR2, + showproc IN VARCHAR2 := 'DBMS_OUTPUT.PUT_LINE', + datatype IN VARCHAR2 := 'VARCHAR2(32767)' + ); +END str2list; +/ +CREATE OR REPLACE PACKAGE BODY str2list +IS +procedure disperr (str in varchar2) is +begin + p.l ('Compilation/Execution Error:'); + p.l (SQLERRM); + p.l ('In:'); + p.l (str); +end; + + PROCEDURE parse ( + str IN VARCHAR2, + delim IN VARCHAR2, + pkg IN VARCHAR2, + tab IN VARCHAR2, + datatype IN VARCHAR2 := 'VARCHAR2(32767)', + extend_needed BOOLEAN := FALSE + ) + IS + tabname VARCHAR2 (100) := pkg || '.' || tab; + dynblock VARCHAR2 (32767); + extstring VARCHAR2 (100); + BEGIN + IF extend_needed + THEN + extstring := tabname || '.EXTEND;' + END IF; + + dynblock := + 'DECLARE + v_loc PLS_INTEGER; + v_startloc PLS_INTEGER := 1; + v_item ' || datatype || '; + BEGIN ' || + tabname || '.DELETE; + IF :str IS NOT NULL + THEN + LOOP + v_loc := INSTR (:str, :delim, v_startloc); + IF v_loc = v_startloc + THEN + v_item := NULL; + ELSIF v_loc = 0 + THEN + v_item := SUBSTR (:str, v_startloc); + ELSE + v_item := SUBSTR (:str, v_startloc, v_loc - v_startloc); + END IF;' || + + extstring || tabname || '(' || tabname || '.LAST) + := v_item; + + IF v_loc = 0 + THEN + EXIT; + ELSE + v_startloc := v_loc + 1; + END IF; + END LOOP; + END IF; + END;'; + + EXECUTE IMMEDIATE dynblock USING str, delim; + EXCEPTION + WHEN OTHERS + THEN + disperr (dynblock); + END; + + PROCEDURE parse ( + str IN VARCHAR2, + delim IN VARCHAR2, + pkg IN VARCHAR2, + appendproc IN VARCHAR2, + deleteproc IN VARCHAR2, + datatype IN VARCHAR2 + )IS + dynblock VARCHAR2 (32767); + BEGIN + dynblock := + 'DECLARE + v_loc PLS_INTEGER; + v_startloc PLS_INTEGER := 1; + v_item ' || datatype || '; + BEGIN + ' || pkg || '.' || deleteproc || '; + IF :str IS NOT NULL + THEN + LOOP + v_loc := INSTR (:str, :delim, v_startloc); + IF v_loc = v_startloc + THEN + v_item := NULL; + ELSIF v_loc = 0 + THEN + v_item := SUBSTR (:str, v_startloc); + ELSE + v_item := SUBSTR (:str, v_startloc, v_loc - v_startloc); + END IF;' || + pkg || + '.' || + appendproc || + '( v_item); + IF v_loc = 0 + THEN + EXIT; + ELSE + v_startloc := v_loc + 1; + END IF; + END LOOP; + END IF; + END;'; + EXECUTE IMMEDIATE dynblock USING str, delim; + EXCEPTioN + when others then disperr (dynblock); + END; + + PROCEDURE showlist ( + pkg IN VARCHAR2, + tab IN VARCHAR2 + ) + IS + tabname VARCHAR2 (100) := pkg || '.' || tab; + dynblock VARCHAR2 (32767); + BEGIN + dynblock := + 'DECLARE + indx PLS_INTEGER := ' || tabname || + '.FIRST; + v_startloc PLS_INTEGER := 1; + v_item VARCHAR2(32767); + BEGIN + LOOP + EXIT WHEN indx IS NULL; + DBMS_OUTPUT.PUT_LINE (' || + tabname || + '(indx)); + indx := ' || + tabname || + '.NEXT (indx); + END LOOP; + END;'; + EXECUTE IMMEDIATE dynblock; + EXCEPTioN + when others then disperr (dynblock); + END; + + PROCEDURE showlist ( + pkg IN VARCHAR2, + firstrowproc IN VARCHAR2, + nextrowproc IN VARCHAR2, + getvalfunc IN VARCHAR2, + showproc IN VARCHAR2 := 'DBMS_OUTPUT.PUT_LINE', + datatype IN VARCHAR2 := 'VARCHAR2(32767)' ) + IS + dynblock VARCHAR2 (32767); + BEGIN + dynblock := + 'DECLARE + indx PLS_INTEGER := ' || pkg || + '.' || firstrowproc || '; + v_startloc PLS_INTEGER := 1; + v_item ' || datatype || '; + BEGIN + LOOP + EXIT WHEN indx IS NULL;' || + showproc || ' (' || + pkg || '.' || getvalfunc || '(indx)); + indx := ' || + pkg || + '.' || nextrowproc || '(indx); + END LOOP; + END;'; + EXECUTE IMMEDIATE dynblock; + EXCEPTioN + when others then disperr (dynblock); + END; + +END str2list; +/ diff --git a/examples/str2list.tst b/examples/str2list.tst new file mode 100644 index 000000000..0c6526642 --- /dev/null +++ b/examples/str2list.tst @@ -0,0 +1,20 @@ +@str2list.pkg + +@filepath.pkg + +BEGIN + p.l ('Str2List Test Using Direct Collection Access'); + fileio.setpath ('a;b;c;d;efg;;'); + str2list.showlist ('fileio', 'dirs'); +END; +/ + +@filepath2.pkg + +BEGIN + p.l ('Str2List Test Using API'); + fileio.setpath ('a;b;c;d;efg;;'); + str2list.showlist ('fileio', 'first', 'next', 'val', 'p.l'); +END; +/ + \ No newline at end of file diff --git a/examples/str_same.pkb b/examples/str_same.pkb new file mode 100644 index 000000000..69a4070fb --- /dev/null +++ b/examples/str_same.pkb @@ -0,0 +1,20 @@ +CREATE OR REPLACE PACKAGE BODY str +IS + FUNCTION betwn ( + string_in IN VARCHAR2, + start_in IN PLS_INTEGER, + end_in IN PLS_INTEGER + ) + RETURN VARCHAR2 + IS + BEGIN + RETURN ( + SUBSTR ( + string_in, + start_in, + end_in - start_in + 1 + ) + ); + END; +END str; +/ diff --git a/examples/str_same.pks b/examples/str_same.pks new file mode 100644 index 000000000..0fac975bd --- /dev/null +++ b/examples/str_same.pks @@ -0,0 +1,10 @@ +CREATE OR REPLACE PACKAGE str +IS + FUNCTION betwn ( + string_in IN VARCHAR2, + start_in IN PLS_INTEGER, + end_in IN PLS_INTEGER + ) + RETURN VARCHAR2; +END str; +/ diff --git a/examples/tabcount.sf b/examples/tabcount.sf new file mode 100644 index 000000000..4c28c8f29 --- /dev/null +++ b/examples/tabcount.sf @@ -0,0 +1,17 @@ +CREATE OR REPLACE FUNCTION tabcount ( + sch IN VARCHAR2, + tab IN VARCHAR2) + RETURN INTEGER +IS + retval INTEGER; +BEGIN + EXECUTE IMMEDIATE + 'SELECT COUNT(*) FROM ' || sch || '.' || tab + INTO retval; + RETURN retval; +EXCEPTION + WHEN OTHERS + THEN + RETURN NULL; +END; +/ diff --git a/examples/te_employee.pkb b/examples/te_employee.pkb new file mode 100644 index 000000000..92f4ea7d1 --- /dev/null +++ b/examples/te_employee.pkb @@ -0,0 +1,1710 @@ +--//----------------------------------------------------------------------- +--// ** PL/Generator Table Encapsulator for "employee" +--//----------------------------------------------------------------------- +--// (c) COPYRIGHT Personnel Policies, Inc. 1999. +--// All rights reserved. +--// +--// No part of this copyrighted work may be reproduced, modified, +--// or distributed in any form or by any means without the prior +--// written permission of Personnel Policies, Inc.. +--//----------------------------------------------------------------------- +--// This software was generated by RevealNet's PL/Generator (TM). +--// +--// For more information, visit www.revealnet.com or call 1.800.REVEAL4 +--//----------------------------------------------------------------------- +--// Stored In: te_employee.pkb +--// Created On: September 05, 2000 20:14:04 +--// Created By: SCOTT +--// PL/Generator Version: PRO-2000.1.1 +--//----------------------------------------------------------------------- +CREATE OR REPLACE PACKAGE BODY te_employee +IS + --// Package name and program name globals --// + c_pkgname VARCHAR2(30) := 'te_employee'; + g_progname VARCHAR2(30) := NULL; + + --// Update Flag private data structures. --// + TYPE frcflg_rt IS RECORD ( + last_name CHAR(1), + first_name CHAR(1), + middle_initial CHAR(1), + job_id CHAR(1), + manager_id CHAR(1), + hire_date CHAR(1), + salary CHAR(1), + commission CHAR(1), + department_id CHAR(1), + changed_by CHAR(1), + changed_on CHAR(1) + ); + + frcflg frcflg_rt; + emptyfrc frcflg_rt; + c_set CHAR(1) := 'Y'; + c_noset CHAR(1) := 'N'; + + TYPE tab_tabtype IS TABLE OF allcols_rt INDEX BY BINARY_INTEGER; + loadtab tab_tabtype; + FUNCTION version RETURN VARCHAR2 + IS + BEGIN + RETURN '7.09'; + END; + +--// Private Modules //-- + + --// For Dynamic SQL operations; currently unused. //-- + PROCEDURE initcur (cur_inout IN OUT INTEGER) + IS + BEGIN + IF NOT DBMS_SQL.IS_OPEN (cur_inout) + THEN + cur_inout := DBMS_SQL.OPEN_CURSOR; + END IF; + EXCEPTION + WHEN invalid_cursor + THEN + cur_inout := DBMS_SQL.OPEN_CURSOR; + END; + + PROCEDURE start_program (nm IN VARCHAR2, msg IN VARCHAR2 := NULL) IS + BEGIN + g_progname := nm; + END; + + PROCEDURE end_program IS + BEGIN + g_progname := NULL; + END; + +--// Cursor management procedures //-- + + --// Open the cursors with some options. //-- + PROCEDURE open_compforpky_cur ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + start_program ('open_compforpky_cur'); + + IF compforpky_cur%ISOPEN AND v_close + THEN + CLOSE compforpky_cur; + ELSIF compforpky_cur%ISOPEN AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN compforpky_cur ( + employee_id_in + ); + END IF; + + end_program; + END; + + PROCEDURE open_compbypky_cur ( + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + IF compbypky_cur%ISOPEN AND v_close + THEN + CLOSE compbypky_cur; + ELSIF compbypky_cur%ISOPEN AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN compbypky_cur; + END IF; + END; + + PROCEDURE open_emp_dept_lookup_comp_cur ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + IF emp_dept_lookup_comp_cur%ISOPEN AND v_close + THEN + CLOSE emp_dept_lookup_comp_cur; + ELSIF emp_dept_lookup_comp_cur%ISOPEN AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN emp_dept_lookup_comp_cur ( + department_id_in + ); + END IF; + END; + + PROCEDURE open_emp_job_lookup_comp_cur ( + job_id_in IN EMPLOYEE.JOB_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + IF emp_job_lookup_comp_cur%ISOPEN AND v_close + THEN + CLOSE emp_job_lookup_comp_cur; + ELSIF emp_job_lookup_comp_cur%ISOPEN AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN emp_job_lookup_comp_cur ( + job_id_in + ); + END IF; + END; + + PROCEDURE open_emp_mgr_lookup_comp_cur ( + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + IF emp_mgr_lookup_comp_cur%ISOPEN AND v_close + THEN + CLOSE emp_mgr_lookup_comp_cur; + ELSIF emp_mgr_lookup_comp_cur%ISOPEN AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN emp_mgr_lookup_comp_cur ( + manager_id_in + ); + END IF; + END; + --// Open the cursors with some options. //-- + PROCEDURE open_nameforpky_cur ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + start_program ('open_nameforpky_cur'); + + IF nameforpky_cur%ISOPEN AND v_close + THEN + CLOSE nameforpky_cur; + ELSIF nameforpky_cur%ISOPEN AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN nameforpky_cur ( + employee_id_in + ); + END IF; + + end_program; + END; + + PROCEDURE open_namebypky_cur ( + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + IF namebypky_cur%ISOPEN AND v_close + THEN + CLOSE namebypky_cur; + ELSIF namebypky_cur%ISOPEN AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN namebypky_cur; + END IF; + END; + + PROCEDURE open_emp_dept_lookup_name_cur ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + IF emp_dept_lookup_name_cur%ISOPEN AND v_close + THEN + CLOSE emp_dept_lookup_name_cur; + ELSIF emp_dept_lookup_name_cur%ISOPEN AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN emp_dept_lookup_name_cur ( + department_id_in + ); + END IF; + END; + + PROCEDURE open_emp_job_lookup_name_cur ( + job_id_in IN EMPLOYEE.JOB_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + IF emp_job_lookup_name_cur%ISOPEN AND v_close + THEN + CLOSE emp_job_lookup_name_cur; + ELSIF emp_job_lookup_name_cur%ISOPEN AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN emp_job_lookup_name_cur ( + job_id_in + ); + END IF; + END; + + PROCEDURE open_emp_mgr_lookup_name_cur ( + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + IF emp_mgr_lookup_name_cur%ISOPEN AND v_close + THEN + CLOSE emp_mgr_lookup_name_cur; + ELSIF emp_mgr_lookup_name_cur%ISOPEN AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN emp_mgr_lookup_name_cur ( + manager_id_in + ); + END IF; + END; + --// Open the cursors with some options. //-- + PROCEDURE open_allforpky_cur ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + start_program ('open_allforpky_cur'); + + IF allforpky_cur%ISOPEN AND v_close + THEN + CLOSE allforpky_cur; + ELSIF allforpky_cur%ISOPEN AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN allforpky_cur ( + employee_id_in + ); + END IF; + + end_program; + END; + + PROCEDURE open_allbypky_cur ( + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + IF allbypky_cur%ISOPEN AND v_close + THEN + CLOSE allbypky_cur; + ELSIF allbypky_cur%ISOPEN AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN allbypky_cur; + END IF; + END; + + PROCEDURE open_emp_dept_lookup_all_cur ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + IF emp_dept_lookup_all_cur%ISOPEN AND v_close + THEN + CLOSE emp_dept_lookup_all_cur; + ELSIF emp_dept_lookup_all_cur%ISOPEN AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN emp_dept_lookup_all_cur ( + department_id_in + ); + END IF; + END; + + PROCEDURE open_emp_job_lookup_all_cur ( + job_id_in IN EMPLOYEE.JOB_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + IF emp_job_lookup_all_cur%ISOPEN AND v_close + THEN + CLOSE emp_job_lookup_all_cur; + ELSIF emp_job_lookup_all_cur%ISOPEN AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN emp_job_lookup_all_cur ( + job_id_in + ); + END IF; + END; + + PROCEDURE open_emp_mgr_lookup_all_cur ( + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + IF emp_mgr_lookup_all_cur%ISOPEN AND v_close + THEN + CLOSE emp_mgr_lookup_all_cur; + ELSIF emp_mgr_lookup_all_cur%ISOPEN AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN emp_mgr_lookup_all_cur ( + manager_id_in + ); + END IF; + END; + + --// Close the cursors if they are open. //-- + PROCEDURE close_compforpky_cur + IS BEGIN + IF compforpky_cur%ISOPEN + THEN + CLOSE compforpky_cur; + END IF; + END; + + PROCEDURE close_compbypky_cur + IS BEGIN + IF compbypky_cur%ISOPEN + THEN + CLOSE compbypky_cur; + END IF; + END; + + PROCEDURE close_emp_dept_lookup_comp_cur + IS BEGIN + IF emp_dept_lookup_comp_cur%ISOPEN + THEN + CLOSE emp_dept_lookup_comp_cur; + END IF; + END; + + PROCEDURE close_emp_job_lookup_comp_cur + IS BEGIN + IF emp_job_lookup_comp_cur%ISOPEN + THEN + CLOSE emp_job_lookup_comp_cur; + END IF; + END; + + PROCEDURE close_emp_mgr_lookup_comp_cur + IS BEGIN + IF emp_mgr_lookup_comp_cur%ISOPEN + THEN + CLOSE emp_mgr_lookup_comp_cur; + END IF; + END; + + PROCEDURE close_nameforpky_cur + IS BEGIN + IF nameforpky_cur%ISOPEN + THEN + CLOSE nameforpky_cur; + END IF; + END; + + PROCEDURE close_namebypky_cur + IS BEGIN + IF namebypky_cur%ISOPEN + THEN + CLOSE namebypky_cur; + END IF; + END; + + PROCEDURE close_emp_dept_lookup_name_cur + IS BEGIN + IF emp_dept_lookup_name_cur%ISOPEN + THEN + CLOSE emp_dept_lookup_name_cur; + END IF; + END; + + PROCEDURE close_emp_job_lookup_name_cur + IS BEGIN + IF emp_job_lookup_name_cur%ISOPEN + THEN + CLOSE emp_job_lookup_name_cur; + END IF; + END; + + PROCEDURE close_emp_mgr_lookup_name_cur + IS BEGIN + IF emp_mgr_lookup_name_cur%ISOPEN + THEN + CLOSE emp_mgr_lookup_name_cur; + END IF; + END; + + PROCEDURE close_allforpky_cur + IS BEGIN + IF allforpky_cur%ISOPEN + THEN + CLOSE allforpky_cur; + END IF; + END; + + PROCEDURE close_allbypky_cur + IS BEGIN + IF allbypky_cur%ISOPEN + THEN + CLOSE allbypky_cur; + END IF; + END; + + PROCEDURE close_emp_dept_lookup_all_cur + IS BEGIN + IF emp_dept_lookup_all_cur%ISOPEN + THEN + CLOSE emp_dept_lookup_all_cur; + END IF; + END; + + PROCEDURE close_emp_job_lookup_all_cur + IS BEGIN + IF emp_job_lookup_all_cur%ISOPEN + THEN + CLOSE emp_job_lookup_all_cur; + END IF; + END; + + PROCEDURE close_emp_mgr_lookup_all_cur + IS BEGIN + IF emp_mgr_lookup_all_cur%ISOPEN + THEN + CLOSE emp_mgr_lookup_all_cur; + END IF; + END; + + PROCEDURE closeall + IS + BEGIN + close_compforpky_cur; + close_compbypky_cur; + close_emp_dept_lookup_comp_cur; + close_emp_job_lookup_comp_cur; + close_emp_mgr_lookup_comp_cur; + close_nameforpky_cur; + close_namebypky_cur; + close_emp_dept_lookup_name_cur; + close_emp_job_lookup_name_cur; + close_emp_mgr_lookup_name_cur; + close_allforpky_cur; + close_allbypky_cur; + close_emp_dept_lookup_all_cur; + close_emp_job_lookup_all_cur; + close_emp_mgr_lookup_all_cur; + END; + +--// Emulate aggregate-level record operations. //-- + + FUNCTION recseq (rec1 IN allcols_rt, rec2 IN allcols_rt) + RETURN BOOLEAN + IS + unequal_records EXCEPTION; + retval BOOLEAN; + BEGIN + retval := rec1.employee_id = rec2.employee_id OR + (rec1.employee_id IS NULL AND rec2.employee_id IS NULL); + IF NOT NVL (retval, FALSE) THEN RAISE unequal_records; END IF; + retval := rec1.last_name = rec2.last_name OR + (rec1.last_name IS NULL AND rec2.last_name IS NULL); + IF NOT NVL (retval, FALSE) THEN RAISE unequal_records; END IF; + retval := rec1.first_name = rec2.first_name OR + (rec1.first_name IS NULL AND rec2.first_name IS NULL); + IF NOT NVL (retval, FALSE) THEN RAISE unequal_records; END IF; + retval := rec1.middle_initial = rec2.middle_initial OR + (rec1.middle_initial IS NULL AND rec2.middle_initial IS NULL); + IF NOT NVL (retval, FALSE) THEN RAISE unequal_records; END IF; + retval := rec1.job_id = rec2.job_id OR + (rec1.job_id IS NULL AND rec2.job_id IS NULL); + IF NOT NVL (retval, FALSE) THEN RAISE unequal_records; END IF; + retval := rec1.manager_id = rec2.manager_id OR + (rec1.manager_id IS NULL AND rec2.manager_id IS NULL); + IF NOT NVL (retval, FALSE) THEN RAISE unequal_records; END IF; + retval := rec1.hire_date = rec2.hire_date OR + (rec1.hire_date IS NULL AND rec2.hire_date IS NULL); + IF NOT NVL (retval, FALSE) THEN RAISE unequal_records; END IF; + retval := rec1.salary = rec2.salary OR + (rec1.salary IS NULL AND rec2.salary IS NULL); + IF NOT NVL (retval, FALSE) THEN RAISE unequal_records; END IF; + retval := rec1.commission = rec2.commission OR + (rec1.commission IS NULL AND rec2.commission IS NULL); + IF NOT NVL (retval, FALSE) THEN RAISE unequal_records; END IF; + retval := rec1.department_id = rec2.department_id OR + (rec1.department_id IS NULL AND rec2.department_id IS NULL); + IF NOT NVL (retval, FALSE) THEN RAISE unequal_records; END IF; + retval := rec1.changed_by = rec2.changed_by OR + (rec1.changed_by IS NULL AND rec2.changed_by IS NULL); + IF NOT NVL (retval, FALSE) THEN RAISE unequal_records; END IF; + retval := rec1.changed_on = rec2.changed_on OR + (rec1.changed_on IS NULL AND rec2.changed_on IS NULL); + IF NOT NVL (retval, FALSE) THEN RAISE unequal_records; END IF; + RETURN TRUE; + EXCEPTION + WHEN unequal_records THEN RETURN FALSE; + END; + + FUNCTION recseq (rec1 IN pky_rt, rec2 IN pky_rt) + RETURN BOOLEAN + IS + unequal_records EXCEPTION; + retval BOOLEAN; + BEGIN + retval := rec1.employee_id = rec2.employee_id OR + (rec1.employee_id IS NULL AND rec2.employee_id IS NULL); + IF NOT NVL (retval, FALSE) THEN RAISE unequal_records; END IF; + RETURN TRUE; + EXCEPTION + WHEN unequal_records THEN RETURN FALSE; + END; + +--// Is the primary key NOT NULL? //-- + + FUNCTION isnullpky ( + rec_in IN allcols_rt + ) + RETURN BOOLEAN + IS + BEGIN + RETURN + rec_in.employee_id IS NULL + ; + END; + + FUNCTION isnullpky ( + rec_in IN pky_rt + ) + RETURN BOOLEAN + IS + BEGIN + RETURN + rec_in.employee_id IS NULL + ; + END; + +--// Query Processing --// + + FUNCTION onerow_internal ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE + ) + RETURN allcols_rt + IS + CURSOR onerow_cur + IS + SELECT + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON + FROM EMPLOYEE + WHERE + EMPLOYEE_ID = employee_id_in + ; + onerow_rec allcols_rt; + BEGIN + OPEN onerow_cur; + FETCH onerow_cur INTO onerow_rec; + CLOSE onerow_cur; + RETURN onerow_rec; + END onerow_internal; + + FUNCTION onerow ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE + ) + RETURN allcols_rt + IS + retval allcols_rt; + BEGIN + IF loadtab.EXISTS (employee_id_in) + THEN + retval := loadtab(employee_id_in); + ELSE + retval := onerow_internal (employee_id_in); + IF retval.EMPLOYEE_ID IS NOT NULL + THEN + --// Load the data into the table. --// + loadtab(employee_id_in) := retval; + END IF; + END IF; + RETURN retval; + END onerow; + + FUNCTION i_employee_name$pky ( + last_name_in IN EMPLOYEE.LAST_NAME%TYPE, + first_name_in IN EMPLOYEE.FIRST_NAME%TYPE, + middle_initial_in IN EMPLOYEE.MIDDLE_INITIAL%TYPE + ) + RETURN pky_rt + IS + CURSOR getpky_cur + IS + SELECT + EMPLOYEE_ID + FROM EMPLOYEE + WHERE + LAST_NAME = i_employee_name$pky.last_name_in AND + FIRST_NAME = i_employee_name$pky.first_name_in AND + MIDDLE_INITIAL = i_employee_name$pky.middle_initial_in + ; + + getpky_rec getpky_cur%ROWTYPE; + retval pky_rt; + BEGIN + OPEN getpky_cur; + FETCH getpky_cur INTO getpky_rec; + IF getpky_cur%FOUND + THEN + retval.employee_id := getpky_rec.EMPLOYEE_ID; + END IF; + CLOSE getpky_cur; + RETURN retval; + END i_employee_name$pky; + + FUNCTION i_employee_name$row ( + last_name_in IN EMPLOYEE.LAST_NAME%TYPE, + first_name_in IN EMPLOYEE.FIRST_NAME%TYPE, + middle_initial_in IN EMPLOYEE.MIDDLE_INITIAL%TYPE + ) + RETURN allcols_rt + IS + CURSOR onerow_cur + IS + SELECT + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON + FROM EMPLOYEE + WHERE + LAST_NAME = i_employee_name$row.last_name_in AND + FIRST_NAME = i_employee_name$row.first_name_in AND + MIDDLE_INITIAL = i_employee_name$row.middle_initial_in + ; + onerow_rec allcols_rt; + BEGIN + OPEN onerow_cur; + FETCH onerow_cur INTO onerow_rec; + CLOSE onerow_cur; + RETURN onerow_rec; + END i_employee_name$row; + + FUNCTION i_employee_name$val ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE + ) + RETURN i_employee_name_rt + IS + v_onerow allcols_rt; + retval i_employee_name_rt; + BEGIN + v_onerow := onerow ( + employee_id_in + ); + + retval.last_name := v_onerow.last_name; + retval.first_name := v_onerow.first_name; + retval.middle_initial := v_onerow.middle_initial; + + RETURN retval; + END i_employee_name$val; + + --// For each update column ... //-- + + FUNCTION hire_date$val ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE + ) + RETURN EMPLOYEE.HIRE_DATE%TYPE + IS + CURSOR onecol_cur + IS + SELECT HIRE_DATE + FROM EMPLOYEE + WHERE + EMPLOYEE_ID = employee_id_in + ; + retval EMPLOYEE.HIRE_DATE%TYPE; + BEGIN + OPEN onecol_cur; + FETCH onecol_cur INTO retval; + CLOSE onecol_cur; + RETURN retval; + END hire_date$val; + --// For each update column ... //-- + + FUNCTION salary$val ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE + ) + RETURN EMPLOYEE.SALARY%TYPE + IS + CURSOR onecol_cur + IS + SELECT SALARY + FROM EMPLOYEE + WHERE + EMPLOYEE_ID = employee_id_in + ; + retval EMPLOYEE.SALARY%TYPE; + BEGIN + OPEN onecol_cur; + FETCH onecol_cur INTO retval; + CLOSE onecol_cur; + RETURN retval; + END salary$val; + + --// Count of all rows in table and for each foreign key. //-- + FUNCTION rowcount RETURN INTEGER + IS + retval INTEGER; + BEGIN + SELECT COUNT(*) INTO retval FROM EMPLOYEE; + RETURN retval; + END; + + FUNCTION pkyrowcount ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE + ) + RETURN INTEGER + IS + retval INTEGER; + BEGIN + SELECT COUNT(*) + INTO retval + FROM EMPLOYEE + WHERE + EMPLOYEE_ID = employee_id_in + ; + RETURN retval; + END; + + FUNCTION emp_dept_lookuprowcount ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE + ) + RETURN INTEGER + IS + retval INTEGER; + BEGIN + SELECT COUNT(*) INTO retval + FROM EMPLOYEE + WHERE + DEPARTMENT_ID = emp_dept_lookuprowcount.department_id_in + ; + RETURN retval; + END; + FUNCTION emp_job_lookuprowcount ( + job_id_in IN EMPLOYEE.JOB_ID%TYPE + ) + RETURN INTEGER + IS + retval INTEGER; + BEGIN + SELECT COUNT(*) INTO retval + FROM EMPLOYEE + WHERE + JOB_ID = emp_job_lookuprowcount.job_id_in + ; + RETURN retval; + END; + FUNCTION emp_mgr_lookuprowcount ( + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE + ) + RETURN INTEGER + IS + retval INTEGER; + BEGIN + SELECT COUNT(*) INTO retval + FROM EMPLOYEE + WHERE + MANAGER_ID = emp_mgr_lookuprowcount.manager_id_in + ; + RETURN retval; + END; + + PROCEDURE lookup_fkydescs ( + --// Foreign key columns for emp_dept_lookup --// + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE, + emp_dept_lookup_out OUT te_department.i_department_name_rt, + --// Foreign key columns for emp_job_lookup --// + job_id_in IN EMPLOYEE.JOB_ID%TYPE, + emp_job_lookup_out OUT te_job.i_job_function_rt, + --// Foreign key columns for emp_mgr_lookup --// + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE, + emp_mgr_lookup_out OUT te_employee.i_employee_name_rt, + record_error BOOLEAN := TRUE + ) + IS + BEGIN + emp_dept_lookup_out := + te_department.i_department_name$val ( + department_id_in + ); + emp_job_lookup_out := + te_job.i_job_function$val ( + job_id_in + ); + emp_mgr_lookup_out := + te_employee.i_employee_name$val ( + manager_id_in + ); + EXCEPTION + WHEN OTHERS + THEN + IF record_error + THEN + RAISE; + END IF; + RAISE; + END lookup_fkydescs; + + --// Generate the next primary key: single column PKYs only --// + FUNCTION nextpky RETURN EMPLOYEE.employee_id%TYPE + IS + retval EMPLOYEE.employee_id%TYPE; + BEGIN + SELECT EMPLOYEE_ID_SEQ.NEXTVAL INTO retval FROM dual; + RETURN retval; + END; + +--// Check Constraint Validation --// + + --// Check Constraint: DEPARTMENT_ID > 0 AND (salary > 0 OR salary IS NULL) --// + FUNCTION employee$complex$chk ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE, + salary_in IN EMPLOYEE.SALARY%TYPE + ) RETURN BOOLEAN + IS + BEGIN + RETURN (DEPARTMENT_ID_in > 0 AND (SALARY_in > 0 OR SALARY_in IS NULL)); + END employee$complex$chk; + + --// Check Constraint: DEPARTMENT_ID IS NOT NULL --// + FUNCTION notnull_department_id$chk ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE + ) RETURN BOOLEAN + IS + BEGIN + RETURN (DEPARTMENT_ID_in IS NOT NULL); + END notnull_department_id$chk; + + --// Check Constraint: EMPLOYEE_ID IS NOT NULL --// + FUNCTION notnull_employee_id$chk ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE + ) RETURN BOOLEAN + IS + BEGIN + RETURN (EMPLOYEE_ID_in IS NOT NULL); + END notnull_employee_id$chk; + + --// Check Constraint: "HIRE_DATE" IS NOT NULL --// + FUNCTION sys_c001373$chk ( + hire_date_in IN EMPLOYEE.HIRE_DATE%TYPE + ) RETURN BOOLEAN + IS + BEGIN + RETURN (HIRE_DATE_in IS NOT NULL); + END sys_c001373$chk; + + --// Check Constraint: "CHANGED_BY" IS NOT NULL --// + FUNCTION sys_c001376$chk ( + changed_by_in IN EMPLOYEE.CHANGED_BY%TYPE + ) RETURN BOOLEAN + IS + BEGIN + RETURN (CHANGED_BY_in IS NOT NULL); + END sys_c001376$chk; + + --// Check Constraint: "CHANGED_ON" IS NOT NULL --// + FUNCTION sys_c001377$chk ( + changed_on_in IN EMPLOYEE.CHANGED_ON%TYPE + ) RETURN BOOLEAN + IS + BEGIN + RETURN (CHANGED_ON_in IS NOT NULL); + END sys_c001377$chk; + + PROCEDURE validate ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + hire_date_in IN EMPLOYEE.HIRE_DATE%TYPE, + salary_in IN EMPLOYEE.SALARY%TYPE, + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE, + changed_by_in IN EMPLOYEE.CHANGED_BY%TYPE, + changed_on_in IN EMPLOYEE.CHANGED_ON%TYPE, + record_error IN BOOLEAN := TRUE + ) + IS + BEGIN + IF NOT employee$complex$chk ( + department_id_in, + salary_in + ) + THEN + --//** General mechanism! //-- + RAISE_APPLICATION_ERROR (-20000, 'ORA-2290: CHECK CONSTRAINT (employee$complex) FAILED!'); + END IF; + IF NOT notnull_department_id$chk ( + department_id_in + ) + THEN + RAISE_APPLICATION_ERROR (-20000, 'Value of DEPARTMENT_ID cannot be NULL'); + END IF; + IF NOT notnull_employee_id$chk ( + employee_id_in + ) + THEN + RAISE_APPLICATION_ERROR (-20000, 'Value of EMPLOYEE_ID cannot be NULL'); + END IF; + IF NOT sys_c001373$chk ( + hire_date_in + ) + THEN + --//** General mechanism! //-- + RAISE_APPLICATION_ERROR (-20000, 'ORA-2290: CHECK CONSTRAINT (sys_c001373) FAILED!'); + END IF; + IF NOT sys_c001376$chk ( + changed_by_in + ) + THEN + --//** General mechanism! //-- + RAISE_APPLICATION_ERROR (-20000, 'ORA-2290: CHECK CONSTRAINT (sys_c001376) FAILED!'); + END IF; + IF NOT sys_c001377$chk ( + changed_on_in + ) + THEN + --//** General mechanism! //-- + RAISE_APPLICATION_ERROR (-20000, 'ORA-2290: CHECK CONSTRAINT (sys_c001377) FAILED!'); + END IF; + EXCEPTION + WHEN OTHERS + THEN + IF record_error + THEN + RAISE; + END IF; + RAISE; + END validate; + + PROCEDURE validate ( + rec_in IN allcols_rt, + record_error IN BOOLEAN := TRUE + ) + IS + BEGIN + validate ( + rec_in.employee_id, + rec_in.hire_date, + rec_in.salary, + rec_in.department_id, + rec_in.changed_by, + rec_in.changed_on, + record_error + ); + END validate; +--// Update Processing --// + + PROCEDURE reset$frc IS + BEGIN + frcflg := emptyfrc; + END reset$frc; + + FUNCTION last_name$frc (last_name_in IN EMPLOYEE.LAST_NAME%TYPE DEFAULT NULL) + RETURN EMPLOYEE.LAST_NAME%TYPE + IS + BEGIN + frcflg.last_name := c_set; + RETURN last_name_in; + END last_name$frc; + + FUNCTION first_name$frc (first_name_in IN EMPLOYEE.FIRST_NAME%TYPE DEFAULT NULL) + RETURN EMPLOYEE.FIRST_NAME%TYPE + IS + BEGIN + frcflg.first_name := c_set; + RETURN first_name_in; + END first_name$frc; + + FUNCTION middle_initial$frc (middle_initial_in IN EMPLOYEE.MIDDLE_INITIAL%TYPE DEFAULT NULL) + RETURN EMPLOYEE.MIDDLE_INITIAL%TYPE + IS + BEGIN + frcflg.middle_initial := c_set; + RETURN middle_initial_in; + END middle_initial$frc; + + FUNCTION job_id$frc (job_id_in IN EMPLOYEE.JOB_ID%TYPE DEFAULT NULL) + RETURN EMPLOYEE.JOB_ID%TYPE + IS + BEGIN + frcflg.job_id := c_set; + RETURN job_id_in; + END job_id$frc; + + FUNCTION manager_id$frc (manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE DEFAULT NULL) + RETURN EMPLOYEE.MANAGER_ID%TYPE + IS + BEGIN + frcflg.manager_id := c_set; + RETURN manager_id_in; + END manager_id$frc; + + FUNCTION hire_date$frc (hire_date_in IN EMPLOYEE.HIRE_DATE%TYPE DEFAULT NULL) + RETURN EMPLOYEE.HIRE_DATE%TYPE + IS + BEGIN + frcflg.hire_date := c_set; + RETURN hire_date_in; + END hire_date$frc; + + FUNCTION salary$frc (salary_in IN EMPLOYEE.SALARY%TYPE DEFAULT NULL) + RETURN EMPLOYEE.SALARY%TYPE + IS + BEGIN + frcflg.salary := c_set; + RETURN salary_in; + END salary$frc; + + FUNCTION commission$frc (commission_in IN EMPLOYEE.COMMISSION%TYPE DEFAULT NULL) + RETURN EMPLOYEE.COMMISSION%TYPE + IS + BEGIN + frcflg.commission := c_set; + RETURN commission_in; + END commission$frc; + + FUNCTION department_id$frc (department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE DEFAULT NULL) + RETURN EMPLOYEE.DEPARTMENT_ID%TYPE + IS + BEGIN + frcflg.department_id := c_set; + RETURN department_id_in; + END department_id$frc; + + FUNCTION changed_by$frc (changed_by_in IN EMPLOYEE.CHANGED_BY%TYPE DEFAULT NULL) + RETURN EMPLOYEE.CHANGED_BY%TYPE + IS + BEGIN + frcflg.changed_by := c_set; + RETURN changed_by_in; + END changed_by$frc; + + FUNCTION changed_on$frc (changed_on_in IN EMPLOYEE.CHANGED_ON%TYPE DEFAULT NULL) + RETURN EMPLOYEE.CHANGED_ON%TYPE + IS + BEGIN + frcflg.changed_on := c_set; + RETURN changed_on_in; + END changed_on$frc; + + PROCEDURE upd ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + last_name_in IN EMPLOYEE.LAST_NAME%TYPE DEFAULT NULL, + first_name_in IN EMPLOYEE.FIRST_NAME%TYPE DEFAULT NULL, + middle_initial_in IN EMPLOYEE.MIDDLE_INITIAL%TYPE DEFAULT NULL, + job_id_in IN EMPLOYEE.JOB_ID%TYPE DEFAULT NULL, + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE DEFAULT NULL, + hire_date_in IN EMPLOYEE.HIRE_DATE%TYPE DEFAULT NULL, + salary_in IN EMPLOYEE.SALARY%TYPE DEFAULT NULL, + commission_in IN EMPLOYEE.COMMISSION%TYPE DEFAULT NULL, + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE DEFAULT NULL, + changed_by_in IN EMPLOYEE.CHANGED_BY%TYPE DEFAULT NULL, + changed_on_in IN EMPLOYEE.CHANGED_ON%TYPE DEFAULT NULL, + rowcount_out OUT INTEGER, + reset_in IN BOOLEAN DEFAULT TRUE + ) + IS + BEGIN + UPDATE EMPLOYEE SET + LAST_NAME = DECODE (frcflg.last_name, c_set, UPPER(last_name_in), + NVL (UPPER(last_name_in), LAST_NAME)), + FIRST_NAME = DECODE (frcflg.first_name, c_set, UPPER(first_name_in), + NVL (UPPER(first_name_in), FIRST_NAME)), + MIDDLE_INITIAL = DECODE (frcflg.middle_initial, c_set, UPPER(middle_initial_in), + NVL (UPPER(middle_initial_in), MIDDLE_INITIAL)), + JOB_ID = DECODE (frcflg.job_id, c_set, job_id_in, + NVL (job_id_in, JOB_ID)), + MANAGER_ID = DECODE (frcflg.manager_id, c_set, manager_id_in, + NVL (manager_id_in, MANAGER_ID)), + HIRE_DATE = DECODE (frcflg.hire_date, c_set, TRUNC(hire_date_in), + NVL (TRUNC(hire_date_in), HIRE_DATE)), + SALARY = DECODE (frcflg.salary, c_set, salary_in, + NVL (salary_in, SALARY)), + COMMISSION = DECODE (frcflg.commission, c_set, commission_in, + NVL (commission_in, COMMISSION)), + DEPARTMENT_ID = DECODE (frcflg.department_id, c_set, department_id_in, + NVL (department_id_in, DEPARTMENT_ID)), + CHANGED_BY = DECODE (frcflg.changed_by, c_set, USER, + NVL (USER, CHANGED_BY)), + CHANGED_ON = DECODE (frcflg.changed_on, c_set, SYSDATE, + NVL (SYSDATE, CHANGED_ON)) + WHERE + EMPLOYEE_ID = employee_id_in + ; + rowcount_out := SQL%ROWCOUNT; + IF reset_in THEN reset$frc; END IF; + EXCEPTION + WHEN OTHERS + THEN + RAISE; + END upd; + + --// Record-based Update --// + PROCEDURE upd ( + rec_in IN allcols_rt, + rowcount_out OUT INTEGER, + reset_in IN BOOLEAN DEFAULT TRUE) + IS + BEGIN + upd ( + rec_in.employee_id, + rec_in.last_name, + rec_in.first_name, + rec_in.middle_initial, + rec_in.job_id, + rec_in.manager_id, + rec_in.hire_date, + rec_in.salary, + rec_in.commission, + rec_in.department_id, + rec_in.changed_by, + rec_in.changed_on, + rowcount_out, + reset_in); + END upd; + + --// Update procedure for HIRE_DATE. --// + PROCEDURE upd$hire_date ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + hire_date_in IN EMPLOYEE.HIRE_DATE%TYPE, + rowcount_out OUT INTEGER + ) + IS + BEGIN + UPDATE EMPLOYEE SET HIRE_DATE = TRUNC(hire_date_in) + WHERE + EMPLOYEE_ID = employee_id_in + ; + rowcount_out := SQL%ROWCOUNT; + EXCEPTION + WHEN OTHERS + THEN + RAISE; + END upd$hire_date; + + --// Update procedure for HIRE_DATE using records. --// + PROCEDURE upd$hire_date ( + rec_in IN pky_rt, + hire_date_in IN EMPLOYEE.HIRE_DATE%TYPE, + rowcount_out OUT INTEGER + ) + IS + BEGIN + upd$hire_date ( + rec_in.employee_id, + hire_date_in, + rowcount_out + ); + END upd$hire_date; + + --// Update procedure for SALARY. --// + PROCEDURE upd$salary ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + salary_in IN EMPLOYEE.SALARY%TYPE, + rowcount_out OUT INTEGER + ) + IS + BEGIN + UPDATE EMPLOYEE SET SALARY = salary_in + WHERE + EMPLOYEE_ID = employee_id_in + ; + rowcount_out := SQL%ROWCOUNT; + EXCEPTION + WHEN OTHERS + THEN + RAISE; + END upd$salary; + + --// Update procedure for SALARY using records. --// + PROCEDURE upd$salary ( + rec_in IN pky_rt, + salary_in IN EMPLOYEE.SALARY%TYPE, + rowcount_out OUT INTEGER + ) + IS + BEGIN + upd$salary ( + rec_in.employee_id, + salary_in, + rowcount_out + ); + END upd$salary; + +--// Insert Processing --// + + --// Initialize record with default values. --// + FUNCTION initrec (allnull IN BOOLEAN := FALSE) RETURN allcols_rt + IS + retval allcols_rt; + BEGIN + IF allnull THEN NULL; /* Default values are NULL already. */ + ELSE + retval.employee_id := NULL; + retval.last_name := NULL; + retval.first_name := NULL; + retval.middle_initial := NULL; + retval.job_id := NULL; + retval.manager_id := NULL; + retval.hire_date := SYSDATE; + retval.salary := NULL; + retval.commission := NULL; + retval.department_id := NULL; + retval.changed_by := USER; + retval.changed_on := SYSDATE; + END IF; + RETURN retval; + END; + + --// Initialize record with default values. --// + PROCEDURE initrec ( + rec_inout IN OUT allcols_rt, + allnull IN BOOLEAN := FALSE) + IS + BEGIN + rec_inout := initrec; + END; + + PROCEDURE ins$ins ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + last_name_in IN EMPLOYEE.LAST_NAME%TYPE DEFAULT NULL, + first_name_in IN EMPLOYEE.FIRST_NAME%TYPE DEFAULT NULL, + middle_initial_in IN EMPLOYEE.MIDDLE_INITIAL%TYPE DEFAULT NULL, + job_id_in IN EMPLOYEE.JOB_ID%TYPE DEFAULT NULL, + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE DEFAULT NULL, + hire_date_in IN EMPLOYEE.HIRE_DATE%TYPE DEFAULT SYSDATE, + salary_in IN EMPLOYEE.SALARY%TYPE DEFAULT NULL, + commission_in IN EMPLOYEE.COMMISSION%TYPE DEFAULT NULL, + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE DEFAULT NULL, + changed_by_in IN EMPLOYEE.CHANGED_BY%TYPE DEFAULT USER, + changed_on_in IN EMPLOYEE.CHANGED_ON%TYPE DEFAULT SYSDATE, + upd_on_dup IN BOOLEAN := FALSE + ) + IS + BEGIN + validate ( + employee_id_in, + TRUNC(hire_date_in), + salary_in, + department_id_in, + USER, + SYSDATE, + TRUE + ); + INSERT INTO EMPLOYEE ( + EMPLOYEE_ID + ,LAST_NAME + ,FIRST_NAME + ,MIDDLE_INITIAL + ,JOB_ID + ,MANAGER_ID + ,HIRE_DATE + ,SALARY + ,COMMISSION + ,DEPARTMENT_ID + ,CHANGED_BY + ,CHANGED_ON + ) + VALUES ( + employee_id_in + ,UPPER(last_name_in) + ,UPPER(first_name_in) + ,UPPER(middle_initial_in) + ,job_id_in + ,manager_id_in + ,TRUNC(hire_date_in) + ,salary_in + ,commission_in + ,department_id_in + ,USER + ,SYSDATE + ); + EXCEPTION + WHEN DUP_VAL_ON_INDEX + THEN + IF NOT NVL (upd_on_dup, FALSE) + THEN + RAISE; + ELSE + DECLARE + v_errm VARCHAR2(2000) := SQLERRM; + v_rowcount INTEGER; + dotloc INTEGER; + leftloc INTEGER; + c_owner ALL_CONSTRAINTS.OWNER%TYPE; + c_name ALL_CONSTRAINTS.CONSTRAINT_NAME%TYPE; + BEGIN + dotloc := INSTR (v_errm,'.'); + leftloc := INSTR (v_errm,'('); + c_owner :=SUBSTR (v_errm, leftloc+1, dotloc-leftloc-1); + c_name := SUBSTR (v_errm, dotloc+1, INSTR (v_errm,')')-dotloc-1); + + --// Duplicate based on primary key //-- + IF 'EMP_PK' = c_name AND 'SCOTT' = c_owner + THEN + upd ( + employee_id_in, + last_name_in, + first_name_in, + middle_initial_in, + job_id_in, + manager_id_in, + hire_date_in, + salary_in, + commission_in, + department_id_in, + changed_by_in, + changed_on_in, + v_rowcount, + FALSE + ); + ELSE + --// Unique index violation. Cannot recover... //-- + RAISE; + END IF; + END; + END IF; + WHEN OTHERS + THEN + RAISE; + END ins$ins; + + --// Insert 1: with individual fields and return primary key //-- + PROCEDURE ins ( + last_name_in IN EMPLOYEE.LAST_NAME%TYPE DEFAULT NULL, + first_name_in IN EMPLOYEE.FIRST_NAME%TYPE DEFAULT NULL, + middle_initial_in IN EMPLOYEE.MIDDLE_INITIAL%TYPE DEFAULT NULL, + job_id_in IN EMPLOYEE.JOB_ID%TYPE DEFAULT NULL, + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE DEFAULT NULL, + hire_date_in IN EMPLOYEE.HIRE_DATE%TYPE DEFAULT SYSDATE, + salary_in IN EMPLOYEE.SALARY%TYPE DEFAULT NULL, + commission_in IN EMPLOYEE.COMMISSION%TYPE DEFAULT NULL, + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE DEFAULT NULL, + changed_by_in IN EMPLOYEE.CHANGED_BY%TYPE DEFAULT USER, + changed_on_in IN EMPLOYEE.CHANGED_ON%TYPE DEFAULT SYSDATE, + employee_id_out IN OUT EMPLOYEE.EMPLOYEE_ID%TYPE, + upd_on_dup IN BOOLEAN := FALSE + ) + IS + v_pky INTEGER := nextpky; + BEGIN + ins$ins ( + v_pky, + last_name_in, + first_name_in, + middle_initial_in, + job_id_in, + manager_id_in, + hire_date_in, + salary_in, + commission_in, + department_id_in, + changed_by_in, + changed_on_in, + upd_on_dup + ); + employee_id_out := v_pky; + END; + + --// Insert 2: with record, returning primary key. //-- + PROCEDURE ins ( + rec_in IN allcols_rt, + employee_id_out IN OUT EMPLOYEE.EMPLOYEE_ID%TYPE, + upd_on_dup IN BOOLEAN := FALSE + ) + IS + v_pky INTEGER := nextpky; + BEGIN + ins$ins ( + v_pky, + rec_in.last_name, + rec_in.first_name, + rec_in.middle_initial, + rec_in.job_id, + rec_in.manager_id, + rec_in.hire_date, + rec_in.salary, + rec_in.commission, + rec_in.department_id, + rec_in.changed_by, + rec_in.changed_on, + upd_on_dup + ); + employee_id_out := v_pky; + END; + +--// Delete Processing --// + + PROCEDURE del ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + rowcount_out OUT INTEGER) + IS + BEGIN + DELETE FROM EMPLOYEE + WHERE + EMPLOYEE_ID = employee_id_in + ; + rowcount_out := SQL%ROWCOUNT; + IF SQL%ROWCOUNT > 0 + THEN + loadtab.DELETE (employee_id_in); + END IF; + EXCEPTION + WHEN OTHERS + THEN + RAISE; + END del; + + --// Record-based delete --// + PROCEDURE del + (rec_in IN pky_rt, + rowcount_out OUT INTEGER) + IS + BEGIN + del ( + rec_in.employee_id, + rowcount_out); + END del; + + PROCEDURE del (rec_in IN allcols_rt, + rowcount_out OUT INTEGER) + IS + BEGIN + del ( + rec_in.employee_id, + rowcount_out); + END del; + + --// Delete all records for foreign key EMP_DEPT_LOOKUP. //-- + PROCEDURE delby_emp_dept_lookup ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE, + rowcount_out OUT INTEGER + ) + IS + BEGIN + DELETE FROM EMPLOYEE + WHERE + DEPARTMENT_ID = delby_emp_dept_lookup.department_id_in + ; + rowcount_out := SQL%ROWCOUNT; + EXCEPTION + WHEN OTHERS + THEN + RAISE; + END delby_emp_dept_lookup; + + --// Delete all records for foreign key EMP_JOB_LOOKUP. //-- + PROCEDURE delby_emp_job_lookup ( + job_id_in IN EMPLOYEE.JOB_ID%TYPE, + rowcount_out OUT INTEGER + ) + IS + BEGIN + DELETE FROM EMPLOYEE + WHERE + JOB_ID = delby_emp_job_lookup.job_id_in + ; + rowcount_out := SQL%ROWCOUNT; + EXCEPTION + WHEN OTHERS + THEN + RAISE; + END delby_emp_job_lookup; + + --// Delete all records for foreign key EMP_MGR_LOOKUP. //-- + PROCEDURE delby_emp_mgr_lookup ( + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE, + rowcount_out OUT INTEGER + ) + IS + BEGIN + DELETE FROM EMPLOYEE + WHERE + MANAGER_ID = delby_emp_mgr_lookup.manager_id_in + ; + rowcount_out := SQL%ROWCOUNT; + EXCEPTION + WHEN OTHERS + THEN + RAISE; + END delby_emp_mgr_lookup; + + + --// Program called by database initialization script to pin the package. //-- + PROCEDURE pinme + IS + BEGIN + --// Doesn't do anything except cause the package to be loaded. //-- + NULL; + END; + + + PROCEDURE load_to_memory + IS + BEGIN + loadtab.DELETE; + FOR rec IN ( + SELECT + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON + FROM EMPLOYEE + ) + LOOP + loadtab (rec.EMPLOYEE_ID) := rec; + END LOOP; + END; + + PROCEDURE showload ( + start_inout IN INTEGER := NULL, + end_inout IN INTEGER := NULL + ) + IS + v_row PLS_INTEGER := loadtab.FIRST; + v_last PLS_INTEGER := loadtab.LAST; + BEGIN + IF v_row IS NULL + THEN + DBMS_OUTPUT.PUT_LINE ('In-memory table for EMPLOYEE is empty!'); + ELSE + IF start_inout > v_row + THEN + v_row := loadtab.NEXT (start_inout-1); + END IF; + IF end_inout < v_last + THEN + v_last := loadtab.PRIOR (end_inout+1); + END IF; + LOOP + EXIT WHEN v_row > v_last OR v_row IS NULL; + DBMS_OUTPUT.PUT_LINE ('PKY Value/Row: ' || loadtab(v_row).EMPLOYEE_ID); + v_row := loadtab.NEXT (v_row); + END LOOP; + END IF; + END; +--// Initialization section for the package. --// +BEGIN + NULL; -- Placeholder. + load_to_memory; +END te_employee; +/ diff --git a/examples/te_employee.pks b/examples/te_employee.pks new file mode 100644 index 000000000..8ebcac964 --- /dev/null +++ b/examples/te_employee.pks @@ -0,0 +1,691 @@ +CREATE OR REPLACE PACKAGE te_employee +--//----------------------------------------------------------------------- +--// ** PL/Generator Table Encapsulator for "employee" +--//----------------------------------------------------------------------- +--// (c) COPYRIGHT Personnel Policies, Inc. 1999. +--// All rights reserved. +--// +--// No part of this copyrighted work may be reproduced, modified, +--// or distributed in any form or by any means without the prior +--// written permission of Personnel Policies, Inc.. +--//----------------------------------------------------------------------- +--// This software was generated by RevealNet's PL/Generator (TM). +--// +--// For more information, visit www.revealnet.com or call 1.800.REVEAL4 +--//----------------------------------------------------------------------- +--// Stored In: te_employee.pks +--// Created On: September 05, 2000 20:14:04 +--// Created By: SCOTT +--// PL/Generator Version: PRO-2000.1.1 +--//----------------------------------------------------------------------- +IS +--// Data Structures //-- + TYPE pky_rt IS RECORD ( + employee_id EMPLOYEE.EMPLOYEE_ID%TYPE + ); + + --// Modified version of %ROWTYPE for table with subset of columns //-- + TYPE allcols_rt IS RECORD ( + employee_id EMPLOYEE.EMPLOYEE_ID%TYPE, + last_name EMPLOYEE.LAST_NAME%TYPE, + first_name EMPLOYEE.FIRST_NAME%TYPE, + middle_initial EMPLOYEE.MIDDLE_INITIAL%TYPE, + job_id EMPLOYEE.JOB_ID%TYPE, + manager_id EMPLOYEE.MANAGER_ID%TYPE, + hire_date EMPLOYEE.HIRE_DATE%TYPE, + salary EMPLOYEE.SALARY%TYPE, + commission EMPLOYEE.COMMISSION%TYPE, + department_id EMPLOYEE.DEPARTMENT_ID%TYPE, + changed_by EMPLOYEE.CHANGED_BY%TYPE, + changed_on EMPLOYEE.CHANGED_ON%TYPE + ); + + TYPE cv_t IS REF CURSOR; + + TYPE i_employee_name_rt IS RECORD ( + last_name EMPLOYEE.LAST_NAME%TYPE, + first_name EMPLOYEE.FIRST_NAME%TYPE, + middle_initial EMPLOYEE.MIDDLE_INITIAL%TYPE + ); + CURSOR totsal_cur + IS + SELECT department_id, SUM(salary) total_salary + FROM employee + GROUP BY department_id; + + +--// Cursors //-- + + CURSOR compbypky_cur + IS + SELECT + employee_id, salary, commission + FROM EMPLOYEE + ORDER BY + EMPLOYEE_ID + ; + + CURSOR compforpky_cur ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE + ) + IS + SELECT + employee_id, salary, commission + FROM EMPLOYEE + WHERE + EMPLOYEE_ID = compforpky_cur.employee_id_in + ; + + --// Specified columns, all rows for this foreign key. //-- + CURSOR emp_dept_lookup_comp_cur ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE + ) + IS + SELECT + employee_id, salary, commission + FROM EMPLOYEE + WHERE + DEPARTMENT_ID = emp_dept_lookup_comp_cur.department_id_in + ; + + --// Specified columns, all rows for this foreign key. //-- + CURSOR emp_job_lookup_comp_cur ( + job_id_in IN EMPLOYEE.JOB_ID%TYPE + ) + IS + SELECT + employee_id, salary, commission + FROM EMPLOYEE + WHERE + JOB_ID = emp_job_lookup_comp_cur.job_id_in + ; + + --// Specified columns, all rows for this foreign key. //-- + CURSOR emp_mgr_lookup_comp_cur ( + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE + ) + IS + SELECT + employee_id, salary, commission + FROM EMPLOYEE + WHERE + MANAGER_ID = emp_mgr_lookup_comp_cur.manager_id_in + ; + + CURSOR namebypky_cur + IS + SELECT + last_name || ', ' || first_name full_name + FROM EMPLOYEE + ORDER BY + EMPLOYEE_ID + ; + + CURSOR nameforpky_cur ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE + ) + IS + SELECT + last_name || ', ' || first_name full_name + FROM EMPLOYEE + WHERE + EMPLOYEE_ID = nameforpky_cur.employee_id_in + ; + + --// Specified columns, all rows for this foreign key. //-- + CURSOR emp_dept_lookup_name_cur ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE + ) + IS + SELECT + last_name || ', ' || first_name full_name + FROM EMPLOYEE + WHERE + DEPARTMENT_ID = emp_dept_lookup_name_cur.department_id_in + ; + + --// Specified columns, all rows for this foreign key. //-- + CURSOR emp_job_lookup_name_cur ( + job_id_in IN EMPLOYEE.JOB_ID%TYPE + ) + IS + SELECT + last_name || ', ' || first_name full_name + FROM EMPLOYEE + WHERE + JOB_ID = emp_job_lookup_name_cur.job_id_in + ; + + --// Specified columns, all rows for this foreign key. //-- + CURSOR emp_mgr_lookup_name_cur ( + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE + ) + IS + SELECT + last_name || ', ' || first_name full_name + FROM EMPLOYEE + WHERE + MANAGER_ID = emp_mgr_lookup_name_cur.manager_id_in + ; + + CURSOR allbypky_cur + IS + SELECT + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON + FROM EMPLOYEE + ORDER BY + EMPLOYEE_ID + ; + + CURSOR allforpky_cur ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE + ) + IS + SELECT + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON + FROM EMPLOYEE + WHERE + EMPLOYEE_ID = allforpky_cur.employee_id_in + ; + + --// Specified columns, all rows for this foreign key. //-- + CURSOR emp_dept_lookup_all_cur ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE + ) + IS + SELECT + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON + FROM EMPLOYEE + WHERE + DEPARTMENT_ID = emp_dept_lookup_all_cur.department_id_in + ; + + --// Specified columns, all rows for this foreign key. //-- + CURSOR emp_job_lookup_all_cur ( + job_id_in IN EMPLOYEE.JOB_ID%TYPE + ) + IS + SELECT + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON + FROM EMPLOYEE + WHERE + JOB_ID = emp_job_lookup_all_cur.job_id_in + ; + + --// Specified columns, all rows for this foreign key. //-- + CURSOR emp_mgr_lookup_all_cur ( + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE + ) + IS + SELECT + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON + FROM EMPLOYEE + WHERE + MANAGER_ID = emp_mgr_lookup_all_cur.manager_id_in + ; + +--// Cursor management procedures //-- + + --// Open the cursors with some options. //-- + PROCEDURE open_compforpky_cur ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ); + + PROCEDURE open_compbypky_cur ( + close_if_open IN BOOLEAN := TRUE + ); + + PROCEDURE open_emp_dept_lookup_comp_cur ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ); + + PROCEDURE open_emp_job_lookup_comp_cur ( + job_id_in IN EMPLOYEE.JOB_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ); + + PROCEDURE open_emp_mgr_lookup_comp_cur ( + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ); + PROCEDURE open_nameforpky_cur ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ); + + PROCEDURE open_namebypky_cur ( + close_if_open IN BOOLEAN := TRUE + ); + + PROCEDURE open_emp_dept_lookup_name_cur ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ); + + PROCEDURE open_emp_job_lookup_name_cur ( + job_id_in IN EMPLOYEE.JOB_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ); + + PROCEDURE open_emp_mgr_lookup_name_cur ( + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ); + PROCEDURE open_allforpky_cur ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ); + + PROCEDURE open_allbypky_cur ( + close_if_open IN BOOLEAN := TRUE + ); + + PROCEDURE open_emp_dept_lookup_all_cur ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ); + + PROCEDURE open_emp_job_lookup_all_cur ( + job_id_in IN EMPLOYEE.JOB_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ); + + PROCEDURE open_emp_mgr_lookup_all_cur ( + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ); + + --// Close the cursors if they are open. //-- + PROCEDURE close_compforpky_cur; + PROCEDURE close_compbypky_cur; + PROCEDURE close_emp_dept_lookup_comp_cur; + PROCEDURE close_emp_job_lookup_comp_cur; + PROCEDURE close_emp_mgr_lookup_comp_cur; + PROCEDURE close_nameforpky_cur; + PROCEDURE close_namebypky_cur; + PROCEDURE close_emp_dept_lookup_name_cur; + PROCEDURE close_emp_job_lookup_name_cur; + PROCEDURE close_emp_mgr_lookup_name_cur; + PROCEDURE close_allforpky_cur; + PROCEDURE close_allbypky_cur; + PROCEDURE close_emp_dept_lookup_all_cur; + PROCEDURE close_emp_job_lookup_all_cur; + PROCEDURE close_emp_mgr_lookup_all_cur; + PROCEDURE closeall; + +--// Analyze presence of primary key: is it NOT NULL? //-- + + FUNCTION isnullpky ( + rec_in IN allcols_rt + ) + RETURN BOOLEAN; + + FUNCTION isnullpky ( + rec_in IN pky_rt + ) + RETURN BOOLEAN; + +--// Emulate aggregate-level record operations. //-- + + FUNCTION recseq (rec1 IN allcols_rt, rec2 IN allcols_rt) + RETURN BOOLEAN; + + FUNCTION recseq (rec1 IN pky_rt, rec2 IN pky_rt) + RETURN BOOLEAN; + +--// Fetch Data //-- + + --// Fetch one row of data for a primary key. //-- + FUNCTION onerow ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE + ) + RETURN allcols_rt; + + --// For each unique index ... //-- + + FUNCTION i_employee_name$pky ( + last_name_in IN EMPLOYEE.LAST_NAME%TYPE, + first_name_in IN EMPLOYEE.FIRST_NAME%TYPE, + middle_initial_in IN EMPLOYEE.MIDDLE_INITIAL%TYPE + ) + RETURN pky_rt + ; + + FUNCTION i_employee_name$val ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE + ) + RETURN i_employee_name_rt; + + FUNCTION i_employee_name$row ( + last_name_in IN EMPLOYEE.LAST_NAME%TYPE, + first_name_in IN EMPLOYEE.FIRST_NAME%TYPE, + middle_initial_in IN EMPLOYEE.MIDDLE_INITIAL%TYPE + ) + RETURN allcols_rt; + + --// For each update column ... //-- + + FUNCTION hire_date$val ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE + ) + RETURN EMPLOYEE.HIRE_DATE%TYPE; + --// For each update column ... //-- + + FUNCTION salary$val ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE + ) + RETURN EMPLOYEE.SALARY%TYPE; + + --// Count of all rows in table and for each foreign key. //-- + FUNCTION rowcount RETURN INTEGER; + FUNCTION pkyrowcount ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE + ) + RETURN INTEGER; + FUNCTION emp_dept_lookuprowcount ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE + ) + RETURN INTEGER; + FUNCTION emp_job_lookuprowcount ( + job_id_in IN EMPLOYEE.JOB_ID%TYPE + ) + RETURN INTEGER; + FUNCTION emp_mgr_lookuprowcount ( + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE + ) + RETURN INTEGER; + + PROCEDURE lookup_fkydescs ( + --// Foreign key columns for emp_dept_lookup //-- + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE, + emp_dept_lookup_out OUT te_department.i_department_name_rt, + --// Foreign key columns for emp_job_lookup //-- + job_id_in IN EMPLOYEE.JOB_ID%TYPE, + emp_job_lookup_out OUT te_job.i_job_function_rt, + --// Foreign key columns for emp_mgr_lookup //-- + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE, + emp_mgr_lookup_out OUT te_employee.i_employee_name_rt, + record_error BOOLEAN := TRUE + ); +--// Check Constraint Validation //-- + + --// Check Constraint: DEPARTMENT_ID > 0 AND (salary > 0 OR salary IS NULL) //-- + FUNCTION employee$complex$chk ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE, + salary_in IN EMPLOYEE.SALARY%TYPE + ) RETURN BOOLEAN; + + --// Check Constraint: DEPARTMENT_ID IS NOT NULL //-- + FUNCTION notnull_department_id$chk ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE + ) RETURN BOOLEAN; + + --// Check Constraint: EMPLOYEE_ID IS NOT NULL //-- + FUNCTION notnull_employee_id$chk ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE + ) RETURN BOOLEAN; + + --// Check Constraint: "HIRE_DATE" IS NOT NULL //-- + FUNCTION sys_c001373$chk ( + hire_date_in IN EMPLOYEE.HIRE_DATE%TYPE + ) RETURN BOOLEAN; + + --// Check Constraint: "CHANGED_BY" IS NOT NULL //-- + FUNCTION sys_c001376$chk ( + changed_by_in IN EMPLOYEE.CHANGED_BY%TYPE + ) RETURN BOOLEAN; + + --// Check Constraint: "CHANGED_ON" IS NOT NULL //-- + FUNCTION sys_c001377$chk ( + changed_on_in IN EMPLOYEE.CHANGED_ON%TYPE + ) RETURN BOOLEAN; + PROCEDURE validate ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + hire_date_in IN EMPLOYEE.HIRE_DATE%TYPE, + salary_in IN EMPLOYEE.SALARY%TYPE, + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE, + changed_by_in IN EMPLOYEE.CHANGED_BY%TYPE, + changed_on_in IN EMPLOYEE.CHANGED_ON%TYPE, + record_error IN BOOLEAN := TRUE + ); + + PROCEDURE validate ( + rec_in IN allcols_rt, + record_error IN BOOLEAN := TRUE + ); +--// Update Processing //-- + + PROCEDURE reset$frc; + + --// Force setting of NULL values //-- + + FUNCTION last_name$frc + (last_name_in IN EMPLOYEE.LAST_NAME%TYPE DEFAULT NULL) + RETURN EMPLOYEE.LAST_NAME%TYPE; + + FUNCTION first_name$frc + (first_name_in IN EMPLOYEE.FIRST_NAME%TYPE DEFAULT NULL) + RETURN EMPLOYEE.FIRST_NAME%TYPE; + + FUNCTION middle_initial$frc + (middle_initial_in IN EMPLOYEE.MIDDLE_INITIAL%TYPE DEFAULT NULL) + RETURN EMPLOYEE.MIDDLE_INITIAL%TYPE; + + FUNCTION job_id$frc + (job_id_in IN EMPLOYEE.JOB_ID%TYPE DEFAULT NULL) + RETURN EMPLOYEE.JOB_ID%TYPE; + + FUNCTION manager_id$frc + (manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE DEFAULT NULL) + RETURN EMPLOYEE.MANAGER_ID%TYPE; + + FUNCTION hire_date$frc + (hire_date_in IN EMPLOYEE.HIRE_DATE%TYPE DEFAULT NULL) + RETURN EMPLOYEE.HIRE_DATE%TYPE; + + FUNCTION salary$frc + (salary_in IN EMPLOYEE.SALARY%TYPE DEFAULT NULL) + RETURN EMPLOYEE.SALARY%TYPE; + + FUNCTION commission$frc + (commission_in IN EMPLOYEE.COMMISSION%TYPE DEFAULT NULL) + RETURN EMPLOYEE.COMMISSION%TYPE; + + FUNCTION department_id$frc + (department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE DEFAULT NULL) + RETURN EMPLOYEE.DEPARTMENT_ID%TYPE; + + FUNCTION changed_by$frc + (changed_by_in IN EMPLOYEE.CHANGED_BY%TYPE DEFAULT NULL) + RETURN EMPLOYEE.CHANGED_BY%TYPE; + + FUNCTION changed_on$frc + (changed_on_in IN EMPLOYEE.CHANGED_ON%TYPE DEFAULT NULL) + RETURN EMPLOYEE.CHANGED_ON%TYPE; + + PROCEDURE upd ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + last_name_in IN EMPLOYEE.LAST_NAME%TYPE DEFAULT NULL, + first_name_in IN EMPLOYEE.FIRST_NAME%TYPE DEFAULT NULL, + middle_initial_in IN EMPLOYEE.MIDDLE_INITIAL%TYPE DEFAULT NULL, + job_id_in IN EMPLOYEE.JOB_ID%TYPE DEFAULT NULL, + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE DEFAULT NULL, + hire_date_in IN EMPLOYEE.HIRE_DATE%TYPE DEFAULT NULL, + salary_in IN EMPLOYEE.SALARY%TYPE DEFAULT NULL, + commission_in IN EMPLOYEE.COMMISSION%TYPE DEFAULT NULL, + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE DEFAULT NULL, + changed_by_in IN EMPLOYEE.CHANGED_BY%TYPE DEFAULT NULL, + changed_on_in IN EMPLOYEE.CHANGED_ON%TYPE DEFAULT NULL, + rowcount_out OUT INTEGER, + reset_in IN BOOLEAN DEFAULT TRUE + ); + + --// Record-based Update //-- + + PROCEDURE upd (rec_in IN allcols_rt, + rowcount_out OUT INTEGER, + reset_in IN BOOLEAN DEFAULT TRUE); + + + --// Update procedure for HIRE_DATE. --// + PROCEDURE upd$hire_date ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + hire_date_in IN EMPLOYEE.HIRE_DATE%TYPE, + rowcount_out OUT INTEGER + ); + + PROCEDURE upd$hire_date ( + rec_in IN pky_rt, + hire_date_in IN EMPLOYEE.HIRE_DATE%TYPE, + rowcount_out OUT INTEGER + ); + + + --// Update procedure for SALARY. --// + PROCEDURE upd$salary ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + salary_in IN EMPLOYEE.SALARY%TYPE, + rowcount_out OUT INTEGER + ); + + PROCEDURE upd$salary ( + rec_in IN pky_rt, + salary_in IN EMPLOYEE.SALARY%TYPE, + rowcount_out OUT INTEGER + ); + +--// Insert Processing //-- + + --// Initialize record with default values. //-- + FUNCTION initrec (allnull IN BOOLEAN := FALSE) RETURN allcols_rt; + + --// Initialize record with default values. //-- + PROCEDURE initrec ( + rec_inout IN OUT allcols_rt, + allnull IN BOOLEAN := FALSE); + + + --// Generate next primary key: for single column PKs only. //-- + FUNCTION nextpky RETURN EMPLOYEE.employee_id%TYPE; + + PROCEDURE ins ( + last_name_in IN EMPLOYEE.LAST_NAME%TYPE DEFAULT NULL, + first_name_in IN EMPLOYEE.FIRST_NAME%TYPE DEFAULT NULL, + middle_initial_in IN EMPLOYEE.MIDDLE_INITIAL%TYPE DEFAULT NULL, + job_id_in IN EMPLOYEE.JOB_ID%TYPE DEFAULT NULL, + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE DEFAULT NULL, + hire_date_in IN EMPLOYEE.HIRE_DATE%TYPE DEFAULT SYSDATE, + salary_in IN EMPLOYEE.SALARY%TYPE DEFAULT NULL, + commission_in IN EMPLOYEE.COMMISSION%TYPE DEFAULT NULL, + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE DEFAULT NULL, + changed_by_in IN EMPLOYEE.CHANGED_BY%TYPE DEFAULT USER, + changed_on_in IN EMPLOYEE.CHANGED_ON%TYPE DEFAULT SYSDATE, + employee_id_out IN OUT EMPLOYEE.EMPLOYEE_ID%TYPE, + upd_on_dup IN BOOLEAN := FALSE + ); + + PROCEDURE ins (rec_in IN allcols_rt, + employee_id_out IN OUT EMPLOYEE.EMPLOYEE_ID%TYPE, + upd_on_dup IN BOOLEAN := FALSE + ); + +--// Delete Processing //-- + PROCEDURE del ( + employee_id_in IN EMPLOYEE.EMPLOYEE_ID%TYPE, + rowcount_out OUT INTEGER); + + --// Record-based delete //-- + PROCEDURE del (rec_in IN pky_rt, + rowcount_out OUT INTEGER); + + PROCEDURE del (rec_in IN allcols_rt, + rowcount_out OUT INTEGER); + + --// Delete all records for this EMP_DEPT_LOOKUP foreign key. //-- + PROCEDURE delby_emp_dept_lookup ( + department_id_in IN EMPLOYEE.DEPARTMENT_ID%TYPE, + rowcount_out OUT INTEGER + ); + + --// Delete all records for this EMP_JOB_LOOKUP foreign key. //-- + PROCEDURE delby_emp_job_lookup ( + job_id_in IN EMPLOYEE.JOB_ID%TYPE, + rowcount_out OUT INTEGER + ); + + --// Delete all records for this EMP_MGR_LOOKUP foreign key. //-- + PROCEDURE delby_emp_mgr_lookup ( + manager_id_in IN EMPLOYEE.MANAGER_ID%TYPE, + rowcount_out OUT INTEGER + ); + + --// Program called by database initialization script to pin the package. //-- + PROCEDURE pinme; + + --// Load and display index table of data - PK only. //-- + PROCEDURE load_to_memory; + + PROCEDURE showload ( + start_inout IN INTEGER := NULL, + end_inout IN INTEGER := NULL + ); + FUNCTION version RETURN VARCHAR2; +END te_employee; +/ diff --git a/examples/te_utpkg.gdr b/examples/te_utpkg.gdr new file mode 100644 index 000000000..a9976937a --- /dev/null +++ b/examples/te_utpkg.gdr @@ -0,0 +1,199 @@ +#===========================================================RevealNet GenX Driver========== +# Description: Create package to perform unit testing against base package with utPLSQL. +#========================================================================================== +# Category: Unit Test Package for Table Encapsulation package +#========================================================================================== +# Summary: Designed to be a DOUBLE PASS generation. Generate once against the +# package, then generate this output against the base table! +# +# WARNING: Generating duplicate of entire package! +# +#========================================================================================== +# Application area: Testing +#========================================================================================== +# Key words: PLSQL,PROG,ARG,UTPLSQL +#========================================================================================== +# Script Requirements/Dependencies +# Backend Version: PL/SQL 2.3 (Oracle 7.3) and above +# INCLUDEs: None +# EXECs: None +#========================================================================================== +# Generated Text Requirements/Dependencies +# Language and Version: PL/SQL 2.3 (Oracle 7.3) and above +# Operating System(s): Non-specific +#========================================================================================== +# Author: Steven Feuerstein, RevealNet: feuerstein@revealnet.com +#========================================================================================== +# Modification History +# +# When Who What +# ----------------------------------------------------------------------------------------- +# 05/2000 SEF Created +#========================================================================================== +[SETALIAS]allprogs[TO]N +[SETALIAS]utprefix[TO]ut_ +[SETALIAS]tabprefix[TO]{utprefix} +[SETALIAS]olprog[TO]\[progname][overload] +[SETALIAS]progtab[TO]\{tabprefix}{olprog} +[SETALIAS]oltestprog[TO]\{utprefix}{olprog} +[STOREIN]{utprefix}[objname].gdr +[ASIS] +[SET]objname[TO]#CHANGE THIS +[SETALIAS]tabprefix[TO]{utprefix} +[ENDASIS] +CREATE OR REPLACE PACKAGE [schema].{utprefix}[objname] AUTHID CURRENT_USER +-- SECOND PASS INSTRUCTIONS: +-- +-- Set the object name and generate this GDR to produce the test package. +-- After generation, save to pks and pkb files and put in the specific +-- code for the various tests. +IS + PROCEDURE {utprefix}setup; + + PROCEDURE {utprefix}teardown; + +[FOREACH]prog + [IF]{allprogs}[EQ]Y[OR][progname][LIKE]UPD%[OR][progname][LIKE]INS%[OR][progname][LIKE]DEL% + PROCEDURE ^{oltestprog}^; + [ENDIF] +[ENDFOREACH] + +END {utprefix}[objname]; +/ +CREATE OR REPLACE PACKAGE BODY [schema].{utprefix}[objname] AUTHID CURRENT_USER +IS + PROCEDURE {utprefix}setup + IS + BEGIN + -- Clean start + {utprefix}teardown; +[ASIS] + -- Generic copy of base table for testing + EXECUTE IMMEDIATE + 'CREATE TABLE {tabprefix}[objname] AS + SELECT * FROM [objname]'; + +[ENDASIS] + [FOREACH]prog + [IF]{allprogs}[EQ]Y[OR][progname][LIKE]UPD%[OR][progname][LIKE]INS%[OR][progname][LIKE]DEL% + -- Create copy of base table for this unit test. + EXECUTE IMMEDIATE + 'CREATE TABLE ^{progtab}^ AS +[ASIS] + SELECT * FROM [objname]'; +[ENDASIS] + + [ENDIF] + [ENDFOREACH] + END; + + PROCEDURE {utprefix}teardown + IS + BEGIN +[ASIS] + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE {tabprefix}[objname]'; + EXCEPTION WHEN OTHERS THEN NULL; + END; +[ENDASIS] + + [FOREACH]prog + [IF]{allprogs}[EQ]Y[OR][progname][LIKE]UPD%[OR][progname][LIKE]INS%[OR][progname][LIKE]DEL% + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE ^{progtab}^'; + EXCEPTION WHEN OTHERS THEN NULL; + END; + [ENDIF] + [ENDFOREACH] + END; +[FOREACH]prog + [IF]{allprogs}[EQ]Y[OR][progname][LIKE]UPD%[OR][progname][LIKE]INS%[OR][progname][LIKE]DEL% + + PROCEDURE {utprefix}{utprefix}[progname][overload] + IS +[IF][progname][LIKE]INS%[OR][progname][LIKE]UPD% +[ASIS] +[FOREACH]col + v_[colname] [objname].[colname]%TYPE; +[ENDFOREACH] +[ENDASIS] +[ENDIF] + fdbk PLS_INTEGER; + BEGIN + -- Perform [progname] operation(s) using + -- explicit actions to measURE {utprefix}against. + + EXECUTE IMMEDIATE ' + [IF][progname][LIKE]INS% + INSERT INTO ^{progtab}^ ( +[ASIS] +[FOREACH]col[between], + [colname] +[ENDFOREACH] + ) + VALUES ( +[FOREACH]col[between], + :[colname] +[ENDFOREACH] + )' + USING +[FOREACH]col[between], + v_[colname] +[ENDFOREACH] + ; +[ENDASIS] + [ELSIF][progname][LIKE]UPD% + UPDATE ^{progtab}^ SET +[ASIS] +[FOREACH]nonpkycol[between], + [colname] = :[colname] +[ENDFOREACH] + WHERE +[FOREACH]pkycol[between] AND + [colname] = [coldmlval] +[ENDFOREACH] + ' + USING +[FOREACH]col[between], + v_[colname] +[ENDFOREACH] +[ENDASIS] + ; + [ELSIF][progname][LIKE]DEL% + DELETE FROM ^{progtab}^ + WHERE +[ASIS] +[FOREACH]pkycol[between] AND + [colname] = [coldmlval] +[ENDFOREACH] +[ENDASIS] + '; + [ENDIF] + + -- Compare to program call: + [progname] ( + ,rowcount => fdbk + ); + + -- Test results + utAssert.eqtable ( + 'Successful [progname][overload]', +[ASIS] + '[objname]', +[ENDASIS] + '^{progtab}^'); + + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failure. + utAssert.this ( + '^{progtab}^ exception ' || SQLERRM, + SQLCODE = 0); + END; + [ENDIF] +[ENDFOREACH] + +END {utprefix}[objname]; +/ diff --git a/examples/temp.sql b/examples/temp.sql new file mode 100644 index 000000000..0a0bf5ff1 --- /dev/null +++ b/examples/temp.sql @@ -0,0 +1,53 @@ +CREATE OR REPLACE FUNCTION betwnStr ( + string_in IN VARCHAR2, + start_in IN INTEGER, + end_in IN INTEGER + ) + RETURN VARCHAR2 +IS +BEGIN + raise value_Error; + + RETURN ( + SUBSTR ( + string_in, + start_in, + end_in - start_in + 1 + ) + ); +END; +/ +CREATE OR REPLACE PACKAGE BODY ut_betwnstr +IS + PROCEDURE ut_setup + IS + BEGIN + NULL; + END; + + PROCEDURE ut_teardown + IS + BEGIN + NULL; + END; + + -- For each program to test... + PROCEDURE ut_BETWNSTR IS + BEGIN + utAssert.throws ( + 'NDF', + BETWNSTR( + STRING_IN => 'abcdefg' + , + START_IN => 3 + , + END_IN => 5 + ), + -6502 + ); + + + END ut_BETWNSTR; + +END ut_betwnstr; +/ diff --git a/examples/tequery_utpkg.gdr b/examples/tequery_utpkg.gdr new file mode 100644 index 000000000..761d06469 --- /dev/null +++ b/examples/tequery_utpkg.gdr @@ -0,0 +1,111 @@ +#===========================================================RevealNet GenX Driver========== +# Description: Create package to perform unit testing against base package with utPLSQL. +#========================================================================================== +# Category: Unit Test Package for Table Encapsulation package +#========================================================================================== +# Summary: Designed to be a DOUBLE PASS generation. Generate once against the +# package, then generate this output against the base table! +# +# WARNING: Generating duplicate of entire package! +# +#========================================================================================== +# Application area: Testing +#========================================================================================== +# Key words: PLSQL,PROG,ARG,UTPLSQL +#========================================================================================== +# Script Requirements/Dependencies +# Backend Version: PL/SQL 2.3 (Oracle 7.3) and above +# INCLUDEs: None +# EXECs: None +#========================================================================================== +# Generated Text Requirements/Dependencies +# Language and Version: PL/SQL 2.3 (Oracle 7.3) and above +# Operating System(s): Non-specific +#========================================================================================== +# Author: Steven Feuerstein, RevealNet: feuerstein@revealnet.com +#========================================================================================== +# Modification History +# +# When Who What +# ----------------------------------------------------------------------------------------- +# 05/2000 SEF Created +#========================================================================================== +[SETALIAS]utprefix[TO]ut# +[SETALIAS]tabprefix[TO]ut_ +[SETALIAS]olprog[TO]\[progname][overload] +[SETALIAS]progtab[TO]\{tabprefix}{olprog} +[SETALIAS]oltestprog[TO]\{utprefix}{olprog} +[STOREIN]{utprefix}[objname].gdr +[ASIS] +[SET]objname[TO]#CHANGE THIS +[SETALIAS]tabprefix[TO]ut_ +[ENDASIS] +CREATE OR REPLACE PACKAGE [schema].{utprefix}[objname] AUTHID CURRENT_USER +-- SECOND PASS INSTRUCTIONS: +-- +-- Set the object name and generate this GDR to produce the test package. +-- After generation, save to pks and pkb files and put in the specific +-- code for the various tests. +IS + [ASIS] + rec [objname]%ROWTYPE; +[ENDASIS] + + PROCEDURE {utprefix}setup; + + PROCEDURE {utprefix}teardown; + +[FOREACH]prog + [IF][progname][LIKE]%ROW%[OR][progname][LIKE]%$VAL[OR][progname][LIKE]$PKY + PROCEDURE ^{oltestprog}^; + [ENDIF] +[ENDFOREACH] + +END {utprefix}[objname]; +/ +CREATE OR REPLACE PACKAGE BODY [schema].{utprefix}[objname] AUTHID CURRENT_USER +IS + PROCEDURE setup + IS + BEGIN + -- Clean start + {utprefix}teardown; + END; + + PROCEDURE teardown + IS + BEGIN + NULL; + END; +[FOREACH]prog + [IF][progname][LIKE]%ROW%[OR][progname][LIKE]%$VAL[OR][progname][LIKE]$PKY + + PROCEDURE {utprefix}[progname][overload] + IS + BEGIN + -- Run baseline code. + + -- Compare to program call: + [progname] ( + ); + + -- Test results + utAssert.eqtable ( + 'Successful [progname][overload]', + [progname], + 'base query' + ); + + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failure. + utAssert.this ( + '[progname] exception ' || SQLERRM, + SQLCODE = 0); + END; + [ENDIF] +[ENDFOREACH] + +END {utprefix}[objname]; +/ diff --git a/examples/test_betwnstr.sql b/examples/test_betwnstr.sql new file mode 100644 index 000000000..5d60da691 --- /dev/null +++ b/examples/test_betwnstr.sql @@ -0,0 +1,3 @@ +begin + utplsql.test ('betwnstr'); +end; diff --git a/examples/test_te_employee.pkb b/examples/test_te_employee.pkb new file mode 100644 index 000000000..c62c857fc --- /dev/null +++ b/examples/test_te_employee.pkb @@ -0,0 +1,916 @@ +CREATE OR REPLACE PACKAGE BODY test_te_employee +IS + g_rowcount1 PLS_INTEGER; + g_rowcount2 PLS_INTEGER; + + FUNCTION recseq ( + rec1 IN te_employee.i_employee_name_rt, + rec2 IN te_employee.i_employee_name_rt + ) + RETURN BOOLEAN + IS + unequal_records EXCEPTION; + retval BOOLEAN; + BEGIN + retval := + rec1.last_name = rec2.last_name + OR ( + rec1.last_name IS NULL + AND rec2.last_name IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := + rec1.first_name = rec2.first_name + OR ( + rec1.first_name IS NULL + AND rec2.first_name IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := + rec1.middle_initial = rec2.middle_initial + OR ( + rec1.middle_initial IS NULL + AND rec2.middle_initial IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + RETURN TRUE; + EXCEPTION + WHEN unequal_records + THEN + RETURN FALSE; + END; + + PROCEDURE test_setup + IS + BEGIN + test_teardown; + EXECUTE IMMEDIATE 'CREATE TABLE test_employee AS + SELECT * FROM employee'; + EXECUTE IMMEDIATE 'CREATE TABLE test_DEL1 AS + SELECT * FROM employee'; + EXECUTE IMMEDIATE 'CREATE TABLE test_DELBY_EMP_DEPT_LOOKUP AS + SELECT * FROM employee'; + EXECUTE IMMEDIATE 'CREATE TABLE test_DELBY_EMP_JOB_LOOKUP AS + SELECT * FROM employee'; + EXECUTE IMMEDIATE 'CREATE TABLE test_DELBY_EMP_MGR_LOOKUP AS + SELECT * FROM employee'; + EXECUTE IMMEDIATE 'CREATE TABLE test_INS1 AS + SELECT * FROM employee'; + EXECUTE IMMEDIATE 'CREATE TABLE test_UPD1 AS + SELECT * FROM employee'; + EXECUTE IMMEDIATE 'CREATE TABLE test_UPD$HIRE_DATE1 AS + SELECT * FROM employee'; + EXECUTE IMMEDIATE 'CREATE TABLE test_UPD$SALARY1 AS + SELECT * FROM employee'; + END; + + PROCEDURE test_teardown + IS + BEGIN + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE test_employee'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE test_DEL1'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE test_DELBY_EMP_DEPT_LOOKUP'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE test_DELBY_EMP_JOB_LOOKUP'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE test_DELBY_EMP_MGR_LOOKUP'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE test_INS1'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE test_UPD1'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE test_UPD$HIRE_DATE1'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE test_UPD$SALARY1'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + END; + + PROCEDURE test_del1 + IS + fdbk PLS_INTEGER; + BEGIN + /* Delete that finds now rows. */ + + EXECUTE IMMEDIATE ' + DELETE FROM test_DEL1 + WHERE employee_id = -1 + '; + te_employee.del (-1, rowcount_out => fdbk); + -- Test results + utassert.eqtable ('Delete rows', 'EMPLOYEE', 'test_DEL1'); + /* Successful delete */ + + EXECUTE IMMEDIATE ' + DELETE FROM test_DEL1 + WHERE employee_id between 7800 and 7899 + '; + + FOR rec IN (SELECT * + FROM employee + WHERE employee_id BETWEEN 7800 AND 7899) + LOOP + te_employee.del ( + rec.employee_id, + rowcount_out => fdbk + ); + END LOOP; + + -- Test results + utassert.eqtable ('Delete rows', 'EMPLOYEE', 'test_DEL1'); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + utassert.this ( + 'DEL1 exception ' || SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE test_delby_emp_dept_lookup + IS + fdbk PLS_INTEGER; + BEGIN + /* Delete that finds now rows. */ + + EXECUTE IMMEDIATE ' + DELETE FROM test_DELBY_EMP_DEPT_LOOKUP + WHERE department_id = -1 + '; + te_employee.delby_emp_dept_lookup ( + -1, + rowcount_out => fdbk + ); + -- Test results + utassert.eqtable ( + 'Delete no rows via DELBY_EMP_DEPT_LOOKUP', + 'EMPLOYEE', + 'test_DELBY_EMP_DEPT_LOOKUP' + ); + /* Successful delete */ + + EXECUTE IMMEDIATE ' + DELETE FROM test_DELBY_EMP_DEPT_LOOKUP + WHERE department_id = 20 + '; + te_employee.delby_emp_dept_lookup ( + 20, + rowcount_out => fdbk + ); + -- Test results + utassert.eqtable ( + 'Successful DELBY_EMP_DEPT_LOOKUP', + 'EMPLOYEE', + 'test_DELBY_EMP_DEPT_LOOKUP' + ); + ROLLBACK; + END; + + PROCEDURE test_delby_emp_job_lookup + IS + fdbk PLS_INTEGER; + BEGIN + /* Delete that finds now rows. */ + + EXECUTE IMMEDIATE ' + DELETE FROM test_DELBY_EMP_JOB_LOOKUP + WHERE job_id = -1 + '; + te_employee.delby_emp_job_lookup ( + -1, + rowcount_out => fdbk + ); + -- Test results + utassert.eqtable ( + 'Delete no rows via DELBY_EMP_JOB_LOOKUP', + 'EMPLOYEE', + 'test_DELBY_EMP_JOB_LOOKUP' + ); + /* Successful delete */ + + EXECUTE IMMEDIATE ' + DELETE FROM test_DELBY_EMP_JOB_LOOKUP + WHERE job_id = 668 + '; + te_employee.delby_emp_job_lookup ( + 668, + rowcount_out => fdbk + ); + -- Test results + utassert.eqtable ( + 'Successful DELBY_EMP_JOB_LOOKUP', + 'EMPLOYEE', + 'test_DELBY_EMP_JOB_LOOKUP' + ); + ROLLBACK; + END; + + PROCEDURE test_delby_emp_mgr_lookup + IS + fdbk PLS_INTEGER; + BEGIN + /* Delete that finds now rows. */ + + EXECUTE IMMEDIATE ' + DELETE FROM test_DELBY_EMP_MGR_LOOKUP + WHERE manager_id = -1 + '; + te_employee.delby_emp_mgr_lookup ( + -1, + rowcount_out => fdbk + ); + -- Test results + utassert.eqtable ( + 'Delete no rows via DELBY_EMP_MGR_LOOKUP', + 'EMPLOYEE', + 'test_DELBY_EMP_MGR_LOOKUP' + ); + /* Successful delete */ + + EXECUTE IMMEDIATE ' + DELETE FROM test_DELBY_EMP_MGR_LOOKUP + WHERE manager_id = 7505 + '; + te_employee.delby_emp_mgr_lookup ( + 7505, + rowcount_out => fdbk + ); + -- Test results + utassert.eqtable ( + 'Successful DELBY_EMP_MGR_LOOKUP', + 'EMPLOYEE', + 'test_DELBY_EMP_MGR_LOOKUP' + ); + ROLLBACK; + END; + + PROCEDURE test_ins1 + IS + v_employee_id employee.employee_id%TYPE; + v_last_name employee.last_name%TYPE := 'GEORGE'; + v_first_name employee.first_name%TYPE := 'WASHINGTON'; + v_middle_initial employee.middle_initial%TYPE := 'M'; + v_job_id employee.job_id%TYPE := 688; + v_manager_id employee.manager_id%TYPE := 7505; + v_hire_date employee.hire_date%TYPE := SYSDATE; + v_salary employee.salary%TYPE := 1000; + v_commission employee.commission%TYPE := 3000; + v_department_id employee.department_id%TYPE := 30; + v_changed_by employee.changed_by%TYPE := USER; + v_changed_on employee.changed_on%TYPE := SYSDATE; + fdbk PLS_INTEGER; + BEGIN + EXECUTE IMMEDIATE ' + INSERT INTO test_INS1 ( + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON, + CREATED_BY, + CREATED_ON + ) + VALUES ( + employee_id_seq.NEXTVAL, + :LAST_NAME, + :FIRST_NAME, + :MIDDLE_INITIAL, + :JOB_ID, + :MANAGER_ID, + :HIRE_DATE, + :SALARY, + :COMMISSION, + :DEPARTMENT_ID, + :CHANGED_BY, + :CHANGED_ON, + USER, + SYSDATE + ) + ' + USING v_last_name, v_first_name, v_middle_initial, v_job_id, v_manager_id, v_hire_date, v_salary, v_commission, v_department_id, v_changed_by, v_changed_on; + SELECT employee_id_seq.nextval + INTO fdbk + FROM dual; + te_employee.ins ( + v_last_name, + v_first_name, + v_middle_initial, + v_job_id, + v_manager_id, + v_hire_date, + v_salary, + v_commission, + v_department_id, + v_changed_by, + v_changed_on, + fdbk + ); + + -- Test results (everything but ID) + utassert.eqquery ( + 'Insert One Row - check data', + 'SELECT + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON from employee where changed_on = ''' || + SYSDATE || + '''', + 'SELECT + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON from test_ins1 where changed_on = ''' || + SYSDATE || + '''' + ); + utassert.eqtabcount ( + 'Insert One Row - check count', + 'employee', + 'test_ins1' + ); + ROLLBACK; + END; + + PROCEDURE test_upd1 + IS + v_employee_id employee.employee_id%TYPE; + v_last_name employee.last_name%TYPE; + v_first_name employee.first_name%TYPE; + v_middle_initial employee.middle_initial%TYPE; + v_job_id employee.job_id%TYPE; + v_manager_id employee.manager_id%TYPE; + v_hire_date employee.hire_date%TYPE; + v_salary employee.salary%TYPE; + v_commission employee.commission%TYPE; + v_department_id employee.department_id%TYPE; + v_changed_by employee.changed_by%TYPE; + v_changed_on employee.changed_on%TYPE; + fdbk PLS_INTEGER; + BEGIN + /* Update 3 columns by ID */ + + EXECUTE IMMEDIATE ' + UPDATE test_UPD1 SET + FIRST_NAME = ''SILLY'', + HIRE_DATE = trunc (SYSDATE+100), + COMMISSION = 5000 + WHERE + EMPLOYEE_ID = 7600 + '; + te_employee.upd ( + 7600, + first_name_in => 'SILLY', + commission_in => 5000, + hire_date_in => TRUNC (SYSDATE + 100), + rowcount_out => fdbk + ); + -- Test results (audit fields are different so do a query) + utassert.eqquery ( + 'Update three columns', + 'select first_name, commission, hire_date from EMPLOYEE', + 'select first_name, commission, hire_date from test_upd1' + ); + ROLLBACK; + END; + + PROCEDURE test_upd$hire_date1 + IS + fdbk PLS_INTEGER; + BEGIN + /* Successful update by ID */ + + EXECUTE IMMEDIATE ' + UPDATE test_UPD$HIRE_DATE1 SET + hire_date = trunc (sysdate) + WHERE employee_id = 7698 + '; + te_employee.upd$hire_date ( + 7698, + TRUNC (SYSDATE), + rowcount_out => fdbk + ); + -- Test results + utassert.eqquery ( + 'Testing UPD$HIRE_DATE1', + 'select hire_date from EMPLOYEE', + 'select hire_date from test_UPD$HIRE_DATE1' + ); + ROLLBACK; + END; + + PROCEDURE test_upd$salary1 + IS + fdbk PLS_INTEGER; + BEGIN + /* Successful update by ID */ + + EXECUTE IMMEDIATE ' + UPDATE test_UPD$SALARY1 SET + salary = 5000 + WHERE employee_id = 7555 + '; + te_employee.upd$salary ( + 7555, + 5000, + rowcount_out => fdbk + ); + -- Test results + utassert.eqquery ( + 'Testing UPD$SALARY1', + 'select salary from EMPLOYEE', + 'select salary from test_UPD$SALARY1' + ); + ROLLBACK; + END; + + PROCEDURE test_emp_dept_lookuprowcount + IS + BEGIN + -- Run baseline code. + SELECT COUNT (*) + INTO g_rowcount1 + FROM employee + WHERE department_id = 30; + -- Compare to program call: + g_rowcount2 := + te_employee.emp_dept_lookuprowcount (30); + -- Test results + utassert.eq ( + 'Successful EMP_DEPT_LOOKUPROWCOUNT', + g_rowcount2, + g_rowcount1 + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE test_. + utassert.this ( + 'test_EMP_DEPT_LOOKUPROWCOUNT exception ' || + SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE test_emp_job_lookuprowcount + IS + BEGIN + -- Run baseline code. + SELECT COUNT (*) + INTO g_rowcount1 + FROM employee + WHERE job_id = 669; + -- Compare to program call: + g_rowcount2 := + te_employee.emp_job_lookuprowcount (669); + -- Test results + utassert.eq ( + 'Successful EMP_JOB_LOOKUPROWCOUNT', + g_rowcount2, + g_rowcount1 + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE test_. + utassert.this ( + 'test_EMP_JOB_LOOKUPROWCOUNT exception ' || + SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE test_emp_mgr_lookuprowcount + IS + BEGIN + -- Run baseline code. + SELECT COUNT (*) + INTO g_rowcount1 + FROM employee + WHERE manager_id = 7782; + -- Compare to program call: + g_rowcount2 := + te_employee.emp_mgr_lookuprowcount (7782); + -- Test results + utassert.eq ( + 'Successful EMP_MGR_LOOKUPROWCOUNT', + g_rowcount2, + g_rowcount1 + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE test_. + utassert.this ( + 'test_EMP_MGR_LOOKUPROWCOUNT exception ' || + SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE test_hire_date$val + IS + BEGIN + -- Test results + utassert.eqquery ( + 'Successful HIRE_DATE$VAL', + 'select te_employee.HIRE_DATE$VAL (employee_id) from employee', + 'select hire_Date from employee' + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE test_. + utassert.this ( + 'test_HIRE_DATE$VAL exception ' || SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE test_i_employee_name$row + IS + rec1 te_employee.allcols_rt; + rec2 te_employee.allcols_rt; + BEGIN + -- Unsuccessful test + BEGIN + SELECT + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON + INTO rec1 + FROM employee + WHERE last_name = 'LANCE' + AND first_name = 'GREG' + AND middle_initial = 'J'; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + NULL; + END; + + -- Run program + begin + rec2 := + te_employee.i_employee_name$row ('LANCE', 'GREG', 'J'); + EXCEPTION + WHEN NO_DATA_FOUND + THEN + NULL; + END; + + -- Test results + utassert.this ( + 'Unsuccessful I_EMPLOYEE_NAME$ROW', + te_employee.recseq (rec1, rec2) + ); + -- Successful test + SELECT + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON + INTO rec1 + FROM employee + WHERE last_name = 'LANCE' + AND first_name = 'GREGORY' + AND middle_initial = 'J'; + -- Run program + rec2 := + te_employee.i_employee_name$row ( + 'LANCE', + 'GREGORY', + 'J' + ); + -- Test results + utassert.this ( + 'Successful I_EMPLOYEE_NAME$ROW', + te_employee.recseq (rec1, rec2) + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE test_. + utassert.this ( + 'test_I_EMPLOYEE_NAME$ROW exception ' || SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE test_i_employee_name$val + IS + rec1 te_employee.i_employee_name_rt; + rec2 te_employee.i_employee_name_rt; + BEGIN + -- Unsuccessful test + BEGIN + SELECT last_name, first_name, middle_initial + INTO rec1 + FROM employee + WHERE employee_id = -1; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + NULL; + END; + + -- Run program + begin + rec2 := te_employee.i_employee_name$val (-1); + EXCEPTION + WHEN NO_DATA_FOUND + THEN + NULL; + END; + -- Test results + utassert.this ( + 'Unsuccessful I_EMPLOYEE_NAME$VAL', + recseq (rec1, rec2) + ); + -- Successful test + SELECT last_name, first_name, middle_initial + INTO rec1 + FROM employee + WHERE employee_id = 7839; + -- Run program + rec2 := te_employee.i_employee_name$val (7839); + -- Test results + utassert.this ( + 'Successful I_EMPLOYEE_NAME$VAL', + recseq (rec1, rec2) + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE test_. + utassert.this ( + 'test_I_EMPLOYEE_NAME$VAL exception ' || SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE test_onerow + IS + rec1 te_employee.allcols_rt; + rec2 te_employee.allcols_rt; + BEGIN + -- Unsuccessful test + BEGIN + SELECT + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON + INTO rec1 + FROM employee + WHERE employee_id = -1; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + NULL; + END; + + -- Run program + begin + rec2 := te_employee.onerow (-1); + EXCEPTION + WHEN NO_DATA_FOUND + THEN + NULL; + END; + -- Test results + utassert.this ( + 'Unsuccessful onerow', + te_employee.recseq (rec1, rec2) + ); + -- Successful test + SELECT + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON + INTO rec1 + FROM employee + WHERE employee_id = 7839; + -- Run program + rec2 := te_employee.onerow (7839); + -- Test results + utassert.this ( + 'Successful onerow', + te_employee.recseq (rec1, rec2) + ); + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE test_. + utassert.this ( + 'test_ONEROW exception ' || SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE test_pkyrowcount + IS + BEGIN + -- Run baseline code. + SELECT COUNT (*) + INTO g_rowcount1 + FROM employee + WHERE employee_id = 7782; + -- Compare to program call: + g_rowcount2 := te_employee.pkyrowcount (7782); + -- Test results + utassert.eq ( + 'Successful PKYROWCOUNT', + g_rowcount2, + g_rowcount1 + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE test_. + utassert.this ( + 'test_PKYROWCOUNT exception ' || SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE test_rowcount + IS + BEGIN + -- Run baseline code. + SELECT COUNT (*) + INTO g_rowcount1 + FROM employee; + -- Compare to program call: + g_rowcount2 := te_employee.rowcount; + -- Test results + utassert.eq ( + 'Successful ROWCOUNT', + g_rowcount2, + g_rowcount1 + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE test_. + utassert.this ( + 'test_ROWCOUNT exception ' || SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE test_salary$val + IS + BEGIN + -- Test results + utassert.eqquery ( + 'Successful SALARY$VAL', + 'select te_employee.SALARY$VAL (employee_id) from employee', + 'select salary from employee' + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE test_. + utassert.this ( + 'test_SALARY$VAL exception ' || SQLERRM, + SQLCODE = 0 + ); + END; +END test_te_employee; +/ diff --git a/examples/test_te_employee.pks b/examples/test_te_employee.pks new file mode 100644 index 000000000..738a1f64c --- /dev/null +++ b/examples/test_te_employee.pks @@ -0,0 +1,28 @@ +create or replace package test_TE_EMPLOYEE +IS + PROCEDURE test_setup; + + PROCEDURE test_teardown; + + PROCEDURE test_DEL1; + PROCEDURE test_DELBY_EMP_DEPT_LOOKUP; + PROCEDURE test_DELBY_EMP_JOB_LOOKUP; + PROCEDURE test_DELBY_EMP_MGR_LOOKUP; + PROCEDURE test_INS1; + PROCEDURE test_UPD1; + PROCEDURE test_UPD$HIRE_DATE1; + PROCEDURE test_UPD$SALARY1; + + PROCEDURE test_EMP_DEPT_LOOKUPROWCOUNT; + PROCEDURE test_EMP_JOB_LOOKUPROWCOUNT; + PROCEDURE test_EMP_MGR_LOOKUPROWCOUNT; + PROCEDURE test_HIRE_DATE$VAL; + PROCEDURE test_I_EMPLOYEE_NAME$ROW; + PROCEDURE test_I_EMPLOYEE_NAME$VAL; + PROCEDURE test_ONEROW; + PROCEDURE test_PKYROWCOUNT; + PROCEDURE test_ROWCOUNT; + PROCEDURE test_SALARY$VAL; + +END test_TE_EMPLOYEE; +/ diff --git a/examples/truncit.sp b/examples/truncit.sp new file mode 100644 index 000000000..854bbd328 --- /dev/null +++ b/examples/truncit.sp @@ -0,0 +1,9 @@ +CREATE OR REPLACE PROCEDURE truncit ( + tab IN VARCHAR2, + sch IN VARCHAR2 := NULL +) +IS +BEGIN + EXECUTE IMMEDIATE 'truncate table ' || NVL (sch, USER) || '.' || tab; +END; +/ \ No newline at end of file diff --git a/examples/ut_betwnstr.pkb b/examples/ut_betwnstr.pkb new file mode 100644 index 000000000..4362e155c --- /dev/null +++ b/examples/ut_betwnstr.pkb @@ -0,0 +1,122 @@ +CREATE OR REPLACE PACKAGE BODY ut_betwnstr +IS + PROCEDURE ut_setup + IS + BEGIN + DBMS_OUTPUT.PUT_LINE ('Ran setup'); + END; + + PROCEDURE ut_teardown + IS + BEGIN + DBMS_OUTPUT.PUT_LINE ('Ran teardown'); + END; + + PROCEDURE ut_BETWNSTR + IS + -- Verify and complete data types. + against_this VARCHAR2(2000); + check_this VARCHAR2(2000); + BEGIN + + -- Define "control" operation for "normal" + against_this := 'cde'; + + -- Execute test code for "normal" + check_this := + BETWNSTR ( + STRING_IN => 'abcdefgh' + , + START_IN => 3 + , + END_IN => 5 + ); + + -- Assert success for "normal" by comparing the two values. + utAssert.eq ( + 'normal', + check_this, + against_this + ); + + -- End of test for "normal" + + -- Define "control" operation for "zero start" + + against_this := 'abc'; + + -- Execute test code for "zero start" + + check_this := + BETWNSTR ( + STRING_IN => 'abcdefgh' + , + START_IN => 0 + , + END_IN => 2 + ); + + -- Assert success for "zero start" + + -- Compare the two values. + utAssert.eq ( + 'zero start', + check_this, + against_this + ); + + -- End of test for "zero start" + + -- Define "control" operation for "null start" + + against_this := NULL; + + -- Execute test code for "null start" + + check_this := + BETWNSTR ( + STRING_IN => 'abcdefgh' + , + START_IN => null + , + END_IN => 2 + ); + + -- Assert success for "null start" + + -- Check for NULL return value. + utAssert.isNULL ( + 'null start', + check_this + ); + + -- End of test for "null start" + + -- Define "control" operation for "null end" + + against_this := NULL; + + -- Execute test code for "null end" + + check_this := + BETWNSTR ( + STRING_IN => 'abcdefgh' + , + START_IN => 3 + , + END_IN => null + ); + + -- Assert success for "null end" + + -- Check for NULL return value. + utAssert.isNULL ( + 'null end', + check_this + ); + + -- End of test for "null end" + END ut_BETWNSTR; + +END ut_betwnstr; +/ diff --git a/examples/ut_betwnstr.pks b/examples/ut_betwnstr.pks new file mode 100644 index 000000000..f40ca5f6b --- /dev/null +++ b/examples/ut_betwnstr.pks @@ -0,0 +1,9 @@ +CREATE OR REPLACE PACKAGE ut_betwnstr +IS + PROCEDURE ut_setup; + PROCEDURE ut_teardown; + + -- For each program to test... + PROCEDURE ut_BETWNSTR; +END ut_betwnstr; +/ diff --git a/examples/ut_betwnstr_failures.pkb b/examples/ut_betwnstr_failures.pkb new file mode 100644 index 000000000..43836f285 --- /dev/null +++ b/examples/ut_betwnstr_failures.pkb @@ -0,0 +1,79 @@ +CREATE OR REPLACE PACKAGE BODY ut_betwnstr +IS + PROCEDURE ut_setup + IS + BEGIN + NULL; + END; + + PROCEDURE ut_teardown + IS + BEGIN + NULL; + END; + + -- For each program to test... + PROCEDURE ut_BETWNSTR IS + BEGIN + utAssert.eq ( + 'Typical valid usage', + BETWNSTR( + STRING_IN => 'abcdefg' + , + START_IN => 3 + , + END_IN => 4 + ), + 'cde' + ); + + utAssert.isnull ( + 'NULL start', + BETWNSTR( + STRING_IN => 'abcdefg' + , + START_IN => 1 + , + END_IN => 5 + ) + ); + + + utAssert.isnull ( + 'NULL end', + BETWNSTR( + STRING_IN => 'abcdefg' + , + START_IN => 2 + , + END_IN => NULL + ) + ); + + utAssert.isnull ( + 'End smaller than start', + BETWNSTR( + STRING_IN => 'abcdefg' + , + START_IN => 5 + , + END_IN => 5 + ) + ); + + utAssert.eq ( + 'End larger than string length', + BETWNSTR( + STRING_IN => 'abcdefg' + , + START_IN => 3 + , + END_IN => 200 + ), + 'cdefg' + ); + + END ut_BETWNSTR; + +END ut_betwnstr; +/ diff --git a/examples/ut_betwnstr_gen.pkg b/examples/ut_betwnstr_gen.pkg new file mode 100644 index 000000000..d9855b047 --- /dev/null +++ b/examples/ut_betwnstr_gen.pkg @@ -0,0 +1,137 @@ +CREATE OR REPLACE PACKAGE ut_betwnstr +IS + PROCEDURE ut_setup; + PROCEDURE ut_teardown; + + -- For each program to test... + PROCEDURE ut_BETWNSTR; +END ut_betwnstr; +/ +CREATE OR REPLACE PACKAGE BODY ut_betwnstr +IS + PROCEDURE ut_setup + IS + BEGIN + NULL; + END; + + PROCEDURE ut_teardown + IS + BEGIN + NULL; + END; + -- For each program to test... + PROCEDURE ut_BETWNSTR + IS + -- Verify and complete data types. + against_this VARCHAR2(2000); + check_this VARCHAR2(2000); + BEGIN + + -- Define "control" operation for "BETWNSTR" + + against_this := 'bcde'; + + -- Execute test code for "BETWNSTR" + + check_this := + BETWNSTR ( + STRING_IN => 'abcdefg' + , + START_IN => 2 + , + END_IN => 5 + ); + + -- Assert success for "BETWNSTR" + + -- Compare the two values. + utAssert.eq ( + 'Typical valid usage', + check_this, + against_this + ); + + -- End of test for "BETWNSTR" + + -- Define "control" operation for "BETWNSTR" + + against_this := 'abcde'; + + -- Execute test code for "BETWNSTR" + + check_this := + BETWNSTR ( + STRING_IN => 'abcdefg' + , + START_IN => 0 + , + END_IN => 5 + ); + + -- Assert success for "BETWNSTR" + + -- Compare the two values. + utAssert.eq ( + 'Zero start value', + check_this, + against_this + ); + + -- End of test for "BETWNSTR" + + -- Define "control" operation for "BETWNSTR" + + against_this := 'efg'; + + -- Execute test code for "BETWNSTR" + + check_this := + BETWNSTR ( + STRING_IN => 'abcdefg' + , + START_IN => 5 + , + END_IN => 500 + ); + + -- Assert success for "BETWNSTR" + + -- Compare the two values. + utAssert.eq ( + 'Way big end value', + check_this, + against_this + ); + + -- End of test for "BETWNSTR" + + -- Define "control" operation for "BETWNSTR" + + against_this := NULL; + + -- Execute test code for "BETWNSTR" + + check_this := + BETWNSTR ( + STRING_IN => NULL + , + START_IN => 5 + , + END_IN => 500 + ); + + -- Assert success for "BETWNSTR" + + -- Compare the two values. + utAssert.eq ( + 'NULL start value', + check_this, + against_this + ); + + -- End of test for "BETWNSTR" + END ut_BETWNSTR; + +END ut_betwnstr; +/ diff --git a/examples/ut_bstr.pkb b/examples/ut_bstr.pkb new file mode 100644 index 000000000..cc9077d4c --- /dev/null +++ b/examples/ut_bstr.pkb @@ -0,0 +1,47 @@ +CREATE OR REPLACE PACKAGE BODY ut_bstr +IS + PROCEDURE ut_setup + IS + BEGIN + DBMS_OUTPUT.PUT_LINE ('Ran bstr setup'); + END; + + PROCEDURE ut_teardown + IS + BEGIN + DBMS_OUTPUT.PUT_LINE ('Ran bstr teardown'); + END; + + PROCEDURE ut_BETWNSTR + IS + -- Verify and complete data types. + against_this VARCHAR2(2000); + check_this VARCHAR2(2000); + BEGIN + + -- Define "control" operation for "normal" + against_this := 'cde'; + + -- Execute test code for "normal" + check_this := + BETWNSTR ( + STRING_IN => 'abcdefgh' + , + START_IN => 3 + , + END_IN => 5 + ); + + -- Assert success for "normal" by comparing the two values. + utAssert.eq ( + 'normal', + check_this, + against_this + ); + + -- End of test for "normal" + + END ut_BETWNSTR; + +END ut_bstr; +/ diff --git a/examples/ut_bstr.pks b/examples/ut_bstr.pks new file mode 100644 index 000000000..e164470df --- /dev/null +++ b/examples/ut_bstr.pks @@ -0,0 +1,9 @@ +CREATE OR REPLACE PACKAGE ut_bstr +IS + PROCEDURE ut_setup; + PROCEDURE ut_teardown; + + -- For each program to test... + PROCEDURE ut_BETWNSTR; +END ut_bstr; +/ diff --git a/examples/ut_calc_secs_between.pkb b/examples/ut_calc_secs_between.pkb new file mode 100644 index 000000000..1c15541a5 --- /dev/null +++ b/examples/ut_calc_secs_between.pkb @@ -0,0 +1,51 @@ +CREATE OR REPLACE PACKAGE BODY ut_calc_secs_between +IS + PROCEDURE ut_setup + IS + BEGIN + NULL; + END; + + PROCEDURE ut_teardown + IS + BEGIN + NULL; + END; + + -- For each program to test... + PROCEDURE ut_CALC_SECS_BETWEEN + IS + secs PLS_INTEGER; + BEGIN + CALC_SECS_BETWEEN ( + DATE1 => SYSDATE + , + DATE2 => SYSDATE + , + SECS => secs + ); + + utAssert.eq ( + 'Same dates', + secs, + 0 + ); + + CALC_SECS_BETWEEN ( + DATE1 => SYSDATE + , + DATE2 => SYSDATE+1 + , + SECS => secs + ); + + utAssert.eq ( + 'Exactly one day', + secs, + 24 * 60 * 60 + ); + + END ut_CALC_SECS_BETWEEN; + +END ut_calc_secs_between; +/ diff --git a/examples/ut_calc_secs_between.pks b/examples/ut_calc_secs_between.pks new file mode 100644 index 000000000..8d9c7f217 --- /dev/null +++ b/examples/ut_calc_secs_between.pks @@ -0,0 +1,9 @@ +CREATE OR REPLACE PACKAGE ut_calc_secs_between +IS + PROCEDURE ut_setup; + PROCEDURE ut_teardown; + + -- For each program to test... + PROCEDURE ut_CALC_SECS_BETWEEN; +END ut_calc_secs_between; +/ diff --git a/examples/ut_department2file.pkg b/examples/ut_department2file.pkg new file mode 100644 index 000000000..458ecc0ba --- /dev/null +++ b/examples/ut_department2file.pkg @@ -0,0 +1,45 @@ +CREATE OR REPLACE PACKAGE ut_DEPARTMENT2file +IS + PROCEDURE ut_setup; + PROCEDURE ut_teardown; + + -- For each program to test... + PROCEDURE ut_DEPARTMENT2FILE; +END ut_DEPARTMENT2file; +/ +CREATE OR REPLACE PACKAGE BODY ut_DEPARTMENT2file +IS + PROCEDURE ut_setup + IS + BEGIN + NULL; + END; + + PROCEDURE ut_teardown + IS + BEGIN + NULL; + END; + + -- For each program to test... + PROCEDURE ut_DEPARTMENT2FILE IS + BEGIN + DEPARTMENT2FILE ( + LOC => 'c:\temp' + , + FILE => 'department2file.dat' + , + DELIM => '***' + ); + + utAssert.eqfile ( + 'Test of DEPARTMENT2FILE', + 'department2file.dat', + 'c:\temp', + 'department2file.tst', + 'c:\temp' + ); + END ut_DEPARTMENT2FILE; + +END ut_DEPARTMENT2file; +/ \ No newline at end of file diff --git a/examples/ut_mybooks_pkg.sql b/examples/ut_mybooks_pkg.sql new file mode 100644 index 000000000..6f13f4f13 --- /dev/null +++ b/examples/ut_mybooks_pkg.sql @@ -0,0 +1,337 @@ +/* Formatted on 2002/08/10 09:24 (Formatter Plus v4.7.0) */ +/**************************************************************************************** + + Author : Venky Mangapillai + Created : Mar'2002 + Description : Example test pcakage to test MYBOOKS_PKG package using UTPLSQL + Prerequests : Run the mybooks_setup.sql + +****************************************************************************************/ + + +/* --------------------------------------------------------------------------------- + This is the test package for the MYBOOKS_PKG package. + The test package name should be prefix with "ut_" before the real package name" + e.g "UT_MYBOOKS_PKG" is test package for "MYBOOKS_PKG" + + Here we are going to test the each procedure/function in MYBOOKS_PKG. + MYBOOKS_PKG package contains the following methods + + FUNCTION sel_book_func(bookid number) return mybooks_rec; + PROCEDURE sel_book_proc(bookid number, rc OUT mybooks_rec); + FUNCTION sel_booknm(bookid number) return varchar2; + PROCEDURE ins(bookid number, booknm varchar2,publishdt date); + PROCEDURE upd(bookid number, booknm varchar2,publishdt date); + PROCEDURE del(bookid number); + + Now we are going to test every function/procedure in MYBOOKS_PKG. Before that let's remember, + all the test procedure should start with "ut_" also. But need not end with with function/procedure name. + e.g you can name the test procedure as "ut_sel_book_func" or "ut_something" for procedure "sel_book_func". + But it is good practice to have the procedure name as test procedure. + Function/procedure can have many test procedures. e.g ut_sel_book_func can have two test procedures like + ut_sel_book_func_1 and ut_sel_book_func_2. + Basically the UTPLSQL tool take all the function/procedures in test packages and run one by one starting + with "ut_setup" and ending with "ut_teardown" in the alphabetical order. + + So the test procedures are + + PROCEDURE ut_2_sel_book_func; + PROCEDURE ut_3_sel_book_proc; + PROCEDURE ut_4_sel_booknm; + PROCEDURE ut_1_ins + PROCEDURE ut_5_upd + PROCEDURE ut_6_del + plus + PROCEDURE ut_setup -- to setup the test data. + PROCEDURE ut_teardown -- to clean up the test data. + + Here I used nunber 1,2,3.. after the "ut_". This is because I wanted the INS function to go first + before the DEL function. Otherwise DEL will get tested first and it will end up FAILURE. + This is one way to force the order of test procedure executions. If you are not + worried about the order you don't have to follow this. One more reason I needed here is because + I am using the same test record. Some tester use different test records for diffrent test procedures. + In that case you don't have to worry about the order. I did't the numbering for the ut_setup and ut_teardown + because ut_setup always gets executed first and ut_teardown always get executed last. Even if the test case fails + ut_teardown gets executed. + + Using these test procedures I will show how most of the assertion methods getting used. + Sounds interesting. Isn't it? + So lets get started writing the test package. + +--------------------------------------------------------------------------------------*/ + +-- As I mentioned earlier the test package whoud be prefixed with "ut_". + +CREATE OR REPLACE PACKAGE ut_mybooks_pkg +IS + -- Also the test procedures in the test package + PROCEDURE ut_setup; + + PROCEDURE ut_teardown; + + PROCEDURE ut_2_sel_book_func; + + PROCEDURE ut_3_sel_book_proc; + + PROCEDURE ut_4_sel_booknm; + + PROCEDURE ut_1_ins; + + PROCEDURE ut_5_upd; + + PROCEDURE ut_6_del; +END; +/ + +CREATE OR REPLACE PACKAGE BODY ut_mybooks_pkg +IS -- package body + +-- Here is my test record. + + bookid INTEGER := 100; + booknm VARCHAR2 (30) := 'American History-Vol1'; + publishdt DATE := '05-JAN-2002'; + +/* -------------------------------------------------- + UT_SETUP : setup the test data here. This is first + procedure gets executed automatically +----------------------------------------------------- */ + PROCEDURE ut_setup + IS + BEGIN + ut_teardown; -- drop the temp tables even though it should be there. Just extract caution + + -- "mybooks_part" table contains test record which we are going to test. + -- I am using 8i syntax. Change needed for 8.0 databases + EXECUTE IMMEDIATE 'create table mybooks_part as select * from mybooks where rownum < 1'; + EXECUTE IMMEDIATE 'insert into mybooks_part values (:bookid,:booknm,:publishdt)' + USING bookid, booknm, publishdt; + END; + +/* -------------------------------------------------- + UT_TEARDOWN : clean you data here. This is the last + procedure gets executed automatically +----------------------------------------------------- */ + PROCEDURE ut_teardown + IS + BEGIN + EXECUTE IMMEDIATE 'drop table mybooks_part'; -- Drop the temporary test table after the test + + DELETE FROM mybooks + WHERE book_id = bookid; --Delete the test record after the test + EXCEPTION + WHEN OTHERS + THEN + NULL; -- Ignore if any errors. + END; + +/* --------------------------------------------------------------------- + FUNCTION mybooks_pkg.sel_book_func( + bookid IN NUMBER, + RETURN REFCURSOR + + Assertion methods used : EQ_REFC_TABLE, EQ_REFC_QUERY +/* -------------------------------------------------------------------- */ + PROCEDURE ut_2_sel_book_func + IS + proc_params utplsql_util.utplsql_params; + BEGIN + -- Register the parameters + -- IMPORTANT: The position starts with 0 for functions. For procedures it starts with 1 + utplsql_util.reg_out_param (0, 'REFCURSOR', proc_params); + utplsql_util.reg_in_param (1, 100, proc_params); + -- Test the sel_book_func function. It compares the refcursor with mybooks_part table. + -- Here we expect the refcursor should return the records for the bookid=1. mybooks_part table + -- has bookid=1 record in it which we setup in the ut_setup procedure. + -- If rows matched then it results in SUCCESS otherwise FAILURE. + -- If SUCCESS then sel_book_func fuction behaves as we expected. + + utassert.eq_refc_table ( + 'sel_book_func-1', + 'mybooks_pkg.sel_book_func', + proc_params, + 0, + 'mybooks_part' + ); + -- Other ways to test this + utassert.eq_refc_query ( + 'sel_book_func-2', + 'mybooks_pkg.sel_book_func', + proc_params, + 0, + 'select * from mybooks_part' + ); + END; + +/* --------------------------------------------------------------------- + PROCEDURE mybooks_pkg.sel_book_proc( + bookid IN NUMBER, + mybooks_rec OUT REFCURSOR) + + Assertion methods used : EQ_REFC_TABLE, EQ_REFC_QUERY +/* -------------------------------------------------------------------- */ + PROCEDURE ut_3_sel_book_proc + IS + proc_params utplsql_util.utplsql_params; + BEGIN + -- This procedure I used this because I want to show how to handle the refcursor as OUT parameter + -- Register the parameters + -- IMPORTANT: The position starts with 0 for functions. For procedures it starts with 1 + utplsql_util.reg_in_param (1, 100, proc_params); + utplsql_util.reg_out_param (2, 'REFCURSOR', proc_params); + utassert.eq_refc_table ( + 'sel_book_proc-1', + 'mybooks_pkg.sel_book_proc', + proc_params, + 2, + 'mybooks_part' + ); + -- Other ways to test this + utassert.eq_refc_query ( + 'sel_book_proc-2', + 'mybooks_pkg.sel_book_proc', + proc_params, + 2, + 'select * from mybooks_part' + ); + END; + +/* -------------------------------------------------- + EQ : FUNCTION sel_booknm ( + bookid IN NUMBER, + ) RETRUN VARCHAR2 + + Assertion methods used : EQ +----------------------------------------------------- */ + PROCEDURE ut_4_sel_booknm + IS + BEGIN + -- We expect "American History-Vol1 " from the sel_booknm(100) function. + utassert.eq ('sel_booknm-1', booknm, mybooks_pkg.sel_booknm (bookid)); -- Success + END; + +/* -------------------------------------------------- + PROCEDURE ins ( + bookid IN NUMBER, + booknm IN VARCHAR2, + publishdt DATE + ) + + Assertion methods used : EQ , EQTABCOUNT, EQQUERYVALUE, EQQUERY, THROWS +----------------------------------------------------- */ + PROCEDURE ut_1_ins + IS + BEGIN + -- Call the INS function. + mybooks_pkg.ins (bookid, booknm, publishdt); + -- Check if the row inserted successfully + utassert.eq ('ins-1-4', booknm, mybooks_pkg.sel_booknm (bookid)); + --Other ways to check row inserted successfully and many more ways + utassert.eqqueryvalue ( + 'ins-2', + 'select count(*) from mybooks where book_id=' || TO_CHAR (bookid), + 1 + ); + utassert.eqqueryvalue ( + 'ins-3', + 'select book_nm from mybooks where book_id=' || bookid, + booknm + ); + utassert.eqquery ( + 'ins-4', + 'select * from mybooks where book_id=' || bookid, + 'select * from mybooks_part' + ); + -- Lets try the THROWS assertion method here. + -- If I insert the same bookid again I should get PRIMARY KEY violation error (ERRORCODE=-1 in oracle) + -- Here is the I am looking for "-1". If I get "-1" then SUCCESS otherwise FAIL + utassert.throws ( + 'ins-5', + 'mybooks_pkg.ins(' || bookid || ',''Something'',sysdate)', + -1 + ); + END; + +/* -------------------------------------------------- + PROCEDURE upd ( + bookid IN NUMBER, + booknm IN VARCHAR2, + publishdt DATE + ) + + Assertion methods used : EQ +----------------------------------------------------- */ + PROCEDURE ut_5_upd + IS + BEGIN + booknm := 'American History-Vol2'; -- new values + publishdt := '06-JAN-2002'; + -- Call the INS function. + mybooks_pkg.upd (bookid, booknm, publishdt); + -- Check if the row inserted successfully + utassert.eq ('ut_upd-1', booknm, mybooks_pkg.sel_booknm (bookid)); + END; + +/* -------------------------------------------------- + PROCEDURE del ( + bookid IN NUMBER + ) + + Assertion methods used : EQQUERY, THROWS +----------------------------------------------------- */ + PROCEDURE ut_6_del + IS + ret_val VARCHAR2 (30); + BEGIN + -- Call the DEL function. + DBMS_OUTPUT.put_line ('Id=' || TO_CHAR (bookid)); + mybooks_pkg.del (bookid); + -- Check if the row deleted successfully + utassert.eqqueryvalue ( + 'ut_del-1', + 'select count(*) from mybooks where book_id=100', + 0 + ); + + -- Other ways to test + --utassert.throws('ut_del-2','v_dummy := mybooks_pkg.sel_booknm(100)',100); -- 100 is "NO DATA FOUND" + + -- here is another way + BEGIN + ret_val := mybooks_pkg.sel_booknm (100); + EXCEPTION + WHEN NO_DATA_FOUND + THEN + NULL; + WHEN OTHERS + THEN + utassert.eq ('ut_del-3', 1, 2); -- Forced to fail 1<>2 + END; + END; +END; + + -- End of test package +/ +CREATE PUBLIC SYNONYM ut_mybooks_pkg for ut_mybooks_pkg +/ +GRANT execute on ut_mybooks_pkg to public +/ +show errors +/* -------------------------------------------------------------------------- + This is how you will run the test packages +-----------------------------------------------------------------------------*/ +set SERVEROUTPUT ON size 1000000 +REM exec utplsql.notrc +spool trc + +BEGIN + utplsql.test ('MYBOOKS_PKG'); + DBMS_OUTPUT.put_line (utplsql2.runnum); +END; +/ + +REM spool off + +/* --------------------------------------------------------------------------- + Now we are done and have wonderfull unit testing using UTPLSQL +-----------------------------------------------------------------------------*/ diff --git a/examples/ut_plvdate.pkb b/examples/ut_plvdate.pkb new file mode 100644 index 000000000..abd42ef3b --- /dev/null +++ b/examples/ut_plvdate.pkb @@ -0,0 +1,38 @@ +create or replace package BODY ut_plvdate +IS + PROCEDURE ut_setup + IS + BEGIN + NULL; + END; + + PROCEDURE ut_teardown + IS + BEGIN + NULL; + END; + + PROCEDURE ut_to_date + IS + str VARCHAR2 (2000) := '1/1/1'; + BEGIN + utassert.eq ( + 'DD-MON-YYYY Conversion', + STANDARD.TO_CHAR (PLVdate.to_date (str), 'DD-MON-YYYY'), + '01-JAN-2001' + ); + END; + + PROCEDURE ut_to_char + IS + dt DATE := SYSDATE; + BEGIN + utassert.eq ( + 'MMDDYYYY conversion', + PLVdate.to_char (SYSDATE, 'MMDDYYYY'), + STANDARD.TO_CHAR (SYSDATE, 'MMDDYYYY') + ); + END; + +END ut_plvdate; +/ diff --git a/examples/ut_plvdate.pks b/examples/ut_plvdate.pks new file mode 100644 index 000000000..83e362c5b --- /dev/null +++ b/examples/ut_plvdate.pks @@ -0,0 +1,12 @@ +create or replace package ut_PLVdate +IS + PROCEDURE ut_setup; + + PROCEDURE ut_teardown; + + PROCEDURE ut_to_date; + + PROCEDURE ut_to_char; + +END ut_PLVdate; +/ diff --git a/examples/ut_plvstr.pkb b/examples/ut_plvstr.pkb new file mode 100644 index 000000000..817b29d9d --- /dev/null +++ b/examples/ut_plvstr.pkb @@ -0,0 +1,134 @@ +CREATE OR REPLACE PACKAGE BODY ut_plvstr +IS + PROCEDURE ut_setup + IS + BEGIN + NULL; + END; + + PROCEDURE ut_teardown + IS + BEGIN + NULL; + END; + -- For each program to test... + PROCEDURE ut_BETWN1 + IS + -- Verify and complete data types. + against_this VARCHAR2(2000); + check_this VARCHAR2(2000); + BEGIN + + -- Define "control" operation for "normal" + + against_this := 'cde'; + + -- Execute test code for "normal" + + check_this := + PLVSTR.BETWN ( + STRING_IN => 'abcdefgh' + , + START_IN => 3 + , + END_IN => 5 + , + INCLUSIVE => TRUE + ); + + -- Assert success for "normal" + + -- Compare the two values. + utAssert.eq ( + 'normal', + check_this, + against_this + ); + + -- End of test for "normal" + + -- Define "control" operation for "zero start" + + against_this := 'abc'; + + -- Execute test code for "zero start" + + check_this := + PLVSTR.BETWN ( + STRING_IN => 'abcdefgh' + , + START_IN => 0 + , + END_IN => 2 + , + INCLUSIVE => TRUE + ); + + -- Assert success for "zero start" + + -- Compare the two values. + utAssert.eq ( + 'zero start', + check_this, + against_this + ); + + -- End of test for "zero start" + + -- Define "control" operation for "null start" + + against_this := NULL; + + -- Execute test code for "null start" + + check_this := + PLVSTR.BETWN ( + STRING_IN => 'abcdefgh' + , + START_IN => null + , + END_IN => 2 + , + INCLUSIVE => TRUE + ); + + -- Assert success for "null start" + + -- Check for NULL return value. + utAssert.isNULL ( + 'null start', + check_this + ); + + -- End of test for "null start" + + -- Define "control" operation for "null end" + + against_this := NULL; + + -- Execute test code for "null end" + + check_this := + PLVSTR.BETWN ( + STRING_IN => 'abcdefgh' + , + START_IN => 3 + , + END_IN => null + , + INCLUSIVE => TRUE + ); + + -- Assert success for "null end" + + -- Check for NULL return value. + utAssert.isNULL ( + 'null end', + check_this + ); + + -- End of test for "null end" + END ut_BETWN1; + +END ut_plvstr; +/ diff --git a/examples/ut_plvstr.pks b/examples/ut_plvstr.pks new file mode 100644 index 000000000..a735c36b4 --- /dev/null +++ b/examples/ut_plvstr.pks @@ -0,0 +1,9 @@ +CREATE OR REPLACE PACKAGE ut_plvstr +IS + PROCEDURE ut_setup; + PROCEDURE ut_teardown; + + -- For each program to test... + PROCEDURE ut_BETWN1; +END ut_plvstr; +/ diff --git a/examples/ut_str.pkb b/examples/ut_str.pkb new file mode 100644 index 000000000..c5b6dfd0d --- /dev/null +++ b/examples/ut_str.pkb @@ -0,0 +1,54 @@ +CREATE OR REPLACE PACKAGE BODY ut_str +IS + PROCEDURE ut_setup + IS + BEGIN + DBMS_OUTPUT.PUT_LINE ('Ran setup'); + END; + + PROCEDURE ut_teardown + IS + BEGIN + DBMS_OUTPUT.PUT_LINE ('Ran teardown'); + END; + + -- For each program to test... + PROCEDURE ut_betwn IS + BEGIN + utAssert.eq ( + 'Typical Valid Usage', + str.betwn ('this is a string', 3, 7), + 'is is' + ); + + utAssert.eq ( + 'Null Start', + str.betwn ('this is a string', NULL, 7), + 'ing' + ); + + utAssert.isNULL ( + 'Start bigger than end', + str.betwn ('this is a string', 3, 1) + ); + + utAssert.eval ( + 'Complex expression', + ':p1 = :p2 or :p1 like :p2', + 'abc', + str.betwn ('abc%efg', 1,4) + ); + END ut_betwn; + + PROCEDURE ut_betwn2 IS + BEGIN + utAssert.eq ( + 'Typical Valid Usage', + str.betwn ('this is a string', -2, -6), + 'strin' + ); + + END ut_betwn2; + +END ut_str; +/ diff --git a/examples/ut_str.pks b/examples/ut_str.pks new file mode 100644 index 000000000..d02a56001 --- /dev/null +++ b/examples/ut_str.pks @@ -0,0 +1,10 @@ +CREATE OR REPLACE PACKAGE ut_str +IS + PROCEDURE ut_setup; + PROCEDURE ut_teardown; + + -- For each program to test... + PROCEDURE ut_betwn; + PROCEDURE ut_betwn2; +END ut_str; +/ diff --git a/examples/ut_te_employee.pkb b/examples/ut_te_employee.pkb new file mode 100644 index 000000000..6f424f4de --- /dev/null +++ b/examples/ut_te_employee.pkb @@ -0,0 +1,916 @@ +CREATE OR REPLACE PACKAGE BODY ut_te_employee +IS + g_rowcount1 PLS_INTEGER; + g_rowcount2 PLS_INTEGER; + + FUNCTION recseq ( + rec1 IN te_employee.i_employee_name_rt, + rec2 IN te_employee.i_employee_name_rt + ) + RETURN BOOLEAN + IS + unequal_records EXCEPTION; + retval BOOLEAN; + BEGIN + retval := + rec1.last_name = rec2.last_name + OR ( + rec1.last_name IS NULL + AND rec2.last_name IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := + rec1.first_name = rec2.first_name + OR ( + rec1.first_name IS NULL + AND rec2.first_name IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := + rec1.middle_initial = rec2.middle_initial + OR ( + rec1.middle_initial IS NULL + AND rec2.middle_initial IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + RETURN TRUE; + EXCEPTION + WHEN unequal_records + THEN + RETURN FALSE; + END; + + PROCEDURE ut_setup + IS + BEGIN + ut_teardown; + EXECUTE IMMEDIATE 'CREATE TABLE ut_employee AS + SELECT * FROM employee'; + EXECUTE IMMEDIATE 'CREATE TABLE ut_DEL1 AS + SELECT * FROM employee'; + EXECUTE IMMEDIATE 'CREATE TABLE ut_DELBY_EMP_DEPT_LOOKUP AS + SELECT * FROM employee'; + EXECUTE IMMEDIATE 'CREATE TABLE ut_DELBY_EMP_JOB_LOOKUP AS + SELECT * FROM employee'; + EXECUTE IMMEDIATE 'CREATE TABLE ut_DELBY_EMP_MGR_LOOKUP AS + SELECT * FROM employee'; + EXECUTE IMMEDIATE 'CREATE TABLE ut_INS1 AS + SELECT * FROM employee'; + EXECUTE IMMEDIATE 'CREATE TABLE ut_UPD1 AS + SELECT * FROM employee'; + EXECUTE IMMEDIATE 'CREATE TABLE ut_UPD$HIRE_DATE1 AS + SELECT * FROM employee'; + EXECUTE IMMEDIATE 'CREATE TABLE ut_UPD$SALARY1 AS + SELECT * FROM employee'; + END; + + PROCEDURE ut_teardown + IS + BEGIN + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE ut_employee'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE ut_DEL1'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE ut_DELBY_EMP_DEPT_LOOKUP'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE ut_DELBY_EMP_JOB_LOOKUP'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE ut_DELBY_EMP_MGR_LOOKUP'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE ut_INS1'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE ut_UPD1'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE ut_UPD$HIRE_DATE1'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + BEGIN + EXECUTE IMMEDIATE 'DROP TABLE ut_UPD$SALARY1'; + EXCEPTION + WHEN OTHERS + THEN + NULL; + END; + + END; + + PROCEDURE ut_del1 + IS + fdbk PLS_INTEGER; + BEGIN + /* Delete that finds no rows. */ + + EXECUTE IMMEDIATE ' + DELETE FROM ut_DEL1 + WHERE employee_id = -1 + '; + te_employee.del (-1, rowcount_out => fdbk); + -- Test results + utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1'); + /* Successful delete */ + + EXECUTE IMMEDIATE ' + DELETE FROM ut_DEL1 + WHERE employee_id between 7800 and 7899 + '; + + FOR rec IN (SELECT * + FROM employee + WHERE employee_id BETWEEN 7800 AND 7899) + LOOP + te_employee.del ( + rec.employee_id, + rowcount_out => fdbk + ); + END LOOP; + + -- Test results + utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1'); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + utassert.this ( + 'DEL1 exception ' || SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE ut_delby_emp_dept_lookup + IS + fdbk PLS_INTEGER; + BEGIN + /* Delete that finds now rows. */ + + EXECUTE IMMEDIATE ' + DELETE FROM ut_DELBY_EMP_DEPT_LOOKUP + WHERE department_id = -1 + '; + te_employee.delby_emp_dept_lookup ( + -1, + rowcount_out => fdbk + ); + -- Test results + utassert.eqtable ( + 'Delete no rows via DELBY_EMP_DEPT_LOOKUP', + 'EMPLOYEE', + 'ut_DELBY_EMP_DEPT_LOOKUP' + ); + /* Successful delete */ + + EXECUTE IMMEDIATE ' + DELETE FROM ut_DELBY_EMP_DEPT_LOOKUP + WHERE department_id = 20 + '; + te_employee.delby_emp_dept_lookup ( + 20, + rowcount_out => fdbk + ); + -- Test results + utassert.eqtable ( + 'Successful DELBY_EMP_DEPT_LOOKUP', + 'EMPLOYEE', + 'ut_DELBY_EMP_DEPT_LOOKUP' + ); + ROLLBACK; + END; + + PROCEDURE ut_delby_emp_job_lookup + IS + fdbk PLS_INTEGER; + BEGIN + /* Delete that finds now rows. */ + + EXECUTE IMMEDIATE ' + DELETE FROM ut_DELBY_EMP_JOB_LOOKUP + WHERE job_id = -1 + '; + te_employee.delby_emp_job_lookup ( + -1, + rowcount_out => fdbk + ); + -- Test results + utassert.eqtable ( + 'Delete no rows via DELBY_EMP_JOB_LOOKUP', + 'EMPLOYEE', + 'ut_DELBY_EMP_JOB_LOOKUP' + ); + /* Successful delete */ + + EXECUTE IMMEDIATE ' + DELETE FROM ut_DELBY_EMP_JOB_LOOKUP + WHERE job_id = 668 + '; + te_employee.delby_emp_job_lookup ( + 668, + rowcount_out => fdbk + ); + -- Test results + utassert.eqtable ( + 'Successful DELBY_EMP_JOB_LOOKUP', + 'EMPLOYEE', + 'ut_DELBY_EMP_JOB_LOOKUP' + ); + ROLLBACK; + END; + + PROCEDURE ut_delby_emp_mgr_lookup + IS + fdbk PLS_INTEGER; + BEGIN + /* Delete that finds now rows. */ + + EXECUTE IMMEDIATE ' + DELETE FROM ut_DELBY_EMP_MGR_LOOKUP + WHERE manager_id = -1 + '; + te_employee.delby_emp_mgr_lookup ( + -1, + rowcount_out => fdbk + ); + -- Test results + utassert.eqtable ( + 'Delete no rows via DELBY_EMP_MGR_LOOKUP', + 'EMPLOYEE', + 'ut_DELBY_EMP_MGR_LOOKUP' + ); + /* Successful delete */ + + EXECUTE IMMEDIATE ' + DELETE FROM ut_DELBY_EMP_MGR_LOOKUP + WHERE manager_id = 7505 + '; + te_employee.delby_emp_mgr_lookup ( + 7505, + rowcount_out => fdbk + ); + -- Test results + utassert.eqtable ( + 'Successful DELBY_EMP_MGR_LOOKUP', + 'EMPLOYEE', + 'ut_DELBY_EMP_MGR_LOOKUP' + ); + ROLLBACK; + END; + + PROCEDURE ut_ins1 + IS + v_employee_id employee.employee_id%TYPE; + v_last_name employee.last_name%TYPE := 'GEORGE'; + v_first_name employee.first_name%TYPE := 'WASHINGTON'; + v_middle_initial employee.middle_initial%TYPE := 'M'; + v_job_id employee.job_id%TYPE := 688; + v_manager_id employee.manager_id%TYPE := 7505; + v_hire_date employee.hire_date%TYPE := SYSDATE; + v_salary employee.salary%TYPE := 1000; + v_commission employee.commission%TYPE := 3000; + v_department_id employee.department_id%TYPE := 30; + v_changed_by employee.changed_by%TYPE := USER; + v_changed_on employee.changed_on%TYPE := SYSDATE; + fdbk PLS_INTEGER; + BEGIN + EXECUTE IMMEDIATE ' + INSERT INTO ut_INS1 ( + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON, + CREATED_BY, + CREATED_ON + ) + VALUES ( + employee_id_seq.NEXTVAL, + :LAST_NAME, + :FIRST_NAME, + :MIDDLE_INITIAL, + :JOB_ID, + :MANAGER_ID, + :HIRE_DATE, + :SALARY, + :COMMISSION, + :DEPARTMENT_ID, + :CHANGED_BY, + :CHANGED_ON, + USER, + SYSDATE + ) + ' + USING v_last_name, v_first_name, v_middle_initial, v_job_id, v_manager_id, v_hire_date, v_salary, v_commission, v_department_id, v_changed_by, v_changed_on; + SELECT employee_id_seq.nextval + INTO fdbk + FROM dual; + te_employee.ins ( + v_last_name, + v_first_name, + v_middle_initial, + v_job_id, + v_manager_id, + v_hire_date, + v_salary, + v_commission, + v_department_id, + v_changed_by, + v_changed_on, + fdbk + ); + + -- Test results (everything but ID) + utassert.eqquery ( + 'Insert One Row - check data', + 'SELECT + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON from employee where changed_on = ''' || + SYSDATE || + '''', + 'SELECT + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON from ut_ins1 where changed_on = ''' || + SYSDATE || + '''' + ); + utassert.eqtabcount ( + 'Insert One Row - check count', + 'employee', + 'ut_ins1' + ); + ROLLBACK; + END; + + PROCEDURE ut_upd1 + IS + v_employee_id employee.employee_id%TYPE; + v_last_name employee.last_name%TYPE; + v_first_name employee.first_name%TYPE; + v_middle_initial employee.middle_initial%TYPE; + v_job_id employee.job_id%TYPE; + v_manager_id employee.manager_id%TYPE; + v_hire_date employee.hire_date%TYPE; + v_salary employee.salary%TYPE; + v_commission employee.commission%TYPE; + v_department_id employee.department_id%TYPE; + v_changed_by employee.changed_by%TYPE; + v_changed_on employee.changed_on%TYPE; + fdbk PLS_INTEGER; + BEGIN + /* Update 3 columns by ID */ + + EXECUTE IMMEDIATE ' + UPDATE ut_UPD1 SET + FIRST_NAME = ''SILLY'', + HIRE_DATE = trunc (SYSDATE+100), + COMMISSION = 5000 + WHERE + EMPLOYEE_ID = 7600 + '; + te_employee.upd ( + 7600, + first_name_in => 'SILLY', + commission_in => 5000, + hire_date_in => TRUNC (SYSDATE + 100), + rowcount_out => fdbk + ); + -- Test results (audit fields are different so do a query) + utassert.eqquery ( + 'Update three columns', + 'select first_name, commission, hire_date from EMPLOYEE', + 'select first_name, commission, hire_date from ut_upd1' + ); + ROLLBACK; + END; + + PROCEDURE ut_upd$hire_date1 + IS + fdbk PLS_INTEGER; + BEGIN + /* Successful update by ID */ + + EXECUTE IMMEDIATE ' + UPDATE ut_UPD$HIRE_DATE1 SET + hire_date = trunc (sysdate) + WHERE employee_id = 7698 + '; + te_employee.upd$hire_date ( + 7698, + TRUNC (SYSDATE), + rowcount_out => fdbk + ); + -- Test results + utassert.eqquery ( + 'Testing UPD$HIRE_DATE1', + 'select hire_date from EMPLOYEE', + 'select hire_date from ut_UPD$HIRE_DATE1' + ); + ROLLBACK; + END; + + PROCEDURE ut_upd$salary1 + IS + fdbk PLS_INTEGER; + BEGIN + /* Successful update by ID */ + + EXECUTE IMMEDIATE ' + UPDATE ut_UPD$SALARY1 SET + salary = 5000 + WHERE employee_id = 7555 + '; + te_employee.upd$salary ( + 7555, + 5000, + rowcount_out => fdbk + ); + -- Test results + utassert.eqquery ( + 'Testing UPD$SALARY1', + 'select salary from EMPLOYEE', + 'select salary from ut_UPD$SALARY1' + ); + ROLLBACK; + END; + + PROCEDURE ut_emp_dept_lookuprowcount + IS + BEGIN + -- Run baseline code. + SELECT COUNT (*) + INTO g_rowcount1 + FROM employee + WHERE department_id = 30; + -- Compare to program call: + g_rowcount2 := + te_employee.emp_dept_lookuprowcount (30); + -- Test results + utassert.eq ( + 'Successful EMP_DEPT_LOOKUPROWCOUNT', + g_rowcount2, + g_rowcount1 + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE ut_. + utassert.this ( + 'ut_EMP_DEPT_LOOKUPROWCOUNT exception ' || + SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE ut_emp_job_lookuprowcount + IS + BEGIN + -- Run baseline code. + SELECT COUNT (*) + INTO g_rowcount1 + FROM employee + WHERE job_id = 669; + -- Compare to program call: + g_rowcount2 := + te_employee.emp_job_lookuprowcount (669); + -- Test results + utassert.eq ( + 'Successful EMP_JOB_LOOKUPROWCOUNT', + g_rowcount2, + g_rowcount1 + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE ut_. + utassert.this ( + 'ut_EMP_JOB_LOOKUPROWCOUNT exception ' || + SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE ut_emp_mgr_lookuprowcount + IS + BEGIN + -- Run baseline code. + SELECT COUNT (*) + INTO g_rowcount1 + FROM employee + WHERE manager_id = 7782; + -- Compare to program call: + g_rowcount2 := + te_employee.emp_mgr_lookuprowcount (7782); + -- Test results + utassert.eq ( + 'Successful EMP_MGR_LOOKUPROWCOUNT', + g_rowcount2, + g_rowcount1 + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE ut_. + utassert.this ( + 'ut_EMP_MGR_LOOKUPROWCOUNT exception ' || + SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE ut_hire_date$val + IS + BEGIN + -- Test results + utassert.eqquery ( + 'Successful HIRE_DATE$VAL', + 'select te_employee.HIRE_DATE$VAL (employee_id) from employee', + 'select hire_Date from employee' + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE ut_. + utassert.this ( + 'ut_HIRE_DATE$VAL exception ' || SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE ut_i_employee_name$row + IS + rec1 te_employee.allcols_rt; + rec2 te_employee.allcols_rt; + BEGIN + -- Unsuccessful test + BEGIN + SELECT + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON + INTO rec1 + FROM employee + WHERE last_name = 'LANCE' + AND first_name = 'GREG' + AND middle_initial = 'J'; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + NULL; + END; + + -- Run program + begin + rec2 := + te_employee.i_employee_name$row ('LANCE', 'GREG', 'J'); + EXCEPTION + WHEN NO_DATA_FOUND + THEN + NULL; + END; + + -- Test results + utassert.this ( + 'Unsuccessful I_EMPLOYEE_NAME$ROW', + te_employee.recseq (rec1, rec2) + ); + -- Successful test + SELECT + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON + INTO rec1 + FROM employee + WHERE last_name = 'LANCE' + AND first_name = 'GREGORY' + AND middle_initial = 'J'; + -- Run program + rec2 := + te_employee.i_employee_name$row ( + 'LANCE', + 'GREGORY', + 'J' + ); + -- Test results + utassert.this ( + 'Successful I_EMPLOYEE_NAME$ROW', + te_employee.recseq (rec1, rec2) + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE ut_. + utassert.this ( + 'ut_I_EMPLOYEE_NAME$ROW exception ' || SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE ut_i_employee_name$val + IS + rec1 te_employee.i_employee_name_rt; + rec2 te_employee.i_employee_name_rt; + BEGIN + -- Unsuccessful test + BEGIN + SELECT last_name, first_name, middle_initial + INTO rec1 + FROM employee + WHERE employee_id = -1; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + NULL; + END; + + -- Run program + begin + rec2 := te_employee.i_employee_name$val (-1); + EXCEPTION + WHEN NO_DATA_FOUND + THEN + NULL; + END; + -- Test results + utassert.this ( + 'Unsuccessful I_EMPLOYEE_NAME$VAL', + recseq (rec1, rec2) + ); + -- Successful test + SELECT last_name, first_name, middle_initial + INTO rec1 + FROM employee + WHERE employee_id = 7839; + -- Run program + rec2 := te_employee.i_employee_name$val (7839); + -- Test results + utassert.this ( + 'Successful I_EMPLOYEE_NAME$VAL', + recseq (rec1, rec2) + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE ut_. + utassert.this ( + 'ut_I_EMPLOYEE_NAME$VAL exception ' || SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE ut_onerow + IS + rec1 te_employee.allcols_rt; + rec2 te_employee.allcols_rt; + BEGIN + -- Unsuccessful test + BEGIN + SELECT + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON + INTO rec1 + FROM employee + WHERE employee_id = -1; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + NULL; + END; + + -- Run program + begin + rec2 := te_employee.onerow (-1); + EXCEPTION + WHEN NO_DATA_FOUND + THEN + NULL; + END; + -- Test results + utassert.this ( + 'Unsuccessful onerow', + te_employee.recseq (rec1, rec2) + ); + -- Successful test + SELECT + EMPLOYEE_ID, + LAST_NAME, + FIRST_NAME, + MIDDLE_INITIAL, + JOB_ID, + MANAGER_ID, + HIRE_DATE, + SALARY, + COMMISSION, + DEPARTMENT_ID, + CHANGED_BY, + CHANGED_ON + INTO rec1 + FROM employee + WHERE employee_id = 7839; + -- Run program + rec2 := te_employee.onerow (7839); + -- Test results + utassert.this ( + 'Successful onerow', + te_employee.recseq (rec1, rec2) + ); + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE ut_. + utassert.this ( + 'ut_ONEROW exception ' || SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE ut_pkyrowcount + IS + BEGIN + -- Run baseline code. + SELECT COUNT (*) + INTO g_rowcount1 + FROM employee + WHERE employee_id = 7782; + -- Compare to program call: + g_rowcount2 := te_employee.pkyrowcount (7782); + -- Test results + utassert.eq ( + 'Successful PKYROWCOUNT', + g_rowcount2, + g_rowcount1 + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE ut_. + utassert.this ( + 'ut_PKYROWCOUNT exception ' || SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE ut_rowcount + IS + BEGIN + -- Run baseline code. + SELECT COUNT (*) + INTO g_rowcount1 + FROM employee; + -- Compare to program call: + g_rowcount2 := te_employee.rowcount; + -- Test results + utassert.eq ( + 'Successful ROWCOUNT', + g_rowcount2, + g_rowcount1 + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE ut_. + utassert.this ( + 'ut_ROWCOUNT exception ' || SQLERRM, + SQLCODE = 0 + ); + END; + + PROCEDURE ut_salary$val + IS + BEGIN + -- Test results + utassert.eqquery ( + 'Successful SALARY$VAL', + 'select te_employee.SALARY$VAL (employee_id) from employee', + 'select salary from employee' + ); + ROLLBACK; + EXCEPTION + WHEN OTHERS + THEN + -- Force registration of test failURE ut_. + utassert.this ( + 'ut_SALARY$VAL exception ' || SQLERRM, + SQLCODE = 0 + ); + END; +END ut_te_employee; +/ diff --git a/examples/ut_te_employee.pks b/examples/ut_te_employee.pks new file mode 100644 index 000000000..bb2160da5 --- /dev/null +++ b/examples/ut_te_employee.pks @@ -0,0 +1,28 @@ +create or replace package ut_TE_EMPLOYEE +IS + PROCEDURE ut_setup; + + PROCEDURE ut_teardown; + + PROCEDURE ut_DEL1; + PROCEDURE ut_DELBY_EMP_DEPT_LOOKUP; + PROCEDURE ut_DELBY_EMP_JOB_LOOKUP; + PROCEDURE ut_DELBY_EMP_MGR_LOOKUP; + PROCEDURE ut_INS1; + PROCEDURE ut_UPD1; + PROCEDURE ut_UPD$HIRE_DATE1; + PROCEDURE ut_UPD$SALARY1; + + PROCEDURE ut_EMP_DEPT_LOOKUPROWCOUNT; + PROCEDURE ut_EMP_JOB_LOOKUPROWCOUNT; + PROCEDURE ut_EMP_MGR_LOOKUPROWCOUNT; + PROCEDURE ut_HIRE_DATE$VAL; + PROCEDURE ut_I_EMPLOYEE_NAME$ROW; + PROCEDURE ut_I_EMPLOYEE_NAME$VAL; + PROCEDURE ut_ONEROW; + PROCEDURE ut_PKYROWCOUNT; + PROCEDURE ut_ROWCOUNT; + PROCEDURE ut_SALARY$VAL; + +END ut_TE_EMPLOYEE; +/ diff --git a/examples/ut_truncit.pkb b/examples/ut_truncit.pkb new file mode 100644 index 000000000..56d6d2fc9 --- /dev/null +++ b/examples/ut_truncit.pkb @@ -0,0 +1,34 @@ +CREATE OR REPLACE PACKAGE BODY ut_truncit +IS + PROCEDURE ut_setup + IS + BEGIN + EXECUTE IMMEDIATE + 'CREATE TABLE temp_emp AS SELECT * FROM employee'; + END; + + PROCEDURE ut_teardown + IS + BEGIN + EXECUTE IMMEDIATE + 'DROP TABLE temp_emp'; + END; + + -- For each program to test... + PROCEDURE ut_TRUNCIT IS + BEGIN + TRUNCIT ( + TAB => 'temp_emp' + , + SCH => USER + ); + + utAssert.eq ( + 'Test of TRUNCIT', + tabcount (USER, 'temp_emp'), + 0 + ); + END ut_TRUNCIT; + +END ut_truncit; +/ diff --git a/examples/ut_truncit.pks b/examples/ut_truncit.pks new file mode 100644 index 000000000..8b2255208 --- /dev/null +++ b/examples/ut_truncit.pks @@ -0,0 +1,9 @@ +CREATE OR REPLACE PACKAGE ut_truncit +IS + PROCEDURE ut_setup; + PROCEDURE ut_teardown; + + -- For each program to test... + PROCEDURE ut_TRUNCIT; +END ut_truncit; +/ diff --git a/examples/ut_vda$strings1.pkg b/examples/ut_vda$strings1.pkg new file mode 100644 index 000000000..6e71e068a --- /dev/null +++ b/examples/ut_vda$strings1.pkg @@ -0,0 +1,1469 @@ +CREATE OR REPLACE PACKAGE ut_VDA$STRINGS +IS + PROCEDURE ut_setup; + PROCEDURE ut_teardown; + + -- For each program to test... + PROCEDURE ut_ALL_TRIM; + PROCEDURE ut_INSTRW1; + PROCEDURE ut_INSTRW2; + PROCEDURE ut_REPLACE; + PROCEDURE ut_SCAN; + PROCEDURE ut_SCAN2; +END ut_VDA$STRINGS; +/ +CREATE OR REPLACE PACKAGE BODY ut_VDA$STRINGS +IS + PROCEDURE ut_setup + IS + BEGIN + NULL; + END; + + PROCEDURE ut_teardown + IS + BEGIN + NULL; + END; + -- For each program to test... + PROCEDURE ut_ALL_TRIM + IS + -- Verify and complete data types. + against_this VARCHAR2(2000); + check_this VARCHAR2(2000); + BEGIN + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 'trim'; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.ALL_TRIM ( + PI_TEXT => ' trim ' + , + PI_TRIM => ' ' + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'trim all spaces', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + END ut_ALL_TRIM; + + PROCEDURE ut_INSTRW1 + IS + -- Verify and complete data types. + against_this BINARY_INTEGER; + check_this BINARY_INTEGER; + BEGIN + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 2; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'this is the search string' + , + VP_EXP => '_is' + , + VP_POS => 1 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of _is', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 13; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 'search' + , + VP_POS => 1 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of search', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 0; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 'search' + , + VP_POS => 1 + , + VP_OCC => 2 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'second occurence of search', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 1; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => '%search%' + , + VP_POS => 1 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of %search%', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 0; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 'search' + , + VP_POS => 14 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of search starting at 14', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 13; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 'search' + , + VP_POS => 13 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of search starting at 13', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 13; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => '%search%' + , + VP_POS => 13 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of %search% starting at 13', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 2; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => '%search%' + , + VP_POS => 1 + , + VP_OCC => 2 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'second occurence of %search%', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 0; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's_r' + , + VP_POS => 21 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of s_r starting at 21', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 20; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's_r' + , + VP_POS => 20 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of s_r starting at 20', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 20; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's_r' + , + VP_POS => 1 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of s_r', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 13; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's%r' + , + VP_POS => 1 + , + VP_OCC => 3 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'third occurence of s%r', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 7; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's%r' + , + VP_POS => 1 + , + VP_OCC => 2 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'second occurence of s%r', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 0; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's%r' + , + VP_POS => 21 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of s%r starting at 21', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 20; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's%r' + , + VP_POS => 14 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of s%r starting at 14', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 13; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's%r' + , + VP_POS => 13 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of s%r starting at 13', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 4; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's%r' + , + VP_POS => 1 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of s%r', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 20; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's_%ng' + , + VP_POS => 1 + , + VP_OCC => 4 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'fourth occurence of s_%ng', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 4; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's_%ng' + , + VP_POS => 1 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of s_%ng', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 0; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's__r' + , + VP_POS => 1 + , + VP_OCC => 3 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'third occurence of s__r', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 0; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's__r' + , + VP_POS => 1 + , + VP_OCC => 2 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'second occurence of s__r', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 0; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's__r' + , + VP_POS => 14 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of s__r starting at 14', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 13; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's__r' + , + VP_POS => 13 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of s__r starting at 13', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 13; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's__r' + , + VP_POS => 1 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of s__r', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 0; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's_r' + , + VP_POS => 1 + , + VP_OCC => 3 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'third occurence of s_r', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 0; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's_r' + , + VP_POS => 1 + , + VP_OCC => 2 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'second occurence of s_r', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 2; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => '%t_i_' + , + VP_POS => 1 + , + VP_OCC => 2 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'second occurence of %t_i_', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 1; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => '%t_i_' + , + VP_POS => 1 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of %t_i_', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 20; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's%_%r' + , + VP_POS => 1 + , + VP_OCC => 4 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'fourth occurence of s%_%r', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 3; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => '_s%s%s%s_' + , + VP_POS => 1 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of _s%s%s%s_', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 0; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => 's_%ng' + , + VP_POS => 1 + , + VP_OCC => 5 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'fifth occurence of s_%ng', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 0; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + VP_WRD => 'This is the search string' + , + VP_EXP => '%search%' + , + VP_POS => 14 + , + VP_OCC => 1 + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of %search% starting at 14', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + END ut_INSTRW1; + + PROCEDURE ut_INSTRW2 + IS + -- Verify and complete data types. + against_this NUMBER; + check_this NUMBER; + BEGIN + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 0; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.INSTRW ( + PI_TEXT => 'this is the search string' + , + PI_SEARCH => '_IS' + , + PI_POS => 1 + , + PI_NTH => 1 + , + PI_CASE => true + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'first occurence of _IS case sensitive', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + END ut_INSTRW2; + + PROCEDURE ut_REPLACE + IS + -- Verify and complete data types. + against_this VARCHAR2(2000); + check_this VARCHAR2(2000); + BEGIN + + -- Define "control" operation for "replace" + + against_this := 'this is the search string'; + + -- Execute test code for "replace" + + check_this := + VDA$STRINGS.REPLACE ( + PI_SRCSTR => 'this is the search string' + , + PI_OLDSUBSTR => 'is' + , + PI_NEWSUBSTR => 'ese' + , + PI_START_OCCURENCE => 1 + , + PI_OCCURENCES => 1 + ); + + -- Assert success for "replace" + + -- Compare the two values. + utAssert.eq ( + 'replace is by ese', + check_this, + against_this + ); + + -- End of test for "replace" + END ut_REPLACE; + + PROCEDURE ut_SCAN + IS + -- Verify and complete data types. + against_this VARCHAR2(2000); + check_this VARCHAR2(2000); + BEGIN + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 'word1'; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.SCAN ( + PI_TEXT => 'word1::word2::word3::word4' + , + PI_NUM => 1 + , + PI_DELIMITER => '::' + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'Find 1st word', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 'word2'; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.SCAN ( + PI_TEXT => 'word1::word2::word3::word4' + , + PI_NUM => 2 + , + PI_DELIMITER => '::' + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'Find 2nd word', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 'word4'; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.SCAN ( + PI_TEXT => 'word1::word2::word3::word4' + , + PI_NUM => -1 + , + PI_DELIMITER => '::' + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + 'Find last word', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + END ut_SCAN; + + PROCEDURE ut_SCAN2 + IS + -- Verify and complete data types. + against_this VARCHAR2(2000); + check_this VARCHAR2(2000); + BEGIN + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 'word1'; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.SCAN2 ( + PI_TEXT => 'word1::word2::::word4::word5' + , + PI_NUM => 1 + , + PI_DELIMETER => '::' + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + '1st word', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 'word4'; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.SCAN2 ( + PI_TEXT => 'word1::word2::::word4::word5' + , + PI_NUM => -2 + , + PI_DELIMETER => '::' + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + '-2nd word', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := NULL; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.SCAN2 ( + PI_TEXT => 'word1::word2::::word4::word5' + , + PI_NUM => -6 + , + PI_DELIMETER => '::' + ); + + -- Assert success for "VDA$STRINGS" + + -- Check for NULL return value. + utAssert.isNULL ( + '-6th word (null value)', + check_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 'word1'; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.SCAN2 ( + PI_TEXT => 'word1::word2::::word4::word5' + , + PI_NUM => -5 + , + PI_DELIMETER => '::' + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + '-5th word', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 'word2'; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.SCAN2 ( + PI_TEXT => 'word1::word2::::word4::word5' + , + PI_NUM => -4 + , + PI_DELIMETER => '::' + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + '-4th word', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := NULL; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.SCAN2 ( + PI_TEXT => 'word1::word2::::word4::word5' + , + PI_NUM => -3 + , + PI_DELIMETER => '::' + ); + + -- Assert success for "VDA$STRINGS" + + -- Check for NULL return value. + utAssert.isNULL ( + '-3nd word (null value)', + check_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 'word5'; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.SCAN2 ( + PI_TEXT => 'word1::word2::::word4::word5' + , + PI_NUM => -1 + , + PI_DELIMETER => '::' + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + '-1st word', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := NULL; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.SCAN2 ( + PI_TEXT => 'word1::word2::::word4::word5' + , + PI_NUM => 3 + , + PI_DELIMETER => '::' + ); + + -- Assert success for "VDA$STRINGS" + + -- Check for NULL return value. + utAssert.isNULL ( + '3rd word (null value)', + check_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 'word5'; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.SCAN2 ( + PI_TEXT => 'word1::word2::::word4::word5' + , + PI_NUM => 5 + , + PI_DELIMETER => '::' + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + '5th word', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := NULL; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.SCAN2 ( + PI_TEXT => 'word1::word2::::word4::word5' + , + PI_NUM => 6 + , + PI_DELIMETER => '::' + ); + + -- Assert success for "VDA$STRINGS" + + -- Check for NULL return value. + utAssert.isNULL ( + '6th word (null value)', + check_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := NULL; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.SCAN2 ( + PI_TEXT => 'word1::word2::::word4::word5' + , + PI_NUM => 0 + , + PI_DELIMETER => '::' + ); + + -- Assert success for "VDA$STRINGS" + + -- Check for NULL return value. + utAssert.isNULL ( + '0th word (null value)', + check_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 'word4'; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.SCAN2 ( + PI_TEXT => 'word1::word2::::word4::word5' + , + PI_NUM => 4 + , + PI_DELIMETER => '::' + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + '4th word', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + + -- Define "control" operation for "VDA$STRINGS" + + against_this := 'word2'; + + -- Execute test code for "VDA$STRINGS" + + check_this := + VDA$STRINGS.SCAN2 ( + PI_TEXT => 'word1::word2::::word4::word5' + , + PI_NUM => 2 + , + PI_DELIMETER => '::' + ); + + -- Assert success for "VDA$STRINGS" + + -- Compare the two values. + utAssert.eq ( + '2nd word', + check_this, + against_this + ); + + -- End of test for "VDA$STRINGS" + END ut_SCAN2; + +END ut_VDA$STRINGS; +/ diff --git a/examples/utgen.txt b/examples/utgen.txt new file mode 100644 index 000000000..d6729d0c9 --- /dev/null +++ b/examples/utgen.txt @@ -0,0 +1,147 @@ +SQL> @@str_same.pks + +Package created. + +SQL> @@str_same.pkb + +Package body created. + +SQL> BEGIN + 2 p.l ('*** Basic package for stand alone procedure'); + 3 utgen.testpkg ('betwnstr'); + 4 + 5 p.l ('*** Basic package for package'); + 6 utgen.testpkg ('str'); + 7 + 8 p.l ('*** Place test code in same package as source'); + 9 utgen.testpkg ('str', samepackage_in => TRUE); + 10 + 11 p.l ('*** Change prefix, direct output to file'); + 12 utgen.testpkg ('str', prefix_in => 'tst_', output_type_in => utgen.c_file, + 13 dir_in => 'c:\temp'); + 14 END; + 15 / +*** Basic package for stand alone procedure +CREATE OR REPLACE PACKAGE ut_betwnstr +IS + PROCEDURE ut_setup; + PROCEDURE ut_teardown; + + -- For each program to test... + PROCEDURE ut_BETWNSTR; +END ut_betwnstr; +/ +CREATE OR REPLACE PACKAGE BODY ut_betwnstr +IS + PROCEDURE ut_setup + IS + BEGIN + NULL; + END; + + PROCEDURE ut_teardown + IS + BEGIN + NULL; + END; + + -- For each program to test... + PROCEDURE ut_BETWNSTR IS + BEGIN + utAssert.this ( + 'Test of BETWNSTR', + BETWNSTR( + STRING_IN => '' + , + START_IN => '' + , + END_IN => '' + ) + ); + END ut_BETWNSTR; + +END ut_betwnstr; +/ +*** Basic package for package +CREATE OR REPLACE PACKAGE ut_str +IS + PROCEDURE ut_setup; + PROCEDURE ut_teardown; + + -- For each program to test... + PROCEDURE ut_BETWN; +END ut_str; +/ +CREATE OR REPLACE PACKAGE BODY ut_str +IS + PROCEDURE ut_setup + IS + BEGIN + NULL; + END; + + PROCEDURE ut_teardown + IS + BEGIN + NULL; + END; + + -- For each program to test... + PROCEDURE ut_BETWN IS + BEGIN + utAssert.this ( + 'Test of BETWN', + STR.BETWN( + STRING_IN => '' + , + START_IN => '' + , + END_IN => '' + ) + ); + END ut_BETWN; + +END ut_str; +/ +*** Place test code in same package as source +-- START: place in specification of source package + PROCEDURE ut_setup; + PROCEDURE ut_teardown; + + -- For each program to test... + PROCEDURE ut_BETWN; +-- END: place in specification of source package +-- START: place in body of source package + PROCEDURE ut_setup + IS + BEGIN + NULL; + END; + + PROCEDURE ut_teardown + IS + BEGIN + NULL; + END; + + -- For each program to test... + PROCEDURE ut_BETWN IS + BEGIN + utAssert.this ( + 'Test of BETWN', + STR.BETWN( + STRING_IN => '' + , + START_IN => '' + , + END_IN => '' + ) + ); + END ut_BETWN; + +-- END: place in body of source package +*** Change prefix, direct output to file + +PL/SQL procedure successfully completed. + +SQL> SPOOL OFF diff --git a/source/ut_aeq.pkb b/source/ut_aeq.pkb new file mode 100644 index 000000000..35dbc037e --- /dev/null +++ b/source/ut_aeq.pkb @@ -0,0 +1,742 @@ +/* Formatted on 2001/09/15 08:57 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE BODY utaeq +--//----------------------------------------------------------------------- +--// ** PL/Generator Table Encapsulator for "UTA_EQ" +--//----------------------------------------------------------------------- +--// (c) COPYRIGHT Personnel Policies, Inc. 2001. +--// All rights reserved. +--// +--// No part of this copyrighted work may be reproduced, modified, +--// or distributed in any form or by any means without the prior +--// written permission of Personnel Policies, Inc.. +--//----------------------------------------------------------------------- +--// This software was generated by RevealNet's PL/Generator (TM). +--// +--// For more information, visit www.revealnet.com or call 1.800.REVEAL4 +--//----------------------------------------------------------------------- +--// Stored In: utaeq.pkb +--// Created On: September 15, 2001 08:44:51 +--// Created By: SCOTT +--// PL/Generator Version: PRO-2000.2.9 +--//----------------------------------------------------------------------- +IS + --// Package name and program name globals --// + c_pkgname VARCHAR2 (30) := 'utaeq'; + g_progname VARCHAR2 (30) := NULL; + + --// Update Flag private data structures. --// + TYPE frcflg_rt IS RECORD ( + outcome_id CHAR (1), + data_type CHAR (1), + check_value_id CHAR (1), + against_value_id CHAR (1)); + + frcflg frcflg_rt; + emptyfrc frcflg_rt; + c_set CHAR (1) := 'Y'; + c_noset CHAR (1) := 'N'; + + FUNCTION version + RETURN VARCHAR2 + IS + BEGIN + RETURN '7.09'; + END; + + +--// Private Modules //-- + + --// For Dynamic SQL operations; currently unused. //-- + PROCEDURE initcur (cur_inout IN OUT INTEGER) + IS + BEGIN + IF NOT DBMS_SQL.is_open (cur_inout) + THEN + cur_inout := DBMS_SQL.open_cursor; + END IF; + EXCEPTION + WHEN INVALID_CURSOR + THEN + cur_inout := DBMS_SQL.open_cursor; + END; + + PROCEDURE start_program (nm IN VARCHAR2, msg IN VARCHAR2 := NULL) + IS + BEGIN + g_progname := nm; + END; + + PROCEDURE end_program + IS + BEGIN + g_progname := NULL; + END; + + +--// Cursor management procedures //-- + + --// Open the cursors with some options. //-- + PROCEDURE open_allforpky_cur ( + id_in IN uta_eq.id%TYPE, + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + start_program ('open_allforpky_cur'); + + IF allforpky_cur%ISOPEN + AND v_close + THEN + CLOSE allforpky_cur; + ELSIF allforpky_cur%ISOPEN + AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN allforpky_cur (id_in); + END IF; + + end_program; + END; + + PROCEDURE open_allbypky_cur (close_if_open IN BOOLEAN := TRUE) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + IF allbypky_cur%ISOPEN + AND v_close + THEN + CLOSE allbypky_cur; + ELSIF allbypky_cur%ISOPEN + AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN allbypky_cur; + END IF; + END; + + PROCEDURE open_uta_eq_outcome_fk_all_cur ( + outcome_id_in IN uta_eq.outcome_id%TYPE, + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + IF uta_eq_outcome_fk_all_cur%ISOPEN + AND v_close + THEN + CLOSE uta_eq_outcome_fk_all_cur; + ELSIF uta_eq_outcome_fk_all_cur%ISOPEN + AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN uta_eq_outcome_fk_all_cur (outcome_id_in); + END IF; + END; + + --// Close the cursors if they are open. //-- + PROCEDURE close_allforpky_cur + IS + BEGIN + IF allforpky_cur%ISOPEN + THEN + CLOSE allforpky_cur; + END IF; + END; + + PROCEDURE close_allbypky_cur + IS + BEGIN + IF allbypky_cur%ISOPEN + THEN + CLOSE allbypky_cur; + END IF; + END; + + PROCEDURE close_uta_eq_outcome_fk_all_cu + IS + BEGIN + IF uta_eq_outcome_fk_all_cur%ISOPEN + THEN + CLOSE uta_eq_outcome_fk_all_cur; + END IF; + END; + + PROCEDURE closeall + IS + BEGIN + close_allforpky_cur; + close_allbypky_cur; + close_uta_eq_outcome_fk_all_cu; + END; + + +--// Emulate aggregate-level record operations. //-- + + FUNCTION recseq (rec1 IN allcols_rt, rec2 IN allcols_rt) + RETURN BOOLEAN + IS + unequal_records EXCEPTION; + retval BOOLEAN; + BEGIN + retval := rec1.id = rec2.id + OR ( rec1.id IS NULL + AND rec2.id IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := rec1.outcome_id = rec2.outcome_id + OR ( rec1.outcome_id IS NULL + AND rec2.outcome_id IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := rec1.data_type = rec2.data_type + OR ( rec1.data_type IS NULL + AND rec2.data_type IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := rec1.check_value_id = rec2.check_value_id + OR ( rec1.check_value_id IS NULL + AND rec2.check_value_id IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := rec1.against_value_id = rec2.against_value_id + OR ( rec1.against_value_id IS NULL + AND rec2.against_value_id IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + RETURN TRUE; + EXCEPTION + WHEN unequal_records + THEN + RETURN FALSE; + END; + + FUNCTION recseq (rec1 IN pky_rt, rec2 IN pky_rt) + RETURN BOOLEAN + IS + unequal_records EXCEPTION; + retval BOOLEAN; + BEGIN + retval := rec1.id = rec2.id + OR ( rec1.id IS NULL + AND rec2.id IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + RETURN TRUE; + EXCEPTION + WHEN unequal_records + THEN + RETURN FALSE; + END; + + +--// Is the primary key NOT NULL? //-- + + FUNCTION isnullpky (rec_in IN allcols_rt) + RETURN BOOLEAN + IS + BEGIN + RETURN rec_in.id IS NULL; + END; + + FUNCTION isnullpky (rec_in IN pky_rt) + RETURN BOOLEAN + IS + BEGIN + RETURN rec_in.id IS NULL; + END; + + +--// Query Processing --// + + FUNCTION onerow_internal (id_in IN uta_eq.id%TYPE) + RETURN allcols_rt + IS + CURSOR onerow_cur + IS + SELECT id, outcome_id, data_type, check_value_id, + against_value_id + FROM uta_eq + WHERE id = id_in; + + onerow_rec allcols_rt; + BEGIN + OPEN onerow_cur; + FETCH onerow_cur INTO onerow_rec; + CLOSE onerow_cur; + RETURN onerow_rec; + END onerow_internal; + + FUNCTION onerow (id_in IN uta_eq.id%TYPE) + RETURN allcols_rt + IS + retval allcols_rt; + BEGIN + retval := onerow_internal (id_in); + RETURN retval; + END onerow; + + --// Count of all rows in table and for each foreign key. //-- + FUNCTION rowcount + RETURN INTEGER + IS + retval INTEGER; + BEGIN + SELECT COUNT (*) + INTO retval + FROM uta_eq; + RETURN retval; + END; + + FUNCTION pkyrowcount (id_in IN uta_eq.id%TYPE) + RETURN INTEGER + IS + retval INTEGER; + BEGIN + SELECT COUNT (*) + INTO retval + FROM uta_eq + WHERE id = id_in; + RETURN retval; + END; + + FUNCTION uta_eq_outcome_fkrowcount ( + outcome_id_in IN uta_eq.outcome_id%TYPE + ) + RETURN INTEGER + IS + retval INTEGER; + BEGIN + SELECT COUNT (*) + INTO retval + FROM uta_eq + WHERE outcome_id = uta_eq_outcome_fkrowcount.outcome_id_in; + RETURN retval; + END; + + --// Generate the next primary key: single column PKYs only --// + FUNCTION nextpky + RETURN uta_eq.id%TYPE + IS + retval uta_eq.id%TYPE; + BEGIN + SELECT uta_eq_seq.NEXTVAL + INTO retval + FROM DUAL; + RETURN retval; + END; + + +--// Update Processing --// + + PROCEDURE reset$frc + IS + BEGIN + frcflg := emptyfrc; + END reset$frc; + + FUNCTION outcome_id$frc ( + outcome_id_in IN uta_eq.outcome_id%TYPE DEFAULT NULL + ) + RETURN uta_eq.outcome_id%TYPE + IS + BEGIN + frcflg.outcome_id := c_set; + RETURN outcome_id_in; + END outcome_id$frc; + + FUNCTION data_type$frc ( + data_type_in IN uta_eq.data_type%TYPE DEFAULT NULL + ) + RETURN uta_eq.data_type%TYPE + IS + BEGIN + frcflg.data_type := c_set; + RETURN data_type_in; + END data_type$frc; + + FUNCTION check_value_id$frc ( + check_value_id_in IN uta_eq.check_value_id%TYPE DEFAULT NULL + ) + RETURN uta_eq.check_value_id%TYPE + IS + BEGIN + frcflg.check_value_id := c_set; + RETURN check_value_id_in; + END check_value_id$frc; + + FUNCTION against_value_id$frc ( + against_value_id_in IN uta_eq.against_value_id%TYPE + DEFAULT NULL + ) + RETURN uta_eq.against_value_id%TYPE + IS + BEGIN + frcflg.against_value_id := c_set; + RETURN against_value_id_in; + END against_value_id$frc; + + PROCEDURE upd ( + id_in IN uta_eq.id%TYPE, + outcome_id_in IN uta_eq.outcome_id%TYPE + DEFAULT NULL, + data_type_in IN uta_eq.data_type%TYPE DEFAULT NULL, + check_value_id_in IN uta_eq.check_value_id%TYPE + DEFAULT NULL, + against_value_id_in IN uta_eq.against_value_id%TYPE + DEFAULT NULL, + rowcount_out OUT INTEGER, + reset_in IN BOOLEAN DEFAULT TRUE + ) + IS + BEGIN + UPDATE uta_eq + SET outcome_id = DECODE ( + frcflg.outcome_id, + c_set, outcome_id_in, + NVL (outcome_id_in, outcome_id) + ), + data_type = DECODE ( + frcflg.data_type, + c_set, data_type_in, + NVL (data_type_in, data_type) + ), + check_value_id = DECODE ( + frcflg.check_value_id, + c_set, check_value_id_in, + NVL ( + check_value_id_in, + check_value_id + ) + ), + against_value_id = DECODE ( + frcflg.against_value_id, + c_set, against_value_id_in, + NVL ( + against_value_id_in, + against_value_id + ) + ) + WHERE id = id_in; + + rowcount_out := SQL%ROWCOUNT; + + IF reset_in + THEN + reset$frc; + END IF; + EXCEPTION + WHEN OTHERS + THEN + RAISE; + END upd; + + --// Record-based Update --// + PROCEDURE upd ( + rec_in IN allcols_rt, + rowcount_out OUT INTEGER, + reset_in IN BOOLEAN DEFAULT TRUE + ) + IS + BEGIN + upd ( + rec_in.id, + rec_in.outcome_id, + rec_in.data_type, + rec_in.check_value_id, + rec_in.against_value_id, + rowcount_out, + reset_in + ); + END upd; + + +--// Insert Processing --// + + --// Initialize record with default values. --// + FUNCTION initrec (allnull IN BOOLEAN := FALSE) + RETURN allcols_rt + IS + retval allcols_rt; + BEGIN + IF allnull + THEN + NULL; /* Default values are NULL already. */ + ELSE + retval.id := NULL; + retval.outcome_id := NULL; + retval.data_type := NULL; + retval.check_value_id := NULL; + retval.against_value_id := NULL; + END IF; + + RETURN retval; + END; + + --// Initialize record with default values. --// + PROCEDURE initrec ( + rec_inout IN OUT allcols_rt, + allnull IN BOOLEAN := FALSE + ) + IS + BEGIN + rec_inout := initrec; + END; + + PROCEDURE ins$ins ( + id_in IN uta_eq.id%TYPE, + outcome_id_in IN uta_eq.outcome_id%TYPE DEFAULT NULL, + data_type_in IN uta_eq.data_type%TYPE DEFAULT NULL, + check_value_id_in IN uta_eq.check_value_id%TYPE + DEFAULT NULL, + against_value_id_in IN uta_eq.against_value_id%TYPE + DEFAULT NULL, + upd_on_dup IN BOOLEAN := FALSE + ) + IS + BEGIN + INSERT INTO uta_eq + (id, outcome_id, data_type, + check_value_id, against_value_id) + VALUES (id_in, outcome_id_in, data_type_in, + check_value_id_in, against_value_id_in); + EXCEPTION + WHEN DUP_VAL_ON_INDEX + THEN + IF NOT NVL (upd_on_dup, FALSE) + THEN + RAISE; + ELSE + DECLARE + v_errm VARCHAR2 (2000) := SQLERRM; + v_rowcount INTEGER; + dotloc INTEGER; + leftloc INTEGER; + c_owner all_constraints.owner%TYPE; + c_name all_constraints.constraint_name%TYPE; + BEGIN + dotloc := INSTR (v_errm, '.'); + leftloc := INSTR (v_errm, '('); + c_owner := SUBSTR ( + v_errm, + leftloc + + 1, + dotloc + - leftloc + - 1 + ); + c_name := SUBSTR ( + v_errm, + dotloc + + 1, + INSTR (v_errm, ')') + - dotloc + - 1 + ); + + --// Duplicate based on primary key //-- + IF 'SYS_C004438' = c_name + AND /* 2000.2 'SCOTT' */ USER = c_owner + THEN + upd ( + id_in, + outcome_id_in, + data_type_in, + check_value_id_in, + against_value_id_in, + v_rowcount, + FALSE + ); + ELSE + --// Unique index violation. Cannot recover... //-- + RAISE; + END IF; + END; + END IF; + WHEN OTHERS + THEN + RAISE; + END ins$ins; + + --// Insert 1: with individual fields and return primary key //-- + PROCEDURE ins ( + outcome_id_in IN uta_eq.outcome_id%TYPE + DEFAULT NULL, + data_type_in IN uta_eq.data_type%TYPE DEFAULT NULL, + check_value_id_in IN uta_eq.check_value_id%TYPE + DEFAULT NULL, + against_value_id_in IN uta_eq.against_value_id%TYPE + DEFAULT NULL, + id_out IN OUT uta_eq.id%TYPE, + upd_on_dup IN BOOLEAN := FALSE + ) + IS + v_pky INTEGER := nextpky; + BEGIN + ins$ins ( + v_pky, + outcome_id_in, + data_type_in, + check_value_id_in, + against_value_id_in, + upd_on_dup + ); + id_out := v_pky; + END; + + PROCEDURE ins ( + outcome_id_in IN uta_eq.outcome_id%TYPE + DEFAULT NULL, + data_type_in IN uta_eq.data_type%TYPE + DEFAULT NULL, + check_value_in IN VARCHAR2, + check_is_expression_in IN BOOLEAN, + against_value_in IN VARCHAR2, + id_out IN OUT uta_eq.id%TYPE, + upd_on_dup IN BOOLEAN := FALSE + ) + IS + l_id uta_eq.id%TYPE; + l_check utv_value.id%TYPE; + l_against utv_value.id%TYPE; + BEGIN + utvvalue.ins ( + data_type_in => data_type_in, + is_expression_in => check_is_expression_in, + value_in => check_value_in, + id_out => l_check); + + utvvalue.ins ( + data_type_in => data_type_in, + is_expression_in => TRUE, + value_in => against_value_in, + id_out => l_against); + + ins (outcome_id_in, data_type_in, l_check, l_against, id_out, upd_on_dup); + END; + + --// Insert 2: with record, returning primary key. //-- + PROCEDURE ins ( + rec_in IN allcols_rt, + id_out IN OUT uta_eq.id%TYPE, + upd_on_dup IN BOOLEAN := FALSE + ) + IS + v_pky INTEGER := nextpky; + BEGIN + ins$ins ( + v_pky, + rec_in.outcome_id, + rec_in.data_type, + rec_in.check_value_id, + rec_in.against_value_id, + upd_on_dup + ); + id_out := v_pky; + END; + + +--// Delete Processing --// + + PROCEDURE del (id_in IN uta_eq.id%TYPE, rowcount_out OUT INTEGER) + IS + BEGIN + DELETE FROM uta_eq + WHERE id = id_in; + + rowcount_out := SQL%ROWCOUNT; + EXCEPTION + WHEN OTHERS + THEN + RAISE; + END del; + + --// Record-based delete --// + PROCEDURE del (rec_in IN pky_rt, rowcount_out OUT INTEGER) + IS + BEGIN + del (rec_in.id, rowcount_out); + END del; + + PROCEDURE del (rec_in IN allcols_rt, rowcount_out OUT INTEGER) + IS + BEGIN + del (rec_in.id, rowcount_out); + END del; + + --// Delete all records for foreign key UTA_EQ_OUTCOME_FK. //-- + PROCEDURE delby_uta_eq_outcome_fk ( + outcome_id_in IN uta_eq.outcome_id%TYPE, + rowcount_out OUT INTEGER + ) + IS + BEGIN + DELETE FROM uta_eq + WHERE outcome_id = delby_uta_eq_outcome_fk.outcome_id_in; + + rowcount_out := SQL%ROWCOUNT; + EXCEPTION + WHEN OTHERS + THEN + RAISE; + END delby_uta_eq_outcome_fk; + + --// Program called by database initialization script to pin the package. //-- + PROCEDURE pinme + IS + BEGIN + --// Doesn't do anything except cause the package to be loaded. //-- + NULL; + END; + +--// Initialization section for the package. --// +BEGIN + NULL; -- Placeholder. +END utaeq; +/ + diff --git a/source/ut_aeq.pks b/source/ut_aeq.pks new file mode 100644 index 000000000..0ba472670 --- /dev/null +++ b/source/ut_aeq.pks @@ -0,0 +1,251 @@ +CREATE OR REPLACE PACKAGE utaeq +--//----------------------------------------------------------------------- +--// ** PL/Generator Table Encapsulator for "UTA_EQ" +--//----------------------------------------------------------------------- +--// (c) COPYRIGHT Personnel Policies, Inc. 2001. +--// All rights reserved. +--// +--// No part of this copyrighted work may be reproduced, modified, +--// or distributed in any form or by any means without the prior +--// written permission of Personnel Policies, Inc.. +--//----------------------------------------------------------------------- +--// This software was generated by RevealNet's PL/Generator (TM). +--// +--// For more information, visit www.revealnet.com or call 1.800.REVEAL4 +--//----------------------------------------------------------------------- +--// Stored In: utaeq.pks +--// Created On: September 15, 2001 08:44:48 +--// Created By: SCOTT +--// PL/Generator Version: PRO-2000.2.9 +--//----------------------------------------------------------------------- +IS +--// Data Structures //-- + TYPE pky_rt IS RECORD ( + id UTA_EQ.ID%TYPE + ); + + --// Modified version of %ROWTYPE for table with subset of columns //-- + TYPE allcols_rt IS RECORD ( + id UTA_EQ.ID%TYPE, + outcome_id UTA_EQ.OUTCOME_ID%TYPE, + data_type UTA_EQ.DATA_TYPE%TYPE, + check_value_id UTA_EQ.CHECK_VALUE_ID%TYPE, + against_value_id UTA_EQ.AGAINST_VALUE_ID%TYPE + ); + + TYPE cv_t IS REF CURSOR; + +--// Cursors //-- + + CURSOR allbypky_cur + IS + SELECT + ID, + OUTCOME_ID, + DATA_TYPE, + CHECK_VALUE_ID, + AGAINST_VALUE_ID + FROM UTA_EQ + ORDER BY + ID + ; + + CURSOR allforpky_cur ( + id_in IN UTA_EQ.ID%TYPE + ) + IS + SELECT + ID, + OUTCOME_ID, + DATA_TYPE, + CHECK_VALUE_ID, + AGAINST_VALUE_ID + FROM UTA_EQ + WHERE + ID = allforpky_cur.id_in + ; + + --// Specified columns, all rows for this foreign key. //-- + CURSOR uta_eq_outcome_fk_all_cur ( + outcome_id_in IN UTA_EQ.OUTCOME_ID%TYPE + ) + IS + SELECT + ID, + OUTCOME_ID, + DATA_TYPE, + CHECK_VALUE_ID, + AGAINST_VALUE_ID + FROM UTA_EQ + WHERE + OUTCOME_ID = uta_eq_outcome_fk_all_cur.outcome_id_in + ; + +--// Cursor management procedures //-- + + --// Open the cursors with some options. //-- + PROCEDURE open_allforpky_cur ( + id_in IN UTA_EQ.ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ); + + PROCEDURE open_allbypky_cur ( + close_if_open IN BOOLEAN := TRUE + ); + + PROCEDURE open_uta_eq_outcome_fk_all_cur ( + outcome_id_in IN UTA_EQ.OUTCOME_ID%TYPE, + close_if_open IN BOOLEAN := TRUE + ); + + --// Close the cursors if they are open. //-- + PROCEDURE close_allforpky_cur; + PROCEDURE close_allbypky_cur; + PROCEDURE close_uta_eq_outcome_fk_all_cu; + PROCEDURE closeall; + +--// Analyze presence of primary key: is it NOT NULL? //-- + + FUNCTION isnullpky ( + rec_in IN allcols_rt + ) + RETURN BOOLEAN; + + FUNCTION isnullpky ( + rec_in IN pky_rt + ) + RETURN BOOLEAN; + +--// Emulate aggregate-level record operations. //-- + + FUNCTION recseq (rec1 IN allcols_rt, rec2 IN allcols_rt) + RETURN BOOLEAN; + + FUNCTION recseq (rec1 IN pky_rt, rec2 IN pky_rt) + RETURN BOOLEAN; + +--// Fetch Data //-- + + --// Fetch one row of data for a primary key. //-- + FUNCTION onerow ( + id_in IN UTA_EQ.ID%TYPE + ) + RETURN allcols_rt; + + + --// Count of all rows in table and for each foreign key. //-- + FUNCTION rowcount RETURN INTEGER; + FUNCTION pkyrowcount ( + id_in IN UTA_EQ.ID%TYPE + ) + RETURN INTEGER; + FUNCTION uta_eq_outcome_fkrowcount ( + outcome_id_in IN UTA_EQ.OUTCOME_ID%TYPE + ) + RETURN INTEGER; +--// Update Processing //-- + + PROCEDURE reset$frc; + + --// Force setting of NULL values //-- + + FUNCTION outcome_id$frc + (outcome_id_in IN UTA_EQ.OUTCOME_ID%TYPE DEFAULT NULL) + RETURN UTA_EQ.OUTCOME_ID%TYPE; + + FUNCTION data_type$frc + (data_type_in IN UTA_EQ.DATA_TYPE%TYPE DEFAULT NULL) + RETURN UTA_EQ.DATA_TYPE%TYPE; + + FUNCTION check_value_id$frc + (check_value_id_in IN UTA_EQ.CHECK_VALUE_ID%TYPE DEFAULT NULL) + RETURN UTA_EQ.CHECK_VALUE_ID%TYPE; + + FUNCTION against_value_id$frc + (against_value_id_in IN UTA_EQ.AGAINST_VALUE_ID%TYPE DEFAULT NULL) + RETURN UTA_EQ.AGAINST_VALUE_ID%TYPE; + + PROCEDURE upd ( + id_in IN UTA_EQ.ID%TYPE, + outcome_id_in IN UTA_EQ.OUTCOME_ID%TYPE DEFAULT NULL, + data_type_in IN UTA_EQ.DATA_TYPE%TYPE DEFAULT NULL, + check_value_id_in IN UTA_EQ.CHECK_VALUE_ID%TYPE DEFAULT NULL, + against_value_id_in IN UTA_EQ.AGAINST_VALUE_ID%TYPE DEFAULT NULL, + rowcount_out OUT INTEGER, + reset_in IN BOOLEAN DEFAULT TRUE + ); + + --// Record-based Update //-- + + PROCEDURE upd (rec_in IN allcols_rt, + rowcount_out OUT INTEGER, + reset_in IN BOOLEAN DEFAULT TRUE); + +--// Insert Processing //-- + + --// Initialize record with default values. //-- + FUNCTION initrec (allnull IN BOOLEAN := FALSE) RETURN allcols_rt; + + --// Initialize record with default values. //-- + PROCEDURE initrec ( + rec_inout IN OUT allcols_rt, + allnull IN BOOLEAN := FALSE); + + + --// Generate next primary key: for single column PKs only. //-- + FUNCTION nextpky RETURN UTA_EQ.id%TYPE; + + PROCEDURE ins ( + outcome_id_in IN UTA_EQ.OUTCOME_ID%TYPE DEFAULT NULL, + data_type_in IN UTA_EQ.DATA_TYPE%TYPE DEFAULT NULL, + check_value_id_in IN UTA_EQ.CHECK_VALUE_ID%TYPE DEFAULT NULL, + against_value_id_in IN UTA_EQ.AGAINST_VALUE_ID%TYPE DEFAULT NULL, + id_out IN OUT UTA_EQ.ID%TYPE, + upd_on_dup IN BOOLEAN := FALSE + ); + + -- Insert values entered by user, create value rows and then + -- insert the uta_eq row. + -- ?? Provide lots of overloading or put the conversion logic + -- inside this procedure based on data_type? For now will + -- opt for the conversion, first implementing simply for + -- VARCHAR2. Obviously this would not work for special + -- datatypes like BLOB. + PROCEDURE ins ( + outcome_id_in IN UTA_EQ.OUTCOME_ID%TYPE DEFAULT NULL, + data_type_in IN UTA_EQ.DATA_TYPE%TYPE DEFAULT NULL, + check_value_in IN VARCHAR2, + check_is_expression_in in BOOLEAN, + against_value_in IN VARCHAR2, + id_out IN OUT UTA_EQ.ID%TYPE, + upd_on_dup IN BOOLEAN := FALSE + ); + + PROCEDURE ins (rec_in IN allcols_rt, + id_out IN OUT UTA_EQ.ID%TYPE, + upd_on_dup IN BOOLEAN := FALSE + ); + +--// Delete Processing //-- + PROCEDURE del ( + id_in IN UTA_EQ.ID%TYPE, + rowcount_out OUT INTEGER); + + --// Record-based delete //-- + PROCEDURE del (rec_in IN pky_rt, + rowcount_out OUT INTEGER); + + PROCEDURE del (rec_in IN allcols_rt, + rowcount_out OUT INTEGER); + + --// Delete all records for this UTA_EQ_OUTCOME_FK foreign key. //-- + PROCEDURE delby_uta_eq_outcome_fk ( + outcome_id_in IN UTA_EQ.OUTCOME_ID%TYPE, + rowcount_out OUT INTEGER + ); + + --// Program called by database initialization script to pin the package. //-- + PROCEDURE pinme; + FUNCTION version RETURN VARCHAR2; +END utaeq; +/ diff --git a/source/ut_argument.tab b/source/ut_argument.tab new file mode 100644 index 000000000..5c6d8ba39 --- /dev/null +++ b/source/ut_argument.tab @@ -0,0 +1,14 @@ +CREATE TABLE ut_argument ( + id INTEGER , + testcase_id INTEGER, + name VARCHAR2(200), + assertion_id INTEGER, + CONSTRAINT ut_argument_pk PRIMARY KEY (id) +); + +ALTER table ut_argument add CONSTRAINT ut_argument_testcase_fk + FOREIGN KEY (testcase_id) REFERENCES ut_testcase; + +ALTER table ut_argument add CONSTRAINT ut_argument_assertion_fk + FOREIGN KEY (assertion_id) REFERENCES ut_assertion; + diff --git a/source/ut_assert.pkb b/source/ut_assert.pkb new file mode 100644 index 000000000..ee9bd3d11 --- /dev/null +++ b/source/ut_assert.pkb @@ -0,0 +1,666 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE BODY utassert +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 +Steven Feuerstein, steven@stevenfeuerstein.com +Chris Rimmer, chris@sunset.force9.co.uk + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*Modification History: +studious:01/20/2002:Assertion for object existance +Venky:08-AUG-2002:Addes refcursor Assertions +*/ + + g_showresults BOOLEAN := FALSE; + + -- DBMS_PIPE functionality based on code provided by John Beresniewicz, + -- Savant Corp, in ORACLE BUILT-IN PACKAGES + + -- For pipe equality checking + TYPE msg_rectype IS RECORD ( + item_type INTEGER, + mvc2 VARCHAR2 (4093), + mdt DATE, + mnum NUMBER, + mrid ROWID, + mraw RAW (4093)); + + /* + || msg_tbltype tables can hold an ordered list of + || message items, thus any message can be captured + */ + TYPE msg_tbltype IS TABLE OF msg_rectype + INDEX BY BINARY_INTEGER; + + PROCEDURE this ( + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE, + register_in IN BOOLEAN := TRUE -- 2.0.1 + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.this ( + l_outcome, + msg_in, + check_this_in, + null_ok_in, + raise_exc_in, + register_in + ); + END; + + PROCEDURE eval ( + msg_in IN VARCHAR2, + using_in IN VARCHAR2, -- The expression + value_name_in IN utAssert2.value_name_tt, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eval ( + l_outcome, + msg_in, + using_in, + value_name_in, + null_ok_in, + raise_exc_in + ); + END; + + PROCEDURE eval ( + msg_in IN VARCHAR2, + using_in IN VARCHAR2, -- The expression + value1_in IN VARCHAR2, + value2_in IN VARCHAR2, + name1_in IN VARCHAR2 := NULL, + name2_in IN VARCHAR2 := NULL, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + value_name utAssert2.value_name_tt; + BEGIN + value_name(1).value := value1_in; + value_name(1).name := name1_in; + value_name(2).value := value2_in; + value_name(2).name := name2_in; + + utassert2.eval ( + l_outcome, + msg_in, + using_in, + value_name, + null_ok_in, + raise_exc_in + ); + END; + + PROCEDURE eq ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eq ( + l_outcome, + msg_in, + check_this_in, + against_this_in, + null_ok_in, + raise_exc_in + ); + END; + + PROCEDURE eq ( + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + against_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eq ( + l_outcome, + msg_in, + check_this_in, + against_this_in, + null_ok_in, + raise_exc_in + ); + END; + + PROCEDURE eq ( + msg_in IN VARCHAR2, + check_this_in IN DATE, + against_this_in IN DATE, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE, + truncate_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eq ( + l_outcome, + msg_in, + check_this_in, + against_this_in, + null_ok_in, + raise_exc_in, + truncate_in + ); + END; + + PROCEDURE eqtable ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + check_where_in IN VARCHAR2 := NULL, + against_where_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eqtable ( + l_outcome, + msg_in, + check_this_in, + against_this_in, + check_where_in, + against_where_in, + raise_exc_in + ); + END; + + PROCEDURE eqtabcount ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + check_where_in IN VARCHAR2 := NULL, + against_where_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eqtabcount ( + l_outcome, + msg_in, + check_this_in, + against_this_in, + check_where_in, + against_where_in, + raise_exc_in + ); + END; + + PROCEDURE eqquery ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eqquery ( + l_outcome, + msg_in, + check_this_in, + against_this_in, + raise_exc_in + ); + END; + + --Check a query against a single VARCHAR2 value + PROCEDURE eqqueryvalue ( + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eqqueryvalue ( + l_outcome, + msg_in, + check_query_in, + against_value_in, + null_ok_in, + raise_exc_in + ); + END; + + -- Check a query against a single DATE value + PROCEDURE eqqueryvalue ( + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN DATE, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eqqueryvalue ( + l_outcome, + msg_in, + check_query_in, + against_value_in, + null_ok_in, + raise_exc_in + ); + END; + + PROCEDURE eqqueryvalue ( + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN NUMBER, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eqqueryvalue ( + l_outcome, + msg_in, + check_query_in, + against_value_in, + null_ok_in, + raise_exc_in + ); + END; + + PROCEDURE eqcursor ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ) + -- User passes in names of two packaged cursors. + -- Have to loop through each row and compare! + -- How do I compare the contents of two records + -- which have been defined dynamically? + IS + BEGIN + utplsql.pl ('utAssert.eqCursor is not yet implemented!'); + END; + + PROCEDURE eqfile ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + check_this_dir_in IN VARCHAR2, + against_this_in IN VARCHAR2, + against_this_dir_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eqfile ( + l_outcome, + msg_in, + check_this_in, + check_this_dir_in, + against_this_in, + against_this_dir_in, + raise_exc_in + ); + END; + + PROCEDURE eqpipe ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + check_nth_in IN VARCHAR2 := NULL, + against_nth_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eqpipe ( + l_outcome, + msg_in, + check_this_in, + against_this_in, + raise_exc_in + ); + END; + + PROCEDURE eqcoll ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + eqfunc_in IN VARCHAR2 := NULL, + check_startrow_in IN PLS_INTEGER := NULL, + check_endrow_in IN PLS_INTEGER := NULL, + against_startrow_in IN PLS_INTEGER := NULL, + against_endrow_in IN PLS_INTEGER := NULL, + match_rownum_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eqcoll ( + l_outcome, + msg_in, + check_this_in, + against_this_in, + eqfunc_in, + check_startrow_in, + check_endrow_in, + against_startrow_in, + against_endrow_in, + match_rownum_in, + null_ok_in, + raise_exc_in + ); + END; + + /* API based access to collections */ + PROCEDURE eqcollapi ( + msg_in IN VARCHAR2, + check_this_pkg_in IN VARCHAR2, + against_this_pkg_in IN VARCHAR2, + eqfunc_in IN VARCHAR2 := NULL, + countfunc_in IN VARCHAR2 := 'COUNT', + firstrowfunc_in IN VARCHAR2 := 'FIRST', + lastrowfunc_in IN VARCHAR2 := 'LAST', + nextrowfunc_in IN VARCHAR2 := 'NEXT', + getvalfunc_in IN VARCHAR2 := 'NTHVAL', + check_startrow_in IN PLS_INTEGER := NULL, + check_endrow_in IN PLS_INTEGER := NULL, + against_startrow_in IN PLS_INTEGER := NULL, + against_endrow_in IN PLS_INTEGER := NULL, + match_rownum_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eqcollapi ( + l_outcome, + msg_in, + check_this_pkg_in, + against_this_pkg_in, + eqfunc_in, + countfunc_in, + firstrowfunc_in, + lastrowfunc_in, + nextrowfunc_in, + getvalfunc_in, + check_startrow_in, + check_endrow_in, + against_startrow_in, + against_endrow_in, + match_rownum_in, + null_ok_in, + raise_exc_in + ); + END; + + PROCEDURE isnotnull ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.isnotnull (l_outcome, msg_in, check_this_in, raise_exc_in); + END; + + PROCEDURE isnull ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.isnull (l_outcome, msg_in, check_this_in, raise_exc_in); + END; + + PROCEDURE isnotnull ( + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.isnotnull (l_outcome, msg_in, check_this_in, raise_exc_in); + END; + + PROCEDURE isnull ( + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.isnull (l_outcome, msg_in, check_this_in, raise_exc_in); + END; + + --Check a given call throws a named exception + PROCEDURE throws ( + msg_in VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN VARCHAR2 + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.throws (l_outcome, msg_in, check_call_in, against_exc_in); + END; + + --Check a given call throws an exception with a given SQLCODE + PROCEDURE throws ( + msg_in VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN NUMBER + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.throws (l_outcome, msg_in, check_call_in, against_exc_in); + END; + + PROCEDURE showresults + IS + BEGIN + g_showresults := TRUE; + END; + + PROCEDURE noshowresults + IS + BEGIN + g_showresults := FALSE; + END; + + FUNCTION showing_results + RETURN BOOLEAN + IS + BEGIN + RETURN g_showresults; + END; + +/* START username:studious Date:01/11/2002 Task_id:42690 +Description: Checking whether object exists */ + + PROCEDURE objExists ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + )IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.objExists ( + l_outcome, + msg_in, + check_this_in, + null_ok_in, + raise_exc_in + ); + END; + + PROCEDURE objnotExists ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + )IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.objnotExists ( + l_outcome, + msg_in, + check_this_in, + null_ok_in, + raise_exc_in + ); + END; +/* END username:studious Task_id:42690*/ + + /* START chrisrimmer 42694 */ + FUNCTION previous_passed + RETURN BOOLEAN + IS + BEGIN + RETURN utAssert2.previous_passed; + END; + + FUNCTION previous_failed + RETURN BOOLEAN + IS + BEGIN + RETURN utAssert2.previous_failed; + END; + /* END chrisrimmer 42694 */ + + /* START chrisrimmer 42696 */ + PROCEDURE eqoutput ( + msg_in IN VARCHAR2, + check_this_in IN DBMS_OUTPUT.CHARARR, + against_this_in IN DBMS_OUTPUT.CHARARR, + ignore_case_in IN BOOLEAN := FALSE, + ignore_whitespace_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eqoutput( + l_outcome, + msg_in, + check_this_in, + against_this_in, + ignore_case_in, + ignore_whitespace_in, + null_ok_in, + raise_exc_in + ); + END; + + PROCEDURE eqoutput ( + msg_in IN VARCHAR2, + check_this_in IN DBMS_OUTPUT.CHARARR, + against_this_in IN VARCHAR2, + line_delimiter_in IN CHAR := NULL, + ignore_case_in IN BOOLEAN := FALSE, + ignore_whitespace_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eqoutput( + l_outcome, + msg_in, + check_this_in, + against_this_in, + line_delimiter_in, + ignore_case_in, + ignore_whitespace_in, + null_ok_in, + raise_exc_in + ); + END; + /* END chrisrimmer 42696 */ + + /* START VENKY11 45789 */ + + PROCEDURE eq_refc_table( + p_msg_nm IN VARCHAR2, + proc_name IN VARCHAR2, + params IN utplsql_util.utplsql_params, + cursor_position IN PLS_INTEGER, + table_name IN VARCHAR2 ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eq_refc_table(l_outcome,p_msg_nm,proc_name,params,cursor_position,table_name); + END; + + PROCEDURE eq_refc_query( + p_msg_nm IN VARCHAR2, + proc_name IN VARCHAR2, + params IN utplsql_util.utplsql_params, + cursor_position IN PLS_INTEGER, + qry IN VARCHAR2 ) + IS + l_outcome ut_outcome.id%TYPE; + BEGIN + utassert2.eq_refc_query(l_outcome,p_msg_nm,proc_name,params,cursor_position,qry); + END; + + /* END VENKY11 45789 */ + +END utassert; +/ +REM SHO ERR diff --git a/source/ut_assert.pks b/source/ut_assert.pks new file mode 100644 index 000000000..f8fc24954 --- /dev/null +++ b/source/ut_assert.pks @@ -0,0 +1,324 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE utassert &start81 AUTHID CURRENT_USER &end81 +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 +Steven Feuerstein, steven@stevenfeuerstein.com +Chris Rimmer, chris@sunset.force9.co.uk + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* +MODIFICATION HISTORY +Who When What +chrisrimmer 19-Feb-2002 Added previous_passed and previous_failed +Venky 08-Aug-2002 Added refcursor assertions +*/ + + test_failure EXCEPTION; + /* On Error behaviors */ + c_continue CONSTANT CHAR (1) := 'c'; + c_stop CONSTANT CHAR (1) := 's'; + + PROCEDURE this ( + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE, + register_in IN BOOLEAN := TRUE -- 2.0.1 + ); + + /* + 2.0.8 General evaluation program. + */ + PROCEDURE eval ( + msg_in IN VARCHAR2, + using_in IN VARCHAR2, -- The expression + value_name_in IN utAssert2.value_name_tt, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eval ( + msg_in IN VARCHAR2, + using_in IN VARCHAR2, -- The expression + value1_in IN VARCHAR2, + value2_in IN VARCHAR2, + name1_in IN VARCHAR2 := NULL, + name2_in IN VARCHAR2 := NULL, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eq ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eq ( + msg_in IN VARCHAR2, + check_this_in IN DATE, + against_this_in IN DATE, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE, + truncate_in IN BOOLEAN := FALSE + ); + + PROCEDURE eq ( + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + against_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqtable ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + check_where_in IN VARCHAR2 := NULL, + against_where_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqtabcount ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + check_where_in IN VARCHAR2 := NULL, + against_where_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqquery ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ); + + --Check a query against a single VARCHAR2 value + PROCEDURE eqqueryvalue ( + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + -- Check a query against a single DATE value + PROCEDURE eqqueryvalue ( + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN DATE, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + -- Check a query against a single NUMERIC value + PROCEDURE eqqueryvalue ( + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN NUMBER, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + -- Not currently implemented + PROCEDURE eqcursor ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqfile ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + check_this_dir_in IN VARCHAR2, + against_this_in IN VARCHAR2, + against_this_dir_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqpipe ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + check_nth_in IN VARCHAR2 := NULL, + against_nth_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ); + + /* Direct access to collections */ + PROCEDURE eqcoll ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, /* pkg1.coll */ + against_this_in IN VARCHAR2, /* pkg2.coll */ + eqfunc_in IN VARCHAR2 := NULL, + check_startrow_in IN PLS_INTEGER := NULL, + check_endrow_in IN PLS_INTEGER := NULL, + against_startrow_in IN PLS_INTEGER := NULL, + against_endrow_in IN PLS_INTEGER := NULL, + match_rownum_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ); + + /* API based access to collections */ + PROCEDURE eqcollapi ( + msg_in IN VARCHAR2, + check_this_pkg_in IN VARCHAR2, + against_this_pkg_in IN VARCHAR2, + eqfunc_in IN VARCHAR2 := NULL, + countfunc_in IN VARCHAR2 := 'COUNT', + firstrowfunc_in IN VARCHAR2 := 'FIRST', + lastrowfunc_in IN VARCHAR2 := 'LAST', + nextrowfunc_in IN VARCHAR2 := 'NEXT', + getvalfunc_in IN VARCHAR2 := 'NTHVAL', + check_startrow_in IN PLS_INTEGER := NULL, + check_endrow_in IN PLS_INTEGER := NULL, + against_startrow_in IN PLS_INTEGER := NULL, + against_endrow_in IN PLS_INTEGER := NULL, + match_rownum_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE isnotnull ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE isnull ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + -- 1.5.2 + PROCEDURE isnotnull ( + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE isnull ( + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + --Check a given call throws a named exception + PROCEDURE throws ( + msg_in VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN VARCHAR2 + ); + + --Check a given call throws an exception with a given SQLCODE + PROCEDURE throws ( + msg_in VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN NUMBER + ); + + PROCEDURE showresults; + + PROCEDURE noshowresults; + + FUNCTION showing_results + RETURN BOOLEAN; + +/* START username:STUDIOUS Date:01/11/2002 Task_id:42690 +Description: Checking whether object exists*/ + + PROCEDURE objExists ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + +PROCEDURE objnotExists ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); +/* END username:STUDIOUS Task_id:42690*/ + + /* START chrisrimmer 42694 */ + FUNCTION previous_passed + RETURN BOOLEAN; + + FUNCTION previous_failed + RETURN BOOLEAN; + /* END chrisrimmer 42694 */ + + /* START chrisrimmer 42696 */ + PROCEDURE eqoutput ( + msg_in IN VARCHAR2, + check_this_in IN DBMS_OUTPUT.CHARARR, + against_this_in IN DBMS_OUTPUT.CHARARR, + ignore_case_in IN BOOLEAN := FALSE, + ignore_whitespace_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqoutput ( + msg_in IN VARCHAR2, + check_this_in IN DBMS_OUTPUT.CHARARR, + against_this_in IN VARCHAR2, + line_delimiter_in IN CHAR := NULL, + ignore_case_in IN BOOLEAN := FALSE, + ignore_whitespace_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ); + /* END chrisrimmer 42696 */ + + /* START VENKY11 45789 */ + PROCEDURE eq_refc_table( + p_msg_nm IN VARCHAR2, + proc_name IN VARCHAR2, + params IN utplsql_util.utplsql_params, + cursor_position IN PLS_INTEGER, + table_name IN VARCHAR2 ); + + PROCEDURE eq_refc_query( + p_msg_nm IN VARCHAR2, + proc_name IN VARCHAR2, + params IN utplsql_util.utplsql_params, + cursor_position IN PLS_INTEGER, + qry IN VARCHAR2 ); + + /* END VENKY11 45789 */ + + +END utassert; +/ diff --git a/source/ut_assert2.pkb b/source/ut_assert2.pkb new file mode 100644 index 000000000..fa613890f --- /dev/null +++ b/source/ut_assert2.pkb @@ -0,0 +1,3737 @@ +CREATE OR REPLACE PACKAGE BODY utassert2 +IS + /* + GNU General Public License for utPLSQL + + Copyright (C) 2000 + Steven Feuerstein, steven@stevenfeuerstein.com + Chris Rimmer, chris@sunset.force9.co.uk + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program (see license.txt); if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + /*Modification History: + chrisrimmer 19-Feb-2002 Added g_previous_pass, previous_passed + and previous_failed + studious:01/20/2002:Assertion for object existance + chrisrimmer 10-Jun-2002 Added eqoutput assertions + Venky 08-AUG-2002 Added refcursor assertions 12345 + */ + + /* START chrisrimmer 42694 */ + g_previous_pass BOOLEAN; + /* END chrisrimmer 42694 */ + + g_showresults BOOLEAN := FALSE ; + c_not_placeholder CONSTANT VARCHAR2 (10) + := '#$NOT$#'; + + -- DBMS_PIPE functionality based on code provided by John Beresniewicz, + -- Savant Corp, in ORACLE BUILT-IN PACKAGES + + -- For pipe equality checking + TYPE msg_rectype IS RECORD ( + item_type INTEGER, + mvc2 VARCHAR2 (4093), + mdt DATE, + mnum NUMBER, + mrid ROWID, + mraw RAW (4093)); + + /* + || msg_tbltype tables can hold an ordered list of + || message items, thus any message can be captured + */ + TYPE msg_tbltype IS TABLE OF msg_rectype + INDEX BY BINARY_INTEGER; + + FUNCTION id (name_in IN ut_assertion.NAME%TYPE) + RETURN ut_assertion.id%TYPE + IS + retval ut_assertion.id%TYPE; + BEGIN + SELECT id + INTO retval + FROM ut_assertion + WHERE NAME = UPPER (name_in); + + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END; + + FUNCTION NAME (id_in IN ut_assertion.id%TYPE) + RETURN ut_assertion.NAME%TYPE + IS + retval ut_assertion.NAME%TYPE; + BEGIN + SELECT NAME + INTO retval + FROM ut_assertion + WHERE id = id_in; + + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END; + + FUNCTION replace_not_placeholder ( + stg_in IN VARCHAR2, + success_in IN BOOLEAN + ) + RETURN VARCHAR2 + IS + BEGIN + IF success_in + THEN + RETURN REPLACE ( + stg_in, + c_not_placeholder, + NULL + ); + ELSE + RETURN REPLACE ( + stg_in, + c_not_placeholder, + ' not ' + ); + END IF; + END; + + PROCEDURE this ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE , + register_in IN BOOLEAN := TRUE + ) + IS + l_failure BOOLEAN + := NOT check_this_in + OR ( check_this_in IS NULL + AND NOT null_ok_in + ); + BEGIN + /* START chrisrimmer 42694 */ + g_previous_pass := NOT l_failure; + + /* END chrisrimmer 42694 */ + + IF utplsql2.tracing + THEN + utplsql.pl ( + 'utPLSQL TRACE on Assert: ' + || msg_in + ); + utplsql.pl ('Results:'); + utplsql.bpl (l_failure); + END IF; + + -- Report results failure and success + + utresult2.report ( + outcome_in, + l_failure, + utplsql.currcase.pkg || '.' || utplsql.currcase.name || ': ' || msg_in, + /* 2.0.10.2 Idea from Alistair Bayley msg_in */ + register_in, + showing_results + ); + + IF raise_exc_in + AND l_failure + THEN + RAISE test_failure; + END IF; + END; + + -- Support success and failure messages + PROCEDURE this ( + outcome_in IN ut_outcome.id%TYPE, + success_msg_in IN VARCHAR2, + failure_msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE , + register_in IN BOOLEAN := TRUE + ) + IS + l_failure BOOLEAN + := NOT check_this_in + OR ( check_this_in IS NULL + AND NOT null_ok_in + ); + BEGIN + IF l_failure + THEN + this ( + outcome_in, + failure_msg_in, + check_this_in, + null_ok_in, + raise_exc_in, + register_in + ); + ELSE + this ( + outcome_in, + success_msg_in, + check_this_in, + null_ok_in, + raise_exc_in, + register_in + ); + END IF; + END; + + FUNCTION expected ( + type_in IN VARCHAR2, + msg_in IN VARCHAR2, + value_in IN VARCHAR2 + ) + RETURN VARCHAR2 + IS + BEGIN + RETURN ( type_in + || ' "' + || msg_in + || '" Result: "' + || value_in + || '"' + ); + END; + + FUNCTION file_descrip ( + file_in IN VARCHAR2, + dir_in IN VARCHAR2 + ) + RETURN VARCHAR2 + IS + BEGIN + RETURN file_in + || '" located in "' + || dir_in; + END; + + FUNCTION message_expected ( + type_in IN VARCHAR2, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2 + ) + RETURN VARCHAR2 + IS + BEGIN + RETURN ( type_in + || ' "' + || msg_in + || '" Expected "' + || against_this_in + || '" and got "' + || check_this_in + || '"' + ); + END; + + FUNCTION message ( + type_in IN VARCHAR2, + msg_in IN VARCHAR2, + value_in IN VARCHAR2 + ) + RETURN VARCHAR2 + IS + BEGIN + RETURN ( type_in + || ' "' + || msg_in + || '" Result: ' + || value_in + ); + END; + + -- Convert outcome name to ID. + PROCEDURE get_id ( + outcome_in IN ut_outcome.NAME%TYPE, + outcome_out OUT ut_outcome.id%TYPE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + l_id := utoutcome.id (outcome_in); + + IF l_id IS NULL + THEN + IF utplsql2.tracing + THEN + utplsql.pl ( + 'Outcome ' + || outcome_in + || ' is not defined.' + ); + END IF; + + utrerror.oc_report ( + run_in=> utplsql2.runnum, + outcome_in=> NULL, + errcode_in=> utrerror.undefined_outcome, + errtext_in=> 'Outcome "' + || outcome_in + || '" is not defined.' + ); + ELSE + outcome_out := l_id; + END IF; + END; + + -- 2.0.8 General evaluation mechanism + PROCEDURE eval ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + using_in IN VARCHAR2, -- The expression + value_name_in IN value_name_tt, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE + ) + IS + fdbk PLS_INTEGER; + cur PLS_INTEGER + := DBMS_SQL.open_cursor; + eval_result CHAR (1); + eval_block utplsql.maxvc2_t; -- Clear issues of size limitation! + value_name_str utplsql.maxvc2_t; + eval_description utplsql.maxvc2_t; + parse_error EXCEPTION; + BEGIN + IF utplsql2.tracing + THEN + -- Optional trace of assertion call. + --utplsql.pl (); + NULL; + END IF; + + FOR indx IN + value_name_in.FIRST .. value_name_in.LAST + LOOP + value_name_str := + value_name_str + || ' ' + || NVL ( + value_name_in (indx).NAME, + 'P' + || indx + ) + || ' = ' + || value_name_in (indx).VALUE; + END LOOP; + + eval_description := 'Evaluation of "' + || using_in + || '" with' + || value_name_str; + eval_block := + 'DECLARE + b_result BOOLEAN; + BEGIN + b_result := ' + || using_in + || '; + IF b_result THEN :result := ''' + || utplsql.c_yes + || '''; ' + || 'ELSIF NOT b_result THEN :result := ''' + || utplsql.c_no + || '''; ' + || 'ELSE :result := NULL; + END IF; + END;'; + + BEGIN + DBMS_SQL.parse ( + cur, + eval_block, + DBMS_SQL.native + ); + EXCEPTION + WHEN OTHERS + THEN + -- Report the parse error! + IF DBMS_SQL.is_open (cur) + THEN + DBMS_SQL.close_cursor (cur); + END IF; + + this ( + outcome_in=> outcome_in, + success_msg_in=> NULL, + failure_msg_in=> 'Error ' + || SQLCODE + || ' parsing ' + || eval_block, + check_this_in=> FALSE , + null_ok_in=> null_ok_in, + raise_exc_in=> raise_exc_in + ); + RAISE parse_error; + END; + + FOR indx IN + value_name_in.FIRST .. value_name_in.LAST + LOOP + DBMS_SQL.bind_variable ( + cur, + NVL ( + value_name_in (indx).NAME, + 'P' + || indx + ), + value_name_in (indx).VALUE + ); + END LOOP; + + DBMS_SQL.bind_variable (cur, 'result', 'a'); + fdbk := DBMS_SQL.EXECUTE (cur); + DBMS_SQL.variable_value ( + cur, + 'result', + eval_result + ); + DBMS_SQL.close_cursor (cur); + this ( + outcome_in=> outcome_in, + success_msg_in=> eval_description + || ' evaluated to TRUE', + failure_msg_in=> eval_description + || ' evaluated to FALSE', + check_this_in=> utplsql.vc2bool ( + eval_result + ), + null_ok_in=> null_ok_in, + raise_exc_in=> raise_exc_in + ); + EXCEPTION + WHEN parse_error + THEN + IF raise_exc_in + THEN + RAISE; + ELSE + NULL; + END IF; + WHEN OTHERS + THEN + IF DBMS_SQL.is_open (cur) + THEN + DBMS_SQL.close_cursor (cur); + END IF; + + -- Likely the block got too large! + this ( + outcome_in=> outcome_in, + success_msg_in=> NULL, + failure_msg_in=> 'Error in ' + || eval_description + || ' SQLERRM: ' + || SQLERRM, + check_this_in=> FALSE , + null_ok_in=> null_ok_in, + raise_exc_in=> raise_exc_in + ); + END; + + PROCEDURE eval ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + using_in IN VARCHAR2, -- The expression + value_name_in IN value_name_tt, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + eval ( + l_id, + msg_in, + using_in, + value_name_in, + null_ok_in, + raise_exc_in + ); + END; + + /* + Template Assertion program + + PROCEDURE ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + BEGIN + IF utplsql2.tracing + THEN + -- Optional trace of assertion call. + utplsql.pl (); + END IF; + + this ( + outcome_in => outcome_in, + success_msg_in => + , + failure_msg_in => + , + check_this_in => + , + null_ok_in => FALSE, + raise_exc_in => raise_exc_in + ); + END; + + You might find the message_expected private program useful in + constructing your message. Also the replace_not_placeholder and + c_not_placeholder may come in handy if you want to use the this + assertion program that accepts just a single message, as many + of the original assertion programs do. + + */ + + PROCEDURE eq ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE + ) + IS + BEGIN + IF utplsql2.tracing + THEN + utplsql.pl ( + 'EQ Compare "' + || check_this_in + || '" to "' + || against_this_in + || '"' + ); + END IF; + + this ( + outcome_in=> outcome_in, + msg_in=> message_expected ( + 'EQ', + msg_in, + check_this_in, + against_this_in + ), + check_this_in=> (NVL ( + check_this_in = + against_this_in, + FALSE + ) + ) + OR ( check_this_in IS NULL + AND against_this_in IS NULL + AND null_ok_in + ), + null_ok_in=> FALSE , + raise_exc_in=> raise_exc_in + ); + END; + + FUNCTION b2v (bool_in IN BOOLEAN) + RETURN VARCHAR2 + IS + BEGIN + IF bool_in + THEN + RETURN 'TRUE'; + ELSIF NOT bool_in + THEN + RETURN 'FALSE'; + ELSE + RETURN 'NULL'; + END IF; + END; + + PROCEDURE eq ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + against_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE + ) + IS + BEGIN + IF utplsql2.tracing + THEN + utplsql.pl ( + 'Compare "' + || b2v (check_this_in) + || '" to "' + || b2v (against_this_in) + || '"' + ); + END IF; + + this ( + outcome_in, + message_expected ( + 'EQ', + msg_in, + utplsql.bool2vc (check_this_in), + utplsql.bool2vc (against_this_in) + ), + (check_this_in = against_this_in) + OR ( check_this_in IS NULL + AND against_this_in IS NULL + AND null_ok_in + ), + FALSE , + raise_exc_in + ); + END; + + PROCEDURE eq ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN DATE, + against_this_in IN DATE, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE , + truncate_in IN BOOLEAN := FALSE + ) + IS + c_format CONSTANT VARCHAR2 (30) + := 'MONTH DD, YYYY HH24MISS'; + v_check VARCHAR2 (100); + v_against VARCHAR2 (100); + BEGIN + IF truncate_in + THEN + v_check := TO_CHAR ( + TRUNC (check_this_in), + c_format + ); + v_against := + TO_CHAR ( + TRUNC (against_this_in), + c_format + ); + ELSE + v_check := + TO_CHAR (check_this_in, c_format); + v_against := + TO_CHAR (against_this_in, c_format); + END IF; + + IF utplsql2.tracing + THEN + utplsql.pl ( + 'Compare "' + || v_check + || '" to "' + || v_against + || '"' + ); + END IF; + + this ( + outcome_in, + message_expected ( + 'EQ', + msg_in, + TO_CHAR ( + check_this_in, + 'MON-DD-YYYY HH:MI:SS' + ), + TO_CHAR ( + against_this_in, + 'MON-DD-YYYY HH:MI:SS' + ) + ), + (check_this_in = against_this_in) + OR ( check_this_in IS NULL + AND against_this_in IS NULL + AND null_ok_in + ), + FALSE , + raise_exc_in + ); + END; + + PROCEDURE ieqminus ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + query1_in IN VARCHAR2, + query2_in IN VARCHAR2, + minus_desc_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + &start73 + fdbk PLS_INTEGER; + cur PLS_INTEGER + := DBMS_SQL.open_cursor; + &end73 + ival PLS_INTEGER; + /* 2.0.8 suggested replacement below by Chris Rimmer +to avoid duplicate column name issues +:= 'DECLARE + CURSOR cur IS (' +|| query1_in +|| ' MINUS ' +|| query2_in +|| ') +UNION +(' +|| query2_in +|| ' MINUS ' +|| query1_in +|| '); */ + v_block VARCHAR2 (32767) + := 'DECLARE + CURSOR cur IS + SELECT 1 + FROM DUAL + WHERE EXISTS ((' + || query1_in + || ' MINUS ' + || query2_in + || ') + UNION + (' + || query2_in + || ' MINUS ' + || query1_in + || ')); + rec cur%ROWTYPE; + BEGIN + OPEN cur; + FETCH cur INTO rec; + IF cur%FOUND + THEN + :retval := 1; + ELSE + :retval := 0; + END IF; + CLOSE cur; + END;'; + BEGIN + &start81 + EXECUTE IMMEDIATE v_block USING OUT ival; + &end81 + &start73 + DBMS_SQL.parse ( + cur, + v_block, + DBMS_SQL.native + ); + DBMS_SQL.bind_variable ( + cur, + ':retval', + ival + ); + -- 1.5.6 + fdbk := DBMS_SQL.EXECUTE (cur); + DBMS_SQL.variable_value ( + cur, + 'retval', + ival + ); + DBMS_SQL.close_cursor (cur); + &end73 + + this ( + outcome_in, + replace_not_placeholder ( + msg_in, + ival = 0 + ), + ival = 0, + FALSE , + raise_exc_in + ); + EXCEPTION + WHEN OTHERS + THEN + &start73 + DBMS_SQL.close_cursor (cur); + &end73 + + + this ( + outcome_in, + replace_not_placeholder ( + msg_in + || ' SQL Failure: ' + || SQLERRM, + SQLCODE = 0 + ), + SQLCODE = 0, + FALSE , + raise_exc_in + ); + END; + + PROCEDURE eqtable ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + check_where_in IN VARCHAR2 := NULL, + against_where_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + CURSOR info_cur ( + sch_in IN VARCHAR2, + tab_in IN VARCHAR2 + ) + IS + SELECT t.column_name + FROM all_tab_columns t + WHERE t.owner = sch_in + AND t.table_name = tab_in + ORDER BY column_id; + + FUNCTION collist (tab IN VARCHAR2) + RETURN VARCHAR2 + IS + l_schema VARCHAR2 (100); + l_table VARCHAR2 (100); + l_dot PLS_INTEGER + := INSTR (tab, '.'); + retval VARCHAR2 (32767); + BEGIN + IF l_dot = 0 + THEN + l_schema := USER; + l_table := UPPER (tab); + ELSE + l_schema := UPPER ( + SUBSTR ( + tab, + 1, + l_dot + - 1 + ) + ); + l_table := + UPPER (SUBSTR (tab, l_dot + + 1)); + END IF; + + FOR rec IN info_cur (l_schema, l_table) + LOOP + retval := + retval + || ',' + || rec.column_name; + END LOOP; + + RETURN LTRIM (retval, ','); + END; + BEGIN + ieqminus ( + outcome_in, + message ( + 'EQTABLE', + msg_in, + 'Contents of "' + || check_this_in + || utplsql.ifelse ( + check_where_in IS NULL, + '"', + '" WHERE ' + || check_where_in + ) + || ' does ' + || c_not_placeholder -- utplsql.ifelse (NOT l_failure, NULL, ' not ') + || 'match "' + || against_this_in + || utplsql.ifelse ( + against_where_in IS NULL, + '"', + '" WHERE ' + || against_where_in + ) + ), + 'SELECT T1.*, COUNT(*) FROM ' + || check_this_in + || ' T1 WHERE ' + || NVL (check_where_in, '1=1') + || ' GROUP BY ' + || collist (check_this_in), + 'SELECT T2.*, COUNT(*) FROM ' + || against_this_in + || ' T2 WHERE ' + || NVL (against_where_in, '1=1') + || ' GROUP BY ' + || collist (against_this_in), + 'Table Equality', + raise_exc_in + ); + END; + + PROCEDURE eqtabcount ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + check_where_in IN VARCHAR2 := NULL, + against_where_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + ival PLS_INTEGER; + BEGIN + ieqminus ( + outcome_in, + message ( + 'EQTABCOUNT', + msg_in, + 'Row count of "' + || check_this_in + || utplsql.ifelse ( + check_where_in IS NULL, + '"', + '" WHERE ' + || check_where_in + ) + || ' does ' + || c_not_placeholder -- utplsql.ifelse (NOT l_failure, NULL, ' not ') + || 'match that of "' + || against_this_in + || utplsql.ifelse ( + against_where_in IS NULL, + '"', + '" WHERE ' + || against_where_in + ) + ), + 'SELECT COUNT(*) FROM ' + || check_this_in + || ' WHERE ' + || NVL (check_where_in, '1=1'), + 'SELECT COUNT(*) FROM ' + || against_this_in + || ' WHERE ' + || NVL (against_where_in, '1=1'), + 'Table Count Equality', + raise_exc_in + ); + END; + + PROCEDURE eqquery ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + -- User passes in two SELECT statements. Use NDS to minus them. + ival PLS_INTEGER; + BEGIN + ieqminus ( + outcome_in, + message ( + 'EQQUERY', + msg_in, + 'Result set for "' + || check_this_in + || ' does ' + || c_not_placeholder -- utplsql.ifelse (NOT l_failure, NULL, ' not ') + || 'match that of "' + || against_this_in + || '"' + ), + check_this_in, + against_this_in, + 'Query Equality', + raise_exc_in + ); + END; + + --Check a query against a single VARCHAR2 value + PROCEDURE eqqueryvalue ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_value VARCHAR2 (2000); + l_success BOOLEAN; + + &start81 + TYPE cv_t IS REF CURSOR; + + cv cv_t; + &end81 + &start73 + cur PLS_INTEGER + := DBMS_SQL.open_cursor; + fdbk PLS_INTEGER; + &end73 + + BEGIN + IF utplsql2.tracing + THEN + utplsql.pl ( + 'V EQQueryValue Compare "' + || check_query_in + || '" to "' + || against_value_in + || '"' + ); + END IF; + + &start81 + OPEN cv FOR check_query_in; + FETCH cv INTO l_value; + CLOSE cv; + &end81 + &start73 + DBMS_SQL.parse ( + cur, + check_query_in, + DBMS_SQL.native + ); + DBMS_SQL.define_column (cur, 1, 'a', 2000); + fdbk := DBMS_SQL.execute_and_fetch (cur); + DBMS_SQL.column_value (cur, 1, l_value); + DBMS_SQL.close_cursor (cur); + &end73 + l_success := + (l_value = against_value_in) + OR ( l_value IS NULL + AND against_value_in IS NULL + AND null_ok_in + ); + this ( + outcome_in, + message ( + 'EQQUERYVALUE', + msg_in, + 'Query "' + || check_query_in + || '" returned value "' + || l_value + || '" that does ' + || utplsql.ifelse ( + l_success, + NULL, + ' not ' + ) + || 'match "' + || against_value_in + || '"' + ), + l_success, + FALSE , + raise_exc_in + ); + /* For now ignore this condition. + How do we handle two assertions inside a single assertion call? + utAssert2.this (outcome_in, msg_in => || + msg_in || + ''' || ''; Got multiple values'', + check_this_in => FALSE, + raise_exc_in => ' || + b2v (raise_exc_in) || + '); + */ + END; + + PROCEDURE eqqueryvalue ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN DATE, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_value DATE; + l_success BOOLEAN; + + &start81 + TYPE cv_t IS REF CURSOR; + + cv cv_t; + &end81 + &start73 + cur PLS_INTEGER + := DBMS_SQL.open_cursor; + fdbk PLS_INTEGER; + &end73 + + BEGIN + IF utplsql2.tracing + THEN + utplsql.pl ( + 'D EQQueryValue Compare "' + || check_query_in + || '" to "' + || against_value_in + || '"' + ); + END IF; + + &start81 + OPEN cv FOR check_query_in; + FETCH cv INTO l_value; + CLOSE cv; + &end81 + &start73 + DBMS_SQL.parse ( + cur, + check_query_in, + DBMS_SQL.native + ); + DBMS_SQL.define_column (cur, 1, l_value); + fdbk := DBMS_SQL.execute_and_fetch (cur); + DBMS_SQL.column_value (cur, 1, l_value); + DBMS_SQL.close_cursor (cur); + &end73 + l_success := + (l_value = against_value_in) + OR ( l_value IS NULL + AND against_value_in IS NULL + AND null_ok_in + ); + this ( + outcome_in, + message ( + 'EQQUERYVALUE', + msg_in, + 'Query "' + || check_query_in + || '" returned value "' + || TO_CHAR ( + l_value, + 'DD-MON-YYYY HH24:MI:SS' + ) + || '" that does ' + || utplsql.ifelse ( + l_success, + NULL, + ' not ' + ) + || 'match "' + || TO_CHAR ( + against_value_in, + 'DD-MON-YYYY HH24:MI:SS' + ) + || '"' + ), + l_success, + FALSE , + raise_exc_in, + TRUE + ); + /* For now ignore this condition. + How do we handle two assertions inside a single assertion call? + utAssert2.this (outcome_in, msg_in => || + msg_in || + ''' || ''; Got multiple values'', + check_this_in => FALSE, + raise_exc_in => ' || + b2v (raise_exc_in) || + '); + */ + END; + + --Check a query against a single VARCHAR2 value + PROCEDURE eqqueryvalue ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN NUMBER, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_value NUMBER; + l_success BOOLEAN; + + &start81 + + TYPE cv_t IS REF CURSOR; + + cv cv_t; + &end81 + &start73 + cur PLS_INTEGER + := DBMS_SQL.open_cursor; + fdbk PLS_INTEGER; + &end73 + + BEGIN + IF utplsql2.tracing + THEN + utplsql.pl ( + 'N EQQueryValue Compare "' + || check_query_in + || '" to "' + || against_value_in + || '"' + ); + END IF; + + &start81 + OPEN cv FOR check_query_in; + FETCH cv INTO l_value; + CLOSE cv; + &end81 + &start73 + DBMS_SQL.parse ( + cur, + check_query_in, + DBMS_SQL.native + ); + DBMS_SQL.define_column (cur, 1, 1); + fdbk := DBMS_SQL.execute_and_fetch (cur); + DBMS_SQL.column_value (cur, 1, l_value); + DBMS_SQL.close_cursor (cur); + &end73 + + l_success := + (l_value = against_value_in) + OR ( l_value IS NULL + AND against_value_in IS NULL + AND null_ok_in + ); + this ( + outcome_in, + message ( + 'EQQUERYVALUE', + msg_in, + 'Query "' + || check_query_in + || '" returned value "' + || l_value + || '" that does ' + || utplsql.ifelse ( + l_success, + NULL, + ' not ' + ) + || 'match "' + || against_value_in + || '"' + ), + l_success, + FALSE , + raise_exc_in, + TRUE + ); + /* For now ignore this condition. + How do we handle two assertions inside a single assertion call? + utAssert2.this (outcome_in, msg_in => || + msg_in || + ''' || ''; Got multiple values'', + check_this_in => FALSE, + raise_exc_in => ' || + b2v (raise_exc_in) || + '); + */ + END; + + PROCEDURE eqcursor ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ) + -- User passes in names of two packaged cursors. + -- Have to loop through each row and compare! + -- How do I compare the contents of two records + -- which have been defined dynamically? + IS + BEGIN + utplsql.pl ( + 'utAssert.eqCursor is not yet implemented!' + ); + END; + + PROCEDURE eqfile ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + check_this_dir_in IN VARCHAR2, + against_this_in IN VARCHAR2, + against_this_dir_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + checkid UTL_FILE.file_type; + againstid UTL_FILE.file_type; + samefiles BOOLEAN := TRUE ; + checkline VARCHAR2 (32767); + diffline VARCHAR2 (32767); + againstline VARCHAR2 (32767); + check_eof BOOLEAN; + against_eof BOOLEAN; + diffline_set BOOLEAN; + nth_line PLS_INTEGER := 1; + cant_open_check_file EXCEPTION; + cant_open_against_file EXCEPTION; + + PROCEDURE cleanup ( + val IN BOOLEAN, + line_in IN VARCHAR2 := NULL, + line_set_in IN BOOLEAN := FALSE , + linenum_in IN PLS_INTEGER := NULL, + msg_in IN VARCHAR2 + ) + IS + BEGIN + UTL_FILE.fclose (checkid); + UTL_FILE.fclose (againstid); + this ( + outcome_in, + message ( + 'EQFILE', + msg_in, + utplsql.ifelse ( + line_set_in, + ' Line ' + || linenum_in + || ' of ', + NULL + ) + || 'File "' + || file_descrip ( + check_this_in, + check_this_dir_in + ) + || '" does ' + || utplsql.ifelse ( + val, + NULL, + ' not ' + ) + || 'match "' + || file_descrip ( + against_this_in, + against_this_dir_in + ) + || '".' + ), + val, + FALSE , + raise_exc_in, + TRUE + ); + END; + BEGIN + -- Compare contents of two files. + BEGIN + checkid := + UTL_FILE.fopen ( + check_this_dir_in, + check_this_in, + 'R' &start81, max_linesize => 32767 &end81 + ); + EXCEPTION + WHEN OTHERS + THEN + RAISE cant_open_check_file; + END; + + BEGIN + againstid := + UTL_FILE.fopen ( + NVL ( + against_this_dir_in, + check_this_dir_in + ), + against_this_in, + 'R' + &start81, max_linesize => 32767 &end81 + ); + EXCEPTION + WHEN OTHERS + THEN + RAISE cant_open_against_file; + END; + + LOOP + BEGIN + UTL_FILE.get_line ( + checkid, + checkline + ); + EXCEPTION + WHEN NO_DATA_FOUND + THEN + check_eof := TRUE ; + END; + + BEGIN + UTL_FILE.get_line ( + againstid, + againstline + ); + EXCEPTION + WHEN NO_DATA_FOUND + THEN + against_eof := TRUE ; + END; + + IF ( check_eof + AND against_eof + ) + THEN + samefiles := TRUE ; + EXIT; + ELSIF (checkline != againstline) + THEN + diffline := checkline; + diffline_set := TRUE ; + samefiles := FALSE ; + EXIT; + ELSIF ( check_eof + OR against_eof + ) + THEN + samefiles := FALSE ; + EXIT; + END IF; + + IF samefiles + THEN + nth_line := nth_line + + 1; + END IF; + END LOOP; + + cleanup ( + samefiles, + diffline, + diffline_set, + nth_line, + msg_in + ); + EXCEPTION + WHEN cant_open_check_file + THEN + cleanup ( + FALSE , + msg_in=> 'Unable to open ' + || file_descrip ( + check_this_in, + check_this_dir_in + ) + ); + WHEN cant_open_against_file + THEN + cleanup ( + FALSE , + msg_in=> 'Unable to open ' + || file_descrip ( + against_this_in, + NVL ( + against_this_dir_in, + check_this_dir_in + ) + ) + ); + WHEN OTHERS + THEN + cleanup (FALSE , msg_in => msg_in); + END; + + PROCEDURE receive_and_unpack ( + pipe_in IN VARCHAR2, + msg_tbl_out OUT msg_tbltype, + pipe_status_out IN OUT PLS_INTEGER + ) + IS + invalid_item_type EXCEPTION; + null_msg_tbl msg_tbltype; + next_item INTEGER; + item_count INTEGER := 0; + BEGIN + pipe_status_out := + DBMS_PIPE.receive_message ( + pipe_in, + TIMEOUT=> 0 + ); + + IF pipe_status_out != 0 + THEN + RAISE invalid_item_type; + END IF; + + LOOP + next_item := DBMS_PIPE.next_item_type; + EXIT WHEN next_item = 0; + item_count := item_count + + 1; + msg_tbl_out (item_count).item_type := + next_item; + + IF next_item = 9 + THEN + DBMS_PIPE.unpack_message ( + msg_tbl_out (item_count).mvc2 + ); + ELSIF next_item = 6 + THEN + DBMS_PIPE.unpack_message ( + msg_tbl_out (item_count).mnum + ); + ELSIF next_item = 11 + THEN + DBMS_PIPE.unpack_message_rowid ( + msg_tbl_out (item_count).mrid + ); + ELSIF next_item = 12 + THEN + DBMS_PIPE.unpack_message ( + msg_tbl_out (item_count).mdt + ); + ELSIF next_item = 23 + THEN + DBMS_PIPE.unpack_message_raw ( + msg_tbl_out (item_count).mraw + ); + ELSE + RAISE invalid_item_type; + END IF; + + next_item := DBMS_PIPE.next_item_type; + END LOOP; + EXCEPTION + WHEN invalid_item_type + THEN + msg_tbl_out := null_msg_tbl; + END receive_and_unpack; + + PROCEDURE compare_pipe_tabs ( + tab1 msg_tbltype, + tab2 msg_tbltype, + same_out IN OUT BOOLEAN + ) + IS + indx PLS_INTEGER := tab1.FIRST; + BEGIN + LOOP + EXIT WHEN indx IS NULL; + + BEGIN + IF tab1 (indx).item_type = 9 + THEN + same_out := tab1 (indx).mvc2 = + tab2 (indx).mvc2; + ELSIF tab1 (indx).item_type = 6 + THEN + same_out := tab1 (indx).mnum = + tab2 (indx).mnum; + ELSIF tab1 (indx).item_type = 12 + THEN + same_out := tab1 (indx).mdt = + tab2 (indx).mdt; + ELSIF tab1 (indx).item_type = 11 + THEN + same_out := tab1 (indx).mrid = + tab2 (indx).mrid; + ELSIF tab1 (indx).item_type = 23 + THEN + same_out := tab1 (indx).mraw = + tab2 (indx).mraw; + END IF; + EXCEPTION + WHEN OTHERS + THEN + same_out := FALSE ; + END; + + EXIT WHEN NOT same_out; + indx := tab1.NEXT (indx); + END LOOP; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + same_out := FALSE ; + END; + + PROCEDURE eqpipe ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + check_tab msg_tbltype; + against_tab msg_tbltype; + check_status PLS_INTEGER; + against_status PLS_INTEGER; + same_message BOOLEAN := FALSE ; + msgset BOOLEAN; + msgnum PLS_INTEGER; + nthmsg PLS_INTEGER := 1; + BEGIN + -- Compare contents of two pipes. + LOOP + receive_and_unpack ( + check_this_in, + check_tab, + check_status + ); + receive_and_unpack ( + against_this_in, + against_tab, + against_status + ); + + IF ( check_status = 0 + AND against_status = 0 + ) + THEN + compare_pipe_tabs ( + check_tab, + against_tab, + same_message + ); + + IF NOT same_message + THEN + msgset := TRUE ; + msgnum := nthmsg; + EXIT; + END IF; + + EXIT WHEN NOT same_message; + ELSIF ( check_status = 1 + AND against_status = 1 + ) -- time out + THEN + same_message := TRUE ; + EXIT; + ELSE + same_message := FALSE ; + EXIT; + END IF; + + nthmsg := nthmsg + + 1; + END LOOP; + + this ( + outcome_in, + message ( + 'EQPIPE', + msg_in, + utplsql.ifelse ( + msgset, + ' Message ' + || msgnum + || ' of ', + NULL + ) + || 'Pipe "' + || check_this_in + || '" does ' + || utplsql.ifelse ( + same_message, + NULL, + ' not ' + ) + || 'match "' + || against_this_in + || '".' + ), + same_message, + FALSE , + raise_exc_in, + TRUE + ); + END; + + FUNCTION numfromstr (str IN VARCHAR2) + RETURN NUMBER + IS + sqlstr VARCHAR2 (1000) + := 'begin :val := ' + || str + || '; end;'; + &start73 + fdbk PLS_INTEGER; + cur PLS_INTEGER + := DBMS_SQL.open_cursor; + &end73 + retval NUMBER; + BEGIN + &start81 + EXECUTE IMMEDIATE sqlstr USING OUT retval; + &end81 + &start73 + DBMS_SQL.parse ( + cur, + sqlstr, + DBMS_SQL.native + ); + fdbk := DBMS_SQL.EXECUTE (cur); + DBMS_SQL.variable_value (cur, 'val', retval); + DBMS_SQL.close_cursor (cur); + &end73 + RETURN retval; + EXCEPTION + WHEN OTHERS + THEN + &start73 + DBMS_SQL.close_cursor (cur); + &end73 + RAISE; + END; + + PROCEDURE validatecoll ( + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + valid_out IN OUT BOOLEAN, + msg_out OUT VARCHAR2, + countproc_in IN VARCHAR2 + := 'COUNT', + firstrowproc_in IN VARCHAR2 + := 'FIRST', + lastrowproc_in IN VARCHAR2 + := 'LAST', + check_startrow_in IN PLS_INTEGER + := NULL, + check_endrow_in IN PLS_INTEGER + := NULL, + against_startrow_in IN PLS_INTEGER + := NULL, + against_endrow_in IN PLS_INTEGER + := NULL, + match_rownum_in IN BOOLEAN + := FALSE , + null_ok_in IN BOOLEAN + := TRUE , + raise_exc_in IN BOOLEAN + := FALSE , + null_and_valid IN OUT BOOLEAN + ) + IS + dynblock VARCHAR2 (32767); + v_matchrow CHAR (1) := 'N'; + badc PLS_INTEGER; + bada PLS_INTEGER; + badtext VARCHAR2 (32767); + eqcheck VARCHAR2 (32767); + BEGIN + valid_out := TRUE ; + null_and_valid := FALSE ; + + IF numfromstr ( + check_this_in + || '.' + || countproc_in + ) = 0 + AND numfromstr ( + against_this_in + || '.' + || countproc_in + ) = 0 + THEN + IF NOT null_ok_in + THEN + valid_out := FALSE ; + msg_out := 'Invalid NULL collections'; + ELSE + /* Empty and valid collections. We are done... */ + null_and_valid := TRUE ; + END IF; + END IF; + + IF valid_out + AND NOT null_and_valid + THEN + IF match_rownum_in + THEN + valid_out := + NVL ( + numfromstr ( + check_this_in + || '.' + || firstrowproc_in + ) = + numfromstr ( + against_this_in + || '.' + || firstrowproc_in + ), + FALSE + ); + + IF NOT valid_out + THEN + msg_out := + 'Different starting rows in ' + || check_this_in + || ' and ' + || against_this_in; + ELSE + valid_out := + NVL ( + numfromstr ( + check_this_in + || '.' + || lastrowproc_in + ) != + numfromstr ( + against_this_in + || '.' + || lastrowproc_in + ), + FALSE + ); + + IF NOT valid_out + THEN + msg_out := + 'Different ending rows in ' + || check_this_in + || ' and ' + || against_this_in; + END IF; + END IF; + END IF; + + IF valid_out + THEN + valid_out := + NVL ( + numfromstr ( + check_this_in + || '.' + || countproc_in + ) = + numfromstr ( + against_this_in + || '.' + || countproc_in + ), + FALSE + ); + + IF NOT valid_out + THEN + msg_out := + 'Different number of rows in ' + || check_this_in + || ' and ' + || against_this_in; + END IF; + END IF; + END IF; + END; + + FUNCTION dyncollstr ( + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + eqfunc_in IN VARCHAR2, + countproc_in IN VARCHAR2, + firstrowproc_in IN VARCHAR2, + lastrowproc_in IN VARCHAR2, + nextrowproc_in IN VARCHAR2, + getvalfunc_in IN VARCHAR2 + ) + RETURN VARCHAR2 + IS + eqcheck VARCHAR2 (32767); + v_check VARCHAR2 (100) := check_this_in; + v_against VARCHAR2 (100) + := against_this_in; + BEGIN + IF getvalfunc_in IS NOT NULL + THEN + v_check := + v_check + || '.' + || getvalfunc_in; + v_against := + v_against + || '.' + || getvalfunc_in; + END IF; + + IF eqfunc_in IS NULL + THEN + eqcheck := '(' + || v_check + || '(cindx) = ' + || v_against + || ' (aindx)) OR ' + || '(' + || v_check + || '(cindx) IS NULL AND ' + || v_against + || ' (aindx) IS NULL)'; + ELSE + eqcheck := eqfunc_in + || '(' + || v_check + || '(cindx), ' + || v_against + || '(aindx))'; + END IF; + + RETURN ( 'DECLARE + cindx PLS_INTEGER; + aindx PLS_INTEGER; + cend PLS_INTEGER := NVL (:cendit, ' + || check_this_in + || '.' + || lastrowproc_in + || '); + aend PLS_INTEGER := NVL (:aendit, ' + || against_this_in + || '.' + || lastrowproc_in + || '); + different_collections exception; + + PROCEDURE setfailure ( + str IN VARCHAR2, + badc IN PLS_INTEGER, + bada IN PLS_INTEGER, + raiseexc IN BOOLEAN := TRUE) + IS + BEGIN + :badcindx := badc; + :badaindx := bada; + :badreason := str; + IF raiseexc THEN RAISE different_collections; END IF; + END; + BEGIN + cindx := NVL (:cstartit, ' + || check_this_in + || '.' + || firstrowproc_in + || '); + aindx := NVL (:astartit, ' + || against_this_in + || '.' + || firstrowproc_in + || '); + + LOOP + IF cindx IS NULL AND aindx IS NULL + THEN + EXIT; + + ELSIF cindx IS NULL and aindx IS NOT NULL + THEN + setfailure ( + ''Check index NULL, Against index NOT NULL'', cindx, aindx); + + ELSIF aindx IS NULL + THEN + setfailure ( + ''Check index NOT NULL, Against index NULL'', cindx, aindx); + END IF; + + IF :matchit = ''Y'' + AND cindx != aindx + THEN + setfailure (''Mismatched row numbers'', cindx, aindx); + END IF; + + BEGIN + IF ' + || eqcheck + || ' + THEN + NULL; + ELSE + setfailure (''Mismatched row values'', cindx, aindx); + END IF; + EXCEPTION + WHEN OTHERS + THEN + setfailure (''On EQ check: ' + || eqcheck + || ''' || '' '' || SQLERRM, cindx, aindx); + END; + + cindx := ' + || check_this_in + || '.' + || nextrowproc_in + || '(cindx); + aindx := ' + || against_this_in + || '.' + || nextrowproc_in + || '(aindx); + END LOOP; + EXCEPTION + WHEN OTHERS THEN + IF :badcindx IS NULL and :badaindx IS NULL + THEN setfailure (SQLERRM, cindx, aindx, FALSE); + END IF; + END;' + ); + END; + + FUNCTION collection_message ( + collapi_in IN BOOLEAN, + msg_in IN VARCHAR2, + chkcoll_in IN VARCHAR2, + chkrow_in IN INTEGER, + agcoll_in IN VARCHAR2, + agrow_in IN INTEGER, + success_in IN BOOLEAN + ) + RETURN VARCHAR2 + IS + assert_name VARCHAR2 (100) := 'EQCOLL'; + BEGIN + IF collapi_in + THEN + assert_name := 'EQCOLLAPI'; + END IF; + + RETURN message ( + assert_name, + msg_in, + utplsql.ifelse ( + success_in, + NULL, + ' Row ' + || NVL ( + TO_CHAR (agrow_in), + '*UNDEFINED*' + ) + || ' of ' + ) + || 'Collection "' + || agcoll_in + || '" does ' + || utplsql.ifelse ( + success_in, + NULL, + ' not ' + ) + || 'match ' + || utplsql.ifelse ( + success_in, + NULL, + ' Row ' + || NVL ( + TO_CHAR (chkrow_in), + '*UNDEFINED*' + ) + || ' of ' + ) + || chkcoll_in + || '".' + ); + END; + + PROCEDURE eqcoll ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + eqfunc_in IN VARCHAR2 := NULL, + check_startrow_in IN PLS_INTEGER + := NULL, + check_endrow_in IN PLS_INTEGER + := NULL, + against_startrow_in IN PLS_INTEGER + := NULL, + against_endrow_in IN PLS_INTEGER + := NULL, + match_rownum_in IN BOOLEAN := FALSE , + null_ok_in IN BOOLEAN := TRUE , + raise_exc_in IN BOOLEAN := FALSE + ) + IS + dynblock VARCHAR2 (32767); + v_matchrow CHAR (1) := 'N'; + valid_interim BOOLEAN; + invalid_interim_msg VARCHAR2 (4000); + badc PLS_INTEGER; + bada PLS_INTEGER; + badtext VARCHAR2 (32767); + null_and_valid BOOLEAN := FALSE ; + &start73 + fdbk PLS_INTEGER; + cur PLS_INTEGER + := DBMS_SQL.open_cursor; + &end73 + + BEGIN + validatecoll ( + msg_in, + check_this_in, + against_this_in, + valid_interim, + invalid_interim_msg, + 'COUNT', + 'FIRST', + 'LAST', + check_startrow_in, + check_endrow_in, + against_startrow_in, + against_endrow_in, + match_rownum_in, + null_ok_in, + raise_exc_in, + null_and_valid + ); + + IF NOT valid_interim + THEN + -- Failure on interim step. Flag and skip rest of processing + this ( + outcome_in, + collection_message ( + FALSE , + msg_in + || ' - ' + || invalid_interim_msg, + check_this_in, + NULL, + against_this_in, + NULL, + FALSE + ), + FALSE , + FALSE , + raise_exc_in, + TRUE + ); + ELSE + -- We have some data to compare. + IF NOT null_and_valid + THEN + IF match_rownum_in + THEN + v_matchrow := 'Y'; + END IF; + + dynblock := + dyncollstr ( + check_this_in, + against_this_in, + eqfunc_in, + 'COUNT', + 'FIRST', + 'LAST', + 'NEXT', + NULL + ); + &start81 + EXECUTE IMMEDIATE dynblock + USING IN check_endrow_in, + IN against_endrow_in, + IN OUT badc, + IN OUT bada, + IN OUT badtext, + IN check_startrow_in, + IN against_startrow_in, + IN v_matchrow; + &end81 + &start73 + DBMS_SQL.parse ( + cur, + dynblock, + DBMS_SQL.native + ); + DBMS_SQL.bind_variable ( + cur, + 'cendit', + check_endrow_in + ); + DBMS_SQL.bind_variable ( + cur, + 'cendit', + against_endrow_in + ); + DBMS_SQL.bind_variable ( + cur, + 'cendit', + check_startrow_in + ); + DBMS_SQL.bind_variable ( + cur, + 'cendit', + against_startrow_in + ); + DBMS_SQL.bind_variable ( + cur, + 'cendit', + v_matchrow + ); + fdbk := DBMS_SQL.EXECUTE (cur); + DBMS_SQL.variable_value ( + cur, + 'badcindx', + badc + ); + DBMS_SQL.variable_value ( + cur, + 'badaindx', + bada + ); + DBMS_SQL.variable_value ( + cur, + 'badreason', + badtext + ); + DBMS_SQL.close_cursor (cur); + &end73 + END IF; + + this ( + outcome_in, + collection_message ( + FALSE , + msg_in, + check_this_in, + badc, + against_this_in, + bada, + badc IS NULL + AND bada IS NULL + ), + badc IS NULL + AND bada IS NULL, + FALSE , + raise_exc_in, + TRUE + ); + END IF; + EXCEPTION + WHEN OTHERS + THEN --p.l (sqlerrm); + &start73 + DBMS_SQL.close_cursor (cur); + &end73 + + this ( + outcome_in, + collection_message ( + FALSE , + msg_in + || ' SQLERROR: ' + || SQLERRM, + check_this_in, + badc, + against_this_in, + bada, + SQLCODE = 0 + ), + SQLCODE = 0, + FALSE , + raise_exc_in, + TRUE + ); + END; + + /* API based access to collections */ + PROCEDURE eqcollapi ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_pkg_in IN VARCHAR2, + against_this_pkg_in IN VARCHAR2, + eqfunc_in IN VARCHAR2 := NULL, + countfunc_in IN VARCHAR2 := 'COUNT', + firstrowfunc_in IN VARCHAR2 := 'FIRST', + lastrowfunc_in IN VARCHAR2 := 'LAST', + nextrowfunc_in IN VARCHAR2 := 'NEXT', + getvalfunc_in IN VARCHAR2 + := 'NTHVAL', + check_startrow_in IN PLS_INTEGER + := NULL, + check_endrow_in IN PLS_INTEGER + := NULL, + against_startrow_in IN PLS_INTEGER + := NULL, + against_endrow_in IN PLS_INTEGER + := NULL, + match_rownum_in IN BOOLEAN := FALSE , + null_ok_in IN BOOLEAN := TRUE , + raise_exc_in IN BOOLEAN := FALSE + ) + IS + dynblock VARCHAR2 (32767); + v_matchrow CHAR (1) := 'N'; + badc PLS_INTEGER; + bada PLS_INTEGER; + badtext VARCHAR2 (32767); + valid_interim BOOLEAN; + invalid_interim_msg VARCHAR2 (4000); + null_and_valid BOOLEAN := FALSE ; + &start73 + fdbk PLS_INTEGER; + cur PLS_INTEGER + := DBMS_SQL.open_cursor; + &end73 + + BEGIN + validatecoll ( + msg_in, + check_this_pkg_in, + against_this_pkg_in, + valid_interim, + invalid_interim_msg, + countfunc_in, + firstrowfunc_in, + lastrowfunc_in, + check_startrow_in, + check_endrow_in, + against_startrow_in, + against_endrow_in, + match_rownum_in, + null_ok_in, + raise_exc_in, + null_and_valid + ); + + IF null_and_valid + THEN + GOTO normal_termination; + END IF; + + IF match_rownum_in + THEN + v_matchrow := 'Y'; + END IF; + + dynblock := dyncollstr ( + check_this_pkg_in, + against_this_pkg_in, + eqfunc_in, + countfunc_in, + firstrowfunc_in, + lastrowfunc_in, + nextrowfunc_in, + getvalfunc_in + ); + &start81 + EXECUTE IMMEDIATE dynblock + USING IN check_endrow_in, + IN against_endrow_in, + IN OUT badc, + IN OUT bada, + IN OUT badtext, + IN check_startrow_in, + IN against_startrow_in, + IN v_matchrow; + &end81 + &start73 + DBMS_SQL.parse ( + cur, + dynblock, + DBMS_SQL.native + ); + DBMS_SQL.bind_variable ( + cur, + 'cendit', + check_endrow_in + ); + DBMS_SQL.bind_variable ( + cur, + 'cendit', + against_endrow_in + ); + DBMS_SQL.bind_variable ( + cur, + 'cendit', + check_startrow_in + ); + DBMS_SQL.bind_variable ( + cur, + 'cendit', + against_startrow_in + ); + DBMS_SQL.bind_variable ( + cur, + 'cendit', + v_matchrow + ); + fdbk := DBMS_SQL.EXECUTE (cur); + DBMS_SQL.variable_value ( + cur, + 'badcindx', + badc + ); + DBMS_SQL.variable_value ( + cur, + 'badaindx', + bada + ); + DBMS_SQL.variable_value ( + cur, + 'badreason', + badtext + ); + DBMS_SQL.close_cursor (cur); + + &end73 + + <> + this ( + outcome_in, + collection_message ( + TRUE , + msg_in, + check_this_pkg_in, + badc, + against_this_pkg_in, + bada, + badc IS NULL + AND bada IS NULL + ), + bada IS NULL + AND badc IS NULL, + FALSE , + raise_exc_in, + TRUE + ); + EXCEPTION + WHEN OTHERS + THEN --p.l (sqlerrm); + &start73 + DBMS_SQL.close_cursor (cur); + &end73 + + this ( + outcome_in, + collection_message ( + TRUE , + msg_in + || ' SQLERROR: ' + || SQLERRM, + check_this_pkg_in, + badc, + against_this_pkg_in, + bada, + badc IS NULL + AND bada IS NULL + ), + SQLCODE = 0, + FALSE , + raise_exc_in, + TRUE + ); + END; + + PROCEDURE isnotnull ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + BEGIN + this ( + outcome_in, + message_expected ( + 'ISNOTNULL', + msg_in, + check_this_in, + 'NOT NULL' + ), + check_this_in IS NOT NULL, + FALSE , + raise_exc_in + ); + END; + + PROCEDURE isnull ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + BEGIN + this ( + outcome_in, + message_expected ( + 'ISNULL', + msg_in, + check_this_in, + '' + ), + check_this_in IS NULL, + TRUE , + raise_exc_in + ); + END; + + PROCEDURE isnotnull ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + BEGIN + this ( + outcome_in, + message_expected ( + 'ISNOTNULL', + msg_in, + utplsql.bool2vc (check_this_in), + 'NOT NULL' + ), + check_this_in IS NOT NULL, + FALSE , + raise_exc_in + ); + END; + + PROCEDURE isnull ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + BEGIN + this ( + outcome_in, + message_expected ( + 'ISNULL', + msg_in, + utplsql.bool2vc (check_this_in), + '' + ), + check_this_in IS NULL, + TRUE , + raise_exc_in + ); + END; + + --Check a given call throws a named exception + PROCEDURE raises ( + outcome_in IN ut_outcome.id%TYPE, + msg_in VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN VARCHAR2 + ) + IS + expected_indicator PLS_INTEGER := 1000; + l_indicator PLS_INTEGER; + v_block VARCHAR2 (32767) + := 'BEGIN ' + || RTRIM (check_call_in, ';') + || '; + :indicator := 0; + EXCEPTION + WHEN ' + || against_exc_in + || ' THEN + :indicator := ' + || expected_indicator + || '; + WHEN OTHERS THEN :indicator := SQLCODE; + END;'; + &start73 + cur PLS_INTEGER + := DBMS_SQL.open_cursor; + ret_val PLS_INTEGER; + &end73 + BEGIN + --Fire off the dynamic PL/SQL + &start81 + EXECUTE IMMEDIATE v_block USING OUT l_indicator; + &end81 + &start73 + DBMS_SQL.parse ( + cur, + v_block, + DBMS_SQL.native + ); + DBMS_SQL.bind_variable (cur, 'indicator', 1); + ret_val := DBMS_SQL.EXECUTE (cur); + DBMS_SQL.variable_value ( + cur, + 'indicator', + l_indicator + ); + DBMS_SQL.close_cursor (cur); + &end73 + + this ( + outcome_in, + message ( + 'RAISES', + msg_in, + 'Block "' + || check_call_in + || '"' + || utplsql.ifelse ( + NOT (NVL ( + l_indicator = + expected_indicator, + FALSE + ) + ), + ' does not raise', + ' raises ' + ) + || ' Exception "' + || against_exc_in + || utplsql.ifelse ( + l_indicator = + expected_indicator, + NULL, + '. Instead it raises SQLCODE = ' + || l_indicator + || '.' + ) + ), + l_indicator = expected_indicator + ); + END; + + --Check a given call throws an exception with a given SQLCODE + PROCEDURE raises ( + outcome_in IN ut_outcome.id%TYPE, + msg_in VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN NUMBER + ) + IS + expected_indicator PLS_INTEGER := 1000; + l_indicator PLS_INTEGER; + v_block VARCHAR2 (32767) + := 'BEGIN ' + || RTRIM (check_call_in, ';') + || '; + :indicator := 0; + EXCEPTION + WHEN OTHERS + THEN IF SQLCODE = ' + || against_exc_in + || ' THEN :indicator := ' + || expected_indicator + || ';' + || ' ELSE :indicator := SQLCODE; END IF; + END;'; + &start73 + cur PLS_INTEGER + := DBMS_SQL.open_cursor; + ret_val PLS_INTEGER; + &end73 + BEGIN + --Fire off the dynamic PL/SQL + &start81 + EXECUTE IMMEDIATE v_block USING OUT l_indicator; + &end81 + &start73 + DBMS_SQL.parse ( + cur, + v_block, + DBMS_SQL.native + ); + DBMS_SQL.bind_variable (cur, 'indicator', 1); + ret_val := DBMS_SQL.EXECUTE (cur); + DBMS_SQL.variable_value ( + cur, + 'indicator', + l_indicator + ); + DBMS_SQL.close_cursor (cur); + &end73 + + this ( + outcome_in, + message ( + 'THROWS', + msg_in, + 'Block "' + || check_call_in + || '"' + || utplsql.ifelse ( + NOT (NVL ( + l_indicator = + expected_indicator, + FALSE + ) + ), + ' does not raise', + ' raises ' + ) + || ' Exception "' + || against_exc_in + || utplsql.ifelse ( + l_indicator = + expected_indicator, + NULL, + '. Instead it raises SQLCODE = ' + || l_indicator + || '.' + ) + ), + l_indicator = expected_indicator + ); + END; + + PROCEDURE throws ( + outcome_in IN ut_outcome.id%TYPE, + msg_in VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN VARCHAR2 + ) + IS + BEGIN + raises ( + outcome_in, + msg_in, + check_call_in, + against_exc_in + ); + END; + + PROCEDURE throws ( + outcome_in IN ut_outcome.id%TYPE, + msg_in VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN NUMBER + ) + IS + BEGIN + raises ( + outcome_in, + msg_in, + check_call_in, + against_exc_in + ); + END; + + -- Same assertions, but using NAME not ID to identify the test case. + + PROCEDURE this ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE , + register_in IN BOOLEAN := TRUE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + this ( + l_id, + msg_in, + check_this_in, + null_ok_in, + raise_exc_in, + register_in + ); + END; + + PROCEDURE eq ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + eq ( + l_id, + msg_in, + check_this_in, + against_this_in, + null_ok_in, + raise_exc_in + ); + END; + + PROCEDURE eq ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + against_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + eq ( + l_id, + msg_in, + check_this_in, + against_this_in, + null_ok_in, + raise_exc_in + ); + END; + + PROCEDURE eq ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_this_in IN DATE, + against_this_in IN DATE, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE , + truncate_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + eq ( + l_id, + msg_in, + check_this_in, + against_this_in, + null_ok_in, + raise_exc_in, + truncate_in + ); + END; + + PROCEDURE eqtable ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + check_where_in IN VARCHAR2 := NULL, + against_where_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + eqtable ( + l_id, + msg_in, + check_this_in, + against_this_in, + check_where_in, + against_where_in, + raise_exc_in + ); + END; + + PROCEDURE eqtabcount ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + check_where_in IN VARCHAR2 := NULL, + against_where_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + eqtabcount ( + l_id, + msg_in, + check_this_in, + against_this_in, + check_where_in, + against_where_in, + raise_exc_in + ); + END; + + PROCEDURE eqquery ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + eqquery ( + l_id, + msg_in, + check_this_in, + against_this_in, + raise_exc_in + ); + END; + + --Check a query against a single VARCHAR2 value + PROCEDURE eqqueryvalue ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + eqqueryvalue ( + l_id, + msg_in, + check_query_in, + against_value_in, + raise_exc_in + ); + END; + + PROCEDURE eqqueryvalue ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN DATE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + eqqueryvalue ( + l_id, + msg_in, + check_query_in, + against_value_in, + raise_exc_in + ); + END; + + --Check a query against a single VARCHAR2 value + PROCEDURE eqqueryvalue ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN NUMBER, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + eqqueryvalue ( + l_id, + msg_in, + check_query_in, + against_value_in, + raise_exc_in + ); + END; + + PROCEDURE eqcursor ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ) + -- User passes in names of two packaged cursors. + -- Have to loop through each row and compare! + -- How do I compare the contents of two records + -- which have been defined dynamically? + IS + BEGIN + utplsql.pl ( + 'utAssert.eqCursor is not yet implemented!' + ); + END; + + PROCEDURE eqfile ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + check_this_dir_in IN VARCHAR2, + against_this_in IN VARCHAR2, + against_this_dir_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + eqfile ( + l_id, + msg_in, + check_this_in, + check_this_dir_in, + against_this_in, + against_this_dir_in, + raise_exc_in + ); + END; + + PROCEDURE eqpipe ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + eqpipe ( + l_id, + msg_in, + check_this_in, + against_this_in, + raise_exc_in + ); + END; + + PROCEDURE eqcoll ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + eqfunc_in IN VARCHAR2 := NULL, + check_startrow_in IN PLS_INTEGER + := NULL, + check_endrow_in IN PLS_INTEGER + := NULL, + against_startrow_in IN PLS_INTEGER + := NULL, + against_endrow_in IN PLS_INTEGER + := NULL, + match_rownum_in IN BOOLEAN := FALSE , + null_ok_in IN BOOLEAN := TRUE , + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + eqcoll ( + l_id, + msg_in, + check_this_in, + against_this_in, + eqfunc_in, + check_startrow_in, + check_endrow_in, + against_startrow_in, + against_endrow_in, + match_rownum_in, + null_ok_in, + raise_exc_in + ); + END; + + /* API based access to collections */ + PROCEDURE eqcollapi ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_this_pkg_in IN VARCHAR2, + against_this_pkg_in IN VARCHAR2, + eqfunc_in IN VARCHAR2 := NULL, + countfunc_in IN VARCHAR2 := 'COUNT', + firstrowfunc_in IN VARCHAR2 := 'FIRST', + lastrowfunc_in IN VARCHAR2 := 'LAST', + nextrowfunc_in IN VARCHAR2 := 'NEXT', + getvalfunc_in IN VARCHAR2 + := 'NTHVAL', + check_startrow_in IN PLS_INTEGER + := NULL, + check_endrow_in IN PLS_INTEGER + := NULL, + against_startrow_in IN PLS_INTEGER + := NULL, + against_endrow_in IN PLS_INTEGER + := NULL, + match_rownum_in IN BOOLEAN := FALSE , + null_ok_in IN BOOLEAN := TRUE , + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + eqcollapi ( + l_id, + msg_in, + check_this_pkg_in, + against_this_pkg_in, + eqfunc_in, + countfunc_in, + firstrowfunc_in, + lastrowfunc_in, + nextrowfunc_in, + getvalfunc_in, + check_startrow_in, + check_endrow_in, + against_startrow_in, + against_endrow_in, + match_rownum_in, + null_ok_in, + raise_exc_in + ); + END; + + PROCEDURE isnotnull ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + isnotnull ( + l_id, + msg_in, + check_this_in, + raise_exc_in + ); + END; + + PROCEDURE isnull ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + isnull ( + l_id, + msg_in, + check_this_in, + raise_exc_in + ); + END; + + PROCEDURE isnotnull ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + isnotnull ( + l_id, + msg_in, + check_this_in, + raise_exc_in + ); + END; + + PROCEDURE isnull ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + isnull ( + l_id, + msg_in, + check_this_in, + raise_exc_in + ); + END; + + --Check a given call throws a named exception + PROCEDURE raises ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN VARCHAR2 + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + raises ( + l_id, + msg_in, + check_call_in, + against_exc_in + ); + END; + + --Check a given call throws an exception with a given SQLCODE + PROCEDURE raises ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN NUMBER + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + raises ( + l_id, + msg_in, + check_call_in, + against_exc_in + ); + END; + + PROCEDURE throws ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN VARCHAR2 + ) + IS + BEGIN + raises ( + outcome_in, + msg_in, + check_call_in, + against_exc_in + ); + END; + + PROCEDURE throws ( + outcome_in IN ut_outcome.NAME%TYPE, + msg_in VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN NUMBER + ) + IS + BEGIN + raises ( + outcome_in, + msg_in, + check_call_in, + against_exc_in + ); + END; + + -- 2.0.7 + PROCEDURE fileexists ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + dir_in IN VARCHAR2, + file_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE + ) + IS + checkid UTL_FILE.file_type; + + PROCEDURE cleanup ( + val IN BOOLEAN, + msg_in IN VARCHAR2 + ) + IS + BEGIN + UTL_FILE.fclose (checkid); + this ( + outcome_in, + message ( + 'FILEEXISTS', + msg_in, + 'File "' + || file_descrip (file_in, dir_in) + || '" could ' + || utplsql.ifelse ( + val, + NULL, + ' not ' + ) + || 'be opened for reading."' + ), + val, + FALSE , + raise_exc_in, + TRUE + ); + END; + BEGIN + checkid := + UTL_FILE.fopen ( + dir_in, + file_in, + 'R' &start81, max_linesize => 32767 &end81 + ); + cleanup (TRUE , msg_in); + EXCEPTION + WHEN OTHERS + THEN + cleanup (FALSE , msg_in); + END; + + PROCEDURE showresults + IS + BEGIN + g_showresults := TRUE ; + END; + + PROCEDURE noshowresults + IS + BEGIN + g_showresults := FALSE ; + END; + + FUNCTION showing_results + RETURN BOOLEAN + IS + BEGIN + RETURN g_showresults; + END; + + /* START username:studious Date:01/11/2002 Task_id:42690 + Description: Checking whether object exists */ + + FUNCTION find_obj (check_this_in IN VARCHAR2) + RETURN BOOLEAN + IS + v_st VARCHAR2 (20); + v_err VARCHAR2 (100); + v_schema VARCHAR2 (100); + v_obj_name VARCHAR2 (100); + v_point NUMBER + := INSTR (check_this_in, '.'); + v_state BOOLEAN := FALSE ; + v_val VARCHAR2 (30); + + CURSOR c_obj + IS + SELECT object_name + FROM all_objects + WHERE object_name = UPPER (v_obj_name) + AND owner = UPPER (v_schema); + BEGIN + IF v_point = 0 + THEN + v_schema := USER; + v_obj_name := check_this_in; + ELSE + v_schema := SUBSTR ( + check_this_in, + 0, + ( v_point + - 1 + ) + ); + v_obj_name := SUBSTR ( + check_this_in, + ( v_point + + 1 + ) + ); + END IF; + + OPEN c_obj; + FETCH c_obj INTO v_val; + + IF c_obj%FOUND + THEN + v_state := TRUE ; + ELSE + v_state := FALSE ; + END IF; + + CLOSE c_obj; + RETURN v_state; + EXCEPTION + WHEN OTHERS + THEN + RETURN FALSE ; + END; + + PROCEDURE objexists ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE + ) + IS + BEGIN + IF utplsql2.tracing + THEN + -- Optional trace of assertion call. + utplsql.pl ( + 'verfying that the object "' + || check_this_in + || '"exists' + ); + END IF; + + this ( + outcome_in, + message ( + msg_in, + check_this_in, + 'This object Exists' + ), + message ( + msg_in, + check_this_in, + 'This object does not Exist' + ), + find_obj (check_this_in), + null_ok_in, + raise_exc_in, + TRUE + ); + END; + + PROCEDURE objnotexists ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE , + raise_exc_in IN BOOLEAN := FALSE + ) + IS + BEGIN + IF utplsql2.tracing + THEN + -- Optional trace of assertion call. + utplsql.pl ( + 'verifying that the object "' + || check_this_in + || '"does not exist' + ); + END IF; + + this ( + outcome_in, + message ( + msg_in, + check_this_in, + 'This object does not Exist' + ), + message ( + msg_in, + check_this_in, + 'This object Exists' + ), + NOT (find_obj (check_this_in)), + null_ok_in, + raise_exc_in, + TRUE + ); + END; +/* END username:studious Task_id:42690*/ + + /* START chrisrimmer 42694 */ + FUNCTION previous_passed + RETURN BOOLEAN + IS + BEGIN + RETURN g_previous_pass; + END; + + FUNCTION previous_failed + RETURN BOOLEAN + IS + BEGIN + RETURN NOT g_previous_pass; + END; +/* END chrisrimmer 42694 */ + + /* START chrisrimmer 42696 */ + PROCEDURE eqoutput ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN DBMS_OUTPUT.CHARARR, + against_this_in IN DBMS_OUTPUT.CHARARR, + ignore_case_in IN BOOLEAN := FALSE, + ignore_whitespace_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + v_check_index BINARY_INTEGER; + v_against_index BINARY_INTEGER; + v_message VARCHAR2(1000); + v_line1 VARCHAR2(1000); + v_line2 VARCHAR2(1000); + WHITESPACE CONSTANT CHAR(5) := '!' || CHR(9) || CHR(10) || CHR(13) || CHR(32) ; + NOWHITESPACE CONSTANT CHAR(1) := '!'; + + FUNCTION Preview_Line(line_in VARCHAR2) + RETURN VARCHAR2 + IS + BEGIN + IF LENGTH(line_in) <= 100 THEN + RETURN line_in; + ELSE + RETURN SUBSTR(line_in, 1, 97) || '...'; + END IF; + END; + + BEGIN + v_check_index := check_this_in.FIRST; + v_against_index := against_this_in.FIRST; + + WHILE v_check_index IS NOT NULL + AND v_against_index IS NOT NULL + AND v_message IS NULL + LOOP + + v_line1 := check_this_in(v_check_index); + v_line2 := against_this_in(v_against_index); + + IF ignore_case_in THEN + v_line1 := UPPER(v_line1); + v_line2 := UPPER(v_line2); + END IF; + + IF ignore_whitespace_in THEN + v_line1 := TRANSLATE(v_line1, WHITESPACE, NOWHITESPACE); + v_line2 := TRANSLATE(v_line2, WHITESPACE, NOWHITESPACE); + END IF; + + IF (NVL (v_line1 <> v_line2, NOT null_ok_in)) THEN + v_message := message_expected ( + 'EQOUTPUT', + msg_in, + Preview_Line(check_this_in(v_check_index)), + Preview_Line(against_this_in(v_against_index))) || + ' (Comparing line ' || v_check_index || + ' of tested collection against line ' || v_against_index || + ' of reference collection)'; + END IF; + + v_check_index := check_this_in.NEXT(v_check_index); + v_against_index := against_this_in.NEXT(v_against_index); + END LOOP; + + IF v_message IS NULL THEN + IF v_check_index IS NULL AND v_against_index IS NOT NULL THEN + v_message := message ( + 'EQOUTPUT', + msg_in , + 'Extra line found at end of reference collection: ' || + Preview_Line(against_this_in(v_against_index))); + ELSIF v_check_index IS NOT NULL AND v_against_index IS NULL THEN + v_message := message ( + 'EQOUTPUT', + msg_in , + 'Extra line found at end of tested collection: ' || + Preview_Line(check_this_in(v_check_index))); + END IF; + END IF; + + this(outcome_in, + NVL(v_message, message('EQOUTPUT', msg_in, 'Collections Match')), + v_message IS NULL, + FALSE, + raise_exc_in, + TRUE); + + END; + + PROCEDURE eqoutput ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN DBMS_OUTPUT.CHARARR, + against_this_in IN DBMS_OUTPUT.CHARARR, + ignore_case_in IN BOOLEAN := FALSE, + ignore_whitespace_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + eqoutput( + l_id, + msg_in, + check_this_in, + against_this_in, + ignore_case_in, + ignore_whitespace_in, + null_ok_in, + raise_exc_in + ); + END; + + PROCEDURE eqoutput ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN DBMS_OUTPUT.CHARARR, + against_this_in IN VARCHAR2, + line_delimiter_in IN CHAR := NULL, + ignore_case_in IN BOOLEAN := FALSE, + ignore_whitespace_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_buffer DBMS_OUTPUT.CHARARR; + l_against_this VARCHAR2(2000) := against_this_in; + l_delimiter_pos BINARY_INTEGER; + BEGIN + + IF line_delimiter_in IS NULL THEN + l_against_this := REPLACE(l_against_this, CHR(13) || CHR(10), CHR(10)); + END IF; + + WHILE l_against_this IS NOT NULL LOOP + l_delimiter_pos := INSTR(l_against_this, NVL(line_delimiter_in, CHR(10))); + IF l_delimiter_pos = 0 THEN + l_buffer(l_buffer.COUNT) := l_against_this; + l_against_this := NULL; + ELSE + l_buffer(l_buffer.COUNT) := SUBSTR(l_against_this, 1, l_delimiter_pos - 1); + l_against_this := SUBSTR(l_against_this, l_delimiter_pos + 1); + --Handle Case of delimiter at end + IF l_against_this IS NULL THEN + l_buffer(l_buffer.COUNT) := NULL; + END IF; + END IF; + END LOOP; + + eqoutput( + outcome_in, + msg_in, + check_this_in, + l_buffer, + ignore_case_in, + ignore_whitespace_in, + null_ok_in, + raise_exc_in + ); + END; + + PROCEDURE eqoutput ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN DBMS_OUTPUT.CHARARR, + against_this_in IN VARCHAR2, + line_delimiter_in IN CHAR := NULL, + ignore_case_in IN BOOLEAN := FALSE, + ignore_whitespace_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ) + IS + l_id ut_outcome.id%TYPE; + BEGIN + get_id (outcome_in, l_id); + eqoutput( + l_id, + msg_in, + check_this_in, + against_this_in, + line_delimiter_in, + ignore_case_in, + ignore_whitespace_in, + null_ok_in, + raise_exc_in + ); + END; + + /* END chrisrimmer 42696 */ + + /* START VENKY11 12345 */ + + PROCEDURE eq_refc_table( + outcome_in IN ut_outcome.id%TYPE, + p_msg_nm IN VARCHAR2, + proc_name IN VARCHAR2, + params IN utplsql_util.utplsql_params, + cursor_position IN PLS_INTEGER, + table_name IN VARCHAR2 ) + IS + refc_table_name VARCHAR2(50); + BEGIN + refc_table_name := utplsql_util.prepare_and_fetch_rc(proc_name,params,cursor_position,1,table_name); + IF (refc_table_name IS NOT NULL) THEN + IF (utplsql.tracing) THEN + dbms_output.put_line('Doing eqtable '); + END IF; + --utassert2.eqtable(outcome_in,p_msg_nm,'UTPLSQL.'||refc_table_name,table_name); + utassert2.eqtable(outcome_in,p_msg_nm,refc_table_name,table_name); + END IF; + IF (utplsql.tracing) THEN + dbms_output.put_line('Table dropped '||refc_table_name); + END IF; + utplsql_util.execute_ddl('DROP TABLE '||refc_table_name); + END; + + PROCEDURE eq_refc_query( + outcome_in IN ut_outcome.id%TYPE, + p_msg_nm IN VARCHAR2, + proc_name IN VARCHAR2, + params IN utplsql_util.utplsql_params, + cursor_position IN PLS_INTEGER, + qry IN VARCHAR2 ) + IS + refc_table_name VARCHAR2(50); + BEGIN + refc_table_name := utplsql_util.prepare_and_fetch_rc(proc_name,params,cursor_position,2,qry); + IF (refc_table_name IS NOT NULL) THEN + --utassert2.eqquery(outcome_in,p_msg_nm,'select * from '||'UTPLSQL.'||refc_table_name,qry); + utassert2.eqquery(outcome_in,p_msg_nm,'select * from '||refc_table_name,qry); + END IF; + IF (utplsql.tracing) THEN + dbms_output.put_line('Table dropped '||refc_table_name); + END IF; + utplsql_util.execute_ddl('DROP TABLE '||refc_table_name); + END; + +/* START VENKY11 12345 */ + + + +END utassert2; +/ +REM SHO ERR + diff --git a/source/ut_assert2.pks b/source/ut_assert2.pks new file mode 100644 index 000000000..acde4ee5f --- /dev/null +++ b/source/ut_assert2.pks @@ -0,0 +1,621 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE utassert2 +&start81 AUTHID CURRENT_USER &end81 +IS + +/* +GNU General Public License for utPLSQL + +Copyright (outcome_in in ut_outcome.id%TYPE,C) 2000 +Steven Feuerstein, steven@stevenfeuerstein.com +Chris Rimmer, chris@sunset.force9.co.uk + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (outcome_in in ut_outcome.id%TYPE,see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*Modification History: +studious:01/20/2002:Assertion for object existance +chrisrimmer 19-Feb-2002 Added previous_passed and previous_failed +Venky 08-AUG-2002 Added refcursor assertions +*/ + + test_failure EXCEPTION; + /* On Error behaviors */ + c_continue CONSTANT CHAR (1) := 'c'; + c_stop CONSTANT CHAR (1) := 's'; + + TYPE value_name_rt IS RECORD ( + value VARCHAR2(32767), + name VARCHAR2(100)); + + TYPE value_name_tt IS TABLE OF value_name_rt INDEX BY BINARY_INTEGER; + + function id (name_in in ut_assertion.name%type) return ut_assertion.id%type; + function name (id_in in ut_assertion.id%type) return ut_assertion.name%type; + + PROCEDURE this ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE, + register_in IN BOOLEAN := TRUE + ); + + /* + 2.0.8 General evaluation program. + */ + PROCEDURE eval ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + using_in IN VARCHAR2, -- The expression + value_name_in IN value_name_tt, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eval ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + using_in IN VARCHAR2, -- The expression + value_name_in IN value_name_tt, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eq ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eq ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN DATE, + against_this_in IN DATE, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE, + truncate_in IN BOOLEAN := FALSE + ); + + PROCEDURE eq ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + against_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqtable ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + check_where_in IN VARCHAR2 := NULL, + against_where_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqtabcount ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + check_where_in IN VARCHAR2 := NULL, + against_where_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqquery ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ); + + --Check a query against a single VARCHAR2 value + PROCEDURE eqqueryvalue ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + -- Check a query against a single DATE value + PROCEDURE eqqueryvalue ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN DATE, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqqueryvalue ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN NUMBER, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + -- Not currently implemented + PROCEDURE eqcursor ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqfile ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + check_this_dir_in IN VARCHAR2, + against_this_in IN VARCHAR2, + against_this_dir_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqpipe ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ); + + /* Direct access to collections */ + PROCEDURE eqcoll ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, /* pkg1.coll */ + against_this_in IN VARCHAR2, /* pkg2.coll */ + eqfunc_in IN VARCHAR2 := NULL, + check_startrow_in IN PLS_INTEGER := NULL, + check_endrow_in IN PLS_INTEGER := NULL, + against_startrow_in IN PLS_INTEGER := NULL, + against_endrow_in IN PLS_INTEGER := NULL, + match_rownum_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ); + + /* API based access to collections */ + PROCEDURE eqcollapi ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_pkg_in IN VARCHAR2, + against_this_pkg_in IN VARCHAR2, + eqfunc_in IN VARCHAR2 := NULL, + countfunc_in IN VARCHAR2 := 'COUNT', + firstrowfunc_in IN VARCHAR2 := 'FIRST', + lastrowfunc_in IN VARCHAR2 := 'LAST', + nextrowfunc_in IN VARCHAR2 := 'NEXT', + getvalfunc_in IN VARCHAR2 := 'NTHVAL', + check_startrow_in IN PLS_INTEGER := NULL, + check_endrow_in IN PLS_INTEGER := NULL, + against_startrow_in IN PLS_INTEGER := NULL, + against_endrow_in IN PLS_INTEGER := NULL, + match_rownum_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE isnotnull ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE isnull ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ); + + -- 1.5.2 + PROCEDURE isnotnull ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE isnull ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + raise_exc_in IN BOOLEAN := FALSE + ); + + --Check a given call throws a named exception + PROCEDURE throws ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN VARCHAR2 + ); + + --Check a given call throws an exception with a given SQLCODE + PROCEDURE throws ( + outcome_in IN ut_outcome.id%TYPE, + msg_in VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN NUMBER + ); + + --Check a given call throws a named exception + PROCEDURE raises ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN VARCHAR2 + ); + + --Check a given call throws an exception with a given SQLCODE + PROCEDURE raises ( + outcome_in IN ut_outcome.id%TYPE, + msg_in VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN NUMBER + ); + + -- Same assertions, but providing the assertion name, not ID. + PROCEDURE this ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE, + register_in IN BOOLEAN := TRUE + ); + + + PROCEDURE eq ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eq ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN DATE, + against_this_in IN DATE, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE, + truncate_in IN BOOLEAN := FALSE + ); + + PROCEDURE eq ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + against_this_in IN BOOLEAN, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqtable ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + check_where_in IN VARCHAR2 := NULL, + against_where_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqtabcount ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + check_where_in IN VARCHAR2 := NULL, + against_where_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqquery ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ); + + --Check a query against a single VARCHAR2 value + PROCEDURE eqqueryvalue ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ); + + -- Check a query against a single DATE value + PROCEDURE eqqueryvalue ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN DATE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqqueryvalue ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_query_in IN VARCHAR2, + against_value_in IN NUMBER, + raise_exc_in IN BOOLEAN := FALSE + ); + + -- Not currently implemented + PROCEDURE eqcursor ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqfile ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + check_this_dir_in IN VARCHAR2, + against_this_in IN VARCHAR2, + against_this_dir_in IN VARCHAR2 := NULL, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqpipe ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + against_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ); + + /* Direct access to collections */ + PROCEDURE eqcoll ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, /* pkg1.coll */ + against_this_in IN VARCHAR2, /* pkg2.coll */ + eqfunc_in IN VARCHAR2 := NULL, + check_startrow_in IN PLS_INTEGER := NULL, + check_endrow_in IN PLS_INTEGER := NULL, + against_startrow_in IN PLS_INTEGER := NULL, + against_endrow_in IN PLS_INTEGER := NULL, + match_rownum_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ); + + /* API based access to collections */ + PROCEDURE eqcollapi ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_pkg_in IN VARCHAR2, + against_this_pkg_in IN VARCHAR2, + eqfunc_in IN VARCHAR2 := NULL, + countfunc_in IN VARCHAR2 := 'COUNT', + firstrowfunc_in IN VARCHAR2 := 'FIRST', + lastrowfunc_in IN VARCHAR2 := 'LAST', + nextrowfunc_in IN VARCHAR2 := 'NEXT', + getvalfunc_in IN VARCHAR2 := 'NTHVAL', + check_startrow_in IN PLS_INTEGER := NULL, + check_endrow_in IN PLS_INTEGER := NULL, + against_startrow_in IN PLS_INTEGER := NULL, + against_endrow_in IN PLS_INTEGER := NULL, + match_rownum_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE isnotnull ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE isnull ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + raise_exc_in IN BOOLEAN := FALSE + ); + + -- 1.5.2 + PROCEDURE isnotnull ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE isnull ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN BOOLEAN, + raise_exc_in IN BOOLEAN := FALSE + ); + + --Check a given call throws a named exception + PROCEDURE throws ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN VARCHAR2 + ); + + --Check a given call throws an exception with a given SQLCODE + PROCEDURE throws ( + outcome_in IN ut_outcome.name%TYPE, + msg_in VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN NUMBER + ); + + --Check a given call throws a named exception + PROCEDURE raises ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN VARCHAR2 + ); + + --Check a given call throws an exception with a given SQLCODE + PROCEDURE raises ( + outcome_in IN ut_outcome.name%TYPE, + msg_in VARCHAR2, + check_call_in IN VARCHAR2, + against_exc_in IN NUMBER + ); + + PROCEDURE showresults; + + PROCEDURE noshowresults; + + FUNCTION showing_results + RETURN BOOLEAN; + + -- 2.0.7 + PROCEDURE fileExists( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + dir_in in varchar2, + file_in in varchar2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + /* START username:studious Date:01/11/2002 Task_id:42690 + Description: Checking object exist */ + + PROCEDURE objExists ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE objnotExists ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN VARCHAR2, + null_ok_in IN BOOLEAN := FALSE, + raise_exc_in IN BOOLEAN := FALSE + ); +/* END username:studious Task_id:42690*/ + + /* START chrisrimmer 42694 */ + FUNCTION previous_passed + RETURN BOOLEAN; + + FUNCTION previous_failed + RETURN BOOLEAN; + /* END chrisrimmer 42694 */ + + /* START chrisrimmer 42696 */ + PROCEDURE eqoutput ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN DBMS_OUTPUT.CHARARR, + against_this_in IN DBMS_OUTPUT.CHARARR, + ignore_case_in IN BOOLEAN := FALSE, + ignore_whitespace_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqoutput ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN DBMS_OUTPUT.CHARARR, + against_this_in IN DBMS_OUTPUT.CHARARR, + ignore_case_in IN BOOLEAN := FALSE, + ignore_whitespace_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqoutput ( + outcome_in IN ut_outcome.id%TYPE, + msg_in IN VARCHAR2, + check_this_in IN DBMS_OUTPUT.CHARARR, + against_this_in IN VARCHAR2, + line_delimiter_in IN CHAR := NULL, + ignore_case_in IN BOOLEAN := FALSE, + ignore_whitespace_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ); + + PROCEDURE eqoutput ( + outcome_in IN ut_outcome.name%TYPE, + msg_in IN VARCHAR2, + check_this_in IN DBMS_OUTPUT.CHARARR, + against_this_in IN VARCHAR2, + line_delimiter_in IN CHAR := NULL, + ignore_case_in IN BOOLEAN := FALSE, + ignore_whitespace_in IN BOOLEAN := FALSE, + null_ok_in IN BOOLEAN := TRUE, + raise_exc_in IN BOOLEAN := FALSE + ); + /* END chrisrimmer 42696 */ + + /* START VENKY11 12345 */ + + PROCEDURE eq_refc_table( + outcome_in IN ut_outcome.id%TYPE, + p_msg_nm IN VARCHAR2, + proc_name IN VARCHAR2, + params IN utplsql_util.utplsql_params, + cursor_position IN PLS_INTEGER, + table_name IN VARCHAR2 ); + + PROCEDURE eq_refc_query( + outcome_in IN ut_outcome.id%TYPE, + p_msg_nm IN VARCHAR2, + proc_name IN VARCHAR2, + params IN utplsql_util.utplsql_params, + cursor_position IN PLS_INTEGER, + qry IN VARCHAR2 ); + + +/* END VENKY11 12345 */ + + +END utassert2; +/ diff --git a/source/ut_assertion.tab b/source/ut_assertion.tab new file mode 100644 index 000000000..146e9cefd --- /dev/null +++ b/source/ut_assertion.tab @@ -0,0 +1,147 @@ +-- Modification History: +-- studious:01/20/2002:Assertion for object existance + +CREATE TABLE ut_assertion ( + id INTEGER , + NAME VARCHAR2(100), -- MUST corresponds to utAssert2 program name + description VARCHAR2(1000), + /* Rest of columns, V1 compatibility; too generic to be useful. */ + use_msg CHAR(1) DEFAULT 'Y', + use_null_ok CHAR(1) DEFAULT 'Y', + use_raise_exc CHAR(1) DEFAULT 'Y', + use_check_this CHAR(1) DEFAULT 'Y', + check_this_label VARCHAR2(100) + DEFAULT 'Check this', + use_check_this_where CHAR(1) DEFAULT 'N', + check_this_where_label VARCHAR2(100) + DEFAULT 'Check this WHERE clause', + use_against_this CHAR(1) DEFAULT 'Y', + against_this_label VARCHAR2(100) + DEFAULT 'Against this', + use_against_this_where CHAR(1) DEFAULT 'N', + against_this_where_label VARCHAR2(100) + DEFAULT 'Against this WHERE clause', + use_check_this_dir CHAR(1) DEFAULT 'N', + check_this_dir_label VARCHAR2(100) + DEFAULT 'Location of "check this" file', + use_against_this_dir CHAR(1) DEFAULT 'N', + against_this_dir_label VARCHAR2(100) + DEFAULT 'Location of "against this" file', + CONSTRAINT ut_assertion_pk PRIMARY KEY (id) +); + +CREATE UNIQUE INDEX ut_assertion_idx1 ON + ut_assertion (NAME); + +BEGIN + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (1, 'THIS', + 'General Boolean expression evaluation'); + + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (2, 'EQ', + 'Scalar equality'); + + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (3, 'EQTABLE', + 'Database table/view equality'); + + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (4, 'EQTABCOUNT', + 'Database table/view row count comparison'); + + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (5, 'EQQUERY', + 'Query result set equality'); + + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (6, 'EQQUERYVALUE', + 'Query return value comparison'); + + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (7, 'EQFILE', + 'Operating system file equality'); + + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (8, 'EQPIPE', + 'Database pipe equality'); + + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (9, 'EQCOLL', + 'Collection equality - direct access'); + + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (10, 'EQCOLLAPI', + 'Collection equality - API access'); + + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (11, 'ISNOTNULL', + 'NOTNULL validation'); + + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (12, 'ISNULL', + 'NULL validation'); + + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (13, 'RAISES', + 'Raised exception validation'); + + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (14, 'FILEEXISTS', + 'Confirm that specified file exists'); + + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (15, 'EVALUATE', + 'General evaluation of specified expression'); + +-- START username:STUDIOUS Date:01/11/2002 Task_id:42690 +-- Description: Checking whether object exists + + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (16, 'OBJEXISTS', + 'Confirm that specified Object exists'); + + INSERT INTO ut_assertion + (id, NAME, + description) + VALUES (17, 'OBJNOTEXISTS', + 'Confirm that specified Object does not exist'); + +-- END username:STUDIOUS Task_id:42690 + + COMMIT; +END; +/ + diff --git a/source/ut_assertion_seq.seq b/source/ut_assertion_seq.seq new file mode 100644 index 000000000..11a8ce337 --- /dev/null +++ b/source/ut_assertion_seq.seq @@ -0,0 +1 @@ +CREATE sequence ut_assertion_seq INCREMENT BY 1 START WITH 1 ORDER NOCACHE; diff --git a/source/ut_config.pkb b/source/ut_config.pkb new file mode 100644 index 000000000..8bffe9faa --- /dev/null +++ b/source/ut_config.pkb @@ -0,0 +1,758 @@ +CREATE OR REPLACE PACKAGE BODY utconfig +IS +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 +Steven Feuerstein, steven@stevenfeuerstein.com +Chris Rimmer, chris@sunset.force9.co.uk + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +------------------------------------------------------------------------------- +--Description +------------------------------------------------------------------------------- +--This package manages the ut_config table, which holds the configuration +--settings for different users. The configuration data to be used by utPLSQL +--by default is set by calling settester. Wherever a username is passed as NULL, +--it is assumed to be that user. This defaults initially to the current user. +------------------------------------------------------------------------------- +--Modification History +------------------------------------------------------------------------------- +--WHO WHEN WHAT +------------------------------------------------------------------------------- +--Chris Rimmer 22 Oct 2000 Created from utplsql package +------------------------------------------------------------------------------- + +---------------------------------------------------------------------------- +--This record holds the default configuration +---------------------------------------------------------------------------- + g_config ut_config%ROWTYPE := NULL; + +---------------------------------------------------------------------------- +-- Get the configuration record for a user from the table +---------------------------------------------------------------------------- + FUNCTION config (username_in IN VARCHAR2 := USER) + RETURN ut_config%ROWTYPE + IS + rec ut_config%ROWTYPE; + BEGIN + --Short cut for current user + IF username_in = tester + THEN + RETURN g_config; + END IF; + + BEGIN + --Try to pull in the record from the table + SELECT * + INTO rec + FROM ut_config + WHERE username = UPPER (username_in); + EXCEPTION + --If we failed to find the record + WHEN OTHERS + THEN + --Set the record to NULL + rec := NULL; + END; + + RETURN rec; + END; + +---------------------------------------------------------------------------- +--This sets the configuration record for a user in the table +---------------------------------------------------------------------------- + PROCEDURE setconfig ( + field_in IN VARCHAR2 + ,value_in VARCHAR2 + ,username_in IN VARCHAR2 := NULL + ) + IS + &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + + --Local procedure to do dynamic SQL + PROCEDURE do_dml (statement_in IN VARCHAR2) + IS + &start73 cursor_handle INTEGER; &end73 + &start73 rows INTEGER; &end73 + BEGIN + --In 8i, just do it + &start81 EXECUTE IMMEDIATE statement_in; COMMIT; &end81 + + --Otherwise use DBMS_SQL + &start73 + --Open the cursor + cursor_handle := DBMS_SQL.open_cursor; + -- Parse the Statement + DBMS_SQL.parse (cursor_handle, statement_in, DBMS_SQL.native); + -- Execute the Statement + ROWS := DBMS_SQL.EXECUTE (cursor_handle); + -- Close the cursor + DBMS_SQL.close_cursor (cursor_handle); + EXCEPTION + WHEN OTHERS + THEN + DBMS_SQL.close_cursor (cursor_handle); + RAISE; + &end73 + END; + BEGIN + BEGIN + --Try to insert the record + do_dml ( 'INSERT INTO ut_config(username, ' + || field_in + || ')' + || 'VALUES (''' + || username_in + || ''', ''' + || value_in + || ''')' + ); + EXCEPTION + WHEN DUP_VAL_ON_INDEX + THEN + --Since it already exists, we'll update instead + do_dml ( 'UPDATE ut_config ' + || 'SET ' + || field_in + || ' = ''' + || value_in + || ''' ' + || 'WHERE username = ''' + || username_in + || ''' ' + ); + WHEN OTHERS + THEN + --Something else went wrong + utplsql.pl (SQLERRM); + &start81 ROLLBACK; &end81 + RETURN; + END; + + &start81 COMMIT; &end81 + + --If it's the current user, force update of package record + IF username_in = tester + THEN + g_config := NULL; + settester (username_in); + END IF; + END; + +---------------------------------------------------------------------------- +--This loads the default configuration from the table +---------------------------------------------------------------------------- + PROCEDURE settester (username_in IN VARCHAR2 := USER) + IS + BEGIN + --Load the record + g_config := config (username_in); + --But set the username record if null + g_config.username := NVL (g_config.username, UPPER (username_in)); + END; + +---------------------------------------------------------------------------- +-- Get the user we use by default +---------------------------------------------------------------------------- + FUNCTION tester + RETURN VARCHAR2 + IS + BEGIN + RETURN g_config.username; + END; + +---------------------------------------------------------------------------- +-- Show the config for a user +---------------------------------------------------------------------------- + PROCEDURE showconfig (username_in IN VARCHAR2 := NULL) + IS + --The schema to show + v_user VARCHAR2 (32) := NVL (username_in, tester); + --This holds the configuration + rec ut_config%ROWTYPE; + BEGIN + --Get the configuration + rec := config (v_user); + --Now show it + utplsql.pl ('=============================================================' + ); + utplsql.pl ('utPLSQL Configuration for ' || v_user); + utplsql.pl (' Directory: ' || rec.DIRECTORY); + utplsql.pl (' Autcompile? ' || rec.autocompile); + utplsql.pl (' Manual test registration? ' || rec.registertest); + utplsql.pl (' Prefix = ' || rec.prefix); + utplsql.pl (' ----- File Output settings:'); + utplsql.pl (' Output directory: ' || rec.filedir); + utplsql.pl (' Output flag = ' || rec.fileout); + utplsql.pl (' User prefix = ' || rec.fileuserprefix); + utplsql.pl (' Include progname? ' || rec.fileincprogname); + utplsql.pl (' Date format = ' || rec.filedateformat); + utplsql.pl (' File extension = ' || rec.fileextension); + utplsql.pl (' ----- End File Output settings'); + utplsql.pl ('=============================================================' + ); + END; + +---------------------------------------------------------------------------- +-- Set the prefix for a user +---------------------------------------------------------------------------- + PROCEDURE setprefix (prefix_in IN VARCHAR2, username_in IN VARCHAR2 := NULL) + IS + --The user to set + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Set the configuration + setconfig ('prefix', prefix_in, v_user); + END; + +---------------------------------------------------------------------------- +-- Get the prefix for a user +---------------------------------------------------------------------------- + FUNCTION prefix (username_in IN VARCHAR2 := NULL) + RETURN VARCHAR2 + IS + --Holds the user's config record + rec ut_config%ROWTYPE; + --Holds the username in question + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Pull in the configuration + rec := config (v_user); + --Return prefix + RETURN NVL (rec.prefix, c_prefix); + END; + +---------------------------------------------------------------------------- +-- Set the delimiter for a user +---------------------------------------------------------------------------- + PROCEDURE setdelimiter ( + delimiter_in IN VARCHAR2 + ,username_in IN VARCHAR2 := NULL + ) + IS + --The user to set + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Set the configuration + setconfig ('delimiter', delimiter_in, v_user); + END; + +---------------------------------------------------------------------------- +-- Get the delimiter for a user +---------------------------------------------------------------------------- + FUNCTION delimiter (username_in IN VARCHAR2 := NULL) + RETURN VARCHAR2 + IS + --Holds the user's config record + rec ut_config%ROWTYPE; + --Holds the username in question + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Pull in the configuration + rec := config (v_user); + --Return prefix + RETURN NVL (rec.delimiter, c_delimiter); + END; + +---------------------------------------------------------------------------- +-- Set the source directory for a user +---------------------------------------------------------------------------- + PROCEDURE setdir (dir_in IN VARCHAR2, username_in IN VARCHAR2 := NULL) + IS + --The user to set + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Set the configuration + setconfig ('directory', dir_in, v_user); + END; + +---------------------------------------------------------------------------- +-- Get the source directory for a user +---------------------------------------------------------------------------- + FUNCTION dir (username_in IN VARCHAR2 := NULL) + RETURN VARCHAR2 + IS + --Holds the user's config record + rec ut_config%ROWTYPE; + --Holds the username in question + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Pull in the configuration + rec := config (v_user); + --Return directory + RETURN rec.DIRECTORY; + END; + +---------------------------------------------------------------------------- +-- Set the autocompile flag for a user +---------------------------------------------------------------------------- + PROCEDURE autocompile (onoff_in IN BOOLEAN, username_in IN VARCHAR2 := NULL) + IS + --Holds the flag as 'Y'/'N' + v_autocompile CHAR (1) := utplsql.bool2vc (onoff_in); + --Holds the user to set + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Set the configuration + setconfig ('autocompile', v_autocompile, v_user); + END; + +---------------------------------------------------------------------------- +-- Get the autocompile flag for a user +---------------------------------------------------------------------------- + FUNCTION autocompiling (username_in IN VARCHAR2 := NULL) + RETURN BOOLEAN + IS + --Holds the user's config record + rec ut_config%ROWTYPE; + --Holds the username in question + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Pull in the configuration + rec := config (v_user); + --Return autocompile, defaulting to TRUE if NULL + RETURN NVL (utplsql.vc2bool (rec.autocompile), TRUE); + END; + +---------------------------------------------------------------------------- +-- Set the manual registration flag for a user +---------------------------------------------------------------------------- + PROCEDURE registertest (onoff_in IN BOOLEAN, username_in IN VARCHAR2 + := NULL) + IS + --Holds the flag as 'Y'/'N' + v_registertest CHAR (1) := utplsql.bool2vc (onoff_in); + --Holds the username in question + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Set the configuration + setconfig ('registertest', v_registertest, v_user); + END; + +---------------------------------------------------------------------------- +-- Get the manual registration flag for a user +---------------------------------------------------------------------------- + FUNCTION registeringtest (username_in IN VARCHAR2 := NULL) + RETURN BOOLEAN + IS + --Holds the user's config record + rec ut_config%ROWTYPE; + --Holds the username in question + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Pull in the configuration + rec := config (v_user); + --Return registertest, defaulting to FALSE if NULL + RETURN NVL (utplsql.vc2bool (rec.registertest), FALSE); + END; + + -- Show failures only? + PROCEDURE showfailuresonly ( + onoff_in IN BOOLEAN + ,username_in IN VARCHAR2 := NULL + ) + IS + --Holds the flag as 'Y'/'N' + v_showfailuresonly CHAR (1) := utplsql.bool2vc (onoff_in); + --Holds the username in question + v_user VARCHAR2 (100) + := NVL (UPPER (username_in), tester); + BEGIN + --Set the configuration + setconfig ('show_failures_only', v_showfailuresonly, v_user); + END; + + FUNCTION showingfailuresonly (username_in IN VARCHAR2 := NULL) + RETURN BOOLEAN + IS + --Holds the user's config record + rec ut_config%ROWTYPE; + --Holds the username in question + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Pull in the configuration + rec := config (v_user); + --Return show_failures_only, defaulting to FALSE if NULL + RETURN NVL (utplsql.vc2bool (rec.show_failures_only), FALSE); + END; + +-- RMM start +---------------------------------------------------------------------------- +-- Set the file directory for a user +---------------------------------------------------------------------------- + PROCEDURE setfiledir ( + dir_in IN VARCHAR2 := NULL + ,username_in IN VARCHAR2 := NULL + ) + IS + --The user to set + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Set the configuration + setconfig ('filedir', dir_in, v_user); + END; + +---------------------------------------------------------------------------- +-- Get the file output directory for a user +---------------------------------------------------------------------------- + FUNCTION filedir (username_in IN VARCHAR2 := NULL) + RETURN VARCHAR2 + IS + --Holds the user's config record + rec ut_config%ROWTYPE; + --Holds the username in question + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Pull in the configuration + rec := config (v_user); + --Return directory + RETURN rec.filedir; + END; + +---------------------------------------------------------------------------- +-- Set the file output flag for a user +---------------------------------------------------------------------------- + PROCEDURE setfile ( + fileout_in IN BOOLEAN := FALSE + ,username_in IN VARCHAR2 := NULL + ) + IS + --Holds the flag as 'Y'/'N' + v_fileout CHAR (1) := utplsql.bool2vc (fileout_in); + --Holds the user to set + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Set the configuration + setconfig ('fileout', v_fileout, v_user); + END; + +---------------------------------------------------------------------------- +-- Get the file output flag for a user +---------------------------------------------------------------------------- + FUNCTION getfile (username_in IN VARCHAR2 := NULL) + RETURN BOOLEAN + IS + --Holds the user's config record + rec ut_config%ROWTYPE; + --Holds the username in question + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Pull in the configuration + rec := config (v_user); + --Return autocompile, defaulting to TRUE if NULL + RETURN NVL (utplsql.vc2bool (rec.fileout), FALSE); + END; + +---------------------------------------------------------------------------- +-- Set the file prefix for a user +---------------------------------------------------------------------------- + PROCEDURE setuserprefix ( + userprefix_in IN VARCHAR2 := NULL + ,username_in IN VARCHAR2 := NULL + ) + IS + --The user to set + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Set the configuration + setconfig ('fileuserprefix', userprefix_in, v_user); + END; + +---------------------------------------------------------------------------- +-- Get the file prefix for a user +---------------------------------------------------------------------------- + FUNCTION userprefix (username_in IN VARCHAR2 := NULL) + RETURN VARCHAR2 + IS + --Holds the user's config record + rec ut_config%ROWTYPE; + --Holds the username in question + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Pull in the configuration + rec := config (v_user); + --Return directory + RETURN rec.fileuserprefix; + END; + +---------------------------------------------------------------------------- +-- Set the include program name flag for a user +---------------------------------------------------------------------------- + PROCEDURE setincludeprogname ( + incname_in IN BOOLEAN := FALSE + ,username_in IN VARCHAR2 := NULL + ) + IS + --Holds the flag as 'Y'/'N' + v_incname CHAR (1) := utplsql.bool2vc (incname_in); + --Holds the user to set + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Set the configuration + setconfig ('fileincprogname', v_incname, v_user); + END; + +---------------------------------------------------------------------------- +-- Get the include program name flag for a user +---------------------------------------------------------------------------- + FUNCTION includeprogname (username_in IN VARCHAR2 := NULL) + RETURN BOOLEAN + IS + --Holds the user's config record + rec ut_config%ROWTYPE; + --Holds the username in question + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Pull in the configuration + rec := config (v_user); + --Return autocompile, defaulting to TRUE if NULL + RETURN NVL (utplsql.vc2bool (rec.fileincprogname), FALSE); + END; + +---------------------------------------------------------------------------- +-- Set the date format for a user +---------------------------------------------------------------------------- + PROCEDURE setdateformat ( + dateformat_in IN VARCHAR2 := 'yyyyddmmhh24miss' + ,username_in IN VARCHAR2 := NULL + ) + IS + --The user to set + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Set the configuration + setconfig ('filedateformat', dateformat_in, v_user); + END; + +---------------------------------------------------------------------------- +-- Get the date format for a user +---------------------------------------------------------------------------- + FUNCTION DATEFORMAT (username_in IN VARCHAR2 := NULL) + RETURN VARCHAR2 + IS + --Holds the user's config record + rec ut_config%ROWTYPE; + --Holds the username in question + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Pull in the configuration + rec := config (v_user); + --Return directory + RETURN rec.filedateformat; + END; + +---------------------------------------------------------------------------- +-- Set the file extension for a user +---------------------------------------------------------------------------- + PROCEDURE setfileextension ( + fileextension_in IN VARCHAR2 := '.UTF' + ,username_in IN VARCHAR2 := NULL + ) + IS + --The user to set + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Set the configuration + setconfig ('fileextension', fileextension_in, v_user); + END; + +---------------------------------------------------------------------------- +-- Get the file extension for a user +---------------------------------------------------------------------------- + FUNCTION fileextension (username_in IN VARCHAR2 := NULL) + RETURN VARCHAR2 + IS + --Holds the user's config record + rec ut_config%ROWTYPE; + --Holds the username in question + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + BEGIN + --Pull in the configuration + rec := config (v_user); + --Return directory + RETURN rec.fileextension; + END; + +---------------------------------------------------------------------------- +-- Set all of the file output columns for a user +---------------------------------------------------------------------------- + PROCEDURE setfileinfo ( + fileout_in IN BOOLEAN := FALSE + ,dir_in IN VARCHAR2 := NULL + ,userprefix_in IN VARCHAR2 := NULL + ,incname_in IN BOOLEAN := FALSE + ,dateformat_in IN VARCHAR2 := 'yyyyddmmhh24miss' + ,fileextension_in IN VARCHAR2 := '.UTF' + ,username_in IN VARCHAR2 := NULL + ) + IS + BEGIN + NULL; + setfile (fileout_in, username_in); + setfiledir (dir_in, username_in); + setuserprefix (userprefix_in, username_in); + setincludeprogname (incname_in, username_in); + setdateformat (dateformat_in, username_in); + setfileextension (fileextension_in, username_in); + END setfileinfo; + +---------------------------------------------------------------------------- +-- Get all of the file output columns for a user +---------------------------------------------------------------------------- + FUNCTION fileinfo (username_in IN VARCHAR2 := NULL) + RETURN rec_fileinfo + IS + --Holds the user's config record + rec ut_config%ROWTYPE; + --Holds the username in question + v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); + -- Holds the return value + fileinfo_rec rec_fileinfo; + BEGIN + --Pull in the configuration + rec := config (v_user); + --populate the record + fileinfo_rec.fileout := rec.fileout; + fileinfo_rec.filedir := rec.filedir; + fileinfo_rec.fileuserprefix := rec.fileuserprefix; + fileinfo_rec.fileincprogname := rec.fileincprogname; + fileinfo_rec.filedateformat := rec.filedateformat; + fileinfo_rec.fileextension := rec.fileextension; + --Return the record + RETURN fileinfo_rec; + END fileinfo; + +-- RMM end + + PROCEDURE upd ( + username_in IN ut_config.username%TYPE + ,autocompile_in IN ut_config.autocompile%TYPE + ,prefix_in IN ut_config.prefix%TYPE + ,show_failures_only_in IN ut_config.show_failures_only%TYPE + ,directory_in IN ut_config.DIRECTORY%TYPE + ,filedir_in IN ut_config.filedir%TYPE + ,show_config_info_in IN ut_config.show_config_info%TYPE + ,editor_in IN ut_config.editor%TYPE + ) + IS + &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + BEGIN + INSERT INTO ut_config + (username, autocompile, prefix + ,show_failures_only, DIRECTORY, filedir + ,show_config_info, editor + ) + VALUES (username_in, autocompile_in, prefix_in + ,show_failures_only_in, directory_in, filedir_in + ,show_config_info_in, editor_in + ); + &start81 COMMIT; &end81 + EXCEPTION + WHEN DUP_VAL_ON_INDEX + THEN + -- Perform an update instead. + UPDATE ut_config + SET autocompile = autocompile_in + ,prefix = prefix_in + ,show_failures_only = show_failures_only_in + ,DIRECTORY = directory_in + ,filedir = filedir_in + ,show_config_info = show_config_info_in + WHERE username = username_in; + WHEN OTHERS + THEN + &start81 ROLLBACK; &end81 + NULL; -- Present to assist in formatting + END; + + FUNCTION browser_contents ( + schema_in IN VARCHAR2 + ,name_like_in IN VARCHAR2 := '%' + ,type_like_in IN VARCHAR2 := '%' + ) + RETURN refcur_t + IS + retval refcur_t; + BEGIN + OPEN retval FOR + SELECT ao.owner, ao.object_name, ao.object_type, ao.created + ,ao.last_ddl_time, utrutp.last_run_status ( + ao.owner, ao.object_name) status + FROM all_objects ao + WHERE ao.owner = UPPER (schema_in) + AND ao.owner NOT IN ('SYS', 'SYSTEM', 'PUBLIC') + AND object_name LIKE UPPER (name_like_in) + AND object_type LIKE UPPER (type_like_in) + AND object_type IN ('PACKAGE', 'FUNCTION', 'PROCEDURE', 'OBJECT TYPE'); + RETURN retval; + END browser_contents; + + FUNCTION source_for_program (schema_in IN VARCHAR2, NAME_IN IN VARCHAR2) + RETURN refcur_t + IS + retval refcur_t; + BEGIN + OPEN retval FOR + SELECT line, text + FROM all_source + WHERE owner = UPPER (schema_in) AND NAME = UPPER (NAME_IN); + RETURN retval; + END source_for_program; + + FUNCTION onerow (schema_in IN VARCHAR2) + RETURN refcur_t + IS + retval refcur_t; + BEGIN + OPEN retval FOR + SELECT autocompile, DIRECTORY, filedir, prefix, show_failures_only + ,show_config_info, editor + FROM ut_config + WHERE username = UPPER (schema_in); + END onerow; + + PROCEDURE get_onerow ( + schema_in IN VARCHAR2 + ,username_out OUT VARCHAR2 + ,autocompile_out OUT ut_config.autocompile%TYPE + ,prefix_out OUT ut_config.prefix%TYPE + ,show_failures_only_out OUT ut_config.show_failures_only%TYPE + ,directory_out OUT ut_config.DIRECTORY%TYPE + ,filedir_out OUT ut_config.filedir%TYPE + ,show_config_info_out OUT ut_config.show_config_info%TYPE + ,editor_out OUT ut_config.editor%TYPE + ) + IS + BEGIN + SELECT username, autocompile, DIRECTORY, filedir + ,prefix, show_failures_only, show_config_info + ,editor + INTO username_out, autocompile_out, directory_out, filedir_out + ,prefix_out, show_failures_only_out, show_config_info_out + ,editor_out + FROM ut_config + WHERE username = UPPER (schema_in); + EXCEPTION + WHEN NO_DATA_FOUND + THEN + username_out := NULL; + END get_onerow; +BEGIN + --Initially, set the user as default tester + settester; +END; +/ diff --git a/source/ut_config.pks b/source/ut_config.pks new file mode 100644 index 000000000..6ea21bf3f --- /dev/null +++ b/source/ut_config.pks @@ -0,0 +1,248 @@ +CREATE OR REPLACE PACKAGE utconfig &start81 AUTHID CURRENT_USER &end81 +IS +------------------------------------------------------------------------------- +--Description +------------------------------------------------------------------------------- +--This package manages the ut_config table, which holds the configuration +--settings for different users. The configuration data to be used by utPLSQL +--by default is set by calling settester. Wherever a username is passed as NULL, +--it is assumed to be that user. This defaults initially to the current user. +------------------------------------------------------------------------------- +--Modification History +------------------------------------------------------------------------------- +--WHO WHEN WHAT +------------------------------------------------------------------------------- +--Chris Rimmer 22 Oct 2000 Created from utplsql package +------------------------------------------------------------------------------- + + --The default prefix + c_prefix CONSTANT CHAR (3) := 'ut_'; + --The default delimiter + c_delimiter CONSTANT CHAR (2) := '##'; + + -- RMM start + -- Record definition used by fileinfo function + TYPE rec_fileinfo IS RECORD ( + fileout ut_config.fileout%TYPE + ,filedir ut_config.filedir%TYPE + ,fileuserprefix ut_config.fileuserprefix%TYPE + ,fileincprogname ut_config.fileincprogname%TYPE + ,filedateformat ut_config.filedateformat%TYPE + ,fileextension ut_config.filedateformat%TYPE + ); + + -- RMM end + + TYPE refcur_t IS REF CURSOR; + + CURSOR browser_cur + IS + SELECT owner, object_name, object_type, created, last_ddl_time, status + FROM all_objects; + + cursor source_cur + IS + SELECT line, text FROM all_source; + + -- Set the user whose configuration we use by default + PROCEDURE settester (username_in IN VARCHAR2 := USER); + + -- Get the user we use by default + FUNCTION tester + RETURN VARCHAR2; + + -- Display the current configuration settings + PROCEDURE showconfig (username_in IN VARCHAR2 := NULL); + + -- Set the default prefix + PROCEDURE setprefix (prefix_in IN VARCHAR2, username_in IN VARCHAR2 := NULL); + + -- Get the default prefix + FUNCTION prefix (username_in IN VARCHAR2 := NULL) + RETURN VARCHAR2; + + -- 2.0.7 Switch to delimiter for V2 + -- Set the default delimiter + PROCEDURE setdelimiter ( + delimiter_in IN VARCHAR2 + ,username_in IN VARCHAR2 := NULL + ); + + -- Get the default delimiter + FUNCTION delimiter (username_in IN VARCHAR2 := NULL) + RETURN VARCHAR2; + + -- Set location of source code + PROCEDURE setdir (dir_in IN VARCHAR2, username_in IN VARCHAR2 := NULL); + + -- Get location of source code + FUNCTION dir (username_in IN VARCHAR2 := NULL) + RETURN VARCHAR2; + + -- Set autocompile flag + PROCEDURE autocompile (onoff_in IN BOOLEAN, username_in IN VARCHAR2 := NULL); + + -- Get autocompile flag + FUNCTION autocompiling (username_in IN VARCHAR2 := NULL) + RETURN BOOLEAN; + + -- Set manual registration flag + PROCEDURE registertest (onoff_in IN BOOLEAN, username_in IN VARCHAR2 + := NULL); + + -- Get manual registration flag + FUNCTION registeringtest (username_in IN VARCHAR2 := NULL) + RETURN BOOLEAN; + + /* start 2.0.10.1 additions */ + -- Show failures only? + PROCEDURE showfailuresonly ( + onoff_in IN BOOLEAN + ,username_in IN VARCHAR2 := NULL + ); + + FUNCTION showingfailuresonly (username_in IN VARCHAR2 := NULL) + RETURN BOOLEAN; + + /* end 2.0.10.1 additions */ + + -- RMM start + -- Get the directory for file output + FUNCTION filedir (username_in IN VARCHAR2 := NULL) + RETURN VARCHAR2; + + -- Set the file output flag + PROCEDURE setfile ( + fileout_in IN BOOLEAN := FALSE + ,username_in IN VARCHAR2 := NULL + ); + + -- Get the file output flag for a user + FUNCTION getfile (username_in IN VARCHAR2 := NULL) + RETURN BOOLEAN; + + -- Set the file prefix for a user + PROCEDURE setuserprefix ( + userprefix_in IN VARCHAR2 := NULL + ,username_in IN VARCHAR2 := NULL + ); + + -- Get the file prefix for a user + FUNCTION userprefix (username_in IN VARCHAR2 := NULL) + RETURN VARCHAR2; + + -- Set the include program name flag for a user + PROCEDURE setincludeprogname ( + incname_in IN BOOLEAN := FALSE + ,username_in IN VARCHAR2 := NULL + ); + + -- Get the include program name flag for a user + FUNCTION includeprogname (username_in IN VARCHAR2 := NULL) + RETURN BOOLEAN; + + -- Set the date format for a user + PROCEDURE setdateformat ( + dateformat_in IN VARCHAR2 := 'yyyyddmmhh24miss' + ,username_in IN VARCHAR2 := NULL + ); + + -- Get the date format for a user + FUNCTION DATEFORMAT (username_in IN VARCHAR2 := NULL) + RETURN VARCHAR2; + + -- Set the file extension for a user + PROCEDURE setfileextension ( + fileextension_in IN VARCHAR2 := '.UTF' + ,username_in IN VARCHAR2 := NULL + ); + + -- Get the file extension for a user + FUNCTION fileextension (username_in IN VARCHAR2 := NULL) + RETURN VARCHAR2; + + -- Set all of the file output columns for a user + PROCEDURE setfileinfo ( + fileout_in IN BOOLEAN := FALSE + ,dir_in IN VARCHAR2 := NULL + ,userprefix_in IN VARCHAR2 := NULL + ,incname_in IN BOOLEAN := FALSE + ,dateformat_in IN VARCHAR2 := 'yyyyddmmhh24miss' + ,fileextension_in IN VARCHAR2 := '.UTF' + ,username_in IN VARCHAR2 := NULL + ); + + -- Get all of the file output columns for a user + FUNCTION fileinfo (username_in IN VARCHAR2 := NULL) + RETURN rec_fileinfo; + + -- RMM end + + -- 2.1.1: Single update and insert procedure + PROCEDURE upd ( + username_in IN ut_config.username%TYPE + ,autocompile_in IN ut_config.autocompile%TYPE + ,prefix_in IN ut_config.prefix%TYPE + ,show_failures_only_in IN ut_config.show_failures_only%TYPE + ,directory_in IN ut_config.DIRECTORY%TYPE + ,filedir_in IN ut_config.filedir%TYPE + ,show_config_info_in IN ut_config.show_config_info%TYPE + ,editor_in IN ut_config.editor%TYPE + ); + + /* The upd procedure does an insert if no row exists. + PROCEDURE add ( + username_in IN ut_config.username%TYPE, + AUTOCOMPILE_in IN ut_config.AUTOCOMPILE%TYPE := 'N', + prefix_in in ut_config.prefix%TYPE := c_prefix, + SHOW_FAILURES_ONLY_in in ut_config.SHOW_FAILURES_ONLY%TYPE := 'N', + directory_in IN ut_config.directory%TYPE := NULL, + FILEDIR_in in ut_config.FILEDIR%TYPE := NULL, + show_config_info_in in ut_config.show_config_info%TYPE := 'Y') ; + */ + FUNCTION browser_contents ( + schema_in IN VARCHAR2 + ,name_like_in IN VARCHAR2 := '%' + ,type_like_in IN VARCHAR2 := '%' + ) + RETURN refcur_t; + + /* + Sample usage: + + DECLARE + rc utconfig.refcur_t; + rec utconfig.browser_cur%ROWTYPE; + BEGIN + rc := utconfig.browser_contents (USER); + + LOOP + FETCH rc INTO rec; + EXIT WHEN rc%NOTFOUND; + p.l (rec.object_name); + END LOOP; + END; + */ + + FUNCTION source_for_program ( + schema_in IN VARCHAR2 + ,name_in IN VARCHAR2 + ) + RETURN refcur_t; + + FUNCTION onerow (schema_in IN VARCHAR2) + RETURN refcur_t; + + PROCEDURE get_onerow ( + schema_in IN VARCHAR2 + ,username_out OUT VARCHAR2 + ,autocompile_out OUT ut_config.autocompile%TYPE + ,prefix_out OUT ut_config.prefix%TYPE + ,show_failures_only_out OUT ut_config.show_failures_only%TYPE + ,directory_out OUT ut_config.DIRECTORY%TYPE + ,filedir_out OUT ut_config.filedir%TYPE + ,show_config_info_out OUT ut_config.show_config_info%TYPE + ,editor_out OUT ut_config.editor%TYPE + ); +END; +/ diff --git a/source/ut_config.tab b/source/ut_config.tab new file mode 100644 index 000000000..14ef7cf26 --- /dev/null +++ b/source/ut_config.tab @@ -0,0 +1,30 @@ +CREATE TABLE ut_config ( + username VARCHAR2(100), + autocompile CHAR(1) DEFAULT 'Y', /* V1 compatibility */ + registertest CHAR(1) DEFAULT 'N', /* V1 compatibility */ + directory VARCHAR2(2000), /* V1 compatibility */ + naming_mode CHAR(2), /* either V1 or V2 */ + prefix VARCHAR2(100) /* V1 name construction */ , + CONSTRAINT ut_config_pk PRIMARY KEY (username) +); + +REM /* V2 name construction */ +ALTER TABLE ut_config ADD delimiter VARCHAR2(10) DEFAULT '##'; + +REM 2.0.10.1 Add show only failure results +ALTER TABLE ut_config ADD show_failures_only CHAR(1) DEFAULT 'N'; + +REM RMM start columns required for file output +ALTER TABLE ut_config ADD filedir VARCHAR2 (2000); +ALTER TABLE ut_config ADD fileout VARCHAR2 (1) DEFAULT 'N'; +ALTER TABLE ut_config ADD fileuserprefix VARCHAR2 (100); +ALTER TABLE ut_config ADD fileincprogname VARCHAR2 (1) DEFAULT 'N'; +ALTER TABLE ut_config ADD filedateformat VARCHAR2 (100) DEFAULT 'yyyyddmmhh24miss'; +ALTER TABLE ut_config ADD fileextension VARCHAR2 (200) DEFAULT '.UTF'; +REM RMM columns required for file output + +REM 2.1.1 +ALTER TABLE ut_config ADD show_config_info VARCHAR2 (1) DEFAULT 'Y'; +ALTER TABLE ut_config ADD editor VARCHAR2 (1000); + + diff --git a/source/ut_deterministic.tab b/source/ut_deterministic.tab new file mode 100644 index 000000000..094dfd7f7 --- /dev/null +++ b/source/ut_deterministic.tab @@ -0,0 +1,12 @@ +create table ut_deterministic ( + package varchar2(100), + overload integer, + name varchar2(100), + tcname varchar2(100), + message varchar2(2000), + arglist varchar2(2000), + result varchar2(2000), + assertion_type varchar2(20)); + +ALTER table ut_deterministic add CONSTRAINT ut_deterministic_pk + primary key (package, overload, name, tcname); diff --git a/source/ut_deterministic_arg.tab b/source/ut_deterministic_arg.tab new file mode 100644 index 000000000..603cfb0a0 --- /dev/null +++ b/source/ut_deterministic_arg.tab @@ -0,0 +1,10 @@ +create table ut_deterministic_arg ( + package varchar2(100), + overload integer, + name varchar2(100), + tcname varchar2(100), + seq integer, + arg_value varchar2(2000)); + +ALTER table ut_deterministic_arg add CONSTRAINT ut_deterministic_fk + FOREIGN KEY (package, overload, name, tcname) REFERENCES ut_deterministic; diff --git a/source/ut_eq.tab b/source/ut_eq.tab new file mode 100644 index 000000000..e8fd252aa --- /dev/null +++ b/source/ut_eq.tab @@ -0,0 +1,15 @@ +create table ut_eq ( +id integer , +outcome_id integer, +data_type integer, +check_v varchar2(2000), +against_v varchar2(2000), +check_d date , +against_d date , +check_n number , +against_n number , +check_b char(1) , +against_b char(1), + CONSTRAINT ut_eq_pk PRIMARY KEY (id) +); + diff --git a/source/ut_gen.pkb b/source/ut_gen.pkb new file mode 100644 index 000000000..03332bc92 --- /dev/null +++ b/source/ut_gen.pkb @@ -0,0 +1,1383 @@ +CREATE OR REPLACE PACKAGE BODY utgen +IS + /* + GNU General Public License for utPLSQL + + Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program (see license.txt); if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + g_pkgstring VARCHAR2 (32767); + g_currrow PLS_INTEGER := NULL; + g_firstbodyrow PLS_INTEGER := NULL; + + TYPE code_tt IS TABLE OF codeline_t + INDEX BY BINARY_INTEGER; + + pkgarray code_tt; + + -- 1.5.6 Generic string parser + + TYPE item_tt IS TABLE OF VARCHAR2 (2000) + INDEX BY BINARY_INTEGER; + + PROCEDURE parse_string ( + string_in IN VARCHAR2, + items_out IN OUT item_tt, + delim_in IN VARCHAR2 := ',' + ) + IS + v_item VARCHAR2 (32767); + v_loc PLS_INTEGER; + v_startloc PLS_INTEGER := 1; + + PROCEDURE add_item (item_in IN VARCHAR2) + IS + BEGIN + IF (item_in != delim_in OR item_in IS NULL) + THEN + items_out (NVL (items_out.LAST, 0) + 1) := item_in; + END IF; + END; + BEGIN + items_out.DELETE; + + LOOP + -- Find next delimiter + v_loc := INSTR (string_in, delim_in, v_startloc); + + IF v_loc = v_startloc -- Previous item is NULL + THEN + v_item := NULL; + ELSIF v_loc = 0 -- Rest of string is last item + THEN + v_item := SUBSTR (string_in, v_startloc); + ELSE + v_item := SUBSTR (string_in, v_startloc, v_loc - v_startloc); + END IF; + + add_item (v_item); + + IF v_loc = 0 + THEN + EXIT; + ELSE + add_item (delim_in); + v_startloc := v_loc + 1; + END IF; + END LOOP; + END parse_string; + + PROCEDURE get_nextline ( + file_in IN UTL_FILE.file_type, + line_out OUT VARCHAR2, + eof_out OUT BOOLEAN + ) + IS + BEGIN + UTL_FILE.get_line (file_in, line_out); + eof_out := FALSE ; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + line_out := NULL; + eof_out := TRUE ; + END; + + -- 1.5.6: add this and rewrite isfunction + + FUNCTION return_type ( + schema_in IN VARCHAR2, + package_in IN VARCHAR2, + program_in IN VARCHAR2, + overload_in IN PLS_INTEGER := NULL + ) + RETURN VARCHAR2 + IS + retval all_arguments.data_type%TYPE; + BEGIN + SELECT data_type + INTO retval + FROM all_arguments + WHERE owner = NVL (UPPER (schema_in), USER) + AND ( package_name = UPPER (package_in) + OR (package_name IS NULL AND package_in IS NULL) + ) + AND object_name = UPPER (program_in) + AND ( overload = overload_in + OR (overload IS NULL AND overload_in IS NULL) + ) + AND argument_name IS NULL + AND POSITION = 0; + + IF retval LIKE 'PL/SQL%' + THEN + -- Change "PL/SQL BOOLEAN" to "BOOLEAN" and so on... + retval := SUBSTR (retval, 8); + ELSIF retval IN ('VARCHAR2', 'VARCHAR', 'CHAR') + THEN + -- Make it a legal string declaration. + retval := retval || '(2000)'; + END IF; + + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + WHEN OTHERS + THEN + RETURN NULL; + END; + + FUNCTION isfunction ( + schema_in IN VARCHAR2, + package_in IN VARCHAR2, + program_in IN VARCHAR2, + overload_in IN PLS_INTEGER := NULL + ) + RETURN BOOLEAN + IS + BEGIN + RETURN (return_type (schema_in, package_in, program_in, overload_in) IS NOT NULL); + END; + + PROCEDURE testpkg ( + package_in IN VARCHAR2, + grid_in IN grid_tt, + program_in IN VARCHAR2 := '%', + samepackage_in IN BOOLEAN := FALSE , + prefix_in IN VARCHAR2 := NULL, + schema_in IN VARCHAR2 := NULL, + output_type_in IN PLS_INTEGER := c_screen, + dir_in IN VARCHAR2 := NULL, + delim_in IN VARCHAR2 := c_delim, + date_format_in IN VARCHAR2 := 'MM/DD/YYYY', + only_if_in_grid_in IN BOOLEAN := FALSE, + override_file_in IN VARCHAR2 := NULL + ) + IS + fid UTL_FILE.file_type; + v_ispkg BOOLEAN := utplsql.ispackage (package_in, schema_in); + v_dir VARCHAR2 (2000) := NVL (dir_in, utconfig.dir); + v_pkg VARCHAR2 (100); + v_progprefix VARCHAR2 (100); + -- Used in queries against ALL_ARGUMENTS + v_objpackage VARCHAR2 (100); + v_objprogram VARCHAR2 (100); + l_grid grid_tt; + + CURSOR prog_cur (package_in IN VARCHAR2, program_in IN VARCHAR2) + IS + SELECT DISTINCT owner, package_name, object_name, overload, + object_name || overload + full_name + FROM all_arguments + WHERE owner = NVL (UPPER (schema_in), USER) + AND ( package_name = UPPER (package_in) + AND object_name LIKE + NVL (UPPER (program_in), '%') + ) + OR ( ( package_name IS NULL + -- 2.0.9.1 9i changes way package_name is set. + OR package_name = UPPER (program_in) + ) + AND package_in IS NULL + AND object_name = UPPER (program_in) + ); + + CURSOR arg_cur ( + schema_in IN VARCHAR2, + package_in IN VARCHAR2, + program_in IN VARCHAR2, + overload_in IN PLS_INTEGER + ) + IS + SELECT argument_name, data_type + FROM all_arguments + WHERE owner = schema_in + AND ( package_name = package_in + OR (package_name IS NULL AND package_in IS NULL) + ) + AND object_name = program_in + AND argument_name IS NOT NULL + AND ( overload = overload_in + OR (overload IS NULL AND overload_in IS NULL) + ) + ORDER BY POSITION; + + arg arg_cur%ROWTYPE; + noargs BOOLEAN; + + PROCEDURE setup (ext IN VARCHAR2 := NULL) + IS + BEGIN + IF output_type_in = c_screen + THEN + NULL; + ELSIF output_type_in = c_string + THEN + g_pkgstring := NULL; + ELSIF output_type_in = c_array + THEN + pkgarray.DELETE; + g_currrow := NULL; + g_firstbodyrow := NULL; + ELSIF output_type_in = c_file + THEN + utassert.this ( + 'Compile error: you must specify a directory with utConfig.setdir!', + v_dir IS NOT NULL, + register_in => FALSE + ); + + IF utplsql.tracing + THEN + utplsql.pl (v_dir || '-' || package_in || '.' || ext); + END IF; + + fid := UTL_FILE.fopen ( + v_dir, + NVL (override_file_in, + NVL (prefix_in, utconfig.prefix (schema_in)) + || package_in + || '.' + || ext), + 'W' + &start81 , max_linesize => 32767 &end81 + ); + END IF; + END; + + PROCEDURE putline (str IN VARCHAR2) + IS + BEGIN + IF output_type_in = c_screen + THEN + utplsql.pl (str); + ELSIF output_type_in = c_string + THEN + g_pkgstring := g_pkgstring || '|' || str; + ELSIF output_type_in = c_array + THEN + pkgarray (NVL (pkgarray.LAST, 0) + 1) := str; + ELSIF output_type_in = c_file + THEN + UTL_FILE.put_line (fid, str); + END IF; + END; + + PROCEDURE cleanup + IS + BEGIN + IF output_type_in = c_screen + THEN + NULL; + ELSIF output_type_in = c_string + THEN + g_pkgstring := LTRIM (g_pkgstring, '|'); + ELSIF output_type_in = c_file + THEN + UTL_FILE.fclose (fid); + END IF; + END; + + FUNCTION program_call ( -- 2.0.9.1 switch to whole record + rec IN prog_cur%ROWTYPE, + is_package IN BOOLEAN /* + package_in IN VARCHAR2, + program_in IN VARCHAR2 */ + ) + RETURN VARCHAR2 + IS + BEGIN + IF rec.package_name IS NOT NULL AND is_package + THEN + RETURN rec.package_name || '.' || rec.object_name; + ELSE + RETURN rec.object_name; + END IF; + END; + + PROCEDURE iputline (string_in IN VARCHAR2, indentby_in IN PLS_INTEGER + := 3) + IS + BEGIN + putline (LPAD (' ', indentby_in, ' ') || string_in); + END; + + PROCEDURE i6putline (string_in IN VARCHAR2) + IS + BEGIN + putline (LPAD (' ', 6, ' ') || string_in); + END; + + FUNCTION include_program ( + NAME_IN IN VARCHAR2, + overload_in IN PLS_INTEGER, + curr_name_in IN VARCHAR2, + curr_overload_in IN PLS_INTEGER + ) + RETURN BOOLEAN + IS + BEGIN + RETURN ( UPPER (NAME_IN) = curr_name_in + AND ( overload_in = curr_overload_in + OR (overload_in = 1 AND curr_overload_in IS NULL) + OR (overload_in IS NULL AND curr_overload_in IS NULL) + ) + ); + -- OR v_objprogram = '%'; + END; + + FUNCTION include_program (rec IN prog_cur%ROWTYPE, grid_in IN grid_tt) + RETURN BOOLEAN + IS + retval BOOLEAN := NOT only_if_in_grid_in; + grid_index PLS_INTEGER := grid_in.FIRST; + BEGIN + -- Does the program in rec appear at all in grid_in? + IF only_if_in_grid_in + THEN + LOOP + EXIT WHEN grid_index IS NULL; + + IF include_program ( + grid_in (grid_index).progname, + grid_in (grid_index).overload, + rec.object_name, + rec.overload + ) + THEN + retval := TRUE ; + EXIT; + ELSE + grid_index := grid_in.NEXT (grid_index); + END IF; + END LOOP; + END IF; + + RETURN retval; + END; + + PROCEDURE generate_setup ( + prefix_in IN VARCHAR2, + schema_in IN VARCHAR2, + objpackage_in IN VARCHAR2, + objprogram_in IN VARCHAR2 + ) + IS + BEGIN + iputline ('PROCEDURE ' || prefix_in || 'setup'); + iputline ('IS'); + iputline ('BEGIN'); + + IF utconfig.registeringtest (schema_in) + THEN + iputline (' -- For each program to test...'); + + FOR rec IN prog_cur (objpackage_in, objprogram_in) + LOOP + IF include_program (rec, grid_in) + THEN + iputline (' utPLSQL.addtest (''' || rec.full_name || ''');'); + END IF; + END LOOP; + ELSE + iputline (' NULL;'); + END IF; + + iputline ('END;'); + iputline (''); + END; + + PROCEDURE generate_teardown (prefix_in IN VARCHAR2) + IS + BEGIN + iputline ('PROCEDURE ' || prefix_in || 'teardown'); + iputline ('IS'); + iputline ('BEGIN'); + iputline (' NULL;'); + iputline ('END;'); + END; + + FUNCTION is_expression (string_in IN VARCHAR2) + RETURN BOOLEAN + IS + BEGIN + RETURN SUBSTR (string_in, 1, 1) = c_asis; + END; + + PROCEDURE generate_ut_procedure ( + prefix_in IN VARCHAR2, + rec IN prog_cur%ROWTYPE, + /*schema_in IN VARCHAR2, + objpackage_in IN VARCHAR2, + objprogram_in IN VARCHAR2,*/ + grid_in IN grid_tt + ) + IS + v_isfunction BOOLEAN; + v_datatype VARCHAR2 (100); + + FUNCTION data_value (value_in IN VARCHAR2, type_in IN VARCHAR2) + RETURN VARCHAR2 + IS + retval VARCHAR2 (2000) := value_in; + BEGIN + IF is_expression (value_in) + THEN + retval := SUBSTR (value_in, 2); + ELSIF value_in IS NULL OR UPPER (value_in) = 'NULL' + THEN + retval := 'NULL'; + ELSIF type_in LIKE '%CHAR%' + THEN + retval := '''' || value_in || ''''; + ELSIF type_in IN ('NUMBER', 'FLOAT') OR type_in LIKE '%INT%' + THEN + retval := value_in; + ELSIF type_in IN ('BOOLEAN', 'PL/SQL BOOLEAN') + THEN + retval := value_in; + ELSIF type_in LIKE '%DATE%' + THEN + retval := 'TO_DATE (''' + || value_in + || ''', ''' + || date_format_in + || ''')'; + END IF; + + RETURN retval; + END; + + PROCEDURE generate_testcase ( + rec IN prog_cur%ROWTYPE, + isfunction_in IN BOOLEAN, + datatype_in IN VARCHAR2, + grid_in IN grid_rt + ) + IS + l_entries item_tt; + + PROCEDURE putarg ( + arg_in IN arg_cur%ROWTYPE, + ntharg_in IN PLS_INTEGER + ) + IS + BEGIN + IF l_entries.COUNT > 0 + THEN + i6putline ( + ' ' + || arg_in.argument_name + || ' => ' + || data_value (l_entries (ntharg_in), arg_in.data_type) + ); + ELSE + i6putline (' ' || arg_in.argument_name || ' => '''''); + END IF; + END; + + FUNCTION testname + RETURN VARCHAR2 + IS + BEGIN + IF grid_in.progname IS NOT NULL + THEN + RETURN ' for "' || grid_in.tcname || '"'; + ELSE + RETURN NULL; + END IF; + END; + BEGIN + i6putline (''); + i6putline ('-- Define "control" operation' || testname); + i6putline (' '); + + IF isfunction_in + THEN + i6putline ( + 'against_this := ' + || data_value (grid_in.return_value, datatype_in) + || ';' + ); + END IF; + + i6putline (' '); + i6putline ('-- Execute test code' || testname); + i6putline (' '); + OPEN arg_cur ( + rec.owner, + rec.package_name, + rec.object_name, + rec.overload + ); + FETCH arg_cur INTO arg; + noargs := arg_cur%NOTFOUND; + + IF isfunction_in + THEN + i6putline ('check_this := '); + END IF; + + IF noargs + THEN + i6putline ( -- 2.0.9.1: use procedure, not explicit concat. + program_call (rec, v_ispkg) || ';' + ); + ELSE + i6putline (program_call (rec, v_ispkg) || ' ('); + + IF grid_in.arglist IS NOT NULL + THEN + parse_string (grid_in.arglist, l_entries, delim_in); + END IF; + + WHILE arg_cur%FOUND + LOOP + putarg (arg, arg_cur%ROWCOUNT); + FETCH arg_cur INTO arg; + + IF arg_cur%FOUND + THEN + i6putline (' ,'); + END IF; + END LOOP; + + iputline (' );'); + END IF; + + CLOSE arg_cur; + i6putline (' '); + i6putline ('-- Assert success' || testname); + i6putline (' '); + + +-- Here I should access information in ut_assertion table to dynamically + -- build the call to the utAssert procedure. For now, I will hard code + -- for EQ and ISNULL to demonstrate the possibilities. + + IF v_isfunction + THEN + IF grid_in.assertion_type = 'EQ' + OR grid_in.assertion_type IS NULL + THEN + i6putline ('-- Compare the two values.'); + i6putline ('utAssert.eq ('); + i6putline ( + ' ''' + || NVL (grid_in.MESSAGE, 'Test of ' || rec.object_name) + || ''',' + ); + i6putline (' check_this,'); + i6putline (' against_this'); + i6putline (' );'); + ELSIF grid_in.assertion_type = 'ISNULL' + THEN + i6putline ('-- Check for NULL return value.'); + i6putline ('utAssert.isNULL ('); + i6putline ( + ' ''' + || NVL ( + grid_in.MESSAGE, + 'NULL Test for ' || rec.object_name + ) + || ''',' + ); + i6putline (' check_this'); + i6putline (' );'); + END IF; + ELSE + i6putline ('utAssert.this ('); + i6putline ( + ' ''' + || NVL (grid_in.MESSAGE, 'Test of ' || rec.object_name) + || ''',' + ); + i6putline (' '''''); + i6putline (' );'); + END IF; + + i6putline (''); + i6putline ('-- End of test' || testname); + END; + + PROCEDURE generate_testcase ( + rec IN prog_cur%ROWTYPE, + isfunction_in IN BOOLEAN, + datatype_in IN VARCHAR2 + ) + IS + l_empty grid_rt; + BEGIN + generate_testcase (rec, isfunction_in, datatype_in, l_empty); + END; + BEGIN + v_isfunction := isfunction ( + rec.owner, + rec.package_name, + rec.object_name, + rec.overload + ); + + IF v_isfunction + THEN + v_datatype := return_type ( + rec.owner, + rec.package_name, + rec.object_name, + rec.overload + ); + END IF; + + iputline ('PROCEDURE ' || prefix_in || rec.full_name); + iputline ('IS'); + + IF v_isfunction + THEN + i6putline ('-- Verify and complete data types.'); + i6putline ('against_this ' || v_datatype || ';'); + i6putline ('check_this ' || v_datatype || ';'); + END IF; + + iputline ('BEGIN'); + + IF grid_in.COUNT = 0 + THEN + generate_testcase (rec, v_isfunction, v_datatype); + ELSE + FOR indx IN grid_in.FIRST .. grid_in.LAST + LOOP + generate_testcase ( + rec, + v_isfunction, + v_datatype, + grid_in (indx) + ); + END LOOP; + END IF; + + iputline ('END ' || v_progprefix || rec.full_name || ';'); + putline (''); + END; + BEGIN /* MAIN TESTPKG */ + utassert.this ( + 'Invalid target to generate a package: ' || output_type_in, + output_type_in IN (c_string, c_screen, c_file, c_array), + register_in => FALSE + ); + v_pkg := utplsql.pkgname ( + package_in, + samepackage_in, + NVL (prefix_in, utconfig.prefix (schema_in)), + v_ispkg + ); + v_progprefix := utplsql.progname ( + NULL, + samepackage_in, + NVL (prefix_in, utconfig.prefix (schema_in)), + v_ispkg + ); + + IF v_ispkg + THEN + v_objpackage := UPPER (package_in); + v_objprogram := UPPER (program_in); + ELSE + v_objpackage := NULL; + v_objprogram := UPPER (package_in); + END IF; + + setup ('pks'); + + -- Spit out the package spec + + IF samepackage_in + THEN + putline ('-- START: place in specification of source package'); + ELSE + putline ('CREATE OR REPLACE PACKAGE ' || v_pkg); + putline ('IS'); + END IF; + + putline (' PROCEDURE ' || v_progprefix || 'setup;'); + putline (' PROCEDURE ' || v_progprefix || 'teardown;'); + putline (' '); + putline (' -- For each program to test...'); + + FOR rec IN prog_cur (v_objpackage, v_objprogram) + LOOP + IF include_program (rec, grid_in) + THEN + putline (' PROCEDURE ' || v_progprefix || rec.full_name || ';'); + END IF; + END LOOP; + + IF samepackage_in + THEN + putline ('-- END: place in specification of source package'); + ELSE + putline ('END ' || v_pkg || ';'); + putline ('/'); + END IF; + + -- Spit out the package body into a separate file + + IF output_type_in = c_file + THEN + cleanup; + setup ('pkb'); + ELSIF output_type_in = c_array + THEN + g_firstbodyrow := pkgarray.LAST + 1; + END IF; + + IF samepackage_in + THEN + putline ('-- START: place in body of source package'); + ELSE + putline ('CREATE OR REPLACE PACKAGE BODY ' || v_pkg); + putline ('IS'); + END IF; + + generate_setup (v_progprefix, schema_in, v_objpackage, v_objprogram); + generate_teardown (v_progprefix); + putline (' -- For each program to test...'); + + FOR rec IN prog_cur (v_objpackage, v_objprogram) + LOOP + l_grid.DELETE; + + IF grid_in.COUNT > 0 + THEN + /* + Go through the grid, pulling out only those test case rows + for the current program and then populate the test case procedure + accordingly. + */ + FOR indx IN grid_in.FIRST .. grid_in.LAST + LOOP + -- should switch to passing in records. + IF include_program ( + grid_in (indx).progname, + grid_in (indx).overload, + rec.object_name, + rec.overload + ) + THEN + l_grid (indx) := grid_in (indx); + END IF; + END LOOP; + END IF; + + IF l_grid.COUNT > 0 OR NOT NVL (only_if_in_grid_in, FALSE ) +-- IF l_grid.COUNT > 0 + THEN + generate_ut_procedure ( + v_progprefix, + rec, /*schema_in, + rec.package_name, + rec.object_name,*/ + l_grid + ); + END IF; + END LOOP; + + IF samepackage_in + THEN + putline ('-- END: place in body of source package'); + ELSE + putline ('END ' || v_pkg || ';'); + putline ('/'); + END IF; + + cleanup; + END testpkg; + + PROCEDURE clean_up_file_io ( + prog_in IN VARCHAR2, + file_in IN OUT UTL_FILE.file_type, + err_in IN VARCHAR2 := NULL + ) + IS + BEGIN + UTL_FILE.fclose (file_in); + + IF err_in IS NOT NULL + THEN + utplsql.pl (prog_in || ' File IO failure: ' || err_in); + END IF; + END; + + PROCEDURE testpkg ( + package_in IN VARCHAR2, + program_in IN VARCHAR2 := '%', + samepackage_in IN BOOLEAN := FALSE , + prefix_in IN VARCHAR2 := NULL, + schema_in IN VARCHAR2 := NULL, + output_type_in IN PLS_INTEGER := c_screen, + dir_in IN VARCHAR2 := NULL, + override_file_in IN VARCHAR2 := NULL + ) + IS + l_grid grid_tt; + BEGIN + -- pass an empty grid to the engine. + testpkg ( + package_in, + l_grid, + program_in, + samepackage_in, + prefix_in, + schema_in, + output_type_in, + dir_in, + only_if_in_grid_in => FALSE, + override_file_in => override_file_in + ); + END; + + FUNCTION valid_entry (string_in IN VARCHAR2) + RETURN BOOLEAN + IS + BEGIN + RETURN string_in IS NOT NULL AND string_in NOT LIKE '#%'; + END; + + PROCEDURE testpkg_from_file ( + package_in IN VARCHAR2, + gridfile_loc_in IN VARCHAR2, + gridfile_in IN VARCHAR2, + program_in IN VARCHAR2 := '%', + samepackage_in IN BOOLEAN := FALSE , + prefix_in IN VARCHAR2 := NULL, + schema_in IN VARCHAR2 := NULL, + output_type_in IN PLS_INTEGER := c_screen, + dir_in IN VARCHAR2 := NULL, + field_delim_in IN VARCHAR2 := '|', + arg_delim_in IN VARCHAR2 := c_delim, + date_format_in IN VARCHAR2 := 'MM/DD/YYYY', + only_if_in_grid_in IN BOOLEAN := FALSE, + override_file_in IN VARCHAR2 := NULL + ) + IS + c_progname VARCHAR2 (30) := 'testpkg_from_file'; + fid UTL_FILE.file_type; + l_line VARCHAR2 (1000); + l_eof BOOLEAN; + l_entries item_tt; + l_grid grid_tt; + l_indx PLS_INTEGER; + BEGIN + fid := UTL_FILE.fopen (gridfile_loc_in, gridfile_in, 'R'); + + LOOP + get_nextline (fid, l_line, l_eof); + l_line := LTRIM (l_line); + EXIT WHEN l_eof; + + IF valid_entry (l_line) + THEN + parse_string (l_line, l_entries, field_delim_in); + l_indx := NVL (l_grid.LAST, 0) + 1; + l_grid (l_indx).progname := UPPER (l_entries (1)); + l_grid (l_indx).overload := l_entries (2); + l_grid (l_indx).tcname := l_entries (3); + l_grid (l_indx).MESSAGE := l_entries (4); + l_grid (l_indx).arglist := l_entries (5); + l_grid (l_indx).return_value := l_entries (6); + l_grid (l_indx).assertion_type := UPPER (l_entries (7)); + END IF; + END LOOP; + + clean_up_file_io (c_progname, fid); + testpkg ( + package_in, + l_grid, + program_in, + samepackage_in, + prefix_in, + schema_in, + output_type_in, + dir_in, + arg_delim_in, + date_format_in, + only_if_in_grid_in, + override_file_in => override_file_in + ); + EXCEPTION + WHEN UTL_FILE.invalid_path + THEN + clean_up_file_io (c_progname, fid, 'invalid_path'); + WHEN UTL_FILE.invalid_mode + THEN + clean_up_file_io (c_progname, fid, 'invalid_mode'); + WHEN UTL_FILE.invalid_filehandle + THEN + clean_up_file_io (c_progname, fid, 'invalid_filehandle'); + WHEN UTL_FILE.invalid_operation + THEN + clean_up_file_io (c_progname, fid, 'invalid_operation'); + WHEN UTL_FILE.read_error + THEN + clean_up_file_io (c_progname, fid, 'read_error'); + WHEN UTL_FILE.write_error + THEN + clean_up_file_io (c_progname, fid, 'write_error'); + WHEN UTL_FILE.internal_error + THEN + clean_up_file_io (c_progname, fid, 'internal_error'); + WHEN OTHERS + THEN + clean_up_file_io (c_progname, fid, SQLERRM); + END testpkg_from_file; + + PROCEDURE testpkg_from_string ( + package_in IN VARCHAR2, + grid_in IN VARCHAR2, + program_in IN VARCHAR2 := '%', + samepackage_in IN BOOLEAN := FALSE , + prefix_in IN VARCHAR2 := NULL, + schema_in IN VARCHAR2 := NULL, + output_type_in IN PLS_INTEGER := c_screen, + dir_in IN VARCHAR2 := NULL, + line_delim_in IN VARCHAR := CHR (10), + field_delim_in IN VARCHAR2 := '|', + arg_delim_in IN VARCHAR2 := c_delim, + date_format_in IN VARCHAR2 := 'MM/DD/YYYY', + only_if_in_grid_in IN BOOLEAN := FALSE, + override_file_in IN VARCHAR2 := NULL + ) + IS + c_progname VARCHAR2 (30) := 'testpkg_from_string'; + l_line VARCHAR2 (1000); + l_lines item_tt; + l_entries item_tt; + l_grid grid_tt; + l_indx PLS_INTEGER; + BEGIN + IF grid_in IS NOT NULL + THEN + parse_string (grid_in, l_lines, line_delim_in); + + FOR l_linenum IN l_lines.FIRST .. l_lines.LAST + LOOP + IF valid_entry (l_lines (l_linenum)) + THEN + parse_string (l_lines (l_linenum), l_entries, field_delim_in); + l_indx := NVL (l_grid.LAST, 0) + 1; + l_grid (l_indx).progname := UPPER (l_entries (1)); + l_grid (l_indx).overload := l_entries (2); + l_grid (l_indx).tcname := l_entries (3); + l_grid (l_indx).MESSAGE := l_entries (4); + l_grid (l_indx).arglist := l_entries (5); + l_grid (l_indx).return_value := l_entries (6); + l_grid (l_indx).assertion_type := UPPER (l_entries (7)); + END IF; + END LOOP; + + testpkg ( + package_in, + l_grid, + program_in, + samepackage_in, + prefix_in, + schema_in, + output_type_in, + dir_in, + arg_delim_in, + date_format_in, + only_if_in_grid_in, + override_file_in => override_file_in + ); + END IF; + END; + + PROCEDURE testpkg_from_string_od ( + package_in IN VARCHAR2, + grid_in IN VARCHAR2, + dir_in IN VARCHAR2 := NULL, + override_file_in IN VARCHAR2 := NULL + ) + IS + BEGIN + testpkg_from_string ( + package_in, + grid_in, + output_type_in => c_file, + dir_in => dir_in, + only_if_in_grid_in => TRUE, + override_file_in => override_file_in + ); + END; + + PROCEDURE clear_grid ( + owner_in IN ut_grid.owner%TYPE + ,package_in IN ut_grid.PACKAGE%TYPE) + IS + BEGIN + delete from ut_grid WHERE ut_grid.owner = UPPER (owner_in) + AND ut_grid.PACKAGE = UPPER (package_in); + + END; + + PROCEDURE add_to_grid ( + owner_in IN ut_grid.owner%TYPE + ,package_in IN ut_grid.PACKAGE%TYPE + ,progname_in IN ut_grid.progname%TYPE + ,overload_in IN ut_grid.overload%TYPE + ,tcname_in IN ut_grid.tcname%TYPE + ,message_in IN ut_grid.MESSAGE%TYPE + ,arglist_in IN ut_grid.arglist%TYPE + ,return_value_in IN ut_grid.return_value%TYPE + ,assertion_type_in IN ut_grid.assertion_type%TYPE + ) + IS + BEGIN + INSERT INTO ut_grid + (owner, PACKAGE, progname, overload, tcname, MESSAGE + ,arglist, return_value, assertion_type + ) + VALUES (owner_in, package_in, progname_in, overload_in, tcname_in, message_in + ,arglist_in, return_value_in, assertion_type_in + ); + END add_to_grid; + + -- 2.0.10.1 From Patrick Barel +/* START Patch72 607131 */ + PROCEDURE testpkg_from_table ( + package_in IN VARCHAR2, + program_in IN VARCHAR2 := '%', + samepackage_in IN BOOLEAN := FALSE , + prefix_in IN VARCHAR2 := NULL, + schema_in IN VARCHAR2 := NULL, + output_type_in IN PLS_INTEGER := c_screen, + dir_in IN VARCHAR2 := NULL, + date_format_in IN VARCHAR2 := 'MM/DD/YYYY', + override_file_in IN VARCHAR2 := NULL + ) + IS + CURSOR c_ut_grid (p_package VARCHAR2, p_owner VARCHAR2) + IS + SELECT ut_grid.owner, + ut_grid.progname, ut_grid.overload, ut_grid.tcname, + ut_grid.MESSAGE, ut_grid.arglist, ut_grid.return_value, + ut_grid.assertion_type + FROM ut_grid + WHERE ut_grid.owner = UPPER (p_owner) + AND ut_grid.PACKAGE = UPPER (p_package) + ORDER BY ut_grid.progname; + + lv_grid utgen.grid_tt; + rc_ut_grid c_ut_grid%ROWTYPE; + lv_index NUMBER := -1; + BEGIN + IF c_ut_grid%ISOPEN + THEN + CLOSE c_ut_grid; + END IF; -- c_ut_grid%IsOpen + + OPEN c_ut_grid (p_package => package_in, p_owner => NVL (schema_in, USER)); + FETCH c_ut_grid INTO rc_ut_grid; + + WHILE c_ut_grid%FOUND + LOOP + lv_index := lv_index + 1; + lv_grid (lv_index).progname := rc_ut_grid.progname; + lv_grid (lv_index).overload := rc_ut_grid.overload; + lv_grid (lv_index).tcname := rc_ut_grid.tcname; + lv_grid (lv_index).MESSAGE := rc_ut_grid.MESSAGE; + lv_grid (lv_index).arglist := rc_ut_grid.arglist; + lv_grid (lv_index).return_value := rc_ut_grid.return_value; + lv_grid (lv_index).assertion_type := rc_ut_grid.assertion_type; + FETCH c_ut_grid INTO rc_ut_grid; + END LOOP; + + IF c_ut_grid%ISOPEN + THEN + CLOSE c_ut_grid; + END IF; -- c_ut_grid%IsOpen + + IF lv_index > -1 + THEN +/* utgen.testpkg ( + package_in => package_in, + grid_in => lv_grid, + date_format_in => date_format_in + ); +*/ +-- We have access to all parameters (either sent in or default). Why not use them? + utgen.testpkg ( + package_in => package_in /* SEF fix 10/9/2 lv_package*/ + , grid_in => lv_grid + , program_in => program_in + , samepackage_in => samepackage_in + , prefix_in => prefix_in + , schema_in => schema_in + , output_type_in => output_type_in + , dir_in => dir_in + , date_format_in => date_format_in + , override_file_in => override_file_in + ); + + END IF; -- lv_index > -1 + END; +/* END Patch72 607131 */ + + FUNCTION pkgstring + RETURN VARCHAR2 + IS + BEGIN + RETURN g_pkgstring; + END; + + /* Returns data in order retrieved (ie, Nth row). */ + FUNCTION nthrow (nth IN PLS_INTEGER, direction IN SIGNTYPE := 1) + RETURN codeline_t + IS + v_nth PLS_INTEGER := 1; + v_row PLS_INTEGER; + retval codeline_t; + BEGIN + IF direction = 1 + THEN + v_row := pkgarray.FIRST; + ELSE + v_row := pkgarray.LAST; + END IF; + + /* Since no prep work was done, do a scan through table. */ + LOOP + EXIT WHEN v_row IS NULL; + + IF v_nth = nth + THEN + retval := pkgarray (v_row); + EXIT; + ELSE + v_nth := v_nth + 1; + + IF direction = 1 + THEN + v_row := pkgarray.NEXT (v_row); + ELSE + v_row := pkgarray.PRIOR (v_row); + END IF; + END IF; + END LOOP; + + RETURN retval; + END; + + FUNCTION firstrow + RETURN PLS_INTEGER + IS + BEGIN + RETURN pkgarray.FIRST; + END; + + FUNCTION lastrow + RETURN PLS_INTEGER + IS + BEGIN + RETURN pkgarray.LAST; + END; + + FUNCTION atfirstrow + RETURN BOOLEAN + IS + BEGIN + RETURN g_currrow = pkgarray.FIRST; + END; + + FUNCTION atlastrow + RETURN BOOLEAN + IS + BEGIN + RETURN g_currrow = pkgarray.LAST; + END; + + FUNCTION firstbodyrow + RETURN PLS_INTEGER + IS + BEGIN + RETURN g_firstbodyrow; + END; + + FUNCTION countrows + RETURN PLS_INTEGER + IS + BEGIN + RETURN pkgarray.COUNT; + END; + + PROCEDURE init_currrow + IS + BEGIN + IF g_currrow IS NULL + THEN + g_currrow := pkgarray.FIRST; + END IF; + END; + + PROCEDURE setrow (nth IN PLS_INTEGER) + IS + BEGIN + g_currrow := nth; + END; + + FUNCTION getrow + RETURN codeline_t + IS + BEGIN + init_currrow; + RETURN pkgarray (g_currrow); + END; + + PROCEDURE nextrow + IS + BEGIN + init_currrow; + g_currrow := pkgarray.NEXT (g_currrow); + END; + + PROCEDURE prevrow + IS + BEGIN + init_currrow; + g_currrow := pkgarray.PRIOR (g_currrow); + END; + + PROCEDURE showrows ( + startrow IN PLS_INTEGER := NULL, + endrow IN PLS_INTEGER := NULL + ) + IS + v_start PLS_INTEGER := NVL (startrow, 1); + v_end PLS_INTEGER := NVL (endrow, countrows); + BEGIN + FOR indx IN 1 .. countrows + LOOP + setrow (indx); + utplsql.pl (getrow); + END LOOP; + END; + + -- TO COMPLETE: apply same output type flexibility + -- from testpkg to receq_compare. + PROCEDURE putline (str IN VARCHAR2) + IS + BEGIN + DBMS_OUTPUT.put_line (str); + END; + +-- 2.0.8 Implementation provided by Dan Spencer! + PROCEDURE receq_package ( + table_in IN VARCHAR2, + pkg_in IN VARCHAR2 := NULL, + owner_in IN VARCHAR2 := NULL + ) + IS + v_pkg VARCHAR2 (30) + := NVL (pkg_in, SUBSTR ('receq_' || table_in, 1, 30)); + v_owner VARCHAR2 (30) := UPPER (NVL (owner_in, USER)); + v_table VARCHAR2 (30) := UPPER (table_in); + BEGIN + putline ('CREATE OR REPLACE PACKAGE ' || v_pkg || ' IS'); + + FOR tabs_rec IN (SELECT * + FROM all_tables + WHERE owner = v_owner AND table_name = v_table) + LOOP + putline ( + 'FUNCTION eq(a ' + || tabs_rec.table_name + || '%ROWTYPE , b ' + || tabs_rec.table_name + || '%ROWTYPE ) RETURN BOOLEAN; ' + ); + END LOOP; + + putline (' END ' || v_pkg || ';'); + putline ('/'); + putline (' '); + putline ('CREATE OR REPLACE PACKAGE BODY ' || v_pkg || ' IS'); + + FOR tabs_rec IN (SELECT * + FROM all_tables + WHERE owner = v_owner AND table_name = v_table) + LOOP + putline ( + 'FUNCTION eq( a ' + || tabs_rec.table_name + || '%ROWTYPE , ' + || 'b ' + || tabs_rec.table_name + || '%ROWTYPE ) ' + || 'RETURN BOOLEAN ' + ); + putline ('IS BEGIN '); + putline (' RETURN ('); + + FOR user_tab_columns_rec IN (SELECT * + FROM user_tab_columns + WHERE table_name = + tabs_rec.table_name + ORDER BY column_id) + LOOP + IF user_tab_columns_rec.column_id > 1 + THEN + putline (' AND '); + END IF; + + IF user_tab_columns_rec.data_type = 'CLOB' + THEN + putline ( + '( ( a.' + || user_tab_columns_rec.column_name + || ' IS NULL AND b.' + || user_tab_columns_rec.column_name + || ' IS NULL ) OR DBMS_LOB.COMPARE( a.' + || user_tab_columns_rec.column_name + || ' , b.' + || user_tab_columns_rec.column_name + || ') = 0 )' + ); + ELSE + putline ( + '( ( a.' + || user_tab_columns_rec.column_name + || ' IS NULL AND b.' + || user_tab_columns_rec.column_name + || ' IS NULL ) OR a.' + || user_tab_columns_rec.column_name + || ' = b.' + || user_tab_columns_rec.column_name + || ')' + ); + END IF; + END LOOP; + + putline ('); END eq;'); + END LOOP; + + putline (' END ' || v_pkg || ';'); + putline ('/'); + putline (' '); + END; +END; +/ diff --git a/source/ut_gen.pks b/source/ut_gen.pks new file mode 100644 index 000000000..88676eba7 --- /dev/null +++ b/source/ut_gen.pks @@ -0,0 +1,218 @@ +CREATE OR REPLACE PACKAGE utgen +&start81 +AUTHID CURRENT_USER +&end81 +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* +11/2001 SEF Add receq_package based on functionality provided by Dan Spencer. +09/2002 PBA Add testpkg_from_table functionality. Depends upon table ut_grid for + input. +*/ + c_screen CONSTANT PLS_INTEGER := 1; + c_string CONSTANT PLS_INTEGER := 2; + c_file CONSTANT PLS_INTEGER := 3; + c_array CONSTANT PLS_INTEGER := 4; + c_delim CONSTANT CHAR (1) := ';'; + c_comment CONSTANT CHAR (1) := '#'; + c_asis CONSTANT CHAR (1) := '!'; + &start81 SUBTYPE codeline_t IS VARCHAR2(200); &end81 + + &start73 + v_codeline VARCHAR2 (200); + + SUBTYPE codeline_t IS v_codeline%TYPE; + + &end73 + + -- Each line in the grid represents a test case + -- + + TYPE grid_rt IS RECORD ( + progname VARCHAR2 (100), + overload PLS_INTEGER, + tcname VARCHAR2 (100), + MESSAGE VARCHAR2 (2000), + arglist VARCHAR2 (2000), + return_value VARCHAR2 (2000), + assertion_type VARCHAR2 (100) + ); + + TYPE grid_tt IS TABLE OF grid_rt + INDEX BY BINARY_INTEGER; + + PROCEDURE testpkg ( + package_in IN VARCHAR2, + program_in IN VARCHAR2 := '%', + samepackage_in IN BOOLEAN := FALSE , + prefix_in IN VARCHAR2 := NULL, + schema_in IN VARCHAR2 := NULL, + output_type_in IN PLS_INTEGER := c_screen, + dir_in IN VARCHAR2 := NULL, + override_file_in IN VARCHAR2 := NULL + ); + + PROCEDURE testpkg ( + package_in IN VARCHAR2, + grid_in IN grid_tt, + program_in IN VARCHAR2 := '%', + samepackage_in IN BOOLEAN := FALSE , + prefix_in IN VARCHAR2 := NULL, + schema_in IN VARCHAR2 := NULL, + output_type_in IN PLS_INTEGER := c_screen, + dir_in IN VARCHAR2 := NULL, + delim_in IN VARCHAR2 := c_delim, + date_format_in IN VARCHAR2 := 'MM/DD/YYYY', + only_if_in_grid_in IN BOOLEAN := FALSE, + override_file_in IN VARCHAR2 := NULL + ); + + PROCEDURE testpkg_from_file ( + package_in IN VARCHAR2, + gridfile_loc_in IN VARCHAR2, + gridfile_in IN VARCHAR2, + program_in IN VARCHAR2 := '%', + samepackage_in IN BOOLEAN := FALSE , + prefix_in IN VARCHAR2 := NULL, + schema_in IN VARCHAR2 := NULL, + output_type_in IN PLS_INTEGER := c_screen, + dir_in IN VARCHAR2 := NULL, + field_delim_in IN VARCHAR2 := '|', + arg_delim_in IN VARCHAR2 := c_delim, + date_format_in IN VARCHAR2 := 'MM/DD/YYYY', + only_if_in_grid_in IN BOOLEAN := FALSE, + override_file_in IN VARCHAR2 := NULL + ); + + PROCEDURE testpkg_from_string ( + package_in IN VARCHAR2, + grid_in IN VARCHAR2, + program_in IN VARCHAR2 := '%', + samepackage_in IN BOOLEAN := FALSE , + prefix_in IN VARCHAR2 := NULL, + schema_in IN VARCHAR2 := NULL, + output_type_in IN PLS_INTEGER := c_screen, + dir_in IN VARCHAR2 := NULL, + line_delim_in IN VARCHAR := CHR (10), + field_delim_in IN VARCHAR2 := '|', + arg_delim_in IN VARCHAR2 := c_delim, + date_format_in IN VARCHAR2 := 'MM/DD/YYYY', + only_if_in_grid_in IN BOOLEAN := FALSE, + override_file_in IN VARCHAR2 := NULL + ); + + PROCEDURE testpkg_from_string_od ( + package_in IN VARCHAR2, + grid_in IN VARCHAR2, + dir_in IN VARCHAR2 := NULL, + override_file_in IN VARCHAR2 := NULL + ); + + -- Retrieve single string with generated package. + FUNCTION pkgstring + RETURN VARCHAR2; + + -- Retrieve individual lines of code in generated package + + FUNCTION nthrow (nth IN PLS_INTEGER, direction IN SIGNTYPE := 1) + RETURN codeline_t; + + FUNCTION countrows + RETURN PLS_INTEGER; + + FUNCTION firstrow + RETURN PLS_INTEGER; + + FUNCTION firstbodyrow + RETURN PLS_INTEGER; + + FUNCTION atfirstrow + RETURN BOOLEAN; + + FUNCTION lastrow + RETURN PLS_INTEGER; + + FUNCTION atlastrow + RETURN BOOLEAN; + + PROCEDURE setrow (nth IN PLS_INTEGER); + + FUNCTION getrow + RETURN codeline_t; + + PROCEDURE nextrow; + + PROCEDURE prevrow; + + PROCEDURE showrows ( + startrow IN PLS_INTEGER := NULL, + endrow IN PLS_INTEGER := NULL + ); + + FUNCTION isfunction ( + schema_in IN VARCHAR2, + package_in IN VARCHAR2, + program_in IN VARCHAR2, + overload_in IN PLS_INTEGER := NULL + ) + RETURN BOOLEAN; + + -- 2.0.10.1 From Patrick Barel + PROCEDURE add_to_grid ( + owner_in IN ut_grid.owner%TYPE + ,package_in IN ut_grid.PACKAGE%TYPE + ,progname_in IN ut_grid.progname%TYPE + ,overload_in IN ut_grid.overload%TYPE + ,tcname_in IN ut_grid.tcname%TYPE + ,message_in IN ut_grid.MESSAGE%TYPE + ,arglist_in IN ut_grid.arglist%TYPE + ,return_value_in IN ut_grid.return_value%TYPE + ,assertion_type_in IN ut_grid.assertion_type%TYPE + ); + + PROCEDURE clear_grid ( + owner_in IN ut_grid.owner%TYPE + ,package_in IN ut_grid.PACKAGE%TYPE); + + /* START Patch72 607131 */ + PROCEDURE testpkg_from_table ( + package_in IN VARCHAR2, + program_in IN VARCHAR2 := '%', + samepackage_in IN BOOLEAN := FALSE , + prefix_in IN VARCHAR2 := NULL, + schema_in IN VARCHAR2 := NULL, + output_type_in IN PLS_INTEGER := c_screen, + dir_in IN VARCHAR2 := NULL, + date_format_in IN VARCHAR2 := 'MM/DD/YYYY', + override_file_in IN VARCHAR2 := NULL + ); +/* END Patch72 607131 */ + +/* -- 2.0.8 Implementation provided by Dan Spencer! + PROCEDURE receq_package ( + table_in IN VARCHAR2, + pkg_in IN VARCHAR2 := NULL, + owner_in IN VARCHAR2 := NULL + ); +*/ +END; +/ diff --git a/source/ut_grid.tab b/source/ut_grid.tab new file mode 100644 index 000000000..fa44ee2ed --- /dev/null +++ b/source/ut_grid.tab @@ -0,0 +1,39 @@ +-- 09/2002 PBA initial version + +-- Patch72 607131 +-- Create table +create table UT_GRID +( + PACKAGE VARCHAR2(100), + PROGNAME VARCHAR2(100), + OVERLOAD NUMBER, + TCNAME VARCHAR2(100), + MESSAGE VARCHAR2(2000) not null, + ARGLIST VARCHAR2(2000), + RETURN_VALUE VARCHAR2(2000), + ASSERTION_TYPE VARCHAR2(100) +); +-- Add comments to the columns +comment on column UT_GRID.PACKAGE + is 'This is the name of the package to be tested.'; +comment on column UT_GRID.PROGNAME + is 'This is the name of the subprogram to be tested.'; +comment on column UT_GRID.OVERLOAD + is 'This is the version of the subprogram where overloaded versions exist. (You may have to look in the data dictionary to work this out).'; +comment on column UT_GRID.TCNAME + is 'The name of the test case.'; +comment on column UT_GRID.MESSAGE + is 'The message to be used in the assertion code.'; +comment on column UT_GRID.ARGLIST + is 'The list of arguments to be passed to the subprogram.'; +comment on column UT_GRID.RETURN_VALUE + is 'The return value to be checked against.'; +comment on column UT_GRID.ASSERTION_TYPE + is 'The type of assertion to be used. Currently this is ignored unless it contains ''EQ'' of ''ISNULL''.'; + +-- Create/Recreate primary, unique and foreign key constraints +alter table UT_GRID + add constraint UK_MESSAGE unique (MESSAGE); + +REM 2.1 +alter table ut_grid add owner varchar2(30); diff --git a/source/ut_i_do.sql b/source/ut_i_do.sql new file mode 100644 index 000000000..0a81402ed --- /dev/null +++ b/source/ut_i_do.sql @@ -0,0 +1,105 @@ +CLEAR SCREEN +SET TERMOUT OFF +SET ECHO OFF +SET VERIFY OFF +SET FEEDBACK OFF +SET TTITLE OFF +SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED +SET DEFINE ON + +---------------------------------------------------- +-- ou installator +-- +-- paprameter 1 values: +-- +-- 1 - UT full installation +-- 2 - Recompile UT code base +-- 3 - Create public synonyms for UT +-- 4 - Deinstall UT +---------------------------------------------------- + +DEFINE line1='-------------------------------------------------------------' +DEFINE line2='=============================================================' +DEFINE finished='. Finished' +DEFINE UT='UT' + +------ [PBA] this will not work when we don't have DBA rights or grant select on V$SESSION +COLUMN col NOPRINT NEW_VALUE ut_owner +select USER col from dual; + + +COLUMN col NOPRINT NEW_VALUE next_script +select decode(&1,1,'ut_i_install', + 2,'ut_i_recompile', + 3,'ut_i_synonyms', + 4,'ut_i_uninstall', + 'ERROR') col from dual; + +COLUMN col NOPRINT NEW_VALUE txt_prompt +select decode(&1,1,'I N S T A L L A T I O N', + 2,'R E C O M P I L A T I O N', + 3,'S Y N O N Y M S', + 4,'D E I N S T A L L A T I O N', + 'ERROR') col from dual; +------------------------------------------------------ +COLUMN col NOPRINT NEW_VALUE v_orcl_vers + +SELECT SUBSTR(version,1,3) col + FROM product_component_version + WHERE UPPER(PRODUCT) LIKE 'ORACLE7%' + OR UPPER(PRODUCT) LIKE 'PERSONAL ORACLE%' + OR UPPER(PRODUCT) LIKE 'ORACLE8%'; + +COLUMN col NOPRINT NEW_VALUE start81 +SELECT DECODE (UPPER('&v_orcl_vers'), + '8.1', '/* Use 8i code! */', + '/* Ignore 8i code') col + FROM dual; + +COLUMN col NOPRINT NEW_VALUE end81 +SELECT DECODE (upper('&v_orcl_vers'), + '8.1', '/* Use 8i code! */', + 'Ignore 8i code */') col + FROM dual; + +COLUMN col NOPRINT NEW_VALUE start73 +SELECT DECODE (UPPER('&v_orcl_vers'), + '8.1', '/* Ignore Oracle7 code! ', + '/* Use Oracle7 code */') col + FROM dual; + +COLUMN col NOPRINT NEW_VALUE end73 +SELECT DECODE (UPPER('&v_orcl_vers'), + '8.1', 'Ignore Oracle7 code! */', + '/* Use Oracle7 code */') col + FROM dual; +------------------------------------------------------ + +SET TERMOUT ON + +PROMPT &line2 +PROMPT GNU General Public License for utPLSQL +PROMPT +PROMPT Copyright (C) 2000 +PROMPT Steven Feuerstein, steven@stevenfeuerstein.com +PROMPT Chris Rimmer, chris@sunset.force9.co.uk +PROMPT +PROMPT +PROMPT This program is free software; you can redistribute it and/or modify +PROMPT it under the terms of the GNU General Public License as published by +PROMPT the Free Software Foundation; either version 2 of the License, or +PROMPT (at your option) any later version. +PROMPT +PROMPT This program is distributed in the hope that it will be useful, +PROMPT but WITHOUT ANY WARRANTY; without even the implied warranty of +PROMPT MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +PROMPT GNU General Public License for more details. +PROMPT +PROMPT You should have received a copy of the GNU General Public License +PROMPT along with this program (see license.txt); if not, write to the Free Software +PROMPT Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +PROMPT &line2 +PROMPT + +PROMPT [ &txt_prompt ] +@@&next_script diff --git a/source/ut_i_grants.sql b/source/ut_i_grants.sql new file mode 100644 index 000000000..296c7e9dc --- /dev/null +++ b/source/ut_i_grants.sql @@ -0,0 +1,40 @@ +SET TERMOUT OFF +SET VERIFY OFF +SET PAGESIZE 0 +SET FEEDBACK OFF +SET TRIMSPOOL ON + +SET DEFINE ON +TTITLE OFF +SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED + +DEFINE uscript='ut_i_spool_temp.sql' + +SET TERMOUT ON +PROMPT &line1 +PROMPT GRANTS FOR &UT OBJECTS +PROMPT &line1 +SET TERMOUT OFF + +SPOOL &uscript + +select 'PROMPT Granting all on every object...' from dual; +select 'grant all on '||object_name||' to public;' +from all_objects +where owner='&ut_owner' and object_name like 'UT%' and + object_type in('TABLE','SEQUENCE','PACKAGE', 'VIEW'); +select 'PROMPT &finished' from dual; + +select 'PROMPT Granting execute on packages...' from dual; +select 'grant execute on '||object_name||' to public;' +from all_objects +where owner='&ut_owner' and object_name like 'UT%' and + object_type ='PACKAGE'; + +select 'PROMPT &finished' from dual; + +SPOOL OFF +SET TERMOUT ON + +@@&uscript + diff --git a/source/ut_i_install.sql b/source/ut_i_install.sql new file mode 100644 index 000000000..a494424c7 --- /dev/null +++ b/source/ut_i_install.sql @@ -0,0 +1,68 @@ +SET TERMOUT OFF +SET ECHO OFF +SET VERIFY OFF +SET FEEDBACK OFF +SET TTITLE OFF + +SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED +SET DEFINE ON +SPOOL ut_i_install.log + +----------------------------------------------------TABLES +SET TERMOUT ON +PROMPT &line1 +PROMPT CREATING &UT TABLES +PROMPT &line1 + +DEFINE prompt_text='Creating &UT tables ' + +@@ut_i_tables + +----------------------------------------------------SEQUENCES +SET TERMOUT ON +PROMPT &line1 +PROMPT CREATING &UT SEQUENCES +PROMPT &line1 + +DEFINE prompt_text='Creating &UT sequence ' + +@@ut_i_sequences + +----------------------------------------------------VIEWS +SET TERMOUT ON +PROMPT &line1 +PROMPT CREATING &UT VIEWS +PROMPT &line1 + +DEFINE prompt_text='Creating &UT view ' + +@@ut_i_views + +----------------------------------------------------PACKAGE HEADERS +SET TERMOUT ON +PROMPT &line1 +PROMPT CREATING OUNIT PACKAGE HEADERS +PROMPT &line1 + +DEFINE prompt_text='Creating &UT package specification ' + +@@ut_i_packages + +----------------------------------------------------PACKAGE BODIES +SET TERMOUT ON +PROMPT &line1 +PROMPT CREATING OUNIT PACKAGE BODIES +PROMPT &line1 + +DEFINE prompt_text='Creating &UT package body ' + +@@ut_i_packages_b + +SET TERMOUT OFF +SPOOL OFF + +----------------------------------------------------GENERIC SCRIPTS + +@@ut_i_synonyms + +@@ut_i_grants diff --git a/source/ut_i_packages.sql b/source/ut_i_packages.sql new file mode 100644 index 000000000..f95f4ae14 --- /dev/null +++ b/source/ut_i_packages.sql @@ -0,0 +1,29 @@ +@@ut_i_run ut_config.pks +@@ut_i_run ut_plsql.pks +@@ut_i_run ut_result.pks +@@ut_i_run ut_plsql_util.pks +@@ut_i_run ut_assert2.pks +@@ut_i_run ut_assert.pks +@@ut_i_run ut_plsql2.pks +@@ut_i_run ut_result2.pks +@@ut_i_run ut_utp.pks +@@ut_i_run ut_testprep.pks +@@ut_i_run ut_unittest.pks +@@ut_i_run ut_testcase.pks +@@ut_i_run ut_outcome.pks +@@ut_i_run ut_suiteutp.pks +@@ut_i_run ut_suite.pks +@@ut_i_run ut_package.pks +@@ut_i_run ut_test.pks +@@ut_i_run ut_gen.pks +@@ut_i_run ut_rsuite.pks +@@ut_i_run ut_rutp.pks +@@ut_i_run ut_runittest.pks +@@ut_i_run ut_rtestcase.pks +@@ut_i_run ut_routcome.pks +@@ut_i_run ut_rerror.pks +@@ut_i_run ut_vvalue.pks +@@ut_i_run ut_aeq.pks +@@ut_i_run ut_receq.pks +@@ut_i_run ut_output.pks +@@ut_i_run ut_utoutput.pks diff --git a/source/ut_i_packages_b.sql b/source/ut_i_packages_b.sql new file mode 100644 index 000000000..ea8c4f065 --- /dev/null +++ b/source/ut_i_packages_b.sql @@ -0,0 +1,29 @@ +@@ut_i_run ut_config.pkb +@@ut_i_run ut_plsql.pkb +@@ut_i_run ut_result.pkb +@@ut_i_run ut_plsql_util.pkb +@@ut_i_run ut_assert2.pkb +@@ut_i_run ut_assert.pkb +@@ut_i_run ut_plsql2.pkb +@@ut_i_run ut_result2.pkb +@@ut_i_run ut_utp.pkb +@@ut_i_run ut_testprep.pkb +@@ut_i_run ut_unittest.pkb +@@ut_i_run ut_testcase.pkb +@@ut_i_run ut_outcome.pkb +@@ut_i_run ut_suiteutp.pkb +@@ut_i_run ut_suite.pkb +@@ut_i_run ut_package.pkb +@@ut_i_run ut_test.pkb +@@ut_i_run ut_gen.pkb +@@ut_i_run ut_rsuite.pkb +@@ut_i_run ut_rutp.pkb +@@ut_i_run ut_runittest.pkb +@@ut_i_run ut_rtestcase.pkb +@@ut_i_run ut_routcome.pkb +@@ut_i_run ut_rerror.pkb +@@ut_i_run ut_vvalue.pkb +@@ut_i_run ut_aeq.pkb +@@ut_i_run ut_receq.pkb +@@ut_i_run ut_output.pkb +@@ut_i_run ut_utoutput.pkb diff --git a/source/ut_i_recompile.sql b/source/ut_i_recompile.sql new file mode 100644 index 000000000..2a8d63b19 --- /dev/null +++ b/source/ut_i_recompile.sql @@ -0,0 +1,31 @@ +SET TERMOUT OFF +SET VERIFY OFF +SET PAGESIZE 0 +SET FEEDBACK OFF +SET TRIMSPOOL ON + +SET DEFINE ON +TTITLE OFF +SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED + +DEFINE uscript='ut_i_spool_temp.sql' + +SET TERMOUT ON +PROMPT &line1 +PROMPT RECOMPILING &UT OBJECTS +PROMPT &line1 +SET TERMOUT OFF + +SPOOL &uscript +select 'PROMPT Recompiling...' from dual; +select 'alter package '||object_name||' compile package;' +from all_objects +where owner='&ut_owner' and object_name like 'UT%' and + object_type=('PACKAGE') +order by created; +select 'PROMPT &finished' from dual; +SPOOL OFF +SET TERMOUT ON + +@@&uscript + diff --git a/source/ut_i_run.sql b/source/ut_i_run.sql new file mode 100644 index 000000000..b64c5696a --- /dev/null +++ b/source/ut_i_run.sql @@ -0,0 +1,12 @@ +SET TERMOUT OFF + +COLUMN col NOPRINT NEW_VALUE run_object +SELECT substr('&1',1,instr('&1','.')-1) col FROM dual; + +SET TERMOUT ON + +PROMPT &prompt_text &run_object +@@&1 +REM PROMPT &line1 + +SET TERMOUT OFF diff --git a/source/ut_i_sequences.sql b/source/ut_i_sequences.sql new file mode 100644 index 000000000..9e48f2e13 --- /dev/null +++ b/source/ut_i_sequences.sql @@ -0,0 +1,14 @@ +@@ut_i_run ut_suite_seq.seq +@@ut_i_run ut_package_seq.seq +@@ut_i_run ut_utp_seq.seq +@@ut_i_run ut_test_seq.seq +@@ut_i_run ut_unittest_seq.seq +@@ut_i_run ut_testcase_seq.seq +@@ut_i_run ut_plsql_runnum_seq.seq +@@ut_i_run uta_eq_seq.seq +@@ut_i_run utv_value_seq.seq +@@ut_i_run ut_assertion_seq.seq +@@ut_i_run ut_receq_seq.seq +@@ut_i_run ut_refcursor_results_seq.seq + + diff --git a/source/ut_i_spool_temp.sql b/source/ut_i_spool_temp.sql new file mode 100644 index 000000000..52730ab0f --- /dev/null +++ b/source/ut_i_spool_temp.sql @@ -0,0 +1,31 @@ +PROMPT Recompiling... +alter package UTCONFIG compile package; +alter package UTPLSQL compile package; +alter package UTRESULT compile package; +alter package UTPLSQL_UTIL compile package; +alter package UTASSERT2 compile package; +alter package UTASSERT compile package; +alter package UTPLSQL2 compile package; +alter package UTUTP compile package; +alter package UTRESULT2 compile package; +alter package UTOUTCOME compile package; +alter package UTUNITTEST compile package; +alter package UTTESTPREP compile package; +alter package UTTESTCASE compile package; +alter package UTPACKAGE compile package; +alter package UTSUITEUTP compile package; +alter package UTSUITE compile package; +alter package UTTEST compile package; +alter package UTAEQ compile package; +alter package UTGEN compile package; +alter package UTROUTCOME compile package; +alter package UTVVALUE compile package; +alter package UTRTESTCASE compile package; +alter package UTRUTP compile package; +alter package UTRUNITTEST compile package; +alter package UTRSUITE compile package; +alter package UTRERROR compile package; +alter package UTOUTPUT compile package; +alter package UTRECEQ compile package; +alter package UT_UTOUTPUT compile package; +PROMPT . Finished diff --git a/source/ut_i_synonyms.sql b/source/ut_i_synonyms.sql new file mode 100644 index 000000000..9de029fa8 --- /dev/null +++ b/source/ut_i_synonyms.sql @@ -0,0 +1,35 @@ +SET TERMOUT OFF +SET VERIFY OFF +SET PAGESIZE 0 +SET FEEDBACK OFF +SET TRIMSPOOL ON + +spool off +SET DEFINE ON +TTITLE OFF +SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED + +DEFINE uscript='ut_i_spool_temp.sql' + +SET TERMOUT ON +PROMPT &line1 +PROMPT CREATING SYNONYMS FOR &UT OBJECTS +PROMPT &line1 +SET TERMOUT OFF + +COLUMN col NOPRINT NEW_VALUE fine +select count(privilege) col from session_privs where privilege='CREATE PUBLIC SYNONYM'; + +SPOOL &uscript +select decode(&fine,0,'','PROMPT Creating synonyms for packages...') from dual; +select decode(&fine,0,'','create public synonym '||object_name||' for '||object_name||';') +from all_objects +where owner='&ut_owner' and object_name like 'UT%' and + object_type in ('PACKAGE','TABLE','VIEW','SEQUENCE'); +select decode(&fine,0,'','PROMPT &finished') from dual; + +select decode(&fine,1,'','PROMPT Skipped - user has no rights to create public synonyms') from dual; +SPOOL OFF +SET TERMOUT ON + +@@&uscript diff --git a/source/ut_i_tables.sql b/source/ut_i_tables.sql new file mode 100644 index 000000000..a5f9f79d4 --- /dev/null +++ b/source/ut_i_tables.sql @@ -0,0 +1,25 @@ +@@ut_i_run ut_config.tab +@@ut_i_run ut_assertion.tab +@@ut_i_run ut_suite.tab +@@ut_i_run ut_utp.tab +@@ut_i_run ut_package.tab +@@ut_i_run ut_test.tab +@@ut_i_run ut_unittest.tab +@@ut_i_run ut_testcase.tab +@@ut_i_run ut_testprep.tab +@@ut_i_run ut_outcome.tab +@@ut_i_run ut_eq.tab +@@ut_i_run ut_suite_utp.tab +@@ut_i_run ut_argument.tab +@@ut_i_run utr_suite.tab +@@ut_i_run utr_utp.tab +@@ut_i_run utr_unittest.tab +@@ut_i_run utr_testcase.tab +@@ut_i_run utr_outcome.tab +@@ut_i_run utr_error.tab +@@ut_i_run ut_deterministic.tab +@@ut_i_run ut_deterministic_arg.tab +@@ut_i_run utv_value.tab +@@ut_i_run uta_eq.tab +@@ut_i_run ut_receq.tab +@@ut_i_run ut_grid.tab diff --git a/source/ut_i_uninstall.sql b/source/ut_i_uninstall.sql new file mode 100644 index 000000000..2197e2918 --- /dev/null +++ b/source/ut_i_uninstall.sql @@ -0,0 +1,111 @@ +SET TERMOUT OFF +SET VERIFY OFF +SET PAGESIZE 0 +SET FEEDBACK OFF +SET TRIMSPOOL ON + +SET DEFINE ON +TTITLE OFF +SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED + +DEFINE uscript='ut_i_spool_temp.sql' + +COLUMN col NOPRINT NEW_VALUE ut_owner +SELECT USER col FROM DUAL; + +DEFINE line1='-------------------------------------------------------------' +DEFINE line2='=============================================================' +DEFINE finished='. Finished' + + +SPOOL &uscript + +REM synonyms: -------------------------------------------------------------- + +COLUMN col NOPRINT NEW_VALUE fine +SELECT COUNT (PRIVILEGE) col + FROM session_privs + WHERE PRIVILEGE = 'DROP PUBLIC SYNONYM'; + +SELECT DECODE (&fine + , 0, '' + , 'PROMPT Dropping &UT public synonyms...' + ) + FROM DUAL; + +SELECT DECODE (&fine + , 0, '' + , 'drop public synonym ' || o1.object_name || ';' + ) + FROM all_objects o1, all_objects o2 + WHERE o1.owner = 'PUBLIC' + AND o1.object_type = 'SYNONYM' + AND o1.object_name = o2.object_name + AND o1.object_name LIKE 'UT%' + AND o2.object_type IN ('PACKAGE', 'TABLE', 'VIEW','SEQUENCE') + AND o2.owner = '&ut_owner'; + +SELECT DECODE (&fine, 0, '', 'PROMPT &finished') + FROM DUAL; + +REM tables: ---------------------------------------------------------------- + +SELECT 'PROMPT Dropping &UT tables...' + FROM DUAL; + +SELECT 'drop table ' || object_name || ' cascade constraints;' + FROM all_objects + WHERE owner = '&ut_owner' + AND object_name LIKE 'UT%' + AND object_type = 'TABLE'; + +SELECT 'PROMPT &finished' + FROM DUAL; + +REM views: ---------------------------------------------------------------- + +SELECT 'PROMPT Dropping &UT views...' + FROM DUAL; + +SELECT 'drop view ' || object_name || ' cascade constraints;' + FROM all_objects + WHERE owner = '&ut_owner' + AND object_name LIKE 'UT%' + AND object_type = 'VIEW'; + +SELECT 'PROMPT &finished' + FROM DUAL; + +REM sequences: -------------------------------------------------------------- + +SELECT 'PROMPT Dropping &UT sequences...' + FROM DUAL; + +SELECT 'drop sequence ' || object_name || ';' + FROM all_objects + WHERE owner = '&ut_owner' + AND object_name LIKE 'UT%' + AND object_type = 'SEQUENCE'; + +SELECT 'PROMPT &finished' + FROM DUAL; + +REM sequences: -------------------------------------------------------------- + +SELECT 'PROMPT Dropping &UT packages...' + FROM DUAL; + +SELECT 'drop package ' || object_name || ';' + FROM all_objects + WHERE owner = '&ut_owner' + AND object_name LIKE 'UT%' + AND object_type = 'PACKAGE'; + +SELECT 'PROMPT &finished' + FROM DUAL; + + +SPOOL OFF +SET TERMOUT ON + +@@&uscript diff --git a/source/ut_i_views.sql b/source/ut_i_views.sql new file mode 100644 index 000000000..594f0d3f5 --- /dev/null +++ b/source/ut_i_views.sql @@ -0,0 +1,2 @@ +@@ut_i_run utv_result_full.sql +@@ut_i_run utv_last_run.sql \ No newline at end of file diff --git a/source/ut_outcome.pkb b/source/ut_outcome.pkb new file mode 100644 index 000000000..b63c46418 --- /dev/null +++ b/source/ut_outcome.pkb @@ -0,0 +1,107 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE BODY utoutcome +IS + FUNCTION name (outcome_id_in IN ut_outcome.id%TYPE) + RETURN ut_outcome.name%TYPE + IS + retval ut_outcome.name%TYPE; + BEGIN + SELECT name + INTO retval + FROM ut_outcome + WHERE id = outcome_id_in; + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END; + + FUNCTION id (name_in IN ut_outcome.name%TYPE) + RETURN ut_outcome.id%TYPE + IS + retval ut_outcome.id%TYPE; + BEGIN + SELECT id + INTO retval + FROM ut_outcome + WHERE name = name_in; + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END; + + FUNCTION onerow (name_in IN ut_outcome.name%TYPE) + RETURN ut_outcome%ROWTYPE + IS + retval ut_outcome%ROWTYPE; + empty_rec ut_outcome%ROWTYPE; + BEGIN + SELECT * + INTO retval + FROM ut_outcome + WHERE name = name_in; + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN empty_rec; + END; + + FUNCTION onerow (outcome_id_in IN ut_outcome.id%TYPE) + RETURN ut_outcome%ROWTYPE + IS + retval ut_outcome%ROWTYPE; + empty_rec ut_outcome%ROWTYPE; + BEGIN + SELECT * + INTO retval + FROM ut_outcome + WHERE id = outcome_id_in; + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN empty_rec; + END; + + FUNCTION utp (outcome_id_in IN ut_outcome.id%TYPE) + RETURN ut_utp.id%TYPE + IS + CURSOR utp_cur + IS + SELECT ut.utp_id + FROM ut_outcome oc, ut_testcase tc, ut_unittest ut + WHERE tc.id = oc.testcase_id + AND tc.unittest_id = ut.id + AND oc.id = outcome_id_in; + + utp_rec utp_cur%ROWTYPE; + BEGIN + OPEN utp_cur; + FETCH utp_cur INTO utp_rec; + CLOSE utp_cur; + RETURN utp_rec.utp_id; + END; + + FUNCTION unittest (outcome_id_in IN ut_outcome.id%TYPE) + RETURN ut_unittest.id%TYPE + IS + CURSOR unittest_cur + IS + SELECT tc.unittest_id + FROM ut_outcome oc, ut_testcase tc + WHERE tc.id = oc.testcase_id + AND oc.id = outcome_id_in; + + unittest_rec unittest_cur%ROWTYPE; + BEGIN + OPEN unittest_cur; + FETCH unittest_cur INTO unittest_rec; + CLOSE unittest_cur; + RETURN unittest_rec.unittest_id; + END; +END utoutcome; +/ diff --git a/source/ut_outcome.pks b/source/ut_outcome.pks new file mode 100644 index 000000000..b6470539a --- /dev/null +++ b/source/ut_outcome.pks @@ -0,0 +1,29 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE utoutcome +IS + c_name CONSTANT CHAR (7) := 'OUTCOME'; + c_abbrev CONSTANT CHAR (2) := 'OC'; + + FUNCTION name (outcome_id_in IN ut_outcome.id%TYPE) + RETURN ut_outcome.name%TYPE; + + FUNCTION id (name_in IN ut_outcome.name%TYPE) + RETURN ut_outcome.id%TYPE; + + FUNCTION onerow (name_in IN ut_outcome.name%TYPE) + RETURN ut_outcome%ROWTYPE; + + FUNCTION onerow (outcome_id_in IN ut_outcome.id%TYPE) + RETURN ut_outcome%ROWTYPE; + + FUNCTION utp (outcome_id_in IN ut_outcome.id%TYPE) + RETURN ut_utp.id%TYPE; + + PRAGMA restrict_references (utp, WNDS, WNPS); + + FUNCTION unittest (outcome_id_in IN ut_outcome.id%TYPE) + RETURN ut_unittest.id%TYPE; + + PRAGMA restrict_references (unittest, WNDS, WNPS); +END utoutcome; +/ diff --git a/source/ut_outcome.tab b/source/ut_outcome.tab new file mode 100644 index 000000000..866c926a7 --- /dev/null +++ b/source/ut_outcome.tab @@ -0,0 +1,26 @@ +CREATE TABLE ut_outcome ( +id integer, +testcase_id integer, +seq integer, +name varchar2(200), +assertion_type varchar2(100), +action_level varchar2(10), -- V1 only; not used +null_ok char(1) default 'N', +raise_exception char(1) default 'N', +declarations varchar2 (2000), +setup varchar2 (2000), +teardown varchar2 (2000), +exceptions varchar2 (2000), + CONSTRAINT ut_outcome_pk PRIMARY KEY (id) +); + +REM 2.0.10.1 Add control and test fields to help specify testing characteristics + +ALTER TABLE ut_outcome ADD control_info VARCHAR2(2000); +ALTER TABLE ut_outcome ADD test_info VARCHAR2(2000); + +CREATE unique index ut_outcome_idx1 ON + ut_outcome (testcase_id, name); + +ALTER table ut_outcome add CONSTRAINT ut_outcome_testcase_fk + FOREIGN KEY (testcase_id) REFERENCES ut_testcase; \ No newline at end of file diff --git a/source/ut_output.pkb b/source/ut_output.pkb new file mode 100644 index 000000000..f776a6621 --- /dev/null +++ b/source/ut_output.pkb @@ -0,0 +1,173 @@ +CREATE OR REPLACE PACKAGE BODY utoutput +IS + /* + GNU General Public License for utPLSQL + + Copyright (C) 2000 + Steven Feuerstein, steven@stevenfeuerstein.com + Chris Rimmer, chris@sunset.force9.co.uk + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program (see license.txt); if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + /*Modification History: + chrisrimmer 03-Apr-2002 Created + */ + + g_temp_buffer DBMS_OUTPUT.CHARARR; + g_save_buffer DBMS_OUTPUT.CHARARR; + g_save BOOLEAN := FALSE; + c_all_lines CONSTANT INTEGER := 1000000; + + FUNCTION saving RETURN BOOLEAN + IS + BEGIN + RETURN g_save; + END; + + PROCEDURE save + IS + BEGIN + g_save := TRUE; + END; + + PROCEDURE nosave + IS + BEGIN + g_save := FALSE; + END; + + --Pull lines into given buffer and optionally + --into the save buffer too. + FUNCTION extract ( + buffer_out OUT DBMS_OUTPUT.CHARARR, + max_lines_in IN INTEGER := NULL, + save_in IN BOOLEAN := saving + ) RETURN INTEGER + IS + l_lines INTEGER := NVL(max_lines_in, c_all_lines); + l_index BINARY_INTEGER; + BEGIN + buffer_out.DELETE; + + DBMS_OUTPUT.Get_Lines(buffer_out, l_lines); + + --Remove the extra empty lines + WHILE l_lines < buffer_out.COUNT LOOP + buffer_out.DELETE(buffer_out.LAST); + END LOOP; + + --Append to save buffer + IF save_in THEN + l_index := buffer_out.FIRST; + WHILE l_index IS NOT NULL LOOP + g_save_buffer(NVL(g_save_buffer.LAST,0) + 1) := buffer_out(l_index); + l_index := buffer_out.NEXT(l_index); + END LOOP; + END IF; + + RETURN l_lines; + END; + + --Get the output ignoring number of lines returned. + PROCEDURE extract ( + buffer_out OUT DBMS_OUTPUT.CHARARR, + max_lines_in IN INTEGER := NULL, + save_in IN BOOLEAN := saving + ) + IS + l_lines INTEGER; + BEGIN + l_lines := extract(buffer_out, max_lines_in, save_in); + END; + + --Get the output ignoring the data itself + FUNCTION extract ( + max_lines_in IN INTEGER := NULL, + save_in IN BOOLEAN := saving + ) RETURN INTEGER + IS + BEGIN + RETURN extract(g_temp_buffer, max_lines_in, save_in); + END; + + --Get the output ignoring number of lines returned + --and ignoring the data itself + PROCEDURE extract ( + max_lines_in IN INTEGER := NULL, + save_in IN BOOLEAN := saving + ) + IS + BEGIN + extract(g_temp_buffer, max_lines_in, save_in); + END; + + --Put a buffer back into DBMS_OUTPUT buffer. + PROCEDURE replace(buffer_inout IN OUT DBMS_OUTPUT.CHARARR) + IS + l_index BINARY_INTEGER; + BEGIN + l_index := buffer_inout.FIRST; + WHILE l_index IS NOT NULL LOOP + DBMS_OUTPUT.Put_Line(buffer_inout(l_index)); + l_index := buffer_inout.NEXT(l_index); + END LOOP; + buffer_inout.DELETE; + END; + + --Put the save buffer back into the DBMS_OUTPUT buffer + PROCEDURE replace + IS + BEGIN + replace(g_save_buffer); + END; + + --Pull out the next line from the DBMS_OUTPUT buffer + FUNCTION nextLine(raise_exc_in BOOLEAN := TRUE, save_in BOOLEAN := saving) RETURN VARCHAR2 + IS + l_lines INTEGER; + BEGIN + + l_lines := extract(buffer_out => g_temp_buffer, + max_lines_in => 1, + save_in => save_in); + + IF l_lines <> 1 THEN + + IF raise_exc_in THEN + RAISE EMPTY_OUTPUT_BUFFER; + ELSE + RETURN NULL; + END IF; + ELSE + RETURN g_temp_buffer(g_temp_buffer.FIRST); + END IF; + + END; + + --Simply count the number of lines in the DBMS_OUTPUT buffer + --but don't remove anything + FUNCTION count RETURN INTEGER + IS + l_lines INTEGER; + BEGIN + l_lines := extract(buffer_out => g_temp_buffer, + max_lines_in => c_all_lines, + save_in => FALSE); + replace(g_temp_buffer); + RETURN l_lines; + END; + +END utoutput; +/ diff --git a/source/ut_output.pks b/source/ut_output.pks new file mode 100644 index 000000000..e6c67e064 --- /dev/null +++ b/source/ut_output.pks @@ -0,0 +1,67 @@ +CREATE OR REPLACE PACKAGE utoutput +&start81 AUTHID CURRENT_USER &end81 +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 +Steven Feuerstein, steven@stevenfeuerstein.com +Chris Rimmer, chris@sunset.force9.co.uk + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*Modification History: +chrisrimmer 03-Apr-2002 Created +*/ + + EMPTY_OUTPUT_BUFFER EXCEPTION; + + FUNCTION saving RETURN BOOLEAN; + + PROCEDURE save; + + PROCEDURE nosave; + + PROCEDURE replace; + + FUNCTION extract ( + buffer_out OUT DBMS_OUTPUT.CHARARR, + max_lines_in IN INTEGER := NULL, + save_in IN BOOLEAN := saving + ) RETURN INTEGER; + + PROCEDURE extract ( + buffer_out OUT DBMS_OUTPUT.CHARARR, + max_lines_in IN INTEGER := NULL, + save_in IN BOOLEAN := saving + ); + + FUNCTION extract( + max_lines_in IN INTEGER := NULL, + save_in IN BOOLEAN := saving + ) RETURN INTEGER; + + PROCEDURE extract( + max_lines_in IN INTEGER := NULL, + save_in IN BOOLEAN := saving + ); + + FUNCTION nextLine(raise_exc_in BOOLEAN := TRUE, save_in BOOLEAN := saving) RETURN VARCHAR2; + + FUNCTION count RETURN INTEGER; + +END utoutput; +/ diff --git a/source/ut_package.pkb b/source/ut_package.pkb new file mode 100644 index 000000000..f6dfd71fb --- /dev/null +++ b/source/ut_package.pkb @@ -0,0 +1,372 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE BODY utpackage +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + FUNCTION name_from_id (id_in IN ut_package.id%TYPE) + RETURN ut_package.name%TYPE + IS + retval ut_package.name%TYPE; + BEGIN + SELECT name + INTO retval + FROM ut_package + WHERE id = id_in; + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END; + + -- Need to add owner to param list and query + FUNCTION id_from_name (name_in IN ut_package.name%TYPE, + owner_in IN ut_package.owner%TYPE := NULL) + RETURN ut_package.id%TYPE + IS + retval ut_package.id%TYPE; + v_owner ut_package.owner%type := nvl(owner_in,USER); + BEGIN + SELECT id + INTO retval + FROM ut_package + WHERE name = UPPER (name_in) + AND owner=v_owner + AND SUITE_ID is null; + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END; + + PROCEDURE ADD ( + suite_in IN INTEGER, + package_in IN VARCHAR2, + samepackage_in IN BOOLEAN := FALSE, + prefix_in IN VARCHAR2 := NULL, + dir_in IN VARCHAR2 := NULL, + seq_in IN PLS_INTEGER := NULL, + owner_in IN VARCHAR2 := NULL, + add_tests_in IN BOOLEAN := FALSE, + test_overloads_in IN BOOLEAN := FALSE + ) + IS + &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + v_owner VARCHAR2 (30) := NVL (owner_in, USER); + v_id ut_package.id%TYPE; + v_same ut_package.samepackage%TYPE := utplsql.c_yes; + v_prefix ut_config.prefix%TYPE + := NVL (prefix_in, utconfig.prefix (owner_in)); + BEGIN + IF NOT (NVL (samepackage_in, FALSE)) + THEN + v_same := utplsql.c_no; + END IF; + + &start81 v_id := utplsql.seqval ('ut_package'); &end81 + &start73 SELECT ut_package_seq.NEXTVAL INTO v_id FROM dual; &end73 + + INSERT INTO ut_package + (id, suite_id, name, + owner, samepackage, prefix, dir, seq, + executions, failures) + VALUES (v_id, suite_in, UPPER (package_in), + UPPER (v_owner), v_same, v_prefix, dir_in, NVL (seq_in, 1), + 0, 0); + IF id_from_name( UPPER (package_in),owner_in) IS NULL + THEN + &start81 v_id := utplsql.seqval ('ut_package'); &end81 + &start73 SELECT ut_package_seq.NEXTVAL INTO v_id FROM dual; &end73 + + INSERT INTO ut_package + (id, suite_id, name, + owner, samepackage, prefix, dir, seq, + executions, failures) + VALUES (v_id, NULL, UPPER (package_in), + UPPER (v_owner), v_same, v_prefix, dir_in, NVL (seq_in, 1), + 0, 0); + + + &start81 COMMIT; &end81 + END IF; + IF add_tests_in + THEN + -- For each program in ALL_ARGUMENTS, add a test. + + &start81 + -- 8i NDS implementation + DECLARE + TYPE cv_t IS REF CURSOR; + + cv cv_t; + v_name VARCHAR2 (100); + v_query VARCHAR2 (32767); + v_suffix VARCHAR2 (100) := NULL; + BEGIN + IF test_overloads_in + THEN + v_suffix := ' || TO_CHAR(overload)'; + END IF; + + v_query := + 'SELECT DISTINCT object_name ' + || v_suffix + || ' name ' + || ' from all_arguments + where owner = :owner and package_name = :package'; + OPEN cv FOR v_query + USING NVL (UPPER (owner_in), USER), UPPER (package_in); + + LOOP + FETCH cv INTO v_name; + EXIT WHEN cv%NOTFOUND; + + IF utplsql.tracing + THEN + utplsql.pl ( 'Adding test ' + || package_in + || '.' + || v_name); + END IF; + + uttest.ADD (v_id, v_name, 'Test ' + || v_name); + END LOOP; + + CLOSE cv; + END; + + &end81 + &start73 + -- 7.3 DBMS_SQL Implementation + DECLARE + cur PLS_INTEGER := DBMS_SQL.open_cursor; + fdbk PLS_INTEGER; + v_name VARCHAR2 (100); + v_query VARCHAR2 (32767); + v_suffix VARCHAR2 (100) := NULL; + BEGIN + IF test_overloads_in + THEN + v_suffix := ' || TO_CHAR(overload)'; + END IF; + + v_query := + 'SELECT DISTINCT object_name ' + || v_suffix + || ' name ' + || ' from all_arguments + where owner = :owner and package_name = :package'; + DBMS_SQL.parse (cur, v_query, DBMS_SQL.native); + DBMS_SQL.bind_variable (cur, 'owner', NVL (UPPER (owner_in), USER)); + DBMS_SQL.bind_variable (cur, 'package', UPPER (package_in)); + fdbk := DBMS_SQL.EXECUTE (cur); + + LOOP + EXIT WHEN DBMS_SQL.fetch_rows (cur) = 0; + DBMS_SQL.column_value (cur, 1, v_name); + + IF utplsql.tracing + THEN + utplsql.pl ( 'Adding test ' + || package_in + || '.' + || v_name); + END IF; + + uttest.ADD (v_id, v_name, 'Test ' + || v_name); + END LOOP; + + DBMS_SQL.close_cursor (cur); + END; + &end73 + END IF; + &start81 COMMIT; &end81 + EXCEPTION + WHEN DUP_VAL_ON_INDEX + THEN + -- Update changeable columns. + UPDATE ut_package + SET samepackage = v_same, + prefix = v_prefix, + dir = dir_in + WHERE owner = UPPER (v_owner) + AND name = UPPER (package_in) + AND suite_id = suite_in; + &start81 COMMIT; &end81 + + WHEN OTHERS + THEN + utplsql.pl ( 'Add package error: ' + || SQLERRM); + &start81 ROLLBACK; &end81 + RAISE; + END; + + PROCEDURE ADD ( + suite_in IN VARCHAR2, + package_in IN VARCHAR2, + samepackage_in IN BOOLEAN := FALSE, + prefix_in IN VARCHAR2 := NULL, + dir_in IN VARCHAR2 := NULL, + seq_in IN PLS_INTEGER := NULL, + owner_in IN VARCHAR2 := NULL, + add_tests_in IN BOOLEAN := FALSE, + test_overloads_in IN BOOLEAN := FALSE + ) + IS + BEGIN + ADD ( + utsuite.id_from_name (suite_in), + package_in, + samepackage_in, + prefix_in, + dir_in, + seq_in, + owner_in, + add_tests_in, + test_overloads_in + ); + END; + + PROCEDURE rem ( + suite_in IN INTEGER, + package_in IN VARCHAR2, + owner_in IN VARCHAR2 := NULL + ) + IS + &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + BEGIN + DELETE FROM ut_package + WHERE ( suite_id = UPPER (suite_in) + OR ( suite_id IS NULL + AND suite_in IS NULL + ) + ) + AND name = UPPER (package_in) + AND owner = NVL (UPPER (owner_in), USER); + &start81 COMMIT; &end81 + EXCEPTION + WHEN OTHERS + THEN + utplsql.pl ( 'Remove package error: ' + || SQLERRM); + &start81 ROLLBACK; &end81 + RAISE; + END; + + PROCEDURE rem ( + suite_in IN VARCHAR2, + package_in IN VARCHAR2, + owner_in IN VARCHAR2 := NULL + ) + IS + BEGIN + rem (utsuite.id_from_name (suite_in), package_in, owner_in); + END; + + PROCEDURE upd ( + suite_id_in IN INTEGER, + package_in IN VARCHAR2, + start_in DATE, + end_in DATE, + successful_in BOOLEAN, + owner_in IN VARCHAR2 := NULL + ) + IS + l_status VARCHAR2 (100) := utplsql.c_success; + &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + v_failure PLS_INTEGER := 0; + + PROCEDURE do_upd + IS + BEGIN + UPDATE ut_package + SET last_status = l_status, + last_start = start_in, + last_end = end_in, + executions = NVL (executions, 0) + + 1, + failures = NVL (failures, 0) + + v_failure + ,last_run_id = utplsql2.runnum -- 2.0.9.1 + WHERE nvl(suite_id,0) = nvl(suite_id_in,0) + AND name = UPPER (package_in) + AND owner = NVL (UPPER (owner_in), USER); + END; + BEGIN + IF NOT successful_in + THEN + v_failure := 1; + l_status := utplsql.c_failure; + END IF; + + do_upd; + + IF SQL%ROWCOUNT = 0 + THEN + ADD ( + suite_id_in, + package_in, + samepackage_in=> FALSE, + prefix_in=> utconfig.prefix (owner_in), + dir_in=> NULL, + seq_in=> NULL, + owner_in=> owner_in, + add_tests_in=> FALSE, + test_overloads_in=> FALSE + ); + do_upd; + END IF; + &start81 COMMIT; &end81 + EXCEPTION + WHEN OTHERS + THEN + utplsql.pl ( 'Update package error: ' + || SQLERRM); + &start81 ROLLBACK; &end81 + RAISE; + END; + + PROCEDURE upd ( + suite_in IN VARCHAR2, + package_in IN VARCHAR2, + start_in DATE, + end_in DATE, + successful_in BOOLEAN, + owner_in IN VARCHAR2 := NULL + ) + IS + BEGIN + upd ( + utsuite.id_from_name (suite_in), + package_in, + start_in, + end_in, + successful_in, + owner_in + ); + END; +END utpackage; +/ diff --git a/source/ut_package.pks b/source/ut_package.pks new file mode 100644 index 000000000..3a8226ad6 --- /dev/null +++ b/source/ut_package.pks @@ -0,0 +1,98 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE utpackage -- &start81 AUTHID CURRENT_USER &end81 +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + -- Unit Test Framework for PL/SQL + -- Steven Feuerstein, Copyright 2000, All rights reserved + -- steven@stevenfeuerstein.com +/* +Modification history +Date Who What +09/08/2000 SEF NVL on updates of executions and failures +*/ + + c_success CONSTANT VARCHAR2 (7) := 'SUCCESS'; + c_failure CONSTANT VARCHAR2 (7) := 'FAILURE'; + + FUNCTION name_from_id (id_in IN ut_package.id%TYPE) + RETURN ut_package.name%TYPE; + + FUNCTION id_from_name (name_in IN ut_package.name%TYPE, + owner_in IN ut_package.owner%TYPE := NULL) + RETURN ut_package.id%TYPE; + + PROCEDURE ADD ( + suite_in IN VARCHAR2, + package_in IN VARCHAR2, + samepackage_in IN BOOLEAN := FALSE, + prefix_in IN VARCHAR2 := NULL, + dir_in IN VARCHAR2 := NULL, + seq_in IN PLS_INTEGER := NULL, + owner_in IN VARCHAR2 := NULL, + add_tests_in IN BOOLEAN := FALSE, + test_overloads_in IN BOOLEAN := FALSE + ); + + PROCEDURE rem ( + suite_in IN VARCHAR2, + package_in IN VARCHAR2, + owner_in IN VARCHAR2 := NULL + ); + + PROCEDURE upd ( + suite_in IN VARCHAR2, + package_in IN VARCHAR2, + start_in DATE, + end_in DATE, + successful_in BOOLEAN, + owner_in IN VARCHAR2 := NULL + ); + + PROCEDURE ADD ( + suite_in IN INTEGER, + package_in IN VARCHAR2, + samepackage_in IN BOOLEAN := FALSE, + prefix_in IN VARCHAR2 := NULL, + dir_in IN VARCHAR2 := NULL, + seq_in IN PLS_INTEGER := NULL, + owner_in IN VARCHAR2 := NULL, + add_tests_in IN BOOLEAN := FALSE, + test_overloads_in IN BOOLEAN := FALSE + ); + + PROCEDURE rem ( + suite_in IN INTEGER, + package_in IN VARCHAR2, + owner_in IN VARCHAR2 := NULL + ); + + PROCEDURE upd ( + suite_id_in IN INTEGER, + package_in IN VARCHAR2, + start_in DATE, + end_in DATE, + successful_in BOOLEAN, + owner_in IN VARCHAR2 := NULL + ); +END utpackage; +/ diff --git a/source/ut_package.tab b/source/ut_package.tab new file mode 100644 index 000000000..55e788bff --- /dev/null +++ b/source/ut_package.tab @@ -0,0 +1,31 @@ +CREATE TABLE ut_package ( + id INTEGER , + suite_id INTEGER, + owner VARCHAR2(30), + name VARCHAR2(200), + description VARCHAR2(2000), + samepackage CHAR(1) DEFAULT 'N', + prefix VARCHAR2(100), + dir VARCHAR2(2000), + seq INTEGER, + executions INTEGER, + failures INTEGER, + last_status VARCHAR2(20), /* either SUCCESS or FAILURE */ + last_start DATE, + last_end DATE, + CONSTRAINT ut_package_pk PRIMARY KEY (id) +); + +REM 2.0.9.1 support cross ref to run, recommended by Dan Spencer + +alter table ut_package add (last_run_id number); + +CREATE unique index ut_package_idx1 ON + ut_package (suite_id, owner, name); + +--CREATE unique index ut_package_idx2 ON +-- ut_package (owner, name); + +ALTER table ut_package add CONSTRAINT ut_package_suite_fk + FOREIGN KEY (suite_id) REFERENCES ut_suite; + diff --git a/source/ut_package_seq.seq b/source/ut_package_seq.seq new file mode 100644 index 000000000..ff8c4d3b4 --- /dev/null +++ b/source/ut_package_seq.seq @@ -0,0 +1 @@ +CREATE sequence ut_package_seq INCREMENT BY 1 START WITH 1 ORDER NOCACHE; diff --git a/source/ut_plsql.pkb b/source/ut_plsql.pkb new file mode 100644 index 000000000..71d85f434 --- /dev/null +++ b/source/ut_plsql.pkb @@ -0,0 +1,1595 @@ +/* Formatted on 2002/03/31 23:53 (Formatter Plus v4.5.2) */ +CREATE OR REPLACE PACKAGE BODY utplsql +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 +Steven Feuerstein, steven@stevenfeuerstein.com +Chris Rimmer, chris@sunset.force9.co.uk + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +------------------------------------------------------------------------------- +--Modification History +------------------------------------------------------------------------------- +--WHO WHEN WHAT +------------------------------------------------------------------------------- +--Dan Spencer 27 DEc 01 Added record comparison logic. +--Steven F 3 Dec 2001 Revamp setpkg logic to populate the test +-- array later in the process. +--Steven F 15 Nov 2001 Add per_method_setup logic +--Chris Rimmer 08 Nov 2000 Changed to use new utConfig package +------------------------------------------------------------------------------- + + g_trc BOOLEAN := FALSE; + g_version VARCHAR2 (100) := '2.1.1'; + +-- RMM start + g_pl_to_file BOOLEAN := FALSE; -- to control pl file output + g_fid UTL_FILE.FILE_TYPE; -- to control pl file output +-- RMM end + + tests test_tt; + testpkg test_rt; + + -- Start utility definitions + /* RMM start */ + /* Added this function for file output control*/ + FUNCTION get_pl_to_file RETURN BOOLEAN + IS + BEGIN + RETURN g_pl_to_file; + END; + + /* RMM */ + /* Added this procedure for file output control*/ + PROCEDURE set_pl_to_file ( + val IN BOOLEAN := FALSE + ) + IS + BEGIN + g_pl_to_file := val; + END; + + /* RMM */ + /* Added this procedure for file output*/ + PROCEDURE pl_to_file ( + v_in IN VARCHAR2, + fid IN OUT UTL_FILE.FILE_TYPE + ) IS + + v VARCHAR2(10) := '-- TEST --'; + c_endcmd VARCHAR2(13) := '-- TESTEND --'; + + dir ut_config.directory%TYPE; + + file_dir ut_config.filedir%TYPE; + file_out ut_config.fileout%TYPE; + userprefix ut_config.fileuserprefix%TYPE; + incprog ut_config.fileincprogname%TYPE; + date_formt ut_config.filedateformat%TYPE; + extension ut_config.fileextension%TYPE; + + progname VARCHAR2(35); + + no_dir EXCEPTION; + + PROCEDURE recNgo (str IN VARCHAR2) + IS + BEGIN + DBMS_OUTPUT.PUT_LINE ('UTL_FILE error ' || str); + UTL_FILE.FCLOSE (fid); + END; + + BEGIN + + -- open file if not already open + -- and write header record + IF NOT UTL_FILE.is_open(fid) THEN + + -- Get the output file directory + file_dir := utConfig.filedir (); + -- check if NULL + IF file_dir IS NULL THEN + -- try directory + file_dir := utConfig.dir (); + -- check if NULL + IF file_dir IS NULL THEN + -- redirect output to DBMS_OUTPUT + set_pl_to_file (FALSE); + raise no_dir; + END IF; + END IF; + + -- Get the userprefix from config + userprefix := utConfig.userprefix(); + IF userprefix IS NULL THEN + -- use the current user if userprefix IS NULL + userprefix := USER; + END IF; + userprefix := userprefix ||'_'; + + -- include progname in filename ? + progname := NULL; + IF utConfig.includeprogname() THEN + progname := v_in|| '_'; + END IF; + + -- get the date format + date_formt := utConfig.dateformat; + + -- get the file extension + extension := utConfig.fileextension(); + + fid := UTL_FILE.FOPEN (file_dir, userprefix||progname|| + to_char(sysdate,date_formt)||extension, 'A'); + UTL_FILE.PUT_LINE (fid, '-- '||to_char(sysdate,date_formt)); + UTL_FILE.PUT_LINE (fid, v); + END IF; + + -- write input to file + UTL_FILE.PUT_LINE (fid, v_in); + + -- close file on testend command + -- '-- TESTEND --' gets written to file as well + IF v_in = c_endcmd AND UTL_FILE.is_open(fid) THEN + -- get the date format + date_formt := utConfig.dateformat; + UTL_FILE.PUT_LINE (fid, '-- '||to_char(sysdate,date_formt)); + UTL_FILE.FCLOSE (fid); + END IF; + + EXCEPTION + WHEN UTL_FILE.INVALID_PATH + THEN recNgo ('invalid_path'); + WHEN UTL_FILE.INVALID_MODE + THEN recNgo ('invalid_mode'); + WHEN UTL_FILE.INVALID_FILEHANDLE + THEN recNgo ('invalid_filehandle'); + WHEN UTL_FILE.INVALID_OPERATION + THEN recNgo ('invalid_operation'); + WHEN UTL_FILE.READ_ERROR + THEN recNgo ('read_error'); + WHEN UTL_FILE.WRITE_ERROR + THEN recNgo ('write_error'); + WHEN UTL_FILE.INTERNAL_ERROR + THEN recNgo ('internal_error'); + WHEN no_dir + THEN recNgo ('utPLSQL.pl_to_file: No directory specified for file output'); + END pl_to_file; + /* RMM end */ + + -- This is an interface to dbms_output.put_line that tries to + -- sensibly split long lines (which is useful if you want to + -- print large dynamic sql statements). From Alistair Bayley + PROCEDURE show ( + s VARCHAR2, + maxlinelenparm NUMBER := 255, + expand BOOLEAN := TRUE + ) + IS + output_buffer_overflow EXCEPTION; + PRAGMA EXCEPTION_INIT (output_buffer_overflow, -20000); + i NUMBER; + maxlinelen NUMBER + := GREATEST (1, LEAST (255, maxlinelenparm)); + + FUNCTION locatenewline (str VARCHAR2) + RETURN NUMBER + IS + i10 NUMBER; + i13 NUMBER; + BEGIN + i13 := NVL (INSTR (SUBSTR (str, 1, maxlinelen), CHR (13)), 0); + i10 := NVL (INSTR (SUBSTR (str, 1, maxlinelen), CHR (10)), 0); + + IF i13 = 0 + THEN + RETURN i10; + ELSIF i10 = 0 + THEN + RETURN i13; + ELSE + RETURN LEAST (i13, i10); + END IF; + END; + BEGIN + -- 2.1.2 if NULL, abort. + IF s IS NULL + THEN + DBMS_OUTPUT.put_line (s); + -- 2.1.2 PBA we should return here... + RETURN; + -- Simple case: s is short. + ELSIF LENGTH (s) <= maxlinelen + THEN + DBMS_OUTPUT.put_line (s); + RETURN; + END IF; + + -- OK, so it's long. Look for newline chars as a good place to split. + i := locatenewline (s); + + IF i > 0 + THEN -- cool, we can split at a newline + DBMS_OUTPUT.put_line (SUBSTR (s, 1, i - 1)); + show (SUBSTR (s, i + 1), maxlinelen, expand); + ELSE + -- No newlines. Look for a convenient space prior to the 255-char limit. + -- Search backwards from maxLineLen. + i := NVL (INSTR (SUBSTR (s, 1, maxlinelen), ' ', -1), 0); + + IF i > 0 + THEN + DBMS_OUTPUT.put_line (SUBSTR (s, 1, i - 1)); + show (SUBSTR (s, i + 1), maxlinelen, expand); + ELSE + -- No whitespace - split at max line length. + i := maxlinelen; + DBMS_OUTPUT.put_line (SUBSTR (s, 1, i)); + show (SUBSTR (s, i + 1), maxlinelen, expand); + END IF; + END IF; + EXCEPTION + WHEN output_buffer_overflow + THEN + IF NOT expand + THEN + RAISE; + ELSE + DBMS_OUTPUT.ENABLE (1000000); + -- set false so won't expand again + show (s, maxlinelen, FALSE); + END IF; + END; + + PROCEDURE pl ( + str IN VARCHAR2, + len IN INTEGER := 80, + expand_in IN BOOLEAN := TRUE + ) + IS + BEGIN + -- RMM start + IF get_pl_to_file THEN + pl_to_file(str,g_fid); + ELSIF NOT get_pl_to_file + -- RMM end + THEN + show (str, len, expand_in); + END IF; + END; + + FUNCTION vc2bool (vc IN VARCHAR2) + RETURN BOOLEAN + IS + BEGIN + IF vc = c_yes + THEN + RETURN TRUE; + ELSIF vc = c_no + THEN + RETURN FALSE; + ELSE + RETURN NULL; + END IF; + END; + + FUNCTION bool2vc (bool IN BOOLEAN) + RETURN VARCHAR2 + IS + BEGIN + IF bool + THEN + RETURN c_yes; + ELSIF NOT bool + THEN + RETURN c_no; + ELSE + RETURN 'NULL'; + END IF; + END; + + PROCEDURE bpl (bool IN BOOLEAN) + IS + BEGIN + pl (bool2vc (bool)); + END; + + FUNCTION progexists ( + prog_in IN VARCHAR2, + sch_in IN VARCHAR2 + ) + RETURN BOOLEAN + IS + v_prog VARCHAR2 (1000) := prog_in; + /* variables to hold components of the name */ + sch VARCHAR2 (100); + part1 VARCHAR2 (100); + part2 VARCHAR2 (100); + dblink VARCHAR2 (100); + part1_type NUMBER; + object_number NUMBER; + BEGIN + IF sch_in IS NOT NULL + THEN + v_prog := sch_in + || '.' + || prog_in; + END IF; + + /* Break down the name into its components */ + DBMS_UTILITY.name_resolve ( + v_prog, + 1, + sch, + part1, + part2, + dblink, + part1_type, + object_number + ); + RETURN TRUE; + EXCEPTION + -- Josh Goldie: 2.0.10.3 handle failure for objects. + WHEN OTHERS + THEN + IF sch_in IS NOT NULL + THEN + RETURN progexists (prog_in, NULL); + ELSE + /* Begin changes to check if v_prog is an object */ + DECLARE + block VARCHAR2(100) := + 'DECLARE obj ' || v_prog || '; BEGIN NULL; END;'; + &start73 + cur PLS_INTEGER := DBMS_SQL.open_cursor; + fdbk PLS_INTEGER; + &end73 + BEGIN + &start81 + EXECUTE IMMEDIATE block; + &end81 + + &start73 + DBMS_SQL.parse ( + cur, + block, + DBMS_SQL.native + ); + + fdbk := DBMS_SQL.EXECUTE(cur); + + DBMS_SQL.close_cursor(cur); + &end73 + + RETURN TRUE; + EXCEPTION + WHEN OTHERS + THEN + &start73 + DBMS_SQL.close_cursor(cur); + &end73 + RETURN FALSE; + END; + /* End changes to check if v_prog is an object */ + END IF; + END; + + + FUNCTION ispackage ( + prog_in IN VARCHAR2, + sch_in IN VARCHAR2 + ) + RETURN BOOLEAN + IS + v_prog VARCHAR2 (1000) := prog_in; + /* variables to hold components of the name */ + sch VARCHAR2 (100); + part1 VARCHAR2 (100); + part2 VARCHAR2 (100); + dblink VARCHAR2 (100); + part1_type NUMBER; + object_number NUMBER; + BEGIN + IF sch_in IS NOT NULL + THEN + v_prog := sch_in + || '.' + || prog_in; + END IF; + + /* Break down the name into its components */ + DBMS_UTILITY.name_resolve ( + v_prog, + 1, + sch, + part1, + part2, + dblink, + part1_type, + object_number + ); + RETURN part1_type = 9; + EXCEPTION + WHEN OTHERS + THEN + IF sch_in IS NOT NULL + THEN + RETURN ispackage (prog_in, NULL); + ELSE + RETURN FALSE; + END IF; + END; + + -- End utility definitions + + PROCEDURE setcurrcase (indx_in IN PLS_INTEGER) + IS + BEGIN + currcase.pkg := testpkg.pkg; + currcase.prefix := testpkg.prefix; + currcase.NAME := tests (indx_in).NAME; + currcase.indx := indx_in; + END; + + FUNCTION pkgname ( + package_in IN VARCHAR2, + samepackage_in IN BOOLEAN, + prefix_in IN VARCHAR2, + ispkg_in IN BOOLEAN, + owner_in IN VARCHAR2 := NULL + ) + RETURN VARCHAR2 + IS + retval VARCHAR2 (1000); + BEGIN + -- 2.0.9.1: revamp for owner/remote schema exec. + IF NOT ispkg_in + AND NOT samepackage_in -- 2.0.9.2 add second clause + THEN + retval := prefix_in + || package_in; + ELSIF samepackage_in + THEN + retval := package_in; + ELSE + retval := prefix_in + || package_in; + END IF; + + IF owner_in IS NOT NULL + THEN + -- 2.0.10.2: embed owner_in in double quotes to support + -- OS authentication + retval := '"' || owner_in || '"' + --retval := owner_in + || '.' + || retval; + END IF; + + RETURN retval; + END; + + /* 1.5.3 No longer in use + FUNCTION do_register + RETURN BOOLEAN + IS + BEGIN + RETURN (NVL (g_config.registertest, c_yes) != c_no); + END; + */ + + FUNCTION progname ( + program_in IN VARCHAR2, + samepackage_in IN BOOLEAN, + prefix_in IN VARCHAR2, + ispkg_in IN BOOLEAN + ) + RETURN VARCHAR2 + IS + -- The default setting... + retval VARCHAR2 (1000) + := prefix_in + || program_in; + BEGIN + -- 1.3.5 If not using setup to register then prefix + -- is already a part of the name; no construction necessary. + IF NOT utconfig.registeringtest + THEN + IF UPPER (program_in) NOT IN + (c_setup, c_teardown) + THEN + retval := program_in; + END IF; + ELSIF NOT ispkg_in + THEN + retval := prefix_in + || program_in; + ELSIF samepackage_in + THEN + retval := prefix_in + || program_in; + ELSE + -- Ignore prefix only for separate test packages of packaged + -- functionality. + retval := program_in; + END IF; + + RETURN retval; + END; + + FUNCTION pkgname ( + package_in IN VARCHAR2, + samepackage_in IN BOOLEAN, + prefix_in IN VARCHAR2, + owner_in IN VARCHAR2 := NULL + ) + RETURN VARCHAR2 + IS + BEGIN + utassert.this ( + 'Pkgname: the package record has not been set!', + testpkg.pkg IS NOT NULL, + register_in=> FALSE + ); + RETURN pkgname ( + package_in, + samepackage_in, + prefix_in, + testpkg.ispkg, + owner_in + ); + END; + + FUNCTION progname ( + program_in IN VARCHAR2, + samepackage_in IN BOOLEAN, + prefix_in IN VARCHAR2 + ) + RETURN VARCHAR2 + IS + BEGIN + utassert.this ( + 'Progname: the package record has not been set!', + testpkg.pkg IS NOT NULL, + register_in=> FALSE + ); + RETURN progname ( + program_in, + samepackage_in, + prefix_in, + testpkg.ispkg + ); + END; + + PROCEDURE runprog ( + name_in IN VARCHAR2, + propagate_in IN BOOLEAN := FALSE + ) + IS + v_pkg VARCHAR2 (100) + := pkgname ( + testpkg.pkg, + testpkg.samepkg, + testpkg.prefix, + testpkg.owner + ); + v_name VARCHAR2 (100) := name_in; + /* + 1.5.3 No longer needed; name is always already prefixed. + := progname (NAME_IN, testpkg.samepkg, testpkg.prefix); + */ + v_str VARCHAR2 (32767); + &start73 + fdbk PLS_INTEGER; + cur PLS_INTEGER + := DBMS_SQL.open_cursor; + &end73 + BEGIN + IF tracing + THEN + pl ( 'Runprog of ' + || name_in); + pl ( + ' Package and program = ' + || v_pkg + || '.' + || v_name + ); + pl ( + ' Same package? ' + || bool2vc (testpkg.samepkg) + ); + pl ( + ' Is package? ' + || bool2vc (testpkg.ispkg) + ); + pl ( ' Prefix = ' + || testpkg.prefix); + END IF; + + v_str := 'BEGIN ' + || v_pkg + || '.' + || v_name + || '; END;'; + &start81 + EXECUTE IMMEDIATE v_str; + &end81 + &start73 + DBMS_SQL.parse (cur, v_str, DBMS_SQL.native); + fdbk := DBMS_SQL.EXECUTE (cur); + DBMS_SQL.close_cursor (cur); + &end73 + EXCEPTION + WHEN OTHERS + THEN + &start73 + DBMS_SQL.close_cursor (cur); + + &end73 + + IF tracing + THEN + pl ( + 'Compile Error "' + || SQLERRM + || '" on: ' + ); + pl (v_str); + END IF; + + utassert.this ( + 'Unable to run ' + || v_pkg + || '.' + || v_name + || ': ' + || SQLERRM, + FALSE, + null_ok_in=> NULL, + raise_exc_in=> propagate_in, + register_in=> TRUE + ); + END; + + PROCEDURE runit ( + indx_in IN PLS_INTEGER, + per_method_setup_in IN BOOLEAN, + prefix_in IN VARCHAR2 + ) + IS + BEGIN + setcurrcase (indx_in); + + IF per_method_setup_in + THEN + runprog ( prefix_in + || c_setup, TRUE); + END IF; + + runprog (tests (indx_in).NAME, FALSE); + + IF per_method_setup_in + THEN + runprog ( + prefix_in + || c_teardown, + TRUE + ); + END IF; + END; + + PROCEDURE init_tests + IS + nulltest test_rt; + nullcase testcase_rt; + BEGIN + tests.DELETE; + currcase := nullcase; + testpkg := nulltest; + END; + + PROCEDURE init ( + prefix_in IN VARCHAR2 := NULL, + dir_in IN VARCHAR2 := NULL, + from_suite_in IN BOOLEAN := FALSE + ) + IS + BEGIN + init_tests; + + --Removed test for null as utConfig.prefix never returns null + IF prefix_in IS NOT NULL + AND prefix_in != utconfig.prefix + THEN + utconfig.setprefix (prefix_in); + END IF; + + IF dir_in IS NOT NULL + AND ( dir_in != utconfig.dir + OR utconfig.dir IS NULL + ) + /* 1.5.3 Check for null config directory as well */ + THEN + utconfig.setdir (dir_in); + END IF; + + utresult.init (from_suite_in); + + -- 2.0.1 compatibilty with utPLSQL2 + utplsql2.set_runnum; + + IF tracing + THEN + pl ('Initialized utPLSQL session...'); + END IF; + END; + + PROCEDURE COMPILE ( + file_in IN VARCHAR2, + dir_in IN VARCHAR2 + ) + IS + fid UTL_FILE.file_type; + v_dir VARCHAR2 (2000) + := NVL (dir_in, utconfig.dir); + lines DBMS_SQL.varchar2s; + cur PLS_INTEGER := DBMS_SQL.open_cursor; + + PROCEDURE recngo (str IN VARCHAR2) + IS + BEGIN + UTL_FILE.fclose (fid); + pl ( + 'Error compiling ' + || file_in + || ' located in "' + || v_dir + || '": ' + || str + ); + pl ( + ' Please make sure the directory for utPLSQL is set by calling ' + || 'utConfig.setdir.' + ); + pl ( + ' Your test package must reside in this directory.' + ); + + IF DBMS_SQL.is_open (cur) + THEN + DBMS_SQL.close_cursor (cur); + END IF; + END; + BEGIN + utrerror.assert ( + v_dir IS NOT NULL, + 'Compile error: you must specify a directory with utConfig.setdir!' + ); + fid := + UTL_FILE.fopen ( + v_dir, + file_in, + 'R' &start81 + , + max_linesize=> 32767 &end81 + ); + + LOOP + BEGIN + UTL_FILE.get_line ( + fid, + lines ( NVL (lines.LAST, 0) + + 1) + ); + -- 2.0.7: helps with compiling in Linux. + lines (lines.LAST) := + RTRIM ( + lines (lines.LAST), + ' ' + || CHR (13) + ); + EXCEPTION + WHEN NO_DATA_FOUND + THEN + EXIT; + END; + END LOOP; + + /* Clean up termination character. */ + LOOP + IF lines (lines.LAST) = '/' + OR RTRIM (lines (lines.LAST)) IS NULL + THEN + lines.DELETE (lines.LAST); + ELSE + EXIT; + END IF; + END LOOP; + + UTL_FILE.fclose (fid); + + if tracing then + pl ('Compiling ' || lines (lines.first)); + end if; + + DBMS_SQL.parse ( + cur, + lines, + lines.FIRST, + lines.LAST, + TRUE, + DBMS_SQL.native + ); + DBMS_SQL.close_cursor (cur); + EXCEPTION + WHEN UTL_FILE.invalid_path + THEN + recngo ('invalid_path'); + WHEN UTL_FILE.invalid_mode + THEN + recngo ('invalid_mode'); + WHEN UTL_FILE.invalid_filehandle + THEN + recngo ('invalid_filehandle'); + WHEN UTL_FILE.invalid_operation + THEN + recngo ('invalid_operation'); + WHEN UTL_FILE.read_error + THEN + recngo ('read_error'); + WHEN UTL_FILE.write_error + THEN + recngo ('write_error'); + WHEN UTL_FILE.internal_error + THEN + recngo ('internal_error'); + WHEN OTHERS + THEN + recngo (SQLERRM); + END; + + /* Programs used in ut_PKG.setup */ + + PROCEDURE setpkg ( + package_in IN VARCHAR2, + samepackage_in IN BOOLEAN := FALSE, + prefix_in IN VARCHAR2 := NULL, + owner_in IN VARCHAR2 := NULL, + subprogram_in IN VARCHAR2 := '%', + override_package_in IN VARCHAR2 + := NULL -- 2.0.9.2 + ) + IS + v_pkg VARCHAR2 (1000); + BEGIN + --testpkg.pkg := package_in; + -- 2.0.9.2 + testpkg.pkg := + NVL (override_package_in, package_in); + testpkg.owner := owner_in; -- 2.0.9.1 remote schema + testpkg.ispkg := + ispackage (package_in, owner_in); + + -- 2.0.9.2 If there is an override package, treat like samepackage + -- No addition of prefix, essentially + + IF override_package_in IS NOT NULL + THEN + testpkg.samepkg := TRUE; + ELSE + testpkg.samepkg := samepackage_in; + END IF; + + testpkg.prefix := + NVL ( + prefix_in, + utconfig.prefix (owner_in) + ); + v_pkg := pkgname ( + testpkg.pkg, + testpkg.samepkg, + testpkg.prefix, + testpkg.owner + ); + + -- 2.1.1 Initialize a ut_utp row/id + DECLARE + rec ut_utp%ROWTYPE; + BEGIN + IF ututp.EXISTS (testpkg.owner, testpkg.pkg) + THEN + rec := ututp.onerow (testpkg.owner, testpkg.pkg); + ELSE + ututp.ADD (testpkg.pkg, testpkg.owner, id_out => rec.ID); + END IF; + + utplsql2.set_current_utp (rec.ID); + utrutp.initiate(utplsql2.runnum,rec.id); + END; + + + IF tracing + THEN + pl ( 'Setpkg to ' + || testpkg.pkg); + pl ( + ' Package and program = ' + || v_pkg + ); + pl ( + ' Same package? ' + || bool2vc (testpkg.samepkg) + ); + pl ( + ' Is package? ' + || bool2vc (testpkg.ispkg) + ); + pl ( ' Prefix = ' + || testpkg.prefix); + END IF; + END; + + -- 2.0.8.2 Separate out population of test array + PROCEDURE populate_test_array ( + testpkg_in IN test_rt, + package_in IN VARCHAR2, + samepackage_in IN BOOLEAN := FALSE, + prefix_in IN VARCHAR2 := NULL, + owner_in IN VARCHAR2 := NULL, + subprogram_in IN VARCHAR2 := '%' + ) + IS + v_pkg VARCHAR2 (1000) + := -- 2.0.9.1 No owner prefix. + pkgname ( + testpkg_in.pkg, + testpkg_in.samepkg, + testpkg_in.prefix + ); + BEGIN + -- 1.3.5 + IF NOT utconfig.registeringtest ( + NVL (UPPER (owner_in), USER) + ) + THEN + -- Populate test information from ALL_ARGUMENTS + FOR rec IN + (SELECT DISTINCT object_name + FROM all_arguments + WHERE owner = + NVL ( + UPPER ( + owner_in + ), + USER + ) + AND package_name = + UPPER (v_pkg) + AND object_name LIKE + UPPER ( + prefix_in + ) + || '%' + AND object_name LIKE + UPPER ( + prefix_in + || subprogram_in + ) + AND object_name NOT IN + (UPPER ( + prefix_in + || c_setup + ), + UPPER ( + prefix_in + || c_teardown + ) + )) + LOOP + addtest ( + testpkg_in.pkg, + rec.object_name, + prefix_in, + iterations_in=> 1, + override_in=> TRUE + ); + END LOOP; + END IF; + END; + + FUNCTION currpkg + RETURN VARCHAR2 + IS + BEGIN + RETURN testpkg.pkg; + END; + + PROCEDURE addtest ( + package_in IN VARCHAR2, + name_in IN VARCHAR2, + prefix_in IN VARCHAR2, + iterations_in IN PLS_INTEGER, + override_in IN BOOLEAN + ) + IS + indx PLS_INTEGER + := NVL (tests.LAST, 0) + + 1; + BEGIN + -- 1.3.5 Disable calls to addtest from setup. + IF utconfig.registeringtest + OR ( NOT utconfig.registeringtest + AND override_in + ) + THEN + IF tracing + THEN + pl ('Addtest'); + pl ( + ' Package and program = ' + || package_in + || '.' + || name_in + ); + pl ( + ' Same package? ' + || bool2vc (testpkg.samepkg) + ); + pl ( + ' Override? ' + || bool2vc (override_in) + ); + pl ( ' Prefix = ' + || prefix_in); + END IF; + + -- 1.5.3: program name always already has prefix! + tests (indx).pkg := package_in; + tests (indx).prefix := prefix_in; + tests (indx).NAME := name_in; + tests (indx).iterations := iterations_in; + END IF; + END; + + PROCEDURE addtest ( + name_in IN VARCHAR2, + prefix_in IN VARCHAR2 := NULL, + iterations_in IN PLS_INTEGER := 1, + override_in IN BOOLEAN := FALSE + ) + IS + indx PLS_INTEGER + := NVL (tests.LAST, 0) + + 1; + BEGIN + addtest ( + testpkg.pkg, + name_in, + prefix_in, + iterations_in, + override_in + ); + END; + + /* Test engine */ + + /* 1.5.3. autocompiling used instead + FUNCTION do_recompile (recomp IN BOOLEAN) + RETURN BOOLEAN + IS + BEGIN + RETURN ( recomp + AND (NVL (g_config.autocompile, c_yes) != c_no)); + END; + */ + + PROCEDURE test ( + package_in IN VARCHAR2, + samepackage_in IN BOOLEAN := FALSE, + prefix_in IN VARCHAR2 := NULL, + recompile_in IN BOOLEAN := TRUE, + dir_in IN VARCHAR2 := NULL, + suite_in IN VARCHAR2 := NULL, + owner_in IN VARCHAR2 := NULL, + reset_results_in IN BOOLEAN := TRUE, + from_suite_in IN BOOLEAN := FALSE, + subprogram_in IN VARCHAR2 := '%', + per_method_setup_in IN BOOLEAN := FALSE, -- 2.0.8 + override_package_in IN VARCHAR2 + := NULL -- 2.0.9.2 + ) + IS + indx PLS_INTEGER; + v_pkg VARCHAR2 (100); + -- 2.0.10.1: use dir in config + v_dir maxvc2_t := NVL (dir_in, utconfig.dir); + v_start DATE := SYSDATE; + v_prefix ut_config.prefix%TYPE + := NVL (prefix_in, utconfig.prefix (owner_in)); + v_per_method_setup BOOLEAN + := NVL (per_method_setup_in, FALSE); + + PROCEDURE cleanup ( + per_method_setup_in IN BOOLEAN + ) + IS + BEGIN + utresult.show; + + IF NOT per_method_setup_in + THEN + runprog ( + v_prefix + || c_teardown, + TRUE + ); + END IF; + + utpackage.upd ( + suite_in, + package_in, + v_start, + SYSDATE, + utresult.success, + owner_in + ); + + -- 2.1.1 add recording of test in tables. + utrutp.terminate(utplsql2.runnum, utplsql2.current_utp); + + IF reset_results_in + THEN + init_tests; + END IF; + -- RMM start + -- close output file if open + IF suite_in IS NULL AND get_pl_to_file THEN + pl('-- TESTEND --'); + END IF; + -- RMM end + END; + BEGIN + init (v_prefix, v_dir, from_suite_in); + -- RMM start + g_pl_to_file := utConfig.getfile(); + IF g_pl_to_file THEN + IF suite_in IS NOT NULL THEN + -- we run a test suite + pl(suite_in); + ELSE + -- we run a single package test + pl(package_in); + END IF; + END IF; + -- RMM end + + IF NOT progexists (package_in, owner_in) + THEN + pl ( + 'Program named "' + || package_in + || '" does not exist.' + ); + ELSE + setpkg ( + package_in, + samepackage_in, + v_prefix, + owner_in, + subprogram_in, + override_package_in + ); + --v_pkg := pkgname (package_in, samepackage_in, v_prefix, owner_in); + -- 2.0.9.2 Make sure record is used. + v_pkg := pkgname ( + testpkg.pkg, + testpkg.samepkg, + testpkg.prefix, + testpkg.owner + ); + + IF recompile_in + AND utconfig.autocompiling ( + owner_in + ) + THEN + IF tracing + THEN + pl ( + 'Recompiling ' + || v_pkg + || ' in ' + || v_dir + ); + END IF; + + utreceq.COMPILE (package_in); + + COMPILE ( + -- 2.0.9.1 Package name without OWNER + -- 2.0.9.2 Switch to use of record based info. + --pkgname (package_in, samepackage_in, v_prefix) + -- || '.pks', dir_in); + pkgname ( + testpkg.pkg, + testpkg.samepkg, + testpkg.prefix + ) + || '.pks', + v_dir + ); + COMPILE ( + -- 2.0.9.1 Package name without OWNER + -- 2.0.9.2 Switch to use of record based info. + --pkgname (package_in, samepackage_in, v_prefix) + -- || '.pks', dir_in); + pkgname ( + testpkg.pkg, + testpkg.samepkg, + testpkg.prefix + ) + || '.pkb', + v_dir + ); + END IF; + + IF NOT v_per_method_setup + THEN + runprog ( + v_prefix + || c_setup, + TRUE + ); + END IF; + + populate_test_array ( + testpkg, + package_in, + samepackage_in, + v_prefix, + owner_in, + subprogram_in + ); + indx := tests.FIRST; + + IF indx IS NULL + THEN + pl ('Warning!'); + pl ( + 'Warning...no tests were identified for execution!' + ); + pl ('Warning!'); + ELSE + LOOP + EXIT WHEN indx IS NULL; + runit ( + indx, + v_per_method_setup, + v_prefix + ); + indx := tests.NEXT (indx); + END LOOP; + END IF; + + cleanup (v_per_method_setup); + END IF; + EXCEPTION + WHEN OTHERS + THEN + utassert.this ( + 'utPLSQL.test failure: ' + || SQLERRM, + FALSE + ); + cleanup (FALSE); + END; + + PROCEDURE testsuite ( + suite_in IN VARCHAR2, + recompile_in IN BOOLEAN := TRUE, + reset_results_in IN BOOLEAN := TRUE, + per_method_setup_in IN BOOLEAN := FALSE, -- 2.0.8 + override_package_in IN BOOLEAN := FALSE + ) + IS + v_suite ut_suite.id%TYPE + := utsuite.id_from_name (suite_in); + v_success BOOLEAN := TRUE; + v_suite_start DATE := SYSDATE; + v_pkg_start DATE; + v_override VARCHAR2 (1000); + BEGIN + IF v_suite IS NULL + THEN + utassert.this ( + 'Test suite with name "' + || suite_in + || '" does not exist.', + FALSE + ); + utresult.show; + ELSE + FOR rec IN (SELECT * + FROM ut_package + WHERE suite_id = v_suite + ORDER BY seq) + LOOP + v_pkg_start := SYSDATE; + + -- 2.0.9.2 Pass override request to individual test. + IF override_package_in + THEN + v_override := rec.NAME; + ELSE + v_override := NULL; + END IF; +-- 2.0.9.2 allow for continuation of tests if a single package fails +begin + test ( + rec.NAME, + vc2bool (rec.samepackage), + rec.prefix, + recompile_in, + rec.dir, + +-- v_suite, + suite_in, + rec.owner, + reset_results_in=> FALSE, + from_suite_in=> TRUE, + per_method_setup_in=> per_method_setup_in, + override_package_in=> v_override + ); + -- 3/4/02 trap exceptions and continue with next package. + EXCEPTION + WHEN OTHERS THEN + v_success := FALSE; + END; + IF utresult.failure + THEN + v_success := FALSE; + END IF; + END LOOP; + + utsuite.upd ( + v_suite, + v_suite_start, + SYSDATE, + v_success + ); + END IF; + + IF reset_results_in + THEN + init; + END IF; + -- RMM start + -- close output file if open + IF get_pl_to_file THEN + pl('-- TESTEND --'); + END IF; + -- RMM end + + END; + + /* Programs used in individual unit test programs. */ + + PROCEDURE setcase (case_in IN VARCHAR2) + IS + BEGIN + NULL; + END; + + PROCEDURE setdata ( + dir_in IN VARCHAR2, + file_in IN VARCHAR2, + delim_in IN VARCHAR2 := ',' + ) + IS + BEGIN + NULL; + END; + + PROCEDURE passdata ( + data_in IN VARCHAR2, + delim_in IN VARCHAR2 := ',' + ) + IS + BEGIN + NULL; + END; + + PROCEDURE trc + IS + BEGIN + g_trc := TRUE; + END; + + PROCEDURE notrc + IS + BEGIN + g_trc := FALSE; + END; + + FUNCTION tracing + RETURN BOOLEAN + IS + BEGIN + RETURN g_trc; + END; + + FUNCTION version + RETURN VARCHAR2 + IS + BEGIN + RETURN g_version; + END; + + FUNCTION seqval (tab_in IN VARCHAR2) + RETURN PLS_INTEGER + IS + sqlstr VARCHAR2 (200) + := 'SELECT ' + || tab_in + || '_seq.NEXTVAL FROM dual'; + fdbk PLS_INTEGER; + retval PLS_INTEGER; + BEGIN + &start81 + EXECUTE IMMEDIATE sqlstr + INTO retval; + + &end81 + &start73 + DECLARE + fdbk PLS_INTEGER; + cur PLS_INTEGER + := DBMS_SQL.open_cursor; + BEGIN + DBMS_SQL.parse ( + cur, + sqlstr, + DBMS_SQL.native + ); + DBMS_SQL.define_column (cur, 1, retval); + fdbk := DBMS_SQL.execute_and_fetch (cur); + DBMS_SQL.column_value (cur, 1, retval); + DBMS_SQL.close_cursor (cur); + EXCEPTION + WHEN OTHERS + THEN + DBMS_SQL.close_cursor (cur); + RAISE; + END; + + &end73 + RETURN retval; + END; + + FUNCTION ifelse ( + bool_in IN BOOLEAN, + tval_in IN BOOLEAN, + fval_in IN BOOLEAN + ) + RETURN BOOLEAN + IS + BEGIN + IF bool_in + THEN + RETURN tval_in; + ELSE + RETURN fval_in; + END IF; + END; + + FUNCTION ifelse ( + bool_in IN BOOLEAN, + tval_in IN DATE, + fval_in IN DATE + ) + RETURN DATE + IS + BEGIN + IF bool_in + THEN + RETURN tval_in; + ELSE + RETURN fval_in; + END IF; + END; + + FUNCTION ifelse ( + bool_in IN BOOLEAN, + tval_in IN NUMBER, + fval_in IN NUMBER + ) + RETURN NUMBER + IS + BEGIN + IF bool_in + THEN + RETURN tval_in; + ELSE + RETURN fval_in; + END IF; + END; + + FUNCTION ifelse ( + bool_in IN BOOLEAN, + tval_in IN VARCHAR2, + fval_in IN VARCHAR2 + ) + RETURN VARCHAR2 + IS + BEGIN + IF bool_in + THEN + RETURN tval_in; + ELSE + RETURN fval_in; + END IF; + END; + + -- 2.0.9.2: run a test package directly + PROCEDURE run ( + testpackage_in IN VARCHAR2, + prefix_in IN VARCHAR2 := NULL, + suite_in IN VARCHAR2 := NULL, + owner_in IN VARCHAR2 := NULL, + reset_results_in IN BOOLEAN := TRUE, + from_suite_in IN BOOLEAN := FALSE, + subprogram_in IN VARCHAR2 := '%', + per_method_setup_in IN BOOLEAN := FALSE + ) + IS + BEGIN + test ( + package_in=> testpackage_in, + samepackage_in=> FALSE, + prefix_in=> prefix_in, + recompile_in=> FALSE, + dir_in=> NULL, + suite_in=> suite_in, + owner_in=> owner_in, + reset_results_in=> reset_results_in, + from_suite_in=> from_suite_in, + subprogram_in=> subprogram_in, + per_method_setup_in=> per_method_setup_in, -- 2.0.8 + override_package_in=> testpackage_in + ); + END; + + PROCEDURE runsuite ( + suite_in IN VARCHAR2, + reset_results_in IN BOOLEAN := TRUE, + per_method_setup_in IN BOOLEAN := FALSE + ) + IS + BEGIN + testsuite ( + suite_in=> suite_in, + recompile_in=> FALSE, + reset_results_in=> reset_results_in, + per_method_setup_in=> per_method_setup_in, -- 2.0.8 + override_package_in=> TRUE + ); + END; +END; +/ diff --git a/source/ut_plsql.pks b/source/ut_plsql.pks new file mode 100644 index 000000000..2c8aa845f --- /dev/null +++ b/source/ut_plsql.pks @@ -0,0 +1,253 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE utplsql &start81 AUTHID CURRENT_USER &end81 +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + c_success CONSTANT VARCHAR2 (7) := 'SUCCESS'; + c_failure CONSTANT VARCHAR2 (7) := 'FAILURE'; + c_yes CONSTANT CHAR (1) := 'Y'; + c_no CONSTANT CHAR (1) := 'N'; + c_setup CONSTANT CHAR (5) := 'SETUP'; + c_teardown CONSTANT CHAR (8) := 'TEARDOWN'; + c_enabled CONSTANT CHAR (7) := 'ENABLED'; + c_disabled CONSTANT CHAR (8) := 'DISABLED'; + &start73 + dbmaxvc2 VARCHAR2 (2000); + &end73 + &start81 + dbmaxvc2 VARCHAR2 (4000); + + &end81 + SUBTYPE dbmaxvc2_t IS dbmaxvc2%TYPE; + + maxvc2 VARCHAR2 (32767); + + SUBTYPE maxvc2_t IS maxvc2%TYPE; + + namevc2 VARCHAR2 (100); + + SUBTYPE name_t IS namevc2%TYPE; + + TYPE test_rt IS RECORD ( + pkg VARCHAR2 (100), + owner VARCHAR2(100), -- 2.0.9.1 support remote schema execution + ispkg BOOLEAN, + samepkg BOOLEAN, + prefix VARCHAR2 (100), + iterations PLS_INTEGER); + + TYPE testcase_rt IS RECORD ( + pkg VARCHAR2 (100), + prefix VARCHAR2 (100), + name VARCHAR2 (100), + indx PLS_INTEGER, + iterations PLS_INTEGER); + + TYPE test_tt IS TABLE OF testcase_rt + INDEX BY BINARY_INTEGER; + + currcase testcase_rt; + + /* Utility programs */ + + -- RMM start + FUNCTION get_pl_to_file RETURN BOOLEAN; + + PROCEDURE set_pl_to_file ( + val IN BOOLEAN := FALSE + ); + -- RMM end + + PROCEDURE pl ( + str IN VARCHAR2, + len IN INTEGER := 80, + expand_in IN BOOLEAN := TRUE + ); + + PROCEDURE bpl (bool IN BOOLEAN); + + FUNCTION vc2bool (vc IN VARCHAR2) + RETURN BOOLEAN; + + FUNCTION bool2vc (bool IN BOOLEAN) + RETURN VARCHAR2; + + FUNCTION ispackage (prog_in IN VARCHAR2, sch_in IN VARCHAR2) + RETURN BOOLEAN; + + /* Single package test engine. */ + + PROCEDURE test ( + package_in IN VARCHAR2, + samepackage_in IN BOOLEAN := FALSE, + prefix_in IN VARCHAR2 := NULL, + recompile_in IN BOOLEAN := TRUE, + dir_in IN VARCHAR2 := NULL, + suite_in IN VARCHAR2 := NULL, + owner_in IN VARCHAR2 := NULL, + reset_results_in IN BOOLEAN := TRUE, + from_suite_in IN BOOLEAN := FALSE, + subprogram_in in varchar2 := '%', + per_method_setup_in in boolean := FALSE, -- 2.0.8 + override_package_in IN varchar2 := NULL -- 2.0.9.2 + -- If recompiling, then always looks for + -- .pks and .pkb files + ); + + PROCEDURE testsuite ( + suite_in IN VARCHAR2, + recompile_in IN BOOLEAN := TRUE, + reset_results_in IN BOOLEAN := TRUE, + per_method_setup_in in boolean := FALSE, -- 2.0.8 + override_package_in IN BOOLEAN := FALSE + -- If recompiling, then always looks for + -- .pks and .pkb files + ); + + /* Single package test engine. */ + -- 2.0.9.2: run a test package directly + PROCEDURE run ( + testpackage_in IN VARCHAR2, + prefix_in IN VARCHAR2 := NULL, + suite_in IN VARCHAR2 := NULL, + owner_in IN VARCHAR2 := NULL, + reset_results_in IN BOOLEAN := TRUE, + from_suite_in IN BOOLEAN := FALSE, + subprogram_in in varchar2 := '%', + per_method_setup_in in boolean := FALSE + ); + + PROCEDURE runsuite ( + suite_in IN VARCHAR2, + reset_results_in IN BOOLEAN := TRUE, + per_method_setup_in in boolean := FALSE + ); + + /* Programs used in ut_PKG.setup */ + + /* 1.3.2: Hide setpkg. Modifies global package state + and is no longer needed by customer. + + PROCEDURE setpkg ( + package_in IN VARCHAR2, + samepackage_in IN BOOLEAN := FALSE, + prefix_in IN VARCHAR2 := NULL + ); + */ + + FUNCTION currpkg + RETURN VARCHAR2; + + PROCEDURE addtest ( + package_in IN VARCHAR2, + name_in IN VARCHAR2, + prefix_in IN VARCHAR2, + iterations_in IN PLS_INTEGER, + override_in IN BOOLEAN + ); + + PROCEDURE addtest ( + name_in IN VARCHAR2, + prefix_in IN VARCHAR2 := NULL, + iterations_in IN PLS_INTEGER := 1, + override_in IN BOOLEAN := FALSE + ); + + -- Not currently used. + PROCEDURE setcase (case_in IN VARCHAR2); + + -- Not currently used. + PROCEDURE setdata ( + dir_in IN VARCHAR2, + file_in IN VARCHAR2, + delim_in IN VARCHAR2 := ',' + ); + + -- Not currently used. + PROCEDURE passdata (data_in IN VARCHAR2, delim_in IN VARCHAR2 := ','); + + -- Utility programs + + PROCEDURE trc; + + PROCEDURE notrc; + + FUNCTION tracing + RETURN BOOLEAN; + + FUNCTION version + RETURN VARCHAR2; + + FUNCTION seqval (tab_in IN VARCHAR2) + RETURN PLS_INTEGER; + + -- Constructs name of package and program based on factors + -- such as same package or test package, prefix, etc. + FUNCTION pkgname ( + package_in IN VARCHAR2, + samepackage_in IN BOOLEAN, + prefix_in IN VARCHAR2, + ispkg_in IN BOOLEAN, + owner_in IN VARCHAR2 := NULL + ) + RETURN VARCHAR2; + + FUNCTION progname ( + program_in IN VARCHAR2, + samepackage_in IN BOOLEAN, + prefix_in IN VARCHAR2, + ispkg_in IN BOOLEAN + ) + RETURN VARCHAR2; + + FUNCTION pkgname ( + package_in IN VARCHAR2, + samepackage_in IN BOOLEAN, + prefix_in IN VARCHAR2, + owner_in IN VARCHAR2 := NULL + ) + RETURN VARCHAR2; + + FUNCTION progname ( + program_in IN VARCHAR2, + samepackage_in IN BOOLEAN, + prefix_in IN VARCHAR2 + ) + RETURN VARCHAR2; + + FUNCTION ifelse (bool_in IN BOOLEAN, tval_in IN BOOLEAN, fval_in IN BOOLEAN) + RETURN BOOLEAN; + + FUNCTION ifelse (bool_in IN BOOLEAN, tval_in IN DATE, fval_in IN DATE) + RETURN DATE; + + FUNCTION ifelse (bool_in IN BOOLEAN, tval_in IN NUMBER, fval_in IN NUMBER) + RETURN NUMBER; + + FUNCTION ifelse ( + bool_in IN BOOLEAN, + tval_in IN VARCHAR2, + fval_in IN VARCHAR2 + ) + RETURN VARCHAR2; +END; +/ diff --git a/source/ut_plsql2.pkb b/source/ut_plsql2.pkb new file mode 100644 index 000000000..815406d21 --- /dev/null +++ b/source/ut_plsql2.pkb @@ -0,0 +1,474 @@ +/* Formatted on 2001/10/15 08:45 (Formatter Plus v4.5.2) */ +CREATE OR REPLACE PACKAGE BODY utplsql2 +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 +Steven Feuerstein, steven@stevenfeuerstein.com +Chris Rimmer, chris@sunset.force9.co.uk + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +------------------------------------------------------------------------------- +--Modification History +------------------------------------------------------------------------------- +--WHO WHEN WHAT +------------------------------------------------------------------------------- +--SEF 15 Nov 2001 2.0.8.1: Add support for unit test level +-- setup/teardown +--Chris Rimmer 08 Nov 2000 Changed to use new utConfig package +------------------------------------------------------------------------------- + + g_trc BOOLEAN := FALSE; + g_version VARCHAR2 (100) := '1.5.6'; + g_current current_test_rt; + + -- Global state information + FUNCTION runnum + RETURN utr_outcome.run_id%TYPE + IS + BEGIN + RETURN g_current.run_id; + END; + + + -- 2.0.9.1: tc_run_id logic + PROCEDURE set_runnum + IS + BEGIN + SELECT utplsql_runnum_seq.NEXTVAL + INTO g_current.run_id + FROM DUAL; + g_current.tc_run_id := 1; + END; + + FUNCTION tc_runnum + RETURN PLS_INTEGER + IS + BEGIN + RETURN g_current.tc_run_id; + END; + + PROCEDURE move_ahead_tc_runnum + IS + BEGIN + g_current.tc_run_id := g_current.tc_run_id + 1; + END; + + FUNCTION current_suite + RETURN ut_suite.id%TYPE + IS + BEGIN + RETURN g_current.suite_id; + END; + + PROCEDURE set_current_suite (suite_in IN ut_suite.id%TYPE) + IS + BEGIN + g_current.suite_id := suite_in; + END; + + FUNCTION current_utp + RETURN ut_utp.id%TYPE + IS + BEGIN + RETURN g_current.utp_id; + END; + + PROCEDURE set_current_utp (utp_in IN ut_utp.id%TYPE) + IS + BEGIN + g_current.utp_id := utp_in; + END; + + FUNCTION current_unittest + RETURN ut_unittest.id%TYPE + IS + BEGIN + RETURN g_current.unittest_id; + END; + + PROCEDURE set_current_unittest ( + unittest_in IN ut_unittest.id%TYPE + ) + IS + BEGIN + g_current.unittest_id := unittest_in; + END; + + FUNCTION current_testcase + RETURN ut_testcase.id%TYPE + IS + BEGIN + RETURN g_current.testcase_id; + END; + + PROCEDURE set_current_testcase ( + testcase_in IN ut_testcase.id%TYPE + ) + IS + BEGIN + g_current.testcase_id := testcase_in; + END; + + FUNCTION current_outcome + RETURN ut_outcome.id%TYPE + IS + BEGIN + RETURN g_current.outcome_id; + END; + + PROCEDURE set_current_outcome ( + outcome_in IN ut_outcome.id%TYPE + ) + IS + BEGIN + g_current.outcome_id := outcome_in; + END; + + PROCEDURE runprog ( + procedure_in IN VARCHAR2, + utp_id_in IN ut_utp.id%TYPE := NULL, + unittest_id_in IN ut_unittest.id%TYPE := NULL, + propagate_in IN BOOLEAN := FALSE, + exceptions_in IN VARCHAR2 := NULL + ) + IS + v_name VARCHAR2 (100) := procedure_in; + v_str VARCHAR2 (32767); + &start73 + fdbk PLS_INTEGER; + cur PLS_INTEGER := DBMS_SQL.open_cursor; + &end73 + BEGIN + IF tracing + THEN + utplsql.pl ( 'Runprog of ' + || procedure_in); + END IF; + + v_str := 'BEGIN ' + || procedure_in + || ';' + || utplsql.ifelse ( + exceptions_in IS NULL, + NULL, + RTRIM ( + 'EXCEPTION ' + || exceptions_in, + ';' + ) + || ';' + ) + || ' END;'; + &start81 + EXECUTE IMMEDIATE v_str; + &end81 + &start73 + DBMS_SQL.parse (cur, v_str, DBMS_SQL.native); + fdbk := DBMS_SQL.EXECUTE (cur); + DBMS_SQL.close_cursor (cur); + &end73 + EXCEPTION + WHEN OTHERS + THEN + &start73 + DBMS_SQL.close_cursor (cur); + + &end73 + + IF tracing + THEN + utplsql.pl ( + 'Procedure execution Error "' + || SQLERRM + || '" on: ' + ); + utplsql.pl (v_str); + END IF; + + IF unittest_id_in IS NOT NULL + THEN + utrerror.ut_report ( + utplsql2.runnum, + unittest_id_in, + utrerror.cannot_run_program, + 'Procedure named "' + || procedure_in + || '" could not be executed.', + SQLERRM + ); + ELSE + utrerror.utp_report ( + utplsql2.runnum, + utp_id_in, + utrerror.cannot_run_program, + 'Procedure named "' + || procedure_in + || '" could not be executed.', + SQLERRM + ); + END IF; + /* + utassert.this ( + 'Unable to run ' + || procedure_in + || ': ' + || SQLERRM, + FALSE, + null_ok_in=> NULL, + raise_exc_in=> propagate_in, + register_in=> TRUE + ); + */ + END; + + PROCEDURE run_utp_setup (utp_in IN ut_utp%ROWTYPE, + package_level_in in boolean := TRUE) + IS + l_program VARCHAR2 (100) + := ututp.setup_procedure (utp_in); + -- V1 uttestprep.setup_program (utp_in) + BEGIN + IF l_program IS NOT NULL and + (package_level_in OR utp_in.per_method_setup = utplsql.c_yes) + THEN + runprog ( + l_program, + utp_in.id, + exceptions_in=> utp_in.EXCEPTIONS + ); + END IF; + END; + + PROCEDURE run_utp_teardown (utp_in IN ut_utp%ROWTYPE, + package_level_in in boolean := TRUE) + IS + l_program VARCHAR2 (100) + := ututp.teardown_procedure (utp_in); + -- V1 uttestprep.teardown_program (utp_in); + BEGIN + IF l_program IS NOT NULL and + (package_level_in OR utp_in.per_method_setup = utplsql.c_yes) + THEN + runprog ( + l_program, + utp_in.id, + exceptions_in=> utp_in.EXCEPTIONS + ); + END IF; + END; + + PROCEDURE run_unittest ( + utp_in IN ut_utp%ROWTYPE, + ut_in IN ut_unittest%ROWTYPE + ) + IS + BEGIN + utrunittest.initiate (utplsql2.runnum, ut_in.id); + + -- 2.0.8.1: Add support for unit test level setup/teardown + + run_utp_setup (utp_in, package_level_in => FALSE); + + runprog ( + utunittest.full_name (utp_in, ut_in), + utp_in.id, + ut_in.id, + exceptions_in=> utp_in.EXCEPTIONS + ); + + run_utp_teardown (utp_in, package_level_in => FALSE); + + utrunittest.terminate (utplsql2.runnum, ut_in.id); + END; + + PROCEDURE test ( + utp_rec IN ut_utp%ROWTYPE, + show_results_in IN BOOLEAN := TRUE, + program_in IN VARCHAR2 := NULL, + naming_mode_in IN VARCHAR2 := v2_naming_mode + ) + IS + CURSOR unit_tests_cur (id_in IN ut_utp.id%TYPE) + IS + SELECT * + FROM ut_unittest + WHERE utp_id = id_in + AND status = utplsql.c_enabled + ORDER BY seq; + + PROCEDURE cleanup (utp_in IN ut_utp%ROWTYPE) + IS + BEGIN + IF utp_in.id IS NOT NULL + THEN + run_utp_teardown (utp_in); + utrutp.terminate (utplsql2.runnum, utp_in.id); + END IF; + + IF show_results_in + THEN + utresult.show (utplsql2.runnum); + END IF; + + COMMIT; + END; + BEGIN + IF utp_rec.id IS NULL + THEN + utrerror.utp_report ( + utplsql2.runnum, + NULL, + utrerror.no_utp_for_program, + 'Program named "' + || program_in + || '" does not have a UTP defined for it.' + ); + ELSE + utrutp.initiate (utplsql2.runnum, utp_rec.id); + run_utp_setup (utp_rec); + + -- Get the information on this program from the ut_utp table. + FOR ut_rec IN unit_tests_cur (utp_rec.id) + LOOP + IF tracing + THEN + utplsql.pl ( + 'Unit testing: ' + || ut_rec.program_name + ); + END IF; + + run_unittest (utp_rec, ut_rec); + + END LOOP; + END IF; + + cleanup (utp_rec); + EXCEPTION + WHEN OTHERS + THEN + utrerror.utp_report ( + utplsql2.runnum, + utp_rec.id, + SQLCODE, + SQLERRM, + raiseexc=> FALSE + ); + cleanup (utp_rec); + END; + + PROCEDURE test ( + program_in IN VARCHAR2, + owner_in IN VARCHAR2 := NULL, + show_results_in IN BOOLEAN := TRUE, + naming_mode_in IN VARCHAR2 := v2_naming_mode + ) + IS + utp_rec ut_utp%ROWTYPE; + BEGIN + set_runnum; + utp_rec := ututp.onerow (owner_in, program_in); + test ( + utp_rec, + show_results_in, + program_in, + naming_mode_in + ); + END; + + PROCEDURE testsuite ( + suite_in IN VARCHAR2, + show_results_in IN BOOLEAN := TRUE, + naming_mode_in IN VARCHAR2 := v2_naming_mode + ) + IS + v_suite ut_suite.id%TYPE; + v_success BOOLEAN := TRUE; + v_suite_start DATE := SYSDATE; + v_pkg_start DATE; + suite_rec ut_suite%ROWTYPE; + + CURSOR utps_cur (suite_in IN ut_suite.id%TYPE) + IS + SELECT ut_utp.* + FROM ut_utp, ut_suite_utp + WHERE suite_id = suite_in + AND ut_utp.id = ut_suite_utp.utp_id; + BEGIN + set_runnum; + suite_rec := utsuite.onerow (suite_in); + + IF suite_rec.id IS NULL + THEN + utrerror.suite_report ( + utplsql2.runnum, + NULL, + utrerror.undefined_suite, + 'Suite named "' + || suite_in + || '" is not defined.' + ); + ELSE + utrsuite.initiate (utplsql2.runnum, suite_rec.id); + + -- Get the information on this program from the ut_utp table. + FOR utp_rec IN utps_cur (suite_rec.id) + LOOP + test ( + utp_rec, + show_results_in=> show_results_in, + naming_mode_in=> naming_mode_in + ); + END LOOP; + + utrsuite.terminate (utplsql2.runnum, suite_rec.id); + END IF; + EXCEPTION + WHEN OTHERS + THEN + utrerror.suite_report ( + utplsql2.runnum, + suite_rec.id, + SQLCODE, + SQLERRM, + raiseexc=> FALSE + ); + END; + + PROCEDURE trc + IS + BEGIN + g_trc := TRUE; + END; + + PROCEDURE notrc + IS + BEGIN + g_trc := FALSE; + END; + + FUNCTION tracing + RETURN BOOLEAN + IS + BEGIN + RETURN g_trc; + END; +END utplsql2; +/ + diff --git a/source/ut_plsql2.pks b/source/ut_plsql2.pks new file mode 100644 index 000000000..2ba445fc4 --- /dev/null +++ b/source/ut_plsql2.pks @@ -0,0 +1,98 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE utplsql2 &start81 AUTHID CURRENT_USER &end81 +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +V2_naming_mode constant char(2) := 'V1'; +V1_naming_mode constant char(2) := 'V2'; + + -- Define and access "current test state" information + + TYPE current_test_rt IS RECORD ( + run_id utr_outcome.run_id%TYPE, + tc_run_id PLS_INTEGER, -- 2.0.9.1 + suite_id ut_suite.id%TYPE, + utp_id ut_utp.id%TYPE, + unittest_id ut_unittest.id%TYPE, + testcase_id ut_testcase.id%TYPE, + outcome_id ut_outcome.id%TYPE); + + FUNCTION runnum + RETURN utr_outcome.run_id%TYPE; + --2.0.9.2 + PRAGMA RESTRICT_REFERENCES (runnum, WNDS); + + PROCEDURE set_runnum; + + FUNCTION tc_runnum + RETURN PLS_INTEGER; + + PROCEDURE move_ahead_tc_runnum; + + FUNCTION current_suite + RETURN ut_suite.id%TYPE; + + PROCEDURE set_current_suite (suite_in IN ut_suite.id%TYPE); + + FUNCTION current_utp + RETURN ut_utp.id%TYPE; + + PROCEDURE set_current_utp (utp_in IN ut_utp.id%TYPE); + + FUNCTION current_unittest + RETURN ut_unittest.id%TYPE; + + PROCEDURE set_current_unittest (unittest_in IN ut_unittest.id%TYPE); + + FUNCTION current_testcase + RETURN ut_testcase.id%TYPE; + + PROCEDURE set_current_testcase (testcase_in IN ut_testcase.id%TYPE); + + FUNCTION current_outcome + RETURN ut_outcome.id%TYPE; + + PROCEDURE set_current_outcome (outcome_in IN ut_outcome.id%TYPE); + + PROCEDURE test ( + program_in IN VARCHAR2, + owner_in IN VARCHAR2 := NULL, + show_results_in IN BOOLEAN := TRUE, + naming_mode_in IN VARCHAR2 := V2_naming_mode + ); + + PROCEDURE testsuite ( + suite_in IN VARCHAR2, + show_results_in IN BOOLEAN := TRUE, + naming_mode_in IN VARCHAR2 := V2_naming_mode + ); + + -- Utility programs + + PROCEDURE trc; + + PROCEDURE notrc; + + FUNCTION tracing + RETURN BOOLEAN; +END utplsql2; +/ diff --git a/source/ut_plsql_runnum_seq.seq b/source/ut_plsql_runnum_seq.seq new file mode 100644 index 000000000..5dd2cf485 --- /dev/null +++ b/source/ut_plsql_runnum_seq.seq @@ -0,0 +1 @@ +CREATE sequence utplsql_runnum_seq INCREMENT BY 1 START WITH 1 ORDER NOCACHE; diff --git a/source/ut_plsql_util.pkb b/source/ut_plsql_util.pkb new file mode 100644 index 000000000..01171c4a3 --- /dev/null +++ b/source/ut_plsql_util.pkb @@ -0,0 +1,1589 @@ +CREATE OR REPLACE PACKAGE BODY utplsql_util +AS + ver_no VARCHAR2 (10) := '1.0.0'; + + TYPE param_rec IS RECORD ( + col_name VARCHAR2 (50), + col_type PLS_INTEGER, + col_len PLS_INTEGER, + col_mode PLS_INTEGER + ); + + TYPE params_tab IS TABLE OF param_rec + INDEX BY BINARY_INTEGER; + + par_in PLS_INTEGER := 1; + par_inout PLS_INTEGER := 2; + par_out PLS_INTEGER := 3; + param_prefix VARCHAR2 (10) := 'ut_'; + + FUNCTION get_version + RETURN VARCHAR2 + IS + BEGIN + RETURN (ver_no); + END; + + FUNCTION get_par_alias (par_type VARCHAR) + RETURN VARCHAR2 + IS + BEGIN + IF (par_type = 'VARCHAR') + THEN + RETURN ('vchar'); + ELSIF (par_type = 'NUMBER') + THEN + RETURN ('num'); + ELSIF (par_type = 'DATE') + THEN + RETURN ('date'); + ELSIF (par_type = 'REF CURSOR') + THEN + RETURN ('refc'); + ELSIF (par_type = 'CHAR') + THEN + RETURN ('chr'); + ELSE + RETURN ('oth'); + END IF; + END; + + PROCEDURE add_params ( + params IN OUT utplsql_params, + par_pos PLS_INTEGER, + par_type VARCHAR2, + par_sql_type VARCHAR2, + par_inout PLS_INTEGER, + par_val VARCHAR2 + ) + IS + idx PLS_INTEGER; + BEGIN + idx := params.COUNT + 1; + params (idx).par_name := param_prefix + || get_par_alias (par_type) + || '_' + || TO_CHAR (par_pos); + params (idx).par_pos := par_pos; + params (idx).par_type := par_type; + params (idx).par_sql_type := par_sql_type; + params (idx).par_inout := par_inout; + params (idx).par_val := par_val; + END; + + PROCEDURE reg_in_param ( + par_pos PLS_INTEGER, + par_val VARCHAR2, + params IN OUT utplsql_params + ) + IS + BEGIN + add_params (params, par_pos, 'VARCHAR2', 'VARCHAR2', par_in, par_val); + END; + + PROCEDURE reg_in_param ( + par_pos PLS_INTEGER, + par_val NUMBER, + params IN OUT utplsql_params + ) + IS + BEGIN + add_params ( + params, + par_pos, + 'NUMBER', + 'NUMBER', + par_in, + TO_CHAR (par_val) + ); + END; + + PROCEDURE reg_in_array ( + par_pos IN PLS_INTEGER, + array_name IN VARCHAR2, + array_vals IN varchar_array, + params IN OUT utplsql_params + ) + IS + idx PLS_INTEGER; + BEGIN + add_params (params, par_pos, 'ARRAY', array_name, par_in, NULL); + idx := array_holder.COUNT + 1; + + FOR i IN 1 .. array_vals.COUNT + LOOP + array_holder (idx).array_pos := par_pos; + array_holder (idx).array_val := array_vals (i); + idx := idx + 1; + END LOOP; + END; + + PROCEDURE reg_in_param ( + par_pos PLS_INTEGER, + par_val DATE, + params IN OUT utplsql_params + ) + IS + BEGIN + add_params ( + params, + par_pos, + 'DATE', + 'DATE', + par_in, + TO_CHAR (par_val, 'DD-MON-YYYY:HH24:MI:SS') + ); + END; + + PROCEDURE reg_inout_param ( + par_pos PLS_INTEGER, + par_val VARCHAR2, + params IN OUT utplsql_params + ) + IS + BEGIN + add_params (params, par_pos, 'VARCHAR2', 'VARCHAR2', par_inout, par_val); + END; + + PROCEDURE reg_inout_param ( + par_pos PLS_INTEGER, + par_val NUMBER, + params IN OUT utplsql_params + ) + IS + BEGIN + add_params ( + params, + par_pos, + 'NUMBER', + 'NUMBER', + par_inout, + TO_CHAR (par_val) + ); + END; + + PROCEDURE reg_inout_param ( + par_pos PLS_INTEGER, + par_val DATE, + params IN OUT utplsql_params + ) + IS + BEGIN + add_params ( + params, + par_pos, + 'DATE', + 'DATE', + par_inout, + TO_CHAR (par_val, 'DD-MON-YYYY:HH24:MI:SS') + ); + END; + + PROCEDURE reg_out_param ( + par_pos PLS_INTEGER, + par_type VARCHAR2, + params IN OUT utplsql_params + ) + IS + int_par_type VARCHAR2 (10); + BEGIN + IF (par_type = 'NUMBER') + THEN + int_par_type := 'NUMBER'; + ELSIF (par_type = 'VARCHAR') + THEN + int_par_type := 'VARCHAR2'; + ELSIF (par_type = 'CHAR') + THEN + int_par_type := 'VARCHAR2'; + ELSIF (par_type = 'REFCURSOR') + THEN + int_par_type := 'REFC'; + ELSE + int_par_type := par_type; + END IF; + + add_params (params, par_pos, int_par_type, int_par_type, par_out, NULL); + END; + + FUNCTION strtoken (s_str IN OUT VARCHAR2, token VARCHAR2) + RETURN VARCHAR2 + IS + pos PLS_INTEGER; + tmpstr VARCHAR2 (4000); + BEGIN + pos := NVL (INSTR (s_str, token), 0); + + IF (pos = 0) + THEN + pos := LENGTH (s_str); + END IF; + + tmpstr := SUBSTR (s_str, 1, pos); + s_str := SUBSTR (s_str, pos); + RETURN (tmpstr); + END; + + PROCEDURE get_table_for_str ( + p_arr OUT v30_table, + p_string VARCHAR2, + delim VARCHAR2 := ',', + enclose_str VARCHAR2 DEFAULT NULL + ) + IS + pos INTEGER := 1; + v_idx INTEGER := 1; + tmp_str VARCHAR2 (4000); + BEGIN + IF p_string IS NULL + THEN + RETURN; + END IF; + + tmp_str := p_string; + + LOOP + EXIT WHEN (pos = 0); + pos := INSTR (tmp_str, delim); + + IF (pos = 0) + THEN + p_arr (v_idx) := enclose_str || tmp_str || enclose_str; + ELSE + p_arr (v_idx) := enclose_str + || SUBSTR (tmp_str, 1, pos - 1) + || enclose_str; + v_idx := v_idx + 1; + tmp_str := SUBSTR (tmp_str, pos + 1); + END IF; + END LOOP; + END; + + FUNCTION describe_proc (vproc_name VARCHAR2, params OUT params_tab) + RETURN VARCHAR2 + IS + outstr VARCHAR2 (3000) := NULL; + seperator VARCHAR2 (10) := NULL; + v_overload DBMS_DESCRIBE.number_table; + v_position DBMS_DESCRIBE.number_table; + v_level DBMS_DESCRIBE.number_table; + v_argumentname DBMS_DESCRIBE.varchar2_table; + v_datatype DBMS_DESCRIBE.number_table; + v_defaultvalue DBMS_DESCRIBE.number_table; + v_inout DBMS_DESCRIBE.number_table; + v_length DBMS_DESCRIBE.number_table; + v_precision DBMS_DESCRIBE.number_table; + v_scale DBMS_DESCRIBE.number_table; + v_radix DBMS_DESCRIBE.number_table; + v_spare DBMS_DESCRIBE.number_table; + v_argcounter PLS_INTEGER := 1; + curr_level PLS_INTEGER := 1; + prev_level PLS_INTEGER := 1; + tab_open BOOLEAN := FALSE ; + rec_open BOOLEAN := FALSE ; + pos PLS_INTEGER; + + PROCEDURE add_param (str VARCHAR2) + IS + vtable v30_table; + BEGIN + get_table_for_str (vtable, str, ':'); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ( + 'Parsed=' + || vtable (1) + || ',' + || vtable (2) + || ',' + || vtable (3) + || ',' + || vtable (4) + ); + END IF; + + params (pos).col_name := vtable (1); + params (pos).col_type := vtable (2); + params (pos).col_len := vtable (3); + params (pos).col_mode := vtable (4); + pos := pos + 1; + END; + BEGIN + DBMS_DESCRIBE.describe_procedure ( + vproc_name, + NULL, + NULL, + v_overload, + v_position, + v_level, + v_argumentname, + v_datatype, + v_defaultvalue, + v_inout, + v_length, + v_precision, + v_scale, + v_radix, + v_spare + ); + v_argcounter := 1; + + IF (v_position (1) = 0) + THEN + outstr := 'FUNCTION'; + ELSE + outstr := 'PROCEDURE'; + END IF; + + pos := 1; + + LOOP + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ( + 'Desc()=' + || v_argumentname (v_argcounter) + || ',' + || TO_CHAR (v_datatype (v_argcounter)) + ); + END IF; + + curr_level := v_level (v_argcounter); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ( + 'Currlevel=' + || TO_CHAR (curr_level) + || ',Prevlevel=' + || TO_CHAR (prev_level) + ); + END IF; + + IF (curr_level <= prev_level) + THEN + IF (rec_open) + THEN + add_param ('RECORDEND:0:0:0'); + rec_open := FALSE ; + ELSIF (tab_open) + THEN + add_param ('TABLEEND:0:0:0'); + tab_open := FALSE ; + END IF; + END IF; + + IF (v_datatype (v_argcounter) = 250) + THEN /* Record */ + rec_open := TRUE ; + add_param ( + 'RECORDBEGIN:' + || TO_CHAR (v_datatype (v_argcounter)) + || ':' + || TO_CHAR (v_length (v_argcounter)) + || ':' + || TO_CHAR (v_inout (v_argcounter)) + ); + seperator := ','; + ELSIF (v_datatype (v_argcounter) = 251) + THEN /* PLSQL Table */ + tab_open := TRUE ; + add_param ( + 'TABLEOPEN:' + || TO_CHAR (v_datatype (v_argcounter)) + || ':' + || TO_CHAR (v_length (v_argcounter)) + || ':' + || TO_CHAR (v_inout (v_argcounter)) + ); + ELSIF (v_datatype (v_argcounter) = 102) + THEN /* REF CURSOR */ + add_param ( + 'CURSOR:' + || TO_CHAR (v_datatype (v_argcounter)) + || ':' + || TO_CHAR (v_length (v_argcounter)) + || ':' + || TO_CHAR (v_inout (v_argcounter)) + ); + ELSE + add_param ( + NVL (v_argumentname (v_argcounter), 'UNKNOWN') + || ':' + || TO_CHAR (v_datatype (v_argcounter)) + || ':' + || TO_CHAR (v_length (v_argcounter)) + || ':' + || TO_CHAR (v_inout (v_argcounter)) + ); + END IF; + + v_argcounter := v_argcounter + 1; + seperator := ','; + END LOOP; + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Done DBMS_DESCRIBE'); + END IF; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + IF (rec_open) + THEN + add_param ('RECORDEND:0:0:0'); + rec_open := FALSE ; + ELSIF (tab_open) + THEN + add_param ('TABLEEND:0:0:0'); + tab_open := FALSE ; + END IF; + + RETURN (outstr); + WHEN OTHERS + THEN + RAISE; + END; + + PROCEDURE print_metadata (metadata sqldata_tab) + IS + BEGIN + FOR i IN 1 .. NVL (metadata.COUNT, 0) + LOOP + DBMS_OUTPUT.put_line ( + 'Name=' + || metadata (i).col_name + || ',Type=' + || TO_CHAR (metadata (i).col_type) + || ',Len=' + || TO_CHAR (metadata (i).col_len) + ); + END LOOP; + END; + + PROCEDURE get_metadata_for_cursor ( + proc_name VARCHAR2, + metadata OUT sqldata_tab + ) + IS + params params_tab; + proc_type VARCHAR2 (10); + idx PLS_INTEGER := 1; + pos PLS_INTEGER := 1; + BEGIN + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Start Describe Proc'); + END IF; + + proc_type := describe_proc (proc_name, params); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('End Describe Proc'); + END IF; + + --print_metadata(params); + LOOP + EXIT WHEN (params (pos).col_name = 'CURSOR'); + pos := pos + 1; + END LOOP; + + pos := pos + 2; + + LOOP + EXIT WHEN (params (pos).col_name = 'RECORDEND'); + metadata (idx).col_name := params (pos).col_name; + metadata (idx).col_type := params (pos).col_type; + metadata (idx).col_len := params (pos).col_len; + idx := idx + 1; + pos := pos + 1; + END LOOP; + END; + + PROCEDURE get_metadata_for_query ( + query_txt VARCHAR2, + metadata OUT sqldata_tab + ) + IS + cols DBMS_SQL.desc_tab; + ncols PLS_INTEGER; + cur INTEGER := DBMS_SQL.open_cursor; + BEGIN + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Query=' || query_txt); + END IF; + + DBMS_SQL.parse (cur, query_txt, DBMS_SQL.native); + DBMS_SQL.describe_columns (cur, ncols, cols); + + FOR i IN 1 .. cols.COUNT + LOOP + metadata (i).col_name := cols (i).col_name; + metadata (i).col_type := cols (i).col_type; + metadata (i).col_len := cols (i).col_max_len; + END LOOP; + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Done get_metadata_for_query'); + END IF; + END; + + PROCEDURE get_metadata_for_table ( + table_name VARCHAR2, + metadata OUT sqldata_tab + ) + IS + BEGIN + get_metadata_for_query ('select * from ' || table_name, metadata); + END; + + PROCEDURE get_metadata_for_proc ( + proc_name VARCHAR2, + POSITION INTEGER, + data_type OUT VARCHAR2, + metadata OUT sqldata_tab + ) + IS + outstr VARCHAR2 (3000) := NULL; + seperator VARCHAR2 (10) := NULL; + v_overload DBMS_DESCRIBE.number_table; + v_position DBMS_DESCRIBE.number_table; + v_level DBMS_DESCRIBE.number_table; + v_argumentname DBMS_DESCRIBE.varchar2_table; + v_datatype DBMS_DESCRIBE.number_table; + v_defaultvalue DBMS_DESCRIBE.number_table; + v_inout DBMS_DESCRIBE.number_table; + v_length DBMS_DESCRIBE.number_table; + v_precision DBMS_DESCRIBE.number_table; + v_scale DBMS_DESCRIBE.number_table; + v_radix DBMS_DESCRIBE.number_table; + v_spare DBMS_DESCRIBE.number_table; + v_argcounter PLS_INTEGER := 1; + curr_level PLS_INTEGER := 1; + prev_level PLS_INTEGER := 1; + tab_open BOOLEAN := FALSE ; + rec_open BOOLEAN := FALSE ; + pos PLS_INTEGER; + idx PLS_INTEGER := 1; + recs_copied PLS_INTEGER; + + FUNCTION get_datatype (l_type INTEGER) + RETURN VARCHAR2 + IS + r_type VARCHAR2 (20); + BEGIN + -- Need to add more data types + SELECT DECODE ( + l_type, + 1, 'VARCHAR2', + 2, 'NUMBER', + 12, 'DATE', + 96, 'CHAR', + 102, 'REF CURSOR', + 250, 'RECORD', + 251, 'PLSQL TABLE', + 'UNKNOWN' + ) + INTO r_type + FROM DUAL; + + RETURN (r_type); + END; + + PROCEDURE copy_metadata (l_idx INTEGER) + IS + m_idx INTEGER; + BEGIN + m_idx := metadata.COUNT + 1; + metadata (m_idx).col_name := v_argumentname (l_idx); + metadata (m_idx).col_type := v_datatype (l_idx); + metadata (m_idx).col_len := v_length (l_idx); + END; + + FUNCTION copy_level (l_idx INTEGER) + RETURN INTEGER + IS + l_counter PLS_INTEGER := 1; + l_level PLS_INTEGER; + BEGIN + l_level := v_level (l_idx); + l_counter := l_idx; + + LOOP + EXIT WHEN ( (l_counter > v_argumentname.COUNT) + OR l_level <> v_level (l_counter) + ); + copy_metadata (l_counter); + l_counter := l_counter + 1; + END LOOP; + + RETURN (l_counter - l_idx); + END; + BEGIN + DBMS_DESCRIBE.describe_procedure ( + proc_name, + NULL, + NULL, + v_overload, + v_position, + v_level, + v_argumentname, + v_datatype, + v_defaultvalue, + v_inout, + v_length, + v_precision, + v_scale, + v_radix, + v_spare + ); + + IF (v_position.COUNT = 0) + THEN + data_type := 'NOTFOUND'; + RETURN; + END IF; + + idx := 1; + + LOOP + EXIT WHEN ( ((v_level (idx) = 0) AND (POSITION = v_position (idx))) + OR (idx = v_position.COUNT) + ); + idx := idx + 1; + END LOOP; + + IF (idx = v_position.COUNT) + THEN + IF (POSITION = v_position (idx)) + THEN + data_type := get_datatype (v_datatype (idx)); + + IF (data_type <> 'REF CURSOR') + THEN -- Weak ref cursor + copy_metadata (idx); + END IF; + ELSE + data_type := 'NOTFOUND'; + END IF; + + RETURN; + END IF; + + data_type := get_datatype (v_datatype (idx)); + + --dbms_output.put_line('data_type = '||data_type||','||'Pos='||TO_CHAR(idx)); + + IF (data_type = 'REF CURSOR') + THEN + IF (v_level (idx + 1) > v_level (idx)) + THEN -- Strong ref cursor + idx := idx + 2; + recs_copied := copy_level (idx); + idx := idx + recs_copied; + END IF; + ELSIF (data_type = 'PLSQL TABLE') + THEN + IF (v_level (idx + 1) > v_level (idx)) + THEN + IF (v_datatype (idx + 1) = 250) + THEN -- RECORD + idx := idx + 2; -- PLSQL TABLE OF RECORD (user defined) + ELSE + idx := idx + 1; -- PLSQL TABLE OF SINGLE COLUMN + END IF; + + recs_copied := copy_level (idx); + idx := idx + recs_copied; + ELSE + copy_metadata (idx); + END IF; + ELSIF (data_type = 'RECORD') + THEN + IF (v_level (idx + 1) > v_level (idx)) + THEN -- I think always true. + idx := idx + 1; + recs_copied := copy_level (idx); + idx := idx + recs_copied; + ELSE -- I guess it should never come here + copy_metadata (idx); + END IF; + ELSE + data_type := get_datatype (v_datatype (idx)); + copy_metadata (idx); + END IF; + END; + + PROCEDURE test_get_metadata_for_cursor (proc_name VARCHAR2) + IS + metadata sqldata_tab; + BEGIN + get_metadata_for_cursor (proc_name, metadata); + + IF (utplsql.tracing) + THEN + print_metadata (metadata); + END IF; + END; + + FUNCTION get_colnamesstr (metadata sqldata_tab) + RETURN VARCHAR2 + IS + cnt PLS_INTEGER; + str VARCHAR2 (32000); + BEGIN + cnt := metadata.COUNT; + + FOR i IN 1 .. cnt + LOOP + str := str || metadata (i).col_name || ','; + END LOOP; + + RETURN (SUBSTR (str, 1, LENGTH (str) - 1)); + END; + + FUNCTION get_coltypesstr (metadata sqldata_tab) + RETURN VARCHAR2 + IS + cnt PLS_INTEGER; + str VARCHAR2 (2000); + BEGIN + cnt := metadata.COUNT; + + FOR i IN 1 .. cnt + LOOP + str := str || TO_CHAR (metadata (i).col_type) || ','; + END LOOP; + + RETURN (SUBSTR (str, 1, LENGTH (str) - 1)); + END; + + FUNCTION get_coltype_syntax (col_type PLS_INTEGER, col_len PLS_INTEGER) + RETURN VARCHAR2 + IS + BEGIN + IF (col_type = 1) + THEN + RETURN ('VARCHAR2(' || TO_CHAR (col_len) || ')'); + ELSIF (col_type = 2) + THEN + RETURN ('NUMBER'); + ELSIF (col_type = 12) + THEN + RETURN ('DATE'); + ELSIF (col_type = 96) + THEN + RETURN ('CHAR(' || TO_CHAR (col_len) || ')'); + END IF; + END; + + FUNCTION get_coltype_syntax (col_type VARCHAR2, col_len PLS_INTEGER) + RETURN VARCHAR2 + IS + BEGIN + IF (col_type = 'VARCHAR2') + THEN + RETURN ('VARCHAR2(' || TO_CHAR (col_len) || ')'); + ELSIF (col_type = 'NUMBER') + THEN + RETURN ('NUMBER'); + ELSIF (col_type = 'DATE') + THEN + RETURN ('DATE'); + ELSIF (col_type = 'CHAR') + THEN + RETURN ('CHAR(' || TO_CHAR (col_len) || ')'); + ELSIF (col_type = 'REFC') + THEN + RETURN ('REFC'); + ELSE + RETURN (col_type); + END IF; + END; + + PROCEDURE PRINT (str VARCHAR2) + IS + len PLS_INTEGER; + BEGIN + len := LENGTH (str); + + FOR i IN 1 .. len + LOOP + DBMS_OUTPUT.put_line (SUBSTR (str, (i - 1) * 255, 255)); + END LOOP; + + IF ((len * 255) > LENGTH (str)) + THEN + DBMS_OUTPUT.put_line (SUBSTR (str, len * 255)); + END IF; + END; + + FUNCTION get_proc_name (p_proc_nm VARCHAR2) + RETURN VARCHAR2 + IS + BEGIN + RETURN (SUBSTR (p_proc_nm, 1, INSTR (p_proc_nm, '(') - 1)); + END; + + FUNCTION get_val_for_table ( + table_name VARCHAR2, + col_name VARCHAR2, + col_val OUT VARCHAR2, + col_type OUT NUMBER + ) + RETURN NUMBER + IS + cur PLS_INTEGER := DBMS_SQL.open_cursor; + cols DBMS_SQL.desc_tab; + ncols PLS_INTEGER; + idx PLS_INTEGER := 0; + tvarchar VARCHAR2 (4000); + tchar CHAR (4000); + tdate DATE; + tnumber NUMBER; + stmt VARCHAR2 (200); + vresult PLS_INTEGER; + BEGIN + stmt := 'select * from ' || table_name; + DBMS_SQL.parse (cur, stmt, DBMS_SQL.native); + DBMS_SQL.describe_columns (cur, ncols, cols); + + FOR i IN 1 .. cols.COUNT + LOOP + IF (cols (i).col_type = 1) + THEN + DBMS_SQL.define_column (cur, i, tvarchar, cols (i).col_max_len); + ELSIF (cols (i).col_type = 2) + THEN + DBMS_SQL.define_column (cur, i, tnumber); + ELSIF (cols (i).col_type = 12) + THEN + DBMS_SQL.define_column (cur, i, tdate); + ELSIF (cols (i).col_type = 96) + THEN + DBMS_SQL.define_column (cur, i, tchar, cols (i).col_max_len); + ELSE + raise_application_error (-20000, 'UNSUPPORTED COLUMN TYPE'); + END IF; + + IF (cols (i).col_name = col_name) + THEN + idx := i; + END IF; + END LOOP; + + IF (idx = 0) + THEN + RETURN (-1); + END IF; + + vresult := DBMS_SQL.EXECUTE (cur); + + IF (DBMS_SQL.fetch_rows (cur) = 0) + THEN + RETURN (1); + END IF; + + IF (cols (idx).col_type = 1) + THEN + DBMS_SQL.column_value (cur, idx, tvarchar); + col_val := tvarchar; + ELSIF (cols (idx).col_type = 2) + THEN + DBMS_SQL.column_value (cur, idx, tnumber); + col_val := TO_CHAR (tnumber); + ELSIF (cols (idx).col_type = 12) + THEN + DBMS_SQL.column_value (cur, idx, tdate); + col_val := TO_CHAR (tdate, 'DD-MON-YYYY:HH24:MI:SS'); + ELSIF (cols (idx).col_type = 96) + THEN + DBMS_SQL.column_value (cur, idx, tchar); + col_val := tchar; + END IF; + + col_type := cols (idx).col_type; + DBMS_SQL.close_cursor (cur); + RETURN (0); + EXCEPTION + WHEN OTHERS + THEN + RAISE; + END; + + FUNCTION get_table_name + RETURN VARCHAR2 + IS + tmp_seq NUMBER; + curr_user VARCHAR2 (20); + BEGIN + SELECT SYS_CONTEXT ('USERENV', 'CURRENT_USER') + INTO curr_user + FROM DUAL; + + SELECT ut_refcursor_results_seq.NEXTVAL + INTO tmp_seq + FROM DUAL; + + --RETURN('utplsql_temp_'||tmp_seq); + RETURN (curr_user || '.' || 'UTPLSQL_TEMP_' || tmp_seq); + END; + + PROCEDURE execute_ddl (stmt VARCHAR2) + IS + --&start73 + fdbk PLS_INTEGER; + cur PLS_INTEGER := DBMS_SQL.open_cursor; + --&end73 + BEGIN + --&start81 + EXECUTE IMMEDIATE stmt; + --&end81 + --&start73 + DBMS_SQL.parse (cur, stmt, DBMS_SQL.native); + fdbk := DBMS_SQL.EXECUTE (cur); + DBMS_SQL.close_cursor (cur); + --&end73 + EXCEPTION + WHEN OTHERS + THEN + RAISE; + END; + + FUNCTION get_create_ddl ( + metadata utplsql_util.sqldata_tab, + table_name VARCHAR2, + owner_name VARCHAR2 DEFAULT NULL + ) + RETURN VARCHAR2 + IS + ddl_stmt VARCHAR2 (5000); + cnt PLS_INTEGER; + BEGIN + IF (NVL (metadata.COUNT, 0) = 0) + THEN + RETURN (NULL); + END IF; + + --ddl_stmt := 'create table '||NVL(owner_name,'UTPLSQL')||'.'||table_name||' ( '; + ddl_stmt := 'create table ' || table_name || ' ( '; + + FOR i IN 1 .. metadata.COUNT + LOOP + ddl_stmt := ddl_stmt + || metadata (i).col_name + || ' ' + || utplsql_util.get_coltype_syntax ( + metadata (i).col_type, + metadata (i).col_len + ) + || ','; + END LOOP; + + ddl_stmt := SUBSTR (ddl_stmt, 1, LENGTH (ddl_stmt) - 1) || ')'; + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Current user = ' || USER); + utplsql_util.PRINT (ddl_stmt); + END IF; + + RETURN (ddl_stmt); + END; + + PROCEDURE prepare_cursor_1 ( + stmt IN OUT VARCHAR2, + table_name VARCHAR2, + call_proc_name VARCHAR2, + metadata utplsql_util.sqldata_tab + ) + IS + col_str VARCHAR2 (200); + BEGIN + IF (NVL (metadata.COUNT, 0) = 0) + THEN + RETURN; + END IF; + + stmt := + 'declare + p_result_id PLS_INTEGER; + p_rec_nm PLS_INTEGER := 0; + TYPE refc is ref cursor; + rc refc;'; + + FOR i IN 1 .. metadata.COUNT + LOOP + stmt := stmt + || metadata (i).col_name + || ' ' + || utplsql_util.get_coltype_syntax ( + metadata (i).col_type, + metadata (i).col_len + ) + || ';' + || CHR (10); + END LOOP; + + col_str := utplsql_util.get_colnamesstr (metadata); + stmt := + stmt + || 'BEGIN + rc := ' + || call_proc_name + || '; + LOOP + FETCH rc INTO ' + || col_str + || '; + EXIT WHEN rc%NOTFOUND; + p_rec_nm := p_rec_nm + 1; + INSERT INTO ' + || table_name + || ' (' + || col_str + || ')' + || ' values (' + || col_str + || ');' + || ' + END LOOP; + CLOSE rc; + END;'; + + IF (utplsql.tracing) + THEN + utplsql_util.PRINT (stmt); + END IF; + END; + + FUNCTION get_par_for_decl (params utplsql_params) + RETURN VARCHAR2 + IS + decl VARCHAR2 (1000); + BEGIN + FOR i IN 1 .. params.COUNT + LOOP + decl := decl + || params (i).par_name + || ' ' + || utplsql_util.get_coltype_syntax ( + params (i).par_sql_type, + 1000 + ) + || ';' + || CHR (10); + END LOOP; + + RETURN (decl); + END; + + FUNCTION get_param_valstr (params utplsql_params, POSITION PLS_INTEGER) + RETURN VARCHAR2 + IS + BEGIN + IF (params (POSITION).par_type = 'DATE') + THEN + RETURN ( 'TO_DATE(''' + || params (POSITION).par_val + || ''',''DD-MON-YYYY:HH24:MI:SS'')' + ); + ELSE + RETURN ('''' || params (POSITION).par_val || ''''); + END IF; + END; + + FUNCTION get_param_valstr_from_array ( + params utplsql_params, + POSITION PLS_INTEGER, + array_pos PLS_INTEGER + ) + RETURN VARCHAR2 + IS + BEGIN + IF (params (POSITION).par_type = 'DATE') + THEN + RETURN ( 'TO_DATE(''' + || array_holder (array_pos).array_val + || ''',''DD-MON-YYYY:HH24:MI:SS'')' + ); + ELSE + RETURN ('''' || array_holder (array_pos).array_val || ''''); + END IF; + END; + + PROCEDURE print_utplsql_params (params utplsql_params) + IS + BEGIN + FOR i IN 1 .. params.COUNT + LOOP + DBMS_OUTPUT.put_line ( + 'Name=' + || params (i).par_name + || ',type=' + || params (i).par_type + || ',mode=' + || TO_CHAR (params (i).par_inout) + || ',pos=' + || TO_CHAR (params (i).par_pos) + || ',val=' + || params (i).par_val + ); + END LOOP; + END; + + PROCEDURE init_array_holder + IS + BEGIN + array_holder.DELETE; + END; + + PROCEDURE print_array_holder + IS + BEGIN + DBMS_OUTPUT.put_line ('Printing array holder'); + + FOR i IN 1 .. array_holder.COUNT + LOOP + DBMS_OUTPUT.put_line ('pos=' || TO_CHAR (array_holder (i).array_pos)); + PRINT ('Val=' || array_holder (i).array_val); + END LOOP; + END; + + FUNCTION get_index_for_array (pos INTEGER) + RETURN INTEGER + IS + idx PLS_INTEGER := 1; + BEGIN + LOOP + EXIT WHEN (array_holder (idx).array_pos = pos); + idx := idx + 1; + END LOOP; + + RETURN (idx); + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN (-1); + END; + + FUNCTION get_par_for_assign (params utplsql_params) + RETURN VARCHAR2 + IS + assign VARCHAR2 (1000); + array_idx PLS_INTEGER; + idx PLS_INTEGER := 1; + BEGIN + IF (utplsql.tracing) + THEN + print_array_holder; + END IF; + + FOR i IN 1 .. params.COUNT + LOOP + IF (params (i).par_inout != par_out) + THEN + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ( + 'In get_par_for_assign<' || params (i).par_type || '>' + ); + END IF; + + IF (params (i).par_type != 'ARRAY') + THEN + assign := assign + || params (i).par_name + || ' := ' + || get_param_valstr (params, i) + || ';' + || CHR (10); + ELSE + array_idx := get_index_for_array (params (i).par_pos); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('start index =' || TO_CHAR ( + array_idx + )); + END IF; + + LOOP + BEGIN + EXIT WHEN array_holder (array_idx).array_pos != + params (i).par_pos; + assign := assign + || params (i).par_name + || '(' + || TO_CHAR (idx) + || ') := ' + || get_param_valstr_from_array ( + params, + i, + array_idx + ) + || ';' + || CHR (10); + array_idx := array_idx + 1; + idx := idx + 1; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + EXIT; + END; + END LOOP; + END IF; + END IF; + END LOOP; + + RETURN (assign); + END; + + FUNCTION get_par_for_call (params utplsql_params, proc_name VARCHAR2) + RETURN VARCHAR2 + IS + call_str VARCHAR2 (1000); + start_idx PLS_INTEGER; + BEGIN + IF (params (1).par_pos = 0) + THEN + call_str := params (1).par_name || ' := ' || proc_name || '('; + start_idx := 2; + ELSE + call_str := proc_name || '('; + start_idx := 1; + END IF; + + FOR i IN start_idx .. params.COUNT + LOOP + IF (i != start_idx) + THEN + call_str := call_str || ',' || params (i).par_name; + ELSE + call_str := call_str || params (i).par_name; + END IF; + END LOOP; + + call_str := call_str || ')'; + RETURN (call_str); + END; + + PROCEDURE get_single_param ( + params utplsql_params, + POSITION PLS_INTEGER, + single_param IN OUT params_rec + ) + IS + idx PLS_INTEGER; + BEGIN + IF (POSITION != 0) + THEN + IF (params (1).par_pos = 0) + THEN + idx := POSITION + 1; + ELSE + idx := POSITION; + END IF; + ELSE + idx := POSITION + 1; + END IF; + + single_param.par_name := params (idx).par_name; + single_param.par_type := params (idx).par_type; + single_param.par_val := params (idx).par_val; + single_param.par_inout := params (idx).par_inout; + END; + + PROCEDURE prepare_cursor_100 ( + stmt IN OUT VARCHAR2, + table_name VARCHAR2, + call_proc_name VARCHAR2, + POSITION PLS_INTEGER, + metadata utplsql_util.sqldata_tab, + params utplsql_params + ) + IS + col_str VARCHAR2 (32000); + single_param params_rec; + BEGIN + IF (NVL (metadata.COUNT, 0) = 0) + THEN + RETURN; + END IF; + + stmt := + 'declare + p_result_id PLS_INTEGER; + p_rec_nm PLS_INTEGER := 0; + TYPE refc is ref cursor; + rc refc;'; + + FOR i IN 1 .. metadata.COUNT + LOOP + stmt := stmt + || metadata (i).col_name + || ' ' + || utplsql_util.get_coltype_syntax ( + metadata (i).col_type, + metadata (i).col_len + ) + || ';' + || CHR (10); + END LOOP; + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Done ref cursor column declarations'); + END IF; + + stmt := stmt || get_par_for_decl (params); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Done params declarations'); + END IF; + + get_single_param (params, POSITION, single_param); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Done get_single_param'); + END IF; + + col_str := utplsql_util.get_colnamesstr (metadata); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Done get_colnamesstr'); + END IF; + + stmt := + stmt + || 'BEGIN + ' + || get_par_for_assign (params) + || ' + ' + || get_par_for_call (params, call_proc_name) + || '; + LOOP + FETCH ' + || single_param.par_name + || ' INTO ' + || col_str + || '; + EXIT WHEN ' + || single_param.par_name + || '%NOTFOUND; + p_rec_nm := p_rec_nm + 1; + INSERT INTO ' + || table_name + || ' (' + || col_str + || ')' + || ' values (' + || col_str + || ');' + || ' + END LOOP; + CLOSE ' + || single_param.par_name + || '; + END;'; + + IF (utplsql.tracing) + THEN + utplsql_util.PRINT (stmt); + END IF; + + init_array_holder; + END; + + FUNCTION prepare_and_fetch_rc (proc_name VARCHAR2) + RETURN VARCHAR2 + IS + vproc_nm VARCHAR2 (50); + metadata utplsql_util.sqldata_tab; + stmt VARCHAR2 (32000); + table_name VARCHAR2 (20); + BEGIN + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Call=' || proc_name); + END IF; + + vproc_nm := utplsql_util.get_proc_name (proc_name); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Proc Name=' || vproc_nm); + END IF; + + utplsql_util.get_metadata_for_cursor (vproc_nm, metadata); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Metadata Done'); + END IF; + + table_name := get_table_name (); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Refcursor Table Name=' || table_name); + END IF; + + stmt := get_create_ddl (metadata, table_name); + + IF (utplsql.tracing) + THEN + utplsql_util.PRINT ('Create ddl=' || stmt); + END IF; + + execute_ddl (stmt); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Table created'); + END IF; + + IF (NVL (metadata.COUNT, 0) = 0) + THEN + RETURN (NULL); + END IF; + + --prepare_cursor_1(stmt,'UTPLSQL'||'.'||table_name,proc_name,metadata); + prepare_cursor_1 (stmt, table_name, proc_name, metadata); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Done prepare_cursor_1'); + END IF; + + execute_ddl (stmt); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Done execute_ddl'); + END IF; + + --RETURN(USER||'.'||table_name); + RETURN (table_name); + END; + + FUNCTION prepare_and_fetch_rc ( + proc_name VARCHAR2, + params utplsql_params, + refc_pos_in_proc PLS_INTEGER, + refc_metadata_from PLS_INTEGER DEFAULT 1, + refc_metadata_str VARCHAR2 DEFAULT NULL + ) + RETURN VARCHAR2 + IS + metadata utplsql_util.sqldata_tab; + stmt VARCHAR2 (32000); + table_name VARCHAR2 (50); + datatype VARCHAR2 (20); + BEGIN + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('In prepare_and_fetch_rc '); + DBMS_OUTPUT.put_line ('proc name =' || proc_name); + print_utplsql_params (params); + DBMS_OUTPUT.put_line ('Method=' || TO_CHAR (refc_metadata_from)); + PRINT ('refc_metadata_str=' || refc_metadata_str); + --dbms_output.put_line('refc_metadata_str='||refc_metadata_str); + DBMS_OUTPUT.put_line ('Position=' || TO_CHAR (refc_pos_in_proc)); + END IF; + + utplsql_util.get_metadata_for_proc ( + proc_name, + refc_pos_in_proc, + datatype, + metadata + ); + + IF (metadata.COUNT = 0) + THEN + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Weak ref cursor'); + END IF; + + IF (refc_metadata_from = 1) + THEN + utplsql_util.get_metadata_for_table (refc_metadata_str, metadata); + ELSIF (refc_metadata_from = 2) + THEN + utplsql_util.get_metadata_for_query (refc_metadata_str, metadata); + END IF; + END IF; + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Done metadata'); + END IF; + + IF (metadata.COUNT = 0) + THEN + DBMS_OUTPUT.put_line ('ERROR: metadata is null'); + RETURN (NULL); + END IF; + + table_name := get_table_name (); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Refcursor Table Name=' || table_name); + END IF; + + stmt := get_create_ddl (metadata, table_name); + + IF (utplsql.tracing) + THEN + utplsql_util.PRINT ('Create ddl=' || stmt); + END IF; + + execute_ddl (stmt); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Table created'); + END IF; + + IF (NVL (metadata.COUNT, 0) = 0) + THEN + RETURN (NULL); + END IF; + + --prepare_cursor_100(stmt,'UTPLSQL'||'.'||table_name,proc_name,refc_pos_in_proc,metadata,params); + prepare_cursor_100 ( + stmt, + table_name, + proc_name, + refc_pos_in_proc, + metadata, + params + ); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Done prepare_cursor_1'); + END IF; + + execute_ddl (stmt); + + IF (utplsql.tracing) + THEN + DBMS_OUTPUT.put_line ('Done execute_ddl'); + END IF; + + --RETURN(USER||'.'||table_name); + RETURN (table_name); + END; +END; +/ diff --git a/source/ut_plsql_util.pks b/source/ut_plsql_util.pks new file mode 100644 index 000000000..2f10ad3f2 --- /dev/null +++ b/source/ut_plsql_util.pks @@ -0,0 +1,188 @@ +CREATE OR REPLACE PACKAGE utplsql_util +--&start81 AUTHID CURRENT_USER --&end81 +AS +/* + This package is custom build for UTPLSQL custom test project + + Author : Venky Mangapillai + Created : May'2000 + +*/ + TYPE SQLDATA IS RECORD ( + col_name VARCHAR2 (50), + col_type PLS_INTEGER, + col_len PLS_INTEGER + ); + + TYPE sqldata_tab IS TABLE OF SQLDATA + INDEX BY BINARY_INTEGER; + + TYPE params_rec IS RECORD ( + par_name VARCHAR2 (50), + par_type VARCHAR2 (10), + par_sql_type VARCHAR2 (50), + par_inout PLS_INTEGER, + par_pos PLS_INTEGER, + par_val VARCHAR2 (32000) + ); + + TYPE utplsql_array IS RECORD ( + array_pos PLS_INTEGER, + array_val VARCHAR2 (32000) + ); + + TYPE utplsql_params IS TABLE OF params_rec + INDEX BY BINARY_INTEGER; + + TYPE array_table IS TABLE OF utplsql_array + INDEX BY BINARY_INTEGER; + + TYPE ut_refc IS REF CURSOR; + + TYPE v30_table IS TABLE OF VARCHAR2 (30) + INDEX BY BINARY_INTEGER; + + TYPE varchar_array IS TABLE OF VARCHAR2 (4000) + INDEX BY BINARY_INTEGER; + + array_holder array_table; + + PROCEDURE reg_in_param ( + par_pos PLS_INTEGER, + par_val VARCHAR2, + params IN OUT utplsql_params + ); + + PROCEDURE reg_in_array ( + par_pos IN PLS_INTEGER, + array_name IN VARCHAR2, + array_vals IN varchar_array, + params IN OUT utplsql_params + ); + + PROCEDURE reg_in_param ( + par_pos PLS_INTEGER, + par_val NUMBER, + params IN OUT utplsql_params + ); + + PROCEDURE reg_in_param ( + par_pos PLS_INTEGER, + par_val DATE, + params IN OUT utplsql_params + ); + + PROCEDURE reg_inout_param ( + par_pos PLS_INTEGER, + par_val VARCHAR2, + params IN OUT utplsql_params + ); + + PROCEDURE reg_inout_param ( + par_pos PLS_INTEGER, + par_val NUMBER, + params IN OUT utplsql_params + ); + + PROCEDURE reg_inout_param ( + par_pos PLS_INTEGER, + par_val DATE, + params IN OUT utplsql_params + ); + + PROCEDURE reg_out_param ( + par_pos PLS_INTEGER, + par_type VARCHAR2, + params IN OUT utplsql_params + ); + + PROCEDURE get_table_for_str ( + p_arr OUT v30_table, + p_string VARCHAR2, + delim VARCHAR2 := ',', + enclose_str VARCHAR2 DEFAULT NULL + ); + + PROCEDURE get_metadata_for_cursor ( + proc_name VARCHAR2, + metadata OUT sqldata_tab + ); + + PROCEDURE get_metadata_for_query ( + query_txt VARCHAR2, + metadata OUT sqldata_tab + ); + + PROCEDURE get_metadata_for_table ( + table_name VARCHAR2, + metadata OUT sqldata_tab + ); + + PROCEDURE get_metadata_for_proc ( + proc_name VARCHAR2, + POSITION INTEGER, + data_type OUT VARCHAR2, + metadata OUT sqldata_tab + ); + + PROCEDURE test_get_metadata_for_cursor (proc_name VARCHAR2); + + PROCEDURE print_metadata (metadata sqldata_tab); + + FUNCTION get_colnamesstr (metadata sqldata_tab) + RETURN VARCHAR2; + + FUNCTION get_coltypesstr (metadata sqldata_tab) + RETURN VARCHAR2; + + FUNCTION get_coltype_syntax (col_type PLS_INTEGER, col_len PLS_INTEGER) + RETURN VARCHAR2; + + PROCEDURE PRINT (str VARCHAR2); + + FUNCTION get_proc_name (p_proc_nm VARCHAR2) + RETURN VARCHAR2; + + FUNCTION get_version + RETURN VARCHAR2; + + FUNCTION get_val_for_table ( + table_name VARCHAR2, + col_name VARCHAR2, + col_val OUT VARCHAR2, + col_type OUT NUMBER + ) + RETURN NUMBER; + + FUNCTION get_table_name + RETURN VARCHAR2; + + PROCEDURE execute_ddl (stmt VARCHAR2); + + FUNCTION get_create_ddl ( + metadata utplsql_util.sqldata_tab, + table_name VARCHAR2, + owner_name VARCHAR2 DEFAULT NULL + ) + RETURN VARCHAR2; + + PROCEDURE prepare_cursor_1 ( + stmt IN OUT VARCHAR2, + table_name VARCHAR2, + call_proc_name VARCHAR2, + metadata utplsql_util.sqldata_tab + ); + + FUNCTION prepare_and_fetch_rc (proc_name VARCHAR2) + RETURN VARCHAR2; + + FUNCTION prepare_and_fetch_rc ( + proc_name VARCHAR2, + params utplsql_params, + refc_pos_in_proc PLS_INTEGER, + refc_metadata_from PLS_INTEGER DEFAULT 1, + refc_metadata_str VARCHAR2 DEFAULT NULL + ) + RETURN VARCHAR2; +END; +/ diff --git a/source/ut_receq.pkb b/source/ut_receq.pkb new file mode 100644 index 000000000..a70670a8d --- /dev/null +++ b/source/ut_receq.pkb @@ -0,0 +1,295 @@ +-- register tables and view that will have record comparison functions created + +-- 26 Dec 2001 Dan Spencer Created + +-- 31 Jul 2002 Chris Rimmer Fixed so that records in foreign schemas work + + + +CREATE OR REPLACE PACKAGE BODY utreceq +IS + PROCEDURE delete_receq (id_in ut_receq.id%TYPE) + IS + v_cur PLS_INTEGER := DBMS_SQL.open_cursor; + sql_str VARCHAR2 (2000); + v_cnt PLS_INTEGER; + BEGIN + SELECT COUNT (*) + INTO v_cnt + FROM ut_receq_pkg + WHERE receq_id = id_in AND created_by = USER; + + IF v_cnt < 1 + THEN + SELECT 'DROP FUNCTION ' || test_name + INTO sql_str + FROM ut_receq + WHERE id = id_in AND created_by = USER; + + DBMS_SQL.parse (v_cur, sql_str, DBMS_SQL.native); + DBMS_SQL.close_cursor (v_cur); + END IF; + + DELETE FROM ut_receq + WHERE id = id_in AND created_by = USER; + EXCEPTION + WHEN OTHERS + THEN + utplsql.pl (SQLERRM); + DBMS_SQL.close_cursor (v_cur); + utplsql.pl ( + 'Delete failed - function probably used by another package' + ); + END; + + FUNCTION id_from_name ( + NAME_IN IN ut_receq.NAME%TYPE, + owner_in IN ut_receq.rec_owner%TYPE := USER + ) + RETURN INTEGER + IS + retval INTEGER; + BEGIN + SELECT id + INTO retval + FROM ut_receq + WHERE NAME = UPPER (NAME_IN) + AND rec_owner = UPPER (owner_in) + AND created_by = USER; + + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END id_from_name; + + FUNCTION name_from_id (id_in IN ut_receq.id%TYPE) + RETURN VARCHAR2 + IS + retval VARCHAR2 (30); + BEGIN + SELECT NAME + INTO retval + FROM ut_receq + WHERE id = id_in; + + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END name_from_id; + + FUNCTION receq_name ( + NAME_IN IN VARCHAR2, + owner_in IN VARCHAR2 DEFAULT USER, + test_name_in IN VARCHAR2 DEFAULT NULL + ) + RETURN VARCHAR2 + IS + retval VARCHAR2 (30); + func_len INTEGER; + BEGIN + IF test_name_in IS NOT NULL + THEN + retval := UPPER (test_name_in); + ELSE + retval := 'eq_'; + + IF owner_in <> USER + THEN + retval := retval || owner_in || '_'; + END IF; + + retval := retval || NAME_IN; + END IF; + + RETURN UPPER (retval); + EXCEPTION + WHEN VALUE_ERROR + THEN + utplsql.pl ('Generated test name is too long'); + utplsql.pl ( + 'Resubmit with a defined test_name_in=>''EQ_your_name''' + ); + RETURN NULL; + END receq_name; + + PROCEDURE COMPILE (receq_id_in IN ut_receq.id%TYPE) + IS + lines DBMS_SQL.varchar2s; + cur PLS_INTEGER := DBMS_SQL.open_cursor; + v_rec ut_receq%ROWTYPE; + v_schema ut_receq.rec_owner%TYPE; + BEGIN + lines.DELETE; + + SELECT * + INTO v_rec + FROM ut_receq + WHERE id = receq_id_in AND created_by = USER; + + IF v_rec.rec_owner <> USER + THEN + v_schema := v_rec.rec_owner || '.'; + END IF; + + lines (1) := 'CREATE OR REPLACE FUNCTION ' || v_rec.test_name || '('; + lines (lines.LAST + 1) := ' a ' || v_schema || v_rec.NAME || '%ROWTYPE , '; + lines (lines.LAST + 1) := ' b ' || v_schema || v_rec.NAME || '%ROWTYPE ) '; + lines (lines.LAST + 1) := 'RETURN BOOLEAN '; + lines (lines.LAST + 1) := 'IS BEGIN '; + lines (lines.LAST + 1) := ' RETURN ('; + + FOR utc_rec IN (SELECT * + FROM all_tab_columns + WHERE table_name = v_rec.NAME + AND owner = v_rec.rec_owner + ORDER BY column_id) + LOOP + IF utc_rec.column_id > 1 + THEN + lines (lines.LAST + 1) := ' AND '; + END IF; + + lines (lines.LAST + 1) := '( ( a.' + || utc_rec.column_name + || ' IS NULL AND b.' + || utc_rec.column_name + || ' IS NULL ) OR '; + + IF utc_rec.data_type = 'CLOB' + THEN + lines (lines.LAST) := lines (lines.LAST) + || 'DBMS_LOB.COMPARE( a.' + || utc_rec.column_name + || ' , b.' + || utc_rec.column_name + || ') = 0 )'; + ELSE + lines (lines.LAST) := lines (lines.LAST) + || 'a.' + || utc_rec.column_name + || ' = b.' + || utc_rec.column_name + || ')'; + END IF; + END LOOP; + + lines (lines.LAST + 1) := '); END ' || v_rec.test_name || ';'; + DBMS_SQL.parse ( + cur, + lines, + lines.FIRST, + lines.LAST, + TRUE , + DBMS_SQL.native + ); + DBMS_SQL.close_cursor (cur); + END COMPILE; + -- Public Methods + + PROCEDURE ADD ( + pkg_name_in IN ut_package.NAME%TYPE, + record_in IN ut_receq.NAME%TYPE, + rec_owner_in IN ut_receq.created_by%TYPE := USER + ) + IS + v_pkg_id NUMBER; + v_receq_id NUMBER; + v_obj_type user_objects.object_type%TYPE; + v_recname VARCHAR2 (30); + BEGIN + v_pkg_id := utpackage.id_from_name (pkg_name_in); + v_receq_id := id_from_name (record_in); + + IF v_pkg_id IS NULL + THEN + utplsql.pl (pkg_name_in || ' does not exist'); + ELSIF v_receq_id IS NULL + THEN + SELECT object_type + INTO v_obj_type + FROM all_objects + WHERE object_name = UPPER (record_in) + AND owner = UPPER (rec_owner_in) + AND object_type IN ('TABLE', 'VIEW'); + + v_receq_id := utplsql.seqval ('ut_receq'); + v_recname := receq_name (record_in, rec_owner_in); + + INSERT INTO ut_receq + VALUES (v_receq_id, UPPER (record_in), v_recname, USER, UPPER ( + rec_owner_in + )); + END IF; + + utreceq.COMPILE (v_receq_id); + utplsql.pl (v_recname || ' compiled for ' || v_obj_type || ' ' || record_in); + + BEGIN + INSERT INTO ut_receq_pkg + VALUES (v_receq_id, v_pkg_id, USER); + EXCEPTION + WHEN DUP_VAL_ON_INDEX + THEN + utplsql.pl ( + v_recname || ' already registered for package ' || pkg_name_in + ); + END; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + utplsql.pl (record_in || ' does not exist in schema ' || rec_owner_in); + END ADD; + + PROCEDURE COMPILE (pkg_name_in IN ut_package.NAME%TYPE) + IS + v_pkg_id NUMBER; + BEGIN + v_pkg_id := utpackage.id_from_name (pkg_name_in); + + FOR j IN (SELECT receq_id + FROM ut_receq_pkg + WHERE pkg_id = v_pkg_id AND created_by = USER) + LOOP + COMPILE (j.receq_id); + END LOOP; + END COMPILE; + + PROCEDURE REM ( + NAME_IN IN ut_receq.NAME%TYPE, + rec_owner_in IN ut_receq.created_by%TYPE, + for_package_in IN BOOLEAN := FALSE + ) + IS + v_pkg_id INTEGER; + v_receq_id INTEGER; + BEGIN + IF for_package_in + THEN + v_pkg_id := utpackage.id_from_name (NAME_IN); + + FOR j IN (SELECT receq_id + FROM ut_receq_pkg + WHERE pkg_id = v_pkg_id) + LOOP + DELETE FROM ut_receq_pkg + WHERE pkg_id = v_pkg_id + AND created_by = USER + AND receq_id = j.receq_id; + + delete_receq (v_receq_id); + END LOOP; + ELSE + v_receq_id := utreceq.id_from_name (NAME_IN, rec_owner_in); + + DELETE FROM ut_receq_pkg + WHERE receq_id = v_receq_id; + + delete_receq (v_receq_id); + END IF; + END REM; +END utreceq; +/ diff --git a/source/ut_receq.pks b/source/ut_receq.pks new file mode 100644 index 000000000..a5b5e51be --- /dev/null +++ b/source/ut_receq.pks @@ -0,0 +1,45 @@ +-- 26 Dec 2001 Dan Spencer Created + +-- 31 Jul 2002 Chris Rimmer Fixed so that records in foreign schemas work + + + +CREATE OR REPLACE PACKAGE utreceq &start81 AUTHID CURRENT_USER &end81 +IS + + PROCEDURE add( + + pkg_name_in IN ut_package.name%TYPE , + + record_in IN ut_receq.name%TYPE , + + rec_owner_in IN ut_receq.created_by%TYPE := USER + + ); + + + + PROCEDURE compile( + + pkg_name_in IN ut_package.name%TYPE + + ); + + + + PROCEDURE rem( + + name_in IN ut_receq.name%TYPE, + + rec_owner_in IN ut_receq.created_by%TYPE := USER, + + for_package_in IN BOOLEAN := FALSE + + ); + + + +END utreceq; + +/ + diff --git a/source/ut_receq.tab b/source/ut_receq.tab new file mode 100644 index 000000000..08cc713c4 --- /dev/null +++ b/source/ut_receq.tab @@ -0,0 +1,30 @@ +-- register tables and view that will have record comparison functions created +-- 12/26/01 dws +CREATE TABLE ut_receq ( + id INTEGER, + name VARCHAR2(30), + test_name VARCHAR2(30), + created_by VARCHAR2(30), + rec_owner VARCHAR2(30), + CONSTRAINT ut_receq_pk PRIMARY KEY (id) +); + +CREATE UNIQUE INDEX ut_receq_idx1 ON + ut_receq(rec_owner , name); + + +-- Intersection table between ut_package and ut_receq +CREATE TABLE ut_receq_pkg ( + receq_id integer, + pkg_id INTEGER, + created_by VARCHAR2(30) +); + +ALTER TABLE ut_receq_pkg ADD CONSTRAINT ut_receq_pkg + primary key(receq_id,pkg_id,created_by); + +ALTER TABLE ut_receq_pkg ADD CONSTRAINT ut_receq_pkg_receq_FK + FOREIGN KEY(receq_id) REFERENCES ut_receq(id); + +ALTER TABLE ut_receq_pkg ADD CONSTRAINT ut_receq_pkg_pkg_FK + FOREIGN KEY(pkg_id) REFERENCES ut_package(id); diff --git a/source/ut_receq_seq.seq b/source/ut_receq_seq.seq new file mode 100644 index 000000000..5c8f218f0 --- /dev/null +++ b/source/ut_receq_seq.seq @@ -0,0 +1 @@ +CREATE sequence ut_receq_seq INCREMENT BY 1 START WITH 1 ORDER NOCACHE; \ No newline at end of file diff --git a/source/ut_refcursor_results_seq.seq b/source/ut_refcursor_results_seq.seq new file mode 100644 index 000000000..4afb20e90 --- /dev/null +++ b/source/ut_refcursor_results_seq.seq @@ -0,0 +1 @@ +create sequence ut_refcursor_results_seq INCREMENT BY 1 START WITH 1 ORDER NOCACHE; diff --git a/source/ut_rerror.pkb b/source/ut_rerror.pkb new file mode 100644 index 000000000..03aeaa78f --- /dev/null +++ b/source/ut_rerror.pkb @@ -0,0 +1,308 @@ +/* Formatted on 2001/07/13 12:30 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE BODY utrerror +IS + FUNCTION uterrcode (errmsg_in IN VARCHAR2 := NULL) + RETURN INTEGER + IS + BEGIN + -- FORMAT ORA-XXXXXX: UT-300XXX: + IF NVL (errmsg_in, SQLERRM) LIKE 'ORA-_____: ' || c_error_indicator + THEN + RETURN SUBSTR (NVL (errmsg_in, SQLERRM), 15, 6); + ELSE + RETURN NULL; + END IF; + END; + + PROCEDURE raise_error ( + errcode_in IN utr_error.errcode%TYPE, + errtext_in IN utr_error.errtext%TYPE + ) + IS + BEGIN + -- Raise "error reported" + IF errcode_in BETWEEN 300000 AND 399999 + THEN + raise_application_error ( + -20000, + SUBSTR ( 'UT-' + || errcode_in + || ': ' + || errtext_in, 1, 255) + ); + ELSE + raise_application_error ( + -20000, + SUBSTR ( errcode_in + || ': ' + || errtext_in + || '"', 1, 255) + ); + END IF; + END; + + PROCEDURE ins ( + run_id_in IN utr_error.run_id%TYPE := NULL, + suite_id_in IN utr_error.suite_id%TYPE := NULL, + utp_id_in IN utr_error.utp_id%TYPE := NULL, + unittest_id_in IN utr_error.unittest_id%TYPE := NULL, + testcase_id_in IN utr_error.testcase_id%TYPE := NULL, + outcome_id_in IN utr_error.outcome_id%TYPE := NULL, + errlevel_in IN utr_error.errlevel%TYPE := NULL, + errcode_in IN utr_error.errcode%TYPE := NULL, + errtext_in IN utr_error.errtext%TYPE := NULL, + description_in IN utr_error.description%TYPE := NULL, + recorderr IN BOOLEAN := TRUE, + raiseexc IN BOOLEAN := TRUE + ) + IS + l_message VARCHAR2 (2000); + &start81 + PRAGMA autonomous_transaction; + &end81 + BEGIN + -- If error already recorded, simply re-raise. + + IF errtext_in LIKE c_error_indicator + THEN + -- Already recorded. SKip this step. + NULL; + ELSE + IF recorderr + THEN + INSERT INTO utr_error + (run_id, suite_id, utp_id, unittest_id, + testcase_id, outcome_id, errlevel, occurred_on, + errcode, errtext, description) + VALUES (run_id_in, suite_id_in, utp_id_in, unittest_id_in, + testcase_id_in, outcome_id_in, errlevel_in, SYSDATE, + errcode_in, errtext_in, description_in); + ELSE + l_message := 'Error UT-' + || NVL (errcode_in, general_error) + || ': ' + || errtext_in; + + IF errlevel_in IS NOT NULL + THEN + l_message := l_message + || ' ' + || errlevel_in; + END IF; + + IF description_in IS NOT NULL + THEN + l_message := l_message + || ' ' + || description_in; + END IF; + + -- Simply display the error information. + utplsql.pl (l_message); + END IF; + END IF; + + &start81 + COMMIT; + + &end81 + + IF raiseexc + THEN + raise_error (errcode_in, errtext_in); + END IF; + &start81 + EXCEPTION + WHEN OTHERS + THEN + ROLLBACK; + RAISE; + &end81 + END; + + PROCEDURE report ( + errcode_in IN INTEGER, + errtext_in IN VARCHAR2 := NULL, + description_in IN VARCHAR2 := NULL, + errlevel_in IN VARCHAR2 := NULL, + recorderr IN BOOLEAN := TRUE, + raiseexc IN BOOLEAN := TRUE + ) + IS + BEGIN + ins ( + run_id_in=> NULL, + suite_id_in=> NULL, + utp_id_in=> NULL, + unittest_id_in=> NULL, + testcase_id_in=> NULL, + outcome_id_in=> NULL, + errlevel_in=> errlevel_in, + errcode_in=> errcode_in, + errtext_in=> errtext_in, + description_in=> description_in, + recorderr=> recorderr, + raiseexc=> raiseexc + ); + END; + + PROCEDURE report_define_error ( + define_in IN VARCHAR2, + message_in IN VARCHAR2 := NULL + ) + IS + BEGIN + report ( + errcode_in=> SQLCODE, + errtext_in=> SQLERRM, + description_in=> message_in, + errlevel_in=> define_in, + recorderr=> FALSE, + raiseexc=> TRUE + ); + END; + + PROCEDURE assert ( + condition_in IN BOOLEAN, + message_in IN VARCHAR2, + raiseexc IN BOOLEAN := TRUE, + raiseerr IN INTEGER := NULL + ) + IS + BEGIN + IF condition_in IS NULL + OR NOT condition_in + THEN + report ( + errcode_in=> NVL (raiseerr, assertion_failure), + errtext_in=> message_in, + description_in=> NULL, + errlevel_in=> NULL, + recorderr=> FALSE, + raiseexc=> raiseexc + ); + END IF; + END; + + PROCEDURE suite_report ( + run_in IN INTEGER, + suite_in IN ut_suite.id%TYPE, + errcode_in IN INTEGER, + errtext_in IN VARCHAR2 := NULL, + description_in IN VARCHAR2 := NULL, + raiseexc IN BOOLEAN := TRUE + ) + IS + BEGIN + ins ( + run_id_in=> run_in, + suite_id_in=> suite_in, + utp_id_in=> NULL, + unittest_id_in=> NULL, + testcase_id_in=> NULL, + outcome_id_in=> NULL, + errlevel_in=> ututp.c_abbrev, + errcode_in=> errcode_in, + errtext_in=> errtext_in, + description_in=> description_in, + raiseexc=> raiseexc + ); + END; + + PROCEDURE utp_report ( + run_in IN INTEGER, + utp_in IN ut_utp.id%TYPE, + errcode_in IN INTEGER, + errtext_in IN VARCHAR2 := NULL, + description_in IN VARCHAR2 := NULL, + raiseexc IN BOOLEAN := TRUE + ) + IS + BEGIN + ins ( + run_id_in=> run_in, + utp_id_in=> utp_in, + unittest_id_in=> NULL, + testcase_id_in=> NULL, + outcome_id_in=> NULL, + errlevel_in=> ututp.c_abbrev, + errcode_in=> errcode_in, + errtext_in=> errtext_in, + description_in=> description_in, + raiseexc=> raiseexc + ); + END; + + PROCEDURE ut_report ( + run_in IN INTEGER, + unittest_in IN ut_unittest.id%TYPE, + errcode_in IN INTEGER, + errtext_in IN VARCHAR2 := NULL, + description_in IN VARCHAR2 := NULL, + raiseexc IN BOOLEAN := TRUE + ) + IS + BEGIN + ins ( + run_id_in=> run_in, + utp_id_in=> NULL, + unittest_id_in=> unittest_in, + testcase_id_in=> NULL, + outcome_id_in=> NULL, + errlevel_in=> utunittest.c_abbrev, + errcode_in=> errcode_in, + errtext_in=> errtext_in, + description_in=> description_in, + raiseexc=> raiseexc + ); + END; + + PROCEDURE tc_report ( + run_in IN INTEGER, + testcase_in IN ut_testcase.id%TYPE, + errcode_in IN INTEGER, + errtext_in IN VARCHAR2 := NULL, + description_in IN VARCHAR2 := NULL, + raiseexc IN BOOLEAN := TRUE + ) + IS + BEGIN + ins ( + run_id_in=> run_in, + utp_id_in=> NULL, + unittest_id_in=> NULL, + testcase_id_in=> testcase_in, + outcome_id_in=> NULL, + errlevel_in=> uttestcase.c_abbrev, + errcode_in=> errcode_in, + errtext_in=> errtext_in, + description_in=> description_in, + raiseexc=> raiseexc + ); + END; + + PROCEDURE oc_report ( + run_in IN INTEGER, + outcome_in IN ut_outcome.id%TYPE, + errcode_in IN INTEGER, + errtext_in IN VARCHAR2 := NULL, + description_in IN VARCHAR2 := NULL, + raiseexc IN BOOLEAN := TRUE + ) + IS + BEGIN + ins ( + run_id_in=> run_in, + utp_id_in=> NULL, + unittest_id_in=> NULL, + testcase_id_in=> NULL, + outcome_id_in=> outcome_in, + errlevel_in=> utoutcome.c_abbrev, + errcode_in=> errcode_in, + errtext_in=> errtext_in, + description_in=> description_in, + raiseexc=> raiseexc + ); + END; +END utrerror; +/ diff --git a/source/ut_rerror.pks b/source/ut_rerror.pks new file mode 100644 index 000000000..0e286af0d --- /dev/null +++ b/source/ut_rerror.pks @@ -0,0 +1,84 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE utrerror &start81 AUTHID CURRENT_USER &end81 +IS + c_error_indicator CONSTANT VARCHAR2 (7) := 'UT-300%'; + general_error CONSTANT INTEGER := 300000; + no_utp_for_program CONSTANT INTEGER := 300001; + cannot_run_program CONSTANT INTEGER := 300002; + undefined_outcome CONSTANT INTEGER := 300003; + undefined_suite CONSTANT INTEGER := 300004; + assertion_failure CONSTANT INTEGER := 300005; + exc_undefined_suite EXCEPTION; + + FUNCTION uterrcode (errmsg_in IN VARCHAR2 := NULL) + RETURN INTEGER; + + PROCEDURE assert ( + condition_in IN BOOLEAN, + message_in IN VARCHAR2, + raiseexc IN BOOLEAN := TRUE, + raiseerr IN INTEGER := NULL + ); + + PROCEDURE report ( + errcode_in IN INTEGER, + errtext_in IN VARCHAR2 := NULL, + description_in IN VARCHAR2 := NULL, + errlevel_in IN VARCHAR2 := NULL, + recorderr IN BOOLEAN := TRUE, + raiseexc IN BOOLEAN := TRUE + ); + + -- Generic reporting for definition actions. + -- Passes SQLCODE and SQLERRM, does NOT record the error + PROCEDURE report_define_error ( + define_in IN VARCHAR2, + message_in IN VARCHAR2 := NULL + ); + + PROCEDURE suite_report ( + run_in IN INTEGER, + suite_in IN ut_suite.id%TYPE, + errcode_in IN INTEGER, + errtext_in IN VARCHAR2 := NULL, + description_in IN VARCHAR2 := NULL, + raiseexc IN BOOLEAN := TRUE + ); + + PROCEDURE utp_report ( + run_in IN INTEGER, + utp_in IN ut_utp.id%TYPE, + errcode_in IN INTEGER, + errtext_in IN VARCHAR2 := NULL, + description_in IN VARCHAR2 := NULL, + raiseexc IN BOOLEAN := TRUE + ); + + PROCEDURE ut_report ( + run_in IN INTEGER, + unittest_in IN ut_unittest.id%TYPE, + errcode_in IN INTEGER, + errtext_in IN VARCHAR2 := NULL, + description_in IN VARCHAR2 := NULL, + raiseexc IN BOOLEAN := TRUE + ); + + PROCEDURE tc_report ( + run_in IN INTEGER, + testcase_in IN ut_testcase.id%TYPE, + errcode_in IN INTEGER, + errtext_in IN VARCHAR2 := NULL, + description_in IN VARCHAR2 := NULL, + raiseexc IN BOOLEAN := TRUE + ); + + PROCEDURE oc_report ( + run_in IN INTEGER, + outcome_in IN ut_outcome.id%TYPE, + errcode_in IN INTEGER, + errtext_in IN VARCHAR2 := NULL, + description_in IN VARCHAR2 := NULL, + raiseexc IN BOOLEAN := TRUE + ); +END utrerror; +/ diff --git a/source/ut_result.pkb b/source/ut_result.pkb new file mode 100644 index 000000000..d8fd380ce --- /dev/null +++ b/source/ut_result.pkb @@ -0,0 +1,352 @@ +CREATE OR REPLACE PACKAGE BODY utresult +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + resultindx PLS_INTEGER; + g_header_shown BOOLEAN := FALSE ; + g_include_successes BOOLEAN := TRUE ; + + PROCEDURE include_successes + IS + BEGIN + g_include_successes := TRUE ; + END; + + PROCEDURE ignore_successes + IS + BEGIN + g_include_successes := FALSE ; + END; + + PROCEDURE showresults ( + success_in IN BOOLEAN, + program_in IN VARCHAR2, + run_id_in IN utr_outcome.run_id%TYPE := NULL + ) + IS + BEGIN + IF success_in + THEN + utplsql.pl ('. '); + utplsql.pl ( + '> SSSS U U CCC CCC EEEEEEE SSSS SSSS ' + ); + utplsql.pl ( + '> S S U U C C C C E S S S S ' + ); + utplsql.pl ( + '> S U U C C C C E S S ' + ); + utplsql.pl ( + '> S U U C C E S S ' + ); + utplsql.pl ( + '> SSSS U U C C EEEE SSSS SSSS ' + ); + utplsql.pl ( + '> S U U C C E S S ' + ); + utplsql.pl ( + '> S U U C C C C E S S ' + ); + utplsql.pl ( + '> S S U U C C C C E S S S S ' + ); + utplsql.pl ( + '> SSSS UUU CCC CCC EEEEEEE SSSS SSSS ' + ); + ELSE + utplsql.pl ('. '); + utplsql.pl ( + '> FFFFFFF AA III L U U RRRRR EEEEEEE ' + ); + utplsql.pl ( + '> F A A I L U U R R E ' + ); + utplsql.pl ( + '> F A A I L U U R R E ' + ); + utplsql.pl ( + '> F A A I L U U R R E ' + ); + utplsql.pl ( + '> FFFF A A I L U U RRRRRR EEEE ' + ); + utplsql.pl ( + '> F AAAAAAAA I L U U R R E ' + ); + utplsql.pl ( + '> F A A I L U U R R E ' + ); + utplsql.pl ( + '> F A A I L U U R R E ' + ); + utplsql.pl ( + '> F A A III LLLLLLL UUU R R EEEEEEE ' + ); + END IF; + + utplsql.pl ('. '); + + IF run_id_in IS NOT NULL + THEN + utplsql.pl ('. Run ID: ' || run_id_in); + ELSE + IF success_in + THEN + utplsql.pl (' SUCCESS: "' || NVL (program_in, 'Unnamed Test') || '"'); + ELSE + utplsql.pl (' FAILURE: "' || NVL (program_in, 'Unnamed Test') || '"'); + END IF; + END IF; + + utplsql.pl ('. '); + END; + + PROCEDURE showheader (run_id_in IN utr_outcome.run_id%TYPE := NULL) + IS + BEGIN + IF g_header_shown + THEN + NULL; + ELSE + showresults (success (run_id_in), utplsql.currpkg, run_id_in); + END IF; + + -- Disable selectivity of showing header for now. + g_header_shown := FALSE ; + END; + + PROCEDURE showone ( + run_id_in IN utr_outcome.run_id%TYPE := NULL, + indx_in IN PLS_INTEGER + ) + IS + BEGIN + utplsql.pl (results (indx_in).NAME || ': ' || results (indx_in).msg); + END; + + PROCEDURE show ( + run_id_in IN utr_outcome.run_id%TYPE := NULL, + reset_in IN BOOLEAN := FALSE + ) + IS + indx PLS_INTEGER := results.FIRST; + l_id utr_outcome.run_id%TYPE := NVL (run_id_in, utplsql2.runnum); + norows BOOLEAN; + BEGIN + showheader (run_id_in); + utplsql.pl ('> Individual Test Case Results:'); + utplsql.pl ('>'); + norows := TRUE ; + + FOR rec IN (SELECT * + FROM utr_outcome + WHERE run_id = l_id + ORDER BY tc_run_id -- 2.0.9.1 + ) + LOOP + IF rec.status = utplsql.c_success + AND + (NOT NVL (g_include_successes, FALSE ) + -- 2.0.10.1 + OR + utconfig.showingfailuresonly) + THEN + -- Ignore in this case + NULL; + ELSIF utconfig.showingfailuresonly + THEN + norows := FALSE ; + utplsql.pl (rec.description); + utplsql.pl ('>'); + ELSE + norows := FALSE ; + utplsql.pl ( + rec.status || ' - ' || + rec.description); + utplsql.pl ('>'); + END IF; + END LOOP; + + IF norows AND utconfig.showingfailuresonly + THEN + utplsql.pl ('> NO FAILURES FOUND'); + ELSIF norows + THEN + utplsql.pl ('> NONE FOUND'); + END IF; + + utplsql.pl ('>'); + utplsql.pl ('> Errors recorded in utPLSQL Error Log:'); + utplsql.pl ('>'); + norows := TRUE ; + + FOR rec IN (SELECT * + FROM utr_error + WHERE run_id = l_id) + LOOP + norows := FALSE ; + utplsql.pl (rec.errlevel || ' - ' || rec.errcode || ': ' || rec.errtext); + END LOOP; + + IF norows + THEN + utplsql.pl ('> NONE FOUND'); + END IF; + + +/*V1 approach + IF failure + THEN + LOOP + EXIT WHEN indx IS NULL; + showone (indx); + indx := results.NEXT (indx); + END LOOP; + END IF; +*/ + IF reset_in + THEN + init; + END IF; + END; + + PROCEDURE showlast (run_id_in IN utr_outcome.run_id%TYPE := NULL) + IS + indx PLS_INTEGER := results.LAST; + BEGIN + -- 2.0.1 showheader; + + IF failure + THEN + showone (run_id_in, indx); + END IF; + END; + + PROCEDURE report (msg_in IN VARCHAR2) + IS + indx PLS_INTEGER := NVL (results.LAST, 0) + 1; + BEGIN + results (indx).NAME := utplsql.currcase.NAME; + results (indx).indx := utplsql.currcase.indx; + results (indx).msg := msg_in; + END; + + PROCEDURE init (from_suite_in IN BOOLEAN := FALSE ) + IS + BEGIN + results.DELETE; + -- Disable functionality + -- IF NOT from_suite_in THEN g_header_shown := FALSE; END IF; + END; + + FUNCTION success (run_id_in IN utr_outcome.run_id%TYPE := NULL) + RETURN BOOLEAN + IS + l_count PLS_INTEGER; + BEGIN + RETURN utresult2.run_succeeded (NVL (run_id_in, utplsql2.runnum)); + END; + + FUNCTION failure (run_id_in IN utr_outcome.run_id%TYPE := NULL) + RETURN BOOLEAN + IS + BEGIN + RETURN (NOT success (run_id_in)); + END; + + PROCEDURE firstresult (run_id_in IN utr_outcome.run_id%TYPE := NULL) + IS + BEGIN + resultindx := results.FIRST; + END; + + FUNCTION nextresult (run_id_in IN utr_outcome.run_id%TYPE := NULL) + RETURN result_rt + IS + BEGIN + /* 1.5.3 Must increment the counter */ + IF resultindx IS NULL + THEN + firstresult; + ELSE + resultindx := results.NEXT (resultindx); + END IF; + + RETURN results (resultindx); + END; + + FUNCTION nthresult ( + indx_in IN PLS_INTEGER, + run_id_in IN utr_outcome.run_id%TYPE := NULL + ) + RETURN result_rt + IS + nullval result_rt; + BEGIN + IF indx_in > resultcount OR NOT results.EXISTS (indx_in) + THEN + RETURN nullval; + ELSE + RETURN results (indx_in); + END IF; + END; + + PROCEDURE nextresult ( + name_out OUT VARCHAR2, + msg_out OUT VARCHAR2, + case_indx_out OUT PLS_INTEGER, + run_id_in IN utr_outcome.run_id%TYPE := NULL + ) + IS + rec result_rt; + BEGIN + rec := nextresult; + name_out := rec.NAME; + msg_out := rec.msg; + case_indx_out := rec.indx; + END; + + PROCEDURE nthresult ( + indx_in IN PLS_INTEGER, + name_out OUT VARCHAR2, + msg_out OUT VARCHAR2, + case_indx_out OUT PLS_INTEGER, + run_id_in IN utr_outcome.run_id%TYPE := NULL + ) + IS + rec result_rt; + BEGIN + rec := nthresult (indx_in); + name_out := rec.NAME; + msg_out := rec.msg; + case_indx_out := rec.indx; + END; + + FUNCTION resultcount (run_id_in IN utr_outcome.run_id%TYPE := NULL) + RETURN PLS_INTEGER + IS + BEGIN + RETURN results.COUNT; + END; +END utresult; +/ diff --git a/source/ut_result.pks b/source/ut_result.pks new file mode 100644 index 000000000..82fa75198 --- /dev/null +++ b/source/ut_result.pks @@ -0,0 +1,98 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE utresult +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + /* Test result record structure */ + TYPE result_rt IS RECORD ( + name VARCHAR2 (100), + msg VARCHAR2 (32767), + indx PLS_INTEGER, + status BOOLEAN /* V2 */); + + TYPE result_tt IS TABLE OF result_rt + INDEX BY BINARY_INTEGER; + + results result_tt; + + PROCEDURE report (msg_in IN VARCHAR2); + + PROCEDURE show ( + run_id_in IN utr_outcome.run_id%TYPE := NULL, + reset_in IN BOOLEAN := FALSE + ); + + PROCEDURE showone ( + run_id_in IN utr_outcome.run_id%TYPE := NULL, + indx_in IN PLS_INTEGER + ); + + PROCEDURE showlast (run_id_in IN utr_outcome.run_id%TYPE := NULL); + + PROCEDURE showresults ( + success_in IN BOOLEAN, + program_in IN VARCHAR2, + run_id_in IN utr_outcome.run_id%TYPE := NULL + ); + + PROCEDURE init (from_suite_in IN BOOLEAN := FALSE); + + FUNCTION success (run_id_in IN utr_outcome.run_id%TYPE := NULL) + RETURN BOOLEAN; + + FUNCTION failure (run_id_in IN utr_outcome.run_id%TYPE := NULL) + RETURN BOOLEAN; + + PROCEDURE firstresult (run_id_in IN utr_outcome.run_id%TYPE := NULL); + + FUNCTION nextresult (run_id_in IN utr_outcome.run_id%TYPE := NULL) + RETURN result_rt; + + PROCEDURE nextresult ( + name_out OUT VARCHAR2, + msg_out OUT VARCHAR2, + case_indx_out OUT PLS_INTEGER, + run_id_in IN utr_outcome.run_id%TYPE := NULL + ); + + FUNCTION nthresult ( + indx_in IN PLS_INTEGER, + run_id_in IN utr_outcome.run_id%TYPE := NULL + ) + RETURN result_rt; + + PROCEDURE nthresult ( + indx_in IN PLS_INTEGER, + name_out OUT VARCHAR2, + msg_out OUT VARCHAR2, + case_indx_out OUT PLS_INTEGER, + run_id_in IN utr_outcome.run_id%TYPE := NULL + ); + + FUNCTION resultcount (run_id_in IN utr_outcome.run_id%TYPE := NULL) + RETURN PLS_INTEGER; + + procedure include_successes; + procedure ignore_successes; + +END utresult; +/ diff --git a/source/ut_result2.pkb b/source/ut_result2.pkb new file mode 100644 index 000000000..825e45f26 --- /dev/null +++ b/source/ut_result2.pkb @@ -0,0 +1,318 @@ +CREATE OR REPLACE PACKAGE BODY utresult2 +IS +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + PROCEDURE report ( + outcome_in IN ut_outcome.ID%TYPE + ,description_in IN VARCHAR2 + ) + IS + BEGIN + NULL; + END; + + PROCEDURE report ( + outcome_in IN ut_outcome.ID%TYPE + ,test_failed_in IN BOOLEAN + ,description_in IN VARCHAR2 + ,register_in IN BOOLEAN := TRUE + , -- v1 compatibility + showresults_in IN BOOLEAN := FALSE -- v1 compatibility + ) + IS + l_id utr_outcome.outcome_id%TYPE := outcome_in; + l_description utr_outcome.description%TYPE := description_in; + BEGIN + IF utplsql2.tracing + THEN + utplsql.pl ('Record outcome result:'); + utplsql.pl (utplsql2.runnum); + utplsql.pl (utplsql2.tc_runnum); + utplsql.pl (outcome_in); + utplsql.bpl (test_failed_in); + utplsql.pl (description_in); + END IF; + + IF register_in + THEN + IF l_id IS NULL + THEN + -- v1 compatibility. Create an outcome ID and + -- construct the message to match screen output. + l_id := utroutcome.next_v1_id (utplsql2.runnum); + l_description := utplsql.currcase.NAME || ': ' || l_description; + END IF; + + utroutcome.RECORD (utplsql2.runnum + ,utplsql2.tc_runnum + , -- 2.0.9.1 + l_id + ,test_failed_in + ,description_in + ); + END IF; + + -- v1 compatibility and output to screen + IF test_failed_in + THEN + IF register_in + THEN + utresult.report (description_in); + ELSE + utplsql.pl (description_in); + END IF; + + IF showresults_in AND register_in + THEN + utresult.showlast; + END IF; + END IF; + END; + + -- NOTE: the logic in the following function is REPEATED three times. + -- Need to move to cursor variables or dynamic SQL. + + FUNCTION run_succeeded (runnum_in IN utr_outcome.run_id%TYPE) + RETURN BOOLEAN + /* A run succeeds if + a. there are no FAILUREs + b. there are no errors + */ + IS + l_val CHAR (1); + success_found BOOLEAN; + failure_found BOOLEAN; + + CURSOR err_cur + IS + SELECT 'x' + FROM utr_error + WHERE run_id = runnum_in; + + CURSOR stat_cur (status_in IN VARCHAR2) + IS + SELECT 'x' + FROM utr_outcome + WHERE run_id = runnum_in AND status LIKE status_in; + BEGIN + -- start: same for all *_succeeded programs + OPEN err_cur; + FETCH err_cur INTO l_val; + failure_found := err_cur%FOUND; + + IF NOT failure_found + THEN + OPEN stat_cur (c_success); + FETCH stat_cur INTO l_val; + success_found := stat_cur%FOUND; + CLOSE stat_cur; + OPEN stat_cur (c_failure); + FETCH stat_cur INTO l_val; + failure_found := stat_cur%FOUND; + CLOSE stat_cur; + END IF; + + IF NOT failure_found AND NOT success_found + THEN + RETURN NULL; -- Nothing was run. + ELSE + RETURN NOT failure_found; + END IF; + -- end: same for all *_succeeded programs + END run_succeeded; + + FUNCTION run_status (runnum_in IN utr_outcome.run_id%TYPE) + RETURN VARCHAR2 + IS + BEGIN + IF run_succeeded (runnum_in) + THEN + RETURN c_success; + ELSE + RETURN c_failure; + END IF; + END; + + FUNCTION utp_succeeded ( + runnum_in IN utr_outcome.run_id%TYPE + ,utp_in IN utr_utp.utp_id%TYPE + ) + RETURN BOOLEAN + IS + l_val CHAR (1); + success_found BOOLEAN; + failure_found BOOLEAN; + + CURSOR err_cur + IS + SELECT 'x' + FROM utr_error + WHERE run_id = runnum_in + AND utp_id = utp_in + AND errlevel = ututp.c_abbrev; + + CURSOR stat_cur (status_in IN VARCHAR2) + IS + SELECT 'x' + FROM utr_outcome + WHERE run_id = runnum_in + AND utoutcome.utp (outcome_id) = utp_in + AND status LIKE status_in; + BEGIN + OPEN err_cur; + FETCH err_cur INTO l_val; + failure_found := err_cur%FOUND; + + IF NOT failure_found + THEN + OPEN stat_cur (c_success); + FETCH stat_cur INTO l_val; + success_found := stat_cur%FOUND; + CLOSE stat_cur; + OPEN stat_cur (c_failure); + FETCH stat_cur INTO l_val; + failure_found := stat_cur%FOUND; + CLOSE stat_cur; + END IF; + + IF NOT failure_found AND NOT success_found + THEN + RETURN NULL; -- Nothing was run. + ELSE + RETURN NOT failure_found; + END IF; + END utp_succeeded; + + FUNCTION utp_status ( + runnum_in IN utr_outcome.run_id%TYPE + ,utp_in IN utr_utp.utp_id%TYPE + ) + RETURN VARCHAR2 + IS + BEGIN + IF utp_succeeded (runnum_in, utp_in) + THEN + RETURN c_success; + ELSE + RETURN c_failure; + END IF; + END; + + FUNCTION unittest_succeeded ( + runnum_in IN utr_outcome.run_id%TYPE + ,unittest_in IN utr_unittest.unittest_id%TYPE + ) + RETURN BOOLEAN + IS + l_val CHAR (1); + success_found BOOLEAN; + failure_found BOOLEAN; + + CURSOR err_cur + IS + SELECT 'x' + FROM utr_error + WHERE run_id = runnum_in + AND unittest_id = unittest_in + AND errlevel = utunittest.c_abbrev; + + CURSOR stat_cur (status_in IN VARCHAR2) + IS + SELECT 'x' + FROM utr_outcome + WHERE run_id = runnum_in + AND utoutcome.unittest (outcome_id) = unittest_in + AND status LIKE status_in; + BEGIN + OPEN err_cur; + FETCH err_cur INTO l_val; + failure_found := err_cur%FOUND; + + IF NOT failure_found + THEN + OPEN stat_cur (c_success); + FETCH stat_cur INTO l_val; + success_found := stat_cur%FOUND; + CLOSE stat_cur; + OPEN stat_cur (c_failure); + FETCH stat_cur INTO l_val; + failure_found := stat_cur%FOUND; + CLOSE stat_cur; + END IF; + + IF NOT failure_found AND NOT success_found + THEN + RETURN NULL; -- Nothing was run. + ELSE + RETURN NOT failure_found; + END IF; + END unittest_succeeded; + + FUNCTION unittest_status ( + runnum_in IN utr_outcome.run_id%TYPE + ,unittest_in IN utr_unittest.unittest_id%TYPE + ) + RETURN VARCHAR2 + IS + BEGIN + IF unittest_succeeded (runnum_in, unittest_in) + THEN + RETURN c_success; + ELSE + RETURN c_failure; + END IF; + END; + + FUNCTION results_headers (schema_in IN VARCHAR2, program_in IN VARCHAR2) + RETURN utconfig.refcur_t + IS + retval utconfig.refcur_t; + BEGIN + OPEN retval FOR + SELECT run_id, start_on, end_on, status + FROM ut_utp utp, utr_utp utpr + WHERE utp.ID = utpr.utp_id + AND utp.program = UPPER (program_in) + AND utp.owner = UPPER (schema_in) + ORDER BY end_on; + RETURN retval; + END results_headers; + + FUNCTION results_details ( + run_id_in IN utr_utp.run_id%TYPE + ,show_failures_only_in IN ut_config.show_failures_only%TYPE + ) + RETURN utconfig.refcur_t + IS + retval utconfig.refcur_t; + BEGIN + OPEN retval FOR + SELECT start_on, end_on, status, description + FROM utr_outcome + WHERE run_id = run_id_in + AND ( show_failures_only_in = 'N' + OR (show_failures_only_in = 'Y' AND status = 'FAILURE' + ) + ) + ORDER BY start_on; + RETURN retval; + END results_details; +END utresult2; +/ diff --git a/source/ut_result2.pks b/source/ut_result2.pks new file mode 100644 index 000000000..d96b81475 --- /dev/null +++ b/source/ut_result2.pks @@ -0,0 +1,96 @@ +CREATE OR REPLACE PACKAGE utresult2 +IS +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + c_success CONSTANT CHAR (7) := 'SUCCESS'; + c_failure CONSTANT CHAR (7) := 'FAILURE'; + + /* Test result record structure */ + TYPE result_rt IS RECORD ( + NAME VARCHAR2 (100) + ,msg VARCHAR2 (32767) + ,indx PLS_INTEGER + ); + + TYPE result_tt IS TABLE OF result_rt + INDEX BY BINARY_INTEGER; + + CURSOR results_header_cur (schema_in IN VARCHAR2, program_in IN VARCHAR2) + IS + SELECT run_id, start_on, end_on, status + FROM ut_utp utp, utr_utp utpr + WHERE utp.ID = utpr.utp_id + AND utp.program = program_in + AND utp.owner = schema_in; + + PROCEDURE report ( + outcome_in IN ut_outcome.ID%TYPE + ,description_in IN VARCHAR2 + ); + + PROCEDURE report ( + outcome_in IN ut_outcome.ID%TYPE + ,test_failed_in IN BOOLEAN + ,description_in IN VARCHAR2 + ,register_in IN BOOLEAN := TRUE + , -- v1 compatibility + showresults_in IN BOOLEAN := FALSE -- v1 compatibility + ); + + FUNCTION run_succeeded (runnum_in IN utr_outcome.run_id%TYPE) + RETURN BOOLEAN; + + FUNCTION run_status (runnum_in IN utr_outcome.run_id%TYPE) + RETURN VARCHAR2; + + FUNCTION utp_succeeded ( + runnum_in IN utr_outcome.run_id%TYPE + ,utp_in IN utr_utp.utp_id%TYPE + ) + RETURN BOOLEAN; + + FUNCTION utp_status ( + runnum_in IN utr_outcome.run_id%TYPE + ,utp_in IN utr_utp.utp_id%TYPE + ) + RETURN VARCHAR2; + + FUNCTION unittest_succeeded ( + runnum_in IN utr_outcome.run_id%TYPE + ,unittest_in IN utr_unittest.unittest_id%TYPE + ) + RETURN BOOLEAN; + + FUNCTION unittest_status ( + runnum_in IN utr_outcome.run_id%TYPE + ,unittest_in IN utr_unittest.unittest_id%TYPE + ) + RETURN VARCHAR2; + + FUNCTION results_headers (schema_in IN VARCHAR2, program_in IN VARCHAR2) + RETURN utconfig.refcur_t; + + FUNCTION results_details ( + run_id_in IN utr_utp.run_id%TYPE + ,show_failures_only_in IN ut_config.show_failures_only%TYPE + ) + RETURN utconfig.refcur_t; +END utresult2; +/ diff --git a/source/ut_routcome.pkb b/source/ut_routcome.pkb new file mode 100644 index 000000000..d044fba17 --- /dev/null +++ b/source/ut_routcome.pkb @@ -0,0 +1,205 @@ + +CREATE OR REPLACE PACKAGE BODY utroutcome +IS + PROCEDURE initiate ( + run_id_in IN utr_outcome.run_id%TYPE + , outcome_id_in IN utr_outcome.outcome_id%TYPE + , start_on_in IN DATE := SYSDATE + ) + IS + &start81 + PRAGMA AUTONOMOUS_TRANSACTION; + &end81 + BEGIN + utplsql2.set_current_outcome (outcome_id_in); + + INSERT INTO utr_outcome + (run_id, outcome_id, start_on + ) + VALUES (run_id_in, outcome_id_in, start_on_in + ); + + &start81 + COMMIT; + &end81 + EXCEPTION + WHEN DUP_VAL_ON_INDEX + THEN + -- Run has already been initiated. Ignore... + NULL; + &start81 + ROLLBACK; + &end81 + WHEN OTHERS + THEN + &start81 + ROLLBACK; + &end81 + utrerror.oc_report (run_id_in + , outcome_id_in + , SQLCODE + , SQLERRM + , 'Unable to initiate outcome for run ' + || run_id_in + || ' outcome ID ' + || outcome_id_in + ); + END initiate; + + PROCEDURE RECORD ( + run_id_in IN utr_outcome.run_id%TYPE + , tc_run_id_in IN PLS_INTEGER + , outcome_id_in IN utr_outcome.outcome_id%TYPE + , test_failed_in IN BOOLEAN + , description_in IN VARCHAR2 := NULL + , end_on_in IN DATE := SYSDATE + ) + IS + &start81 + PRAGMA AUTONOMOUS_TRANSACTION; + + &end81 + + CURSOR start_cur (id_in IN utr_outcome.outcome_id%TYPE) + IS + SELECT start_on, end_on + FROM utr_outcome + WHERE run_id = run_id_in AND outcome_id = id_in; + + rec start_cur%ROWTYPE; + l_status utr_outcome.status%TYPE; + BEGIN + -- FALSE means that the test succeeded. + IF test_failed_in + THEN + l_status := utresult2.c_failure; + ELSE + l_status := utresult2.c_success; + END IF; + + OPEN start_cur (outcome_id_in); + FETCH start_cur INTO rec; + + IF start_cur%FOUND AND rec.end_on IS NULL + THEN + UPDATE utr_outcome + SET end_on = end_on_in + , status = l_status + , description = description_in + WHERE run_id = run_id_in AND outcome_id = outcome_id_in; + ELSIF start_cur%FOUND AND rec.end_on IS NOT NULL + THEN + -- Run is already terminated. Ignore... + NULL; + ELSE + INSERT INTO utr_outcome + (run_id, tc_run_id, outcome_id, status + , end_on, description + ) + VALUES (run_id_in, tc_run_id_in, outcome_id_in, l_status + , end_on_in, description_in + ); + + utplsql2.move_ahead_tc_runnum; -- 2.0.9.1 + END IF; + + CLOSE start_cur; + &start81 + COMMIT; + &end81 + EXCEPTION + WHEN OTHERS + THEN + &start81 + ROLLBACK; + &end81 + utrerror.oc_report (run_id_in + , outcome_id_in + , SQLCODE + , SQLERRM + , 'Unable to insert or update the utr_outcome table for run ' + || run_id_in + || ' outcome ID ' + || outcome_id_in + ); + END RECORD; + + FUNCTION next_v1_id (run_id_in IN utr_outcome.run_id%TYPE) + RETURN utr_outcome.outcome_id%TYPE + IS + retval utr_outcome.outcome_id%TYPE; + BEGIN + SELECT MIN (outcome_id) + INTO retval + FROM utr_outcome + WHERE run_id = run_id_in; + + retval := LEAST (NVL (retval, 0), 0) - 1; + RETURN retval; + END; + + PROCEDURE clear_results (run_id_in IN utr_outcome.run_id%TYPE) + IS + &start81 + PRAGMA AUTONOMOUS_TRANSACTION; + &end81 + BEGIN + DELETE FROM utr_outcome + WHERE run_id = run_id_in; + + &start81 + COMMIT; + &end81 + END; + + PROCEDURE clear_results ( + owner_in IN VARCHAR2 + , program_in IN VARCHAR2 + , start_from_in IN DATE + ) + IS + &start81 + PRAGMA AUTONOMOUS_TRANSACTION; + &end81 + BEGIN + DELETE FROM utr_outcome + WHERE start_on >= start_from_in + AND run_id IN ( + SELECT r.run_id + FROM utr_utp r, ut_utp u + WHERE r.utp_id = u.ID + AND u.owner = owner_in + AND u.program = program_in); + + &start81 + COMMIT; + &end81 + END; + + PROCEDURE clear_all_but_last (owner_in IN VARCHAR2, program_in IN VARCHAR2) + IS + &start81 + PRAGMA AUTONOMOUS_TRANSACTION; + &end81 + BEGIN + DELETE FROM utr_outcome + WHERE start_on < + (SELECT MAX (o.start_on) + FROM utr_outcome o, utr_utp r, ut_utp u + WHERE r.utp_id = u.ID + AND u.owner = owner_in + AND u.program = program_in + AND o.run_id = r.run_id) + AND run_id IN ( + SELECT r.run_id + FROM utr_utp r, ut_utp u + WHERE r.utp_id = u.ID + AND u.owner = owner_in + AND u.program = program_in); + &start81 + COMMIT; + &end81 + END; +END utroutcome; +/ + diff --git a/source/ut_routcome.pks b/source/ut_routcome.pks new file mode 100644 index 000000000..6b9352dfa --- /dev/null +++ b/source/ut_routcome.pks @@ -0,0 +1,32 @@ +CREATE OR REPLACE PACKAGE utroutcome +IS + PROCEDURE RECORD ( + run_id_in IN utr_outcome.run_id%TYPE + , tc_run_id_in IN PLS_INTEGER + , outcome_id_in IN utr_outcome.outcome_id%TYPE + , test_failed_in IN BOOLEAN + , description_in IN VARCHAR2 := NULL + , end_on_in IN DATE := SYSDATE + ); + + PROCEDURE initiate ( + run_id_in IN utr_outcome.run_id%TYPE + , outcome_id_in IN utr_outcome.outcome_id%TYPE + , start_on_in IN DATE := SYSDATE + ); + + FUNCTION next_v1_id (run_id_in IN utr_outcome.run_id%TYPE) + RETURN utr_outcome.outcome_id%TYPE; + + PROCEDURE clear_results (run_id_in IN utr_outcome.run_id%TYPE); + + PROCEDURE clear_results ( + owner_in IN VARCHAR2 + , program_in IN VARCHAR2 + , start_from_in IN DATE + ); + + PROCEDURE clear_all_but_last (owner_in IN VARCHAR2, program_in IN VARCHAR2); +END utroutcome; +/ + diff --git a/source/ut_rsuite.pkb b/source/ut_rsuite.pkb new file mode 100644 index 000000000..6e81ef069 --- /dev/null +++ b/source/ut_rsuite.pkb @@ -0,0 +1,114 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE BODY utrsuite +IS + PROCEDURE initiate ( + run_id_in IN utr_suite.run_id%TYPE, + suite_id_in IN utr_suite.suite_id%TYPE, + start_on_in IN DATE := SYSDATE + ) + IS + &start81 + PRAGMA autonomous_transaction; + &end81 + + BEGIN + utplsql2.set_current_suite (suite_id_in); + + INSERT INTO utr_suite + (run_id, suite_id, start_on) + VALUES (run_id_in, suite_id_in, start_on_in); + + &start81 + COMMIT; + &end81 + EXCEPTION + WHEN DUP_VAL_ON_INDEX + THEN + -- Run has already been initiated. Ignore... + NULL; + &start81 + ROLLBACK; + &end81 + WHEN OTHERS + THEN + &start81 + ROLLBACK; + &end81 + utrerror.suite_report ( + run_id_in, + suite_id_in, + SQLCODE, + SQLERRM, + 'Unable to initiate suite for run ' + || run_id_in + || ' SUITE ID ' + || suite_id_in + ); + END initiate; + + PROCEDURE terminate ( + run_id_in IN utr_suite.run_id%TYPE, + suite_id_in IN utr_suite.suite_id%TYPE, + end_on_in IN DATE := SYSDATE + ) + IS + &start81 + PRAGMA autonomous_transaction; + + &end81 + + CURSOR start_cur + IS + SELECT start_on, end_on + FROM utr_suite + WHERE run_id = run_id_in + AND suite_id_in = suite_id; + + rec start_cur%ROWTYPE; + l_status utr_suite.status%TYPE; + BEGIN + l_status := utresult2.run_status (run_id_in); + OPEN start_cur; + FETCH start_cur INTO rec; + + IF start_cur%FOUND + AND rec.end_on IS NULL + THEN + UPDATE utr_suite + SET end_on = end_on_in, + status = l_status + WHERE run_id = run_id_in + AND suite_id_in = suite_id; + ELSIF start_cur%FOUND + AND rec.end_on IS NOT NULL + THEN + -- Run is already terminated. Ignore... + NULL; + ELSE + INSERT INTO utr_suite + (run_id, suite_id, status, end_on) + VALUES (run_id_in, suite_id_in, l_status, end_on_in); + END IF; + + &start81 + COMMIT; + &end81 + EXCEPTION + WHEN OTHERS + THEN + &start81 + ROLLBACK; + &end81 + utrerror.suite_report ( + run_id_in, + suite_id_in, + SQLCODE, + SQLERRM, + 'Unable to insert or update the utr_suite table for run ' + || run_id_in + || ' SUITE ID ' + || suite_id_in + ); + END terminate; +END utrsuite; +/ diff --git a/source/ut_rsuite.pks b/source/ut_rsuite.pks new file mode 100644 index 000000000..9cd9d994f --- /dev/null +++ b/source/ut_rsuite.pks @@ -0,0 +1,16 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE utrsuite +IS + PROCEDURE terminate ( + run_id_in IN utr_suite.run_id%TYPE, + suite_id_in IN utr_suite.suite_id%TYPE, + end_on_in IN DATE := SYSDATE + ); + + PROCEDURE initiate ( + run_id_in IN utr_suite.run_id%TYPE, + suite_id_in IN utr_suite.suite_id%TYPE, + start_on_in IN DATE := SYSDATE + ); +END utrsuite; +/ diff --git a/source/ut_rtestcase.pkb b/source/ut_rtestcase.pkb new file mode 100644 index 000000000..52ae2b2de --- /dev/null +++ b/source/ut_rtestcase.pkb @@ -0,0 +1,108 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE BODY utrtestcase +IS + PROCEDURE initiate ( + run_id_in IN utr_testcase.run_id%TYPE, + testcase_id_in IN utr_testcase.testcase_id%TYPE, + start_on_in IN DATE := SYSDATE + ) + IS + &start81 + PRAGMA autonomous_transaction; + &end81 + BEGIN + INSERT INTO utr_testcase + (run_id, testcase_id, start_on) + VALUES (run_id_in, testcase_id_in, start_on_in); + EXCEPTION + WHEN DUP_VAL_ON_INDEX + THEN + -- Run has already been initiated. Ignore... + NULL; + &start81 + ROLLBACK; + &end81 + WHEN OTHERS + THEN + &start81 + ROLLBACK; + &end81 + utrerror.tc_report ( + run_id_in, + testcase_id_in, + SQLCODE, + SQLERRM, + 'Unable to initiate testcase for run ' + || run_id_in + || ' testcase ID ' + || testcase_id_in + ); + END initiate; + + PROCEDURE terminate ( + run_id_in IN utr_testcase.run_id%TYPE, + testcase_id_in IN utr_testcase.testcase_id%TYPE, + end_on_in IN DATE := SYSDATE + ) + IS + &start81 + PRAGMA autonomous_transaction; + + &end81 + CURSOR start_cur + IS + SELECT start_on, end_on + FROM utr_testcase + WHERE run_id = run_id_in + AND testcase_id_in = testcase_id; + + rec start_cur%ROWTYPE; + l_status utr_testcase.status%TYPE; + BEGIN + l_status := utresult2.run_status (run_id_in); + OPEN start_cur; + FETCH start_cur INTO rec; + + IF start_cur%FOUND + AND rec.end_on IS NULL + THEN + UPDATE utr_testcase + SET end_on = end_on_in, + status = l_status + WHERE run_id = run_id_in + AND testcase_id_in = testcase_id; + ELSIF start_cur%FOUND + AND rec.end_on IS NOT NULL + THEN + -- Run is already terminated. Ignore... + NULL; + ELSE + INSERT INTO utr_testcase + (run_id, testcase_id, status, end_on) + VALUES (run_id_in, testcase_id_in, l_status, end_on_in); + END IF; + + CLOSE start_cur; + CLOSE start_cur; + &start81 + COMMIT; + &end81 + EXCEPTION + WHEN OTHERS + THEN + &start81 + ROLLBACK; + &end81 + utrerror.oc_report ( + run_id_in, + testcase_id_in, + SQLCODE, + SQLERRM, + 'Unable to insert or update the utr_testcase table for run ' + || run_id_in + || ' testcase ID ' + || testcase_id_in + ); + END terminate; +END utrtestcase; +/ diff --git a/source/ut_rtestcase.pks b/source/ut_rtestcase.pks new file mode 100644 index 000000000..1f6177099 --- /dev/null +++ b/source/ut_rtestcase.pks @@ -0,0 +1,16 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE utrtestcase +IS + PROCEDURE terminate ( + run_id_in IN utr_testcase.run_id%TYPE, + testcase_id_in IN utr_testcase.testcase_id%TYPE, + end_on_in IN DATE := SYSDATE + ); + + PROCEDURE initiate ( + run_id_in IN utr_testcase.run_id%TYPE, + testcase_id_in IN utr_testcase.testcase_id%TYPE, + start_on_in IN DATE := SYSDATE + ); +END utrtestcase; +/ diff --git a/source/ut_runittest.pkb b/source/ut_runittest.pkb new file mode 100644 index 000000000..67b38f105 --- /dev/null +++ b/source/ut_runittest.pkb @@ -0,0 +1,116 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE BODY utrunittest +IS + PROCEDURE initiate ( + run_id_in IN utr_unittest.run_id%TYPE, + unittest_id_in IN utr_unittest.unittest_id%TYPE, + start_on_in IN DATE := SYSDATE + ) + IS + &start81 + PRAGMA autonomous_transaction; + &end81 + BEGIN + utplsql2.set_current_unittest (unittest_id_in); + + INSERT INTO utr_unittest + (run_id, unittest_id, start_on) + VALUES (run_id_in, unittest_id_in, start_on_in); + + &start81 + COMMIT; + &end81 + EXCEPTION + WHEN DUP_VAL_ON_INDEX + THEN + -- Run has already been initiated. Ignore... + NULL; + &start81 + ROLLBACK; + &end81 + WHEN OTHERS + THEN + &start81 + ROLLBACK; + &end81 + utrerror.ut_report ( + run_id_in, + unittest_id_in, + SQLCODE, + SQLERRM, + 'Unable to initiate unit test for run ' + || run_id_in + || ' unit test ID ' + || unittest_id_in + ); + END initiate; + + PROCEDURE terminate ( + run_id_in IN utr_unittest.run_id%TYPE, + unittest_id_in IN utr_unittest.unittest_id%TYPE, + end_on_in IN DATE := SYSDATE + ) + IS + &start81 + PRAGMA autonomous_transaction; + + &end81 + + CURSOR start_cur + IS + SELECT start_on, end_on + FROM utr_unittest + WHERE run_id = run_id_in + AND unittest_id_in = unittest_id; + + rec start_cur%ROWTYPE; + l_status utr_unittest.status%TYPE + := utresult2.unittest_status (run_id_in, unittest_id_in); + BEGIN + OPEN start_cur; + FETCH start_cur INTO rec; + + IF start_cur%FOUND + AND rec.end_on IS NULL + THEN + UPDATE utr_unittest + SET end_on = end_on_in, + status = l_status + WHERE run_id = run_id_in + AND unittest_id_in = unittest_id; + ELSIF start_cur%FOUND + AND rec.end_on IS NOT NULL + THEN + -- Run is already terminated. Ignore... + NULL; + ELSE + INSERT INTO utr_unittest + (run_id, unittest_id, status, start_on, + end_on) + VALUES (run_id_in, unittest_id_in, l_status, SYSDATE, + end_on_in); + END IF; + + CLOSE start_cur; + &start81 + COMMIT; + &end81 + EXCEPTION + WHEN OTHERS + THEN + &start81 + ROLLBACK; + &end81 + utrerror.ut_report ( + run_id_in, + unittest_id_in, + SQLCODE, + SQLERRM, + 'Unable to insert or update the utr_unittest table for run ' + || run_id_in + || ' outcome ID ' + || unittest_id_in + ); + END terminate; +END utrunittest; +/ diff --git a/source/ut_runittest.pks b/source/ut_runittest.pks new file mode 100644 index 000000000..8ce731917 --- /dev/null +++ b/source/ut_runittest.pks @@ -0,0 +1,16 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE utrunittest +IS + PROCEDURE terminate ( + run_id_in IN utr_unittest.run_id%TYPE, + unittest_id_in IN utr_unittest.unittest_id%TYPE, + end_on_in IN DATE := SYSDATE + ); + + PROCEDURE initiate ( + run_id_in IN utr_unittest.run_id%TYPE, + unittest_id_in IN utr_unittest.unittest_id%TYPE, + start_on_in IN DATE := SYSDATE + ); +END utrunittest; +/ diff --git a/source/ut_rutp.pkb b/source/ut_rutp.pkb new file mode 100644 index 000000000..c47977e4e --- /dev/null +++ b/source/ut_rutp.pkb @@ -0,0 +1,202 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE BODY utrutp +IS + PROCEDURE initiate ( + run_id_in IN utr_utp.run_id%TYPE, + utp_id_in IN utr_utp.utp_id%TYPE, + start_on_in IN DATE := SYSDATE + ) + IS + &start81 + PRAGMA autonomous_transaction; + &end81 + + BEGIN + utplsql2.set_current_utp (utp_id_in); + + INSERT INTO utr_utp + (run_id, utp_id, start_on) + VALUES (run_id_in, utp_id_in, start_on_in); + + &start81 + COMMIT; + &end81 + EXCEPTION + WHEN DUP_VAL_ON_INDEX + THEN + -- Run has already been initiated. Ignore... + NULL; + &start81 + ROLLBACK; + &end81 + WHEN OTHERS + THEN + &start81 + ROLLBACK; + &end81 + utrerror.utp_report ( + run_id_in, + utp_id_in, + SQLCODE, + SQLERRM, + 'Unable to initiate UTP for run ' + || run_id_in + || ' UTP ID ' + || utp_id_in + ); + END initiate; + + PROCEDURE terminate ( + run_id_in IN utr_utp.run_id%TYPE, + utp_id_in IN utr_utp.utp_id%TYPE, + end_on_in IN DATE := SYSDATE + ) + IS + &start81 + PRAGMA autonomous_transaction; + + &end81 + + CURSOR start_cur + IS + SELECT start_on, end_on + FROM utr_utp + WHERE run_id = run_id_in + AND utp_id_in = utp_id; + + rec start_cur%ROWTYPE; + l_status utr_utp.status%TYPE; + BEGIN + l_status := utresult2.run_status (run_id_in); + OPEN start_cur; + FETCH start_cur INTO rec; + + IF start_cur%FOUND + AND rec.end_on IS NULL + THEN + UPDATE utr_utp + SET end_on = end_on_in, + status = l_status + WHERE run_id = run_id_in + AND utp_id_in = utp_id; + ELSIF start_cur%FOUND + AND rec.end_on IS NOT NULL + THEN + -- Run is already terminated. Ignore... + NULL; + ELSE + INSERT INTO utr_utp + (run_id, utp_id, status, start_on, end_on) + VALUES (run_id_in, utp_id_in, l_status, end_on_in, end_on_in); + END IF; + + CLOSE start_cur; + &start81 + COMMIT; + &end81 + EXCEPTION + WHEN OTHERS + THEN + &start81 + ROLLBACK; + &end81 + utrerror.utp_report ( + run_id_in, + utp_id_in, + SQLCODE, + SQLERRM, + 'Unable to insert or update the utr_utp table for run ' + || run_id_in + || ' outcome ID ' + || utp_id_in + ); + END terminate; + + PROCEDURE clear_results (run_id_in IN utr_utp.run_id%TYPE) + IS + &start81 + PRAGMA AUTONOMOUS_TRANSACTION; + &end81 + BEGIN + DELETE FROM utr_utp + WHERE run_id = run_id_in; + + &start81 + COMMIT; + &end81 + END; + + PROCEDURE clear_results ( + owner_in IN VARCHAR2 + , program_in IN VARCHAR2 + , start_from_in IN DATE + ) + IS + &start81 + PRAGMA AUTONOMOUS_TRANSACTION; + &end81 + BEGIN + DELETE FROM utr_utp + WHERE start_on >= start_from_in + AND run_id IN ( + SELECT r.run_id + FROM utr_utp r, ut_utp u + WHERE r.utp_id = u.ID + AND u.owner = owner_in + AND u.program = program_in); + + &start81 + COMMIT; + &end81 + END; + + PROCEDURE clear_all_but_last (owner_in IN VARCHAR2, program_in IN VARCHAR2) + IS + &start81 + PRAGMA AUTONOMOUS_TRANSACTION; + &end81 + BEGIN + DELETE FROM utr_utp + WHERE start_on < + (SELECT MAX (r.start_on) + FROM utr_utp r, ut_utp u + WHERE r.utp_id = u.ID + AND u.owner = owner_in + AND u.program = program_in) + AND run_id IN ( + SELECT r.run_id + FROM utr_utp r, ut_utp u + WHERE r.utp_id = u.ID + AND u.owner = owner_in + AND u.program = program_in); + &start81 + COMMIT; + &end81 + END; + + FUNCTION last_run_status (owner_in IN VARCHAR2, program_in IN VARCHAR2) + RETURN utr_utp.status%TYPE + IS + retval utr_utp.status%TYPE; + BEGIN + SELECT status + INTO retval + FROM utr_utp + WHERE (utp_id, start_on) = + (SELECT r.utp_id, MAX (r.start_on) + FROM utr_utp r, ut_utp u + WHERE r.utp_id = u.ID + AND u.owner = owner_in + AND u.program = program_in + GROUP BY r.utp_id) + AND ROWNUM < 2; + + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END; + +END utrutp; +/ diff --git a/source/ut_rutp.pks b/source/ut_rutp.pks new file mode 100644 index 000000000..45f4029b1 --- /dev/null +++ b/source/ut_rutp.pks @@ -0,0 +1,33 @@ + +CREATE OR REPLACE PACKAGE utrutp +IS + PROCEDURE TERMINATE ( + run_id_in IN utr_utp.run_id%TYPE + , utp_id_in IN utr_utp.utp_id%TYPE + , end_on_in IN DATE := SYSDATE + ); + + PROCEDURE initiate ( + run_id_in IN utr_utp.run_id%TYPE + , utp_id_in IN utr_utp.utp_id%TYPE + , start_on_in IN DATE := SYSDATE + ); + + PROCEDURE clear_results (run_id_in IN utr_utp.run_id%TYPE); + + PROCEDURE clear_results ( + owner_in IN VARCHAR2 + , program_in IN VARCHAR2 + , start_from_in IN DATE + ); + + PROCEDURE clear_all_but_last (owner_in IN VARCHAR2, program_in IN VARCHAR2); + + function last_run_status ( + owner_in IN VARCHAR2 + , program_in IN VARCHAR2 + ) + return utr_utp.status%type; +END utrutp; +/ + diff --git a/source/ut_suite.pkb b/source/ut_suite.pkb new file mode 100644 index 000000000..61a55f0ca --- /dev/null +++ b/source/ut_suite.pkb @@ -0,0 +1,238 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE BODY utsuite +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + FUNCTION name_from_id (id_in IN ut_suite.id%TYPE) + RETURN ut_suite.name%TYPE + IS + retval ut_suite.name%TYPE; + BEGIN + SELECT name + INTO retval + FROM ut_suite + WHERE id = id_in; + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END; + + FUNCTION id_from_name (name_in IN ut_suite.name%TYPE) + RETURN ut_suite.id%TYPE + IS + retval ut_suite.id%TYPE; + BEGIN + SELECT id + INTO retval + FROM ut_suite + WHERE name = UPPER (name_in); + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END; + + FUNCTION onerow (name_in IN ut_suite.name%TYPE) + RETURN ut_suite%ROWTYPE + IS + retval ut_suite%ROWTYPE; + BEGIN + SELECT * + INTO retval + FROM ut_suite + WHERE name = UPPER (name_in); + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN retval; + END; + + PROCEDURE ADD ( + name_in IN ut_suite.name%TYPE, + desc_in IN VARCHAR2 := NULL, + rem_if_exists_in IN BOOLEAN := TRUE, + per_method_setup_in in ut_suite.per_method_setup%type := null + ) + IS + &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + v_id ut_suite.id%TYPE; + BEGIN + utrerror.assert (name_in IS NOT NULL, 'Suite names cannot be null.'); + + &start81 v_id := utplsql.seqval ('ut_suite'); &end81 + &start73 SELECT ut_suite_seq.NEXTVAL INTO v_id FROM dual; &end73 + + INSERT INTO ut_suite + (id, name, description, executions, failures,per_method_setup) + VALUES (v_id, UPPER (name_in), desc_in, 0, 0,per_method_setup_in); + &start81 COMMIT; &end81 + EXCEPTION + WHEN DUP_VAL_ON_INDEX + THEN + IF rem_if_exists_in + THEN + rem (name_in); + ADD (name_in, desc_in, per_method_setup_in => per_method_setup_in); + ELSE + &start81 ROLLBACK; &end81 + RAISE; + END IF; + WHEN OTHERS + THEN + + IF utrerror.uterrcode = utrerror.assertion_failure + THEN + &start81 ROLLBACK; &end81 + raise; + ELSE + &start81 ROLLBACK; &end81 + utrerror.report_define_error ( + c_abbrev, + 'Suite ' + || name_in + ); + END IF; + + END; + + PROCEDURE rem (id_in IN ut_suite.id%TYPE) + IS + &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + BEGIN + -- V1 compatibility + DELETE FROM ut_package + WHERE suite_id = id_in; + + DELETE FROM ut_suite_utp + WHERE suite_id = id_in; + + DELETE FROM ut_suite + WHERE id = id_in; + &start81 COMMIT; &end81 + EXCEPTION + WHEN OTHERS + THEN + utplsql.pl ( 'Remove suite error: ' + || SQLERRM); + &start81 ROLLBACK; &end81 + RAISE; + END; + + PROCEDURE rem (name_in IN ut_suite.name%TYPE) + IS + &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + v_id ut_suite.id%TYPE; + BEGIN + rem (id_from_name (name_in)); + END; + + PROCEDURE upd ( + id_in IN ut_suite.id%TYPE, + start_in DATE, + end_in DATE, + successful_in in BOOLEAN, + per_method_setup_in in ut_suite.per_method_setup%type := null + ) + IS + &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + l_status VARCHAR2 (100) := utplsql.c_success; + v_failure PLS_INTEGER := 0; + + PROCEDURE do_upd + IS + BEGIN + UPDATE ut_suite + SET last_status = l_status, + last_start = start_in, + last_end = end_in, + per_method_setup = per_method_setup_in, + executions = NVL (executions, 0) + + 1, + failures = NVL (failures, 0) + + v_failure + WHERE id = id_in; + END; + BEGIN + IF NOT successful_in + THEN + v_failure := 1; + l_status := utplsql.c_failure; + END IF; + + do_upd; + + IF SQL%ROWCOUNT = 0 + THEN + ADD ( + name_in=> name_from_id (id_in), + desc_in=> 'No description for "' + || name_from_id (id_in) + || '"', + rem_if_exists_in=> FALSE, + per_method_setup_in=>per_method_setup_in + ); + do_upd; + END IF; + &start81 COMMIT; &end81 + EXCEPTION + WHEN OTHERS + THEN + utplsql.pl ( 'Update suite error: ' + || SQLERRM); + &start81 ROLLBACK; &end81 + RAISE; + END; + + PROCEDURE upd ( + name_in IN ut_suite.name%TYPE, + start_in DATE, + end_in DATE, + successful_in BOOLEAN, + per_method_setup_in in ut_suite.per_method_setup%type := null + ) + IS + BEGIN + upd (id_from_name (name_in), start_in, end_in, successful_in, + per_method_setup_in); + END; + + FUNCTION suites (name_like_in IN VARCHAR2 := '%') + RETURN utconfig.refcur_t + IS + retval utconfig.refcur_t; + BEGIN + OPEN retval FOR + SELECT * + FROM ut_suite + WHERE NAME LIKE UPPER (name_like_in); + RETURN retval; + EXCEPTION + WHEN OTHERS + THEN + RETURN retval; + END; +END utsuite; +/ diff --git a/source/ut_suite.pks b/source/ut_suite.pks new file mode 100644 index 000000000..796d85ab9 --- /dev/null +++ b/source/ut_suite.pks @@ -0,0 +1,83 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE utsuite -- &start81 AUTHID CURRENT_USER &end81 +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + -- Unit Test Framework for PL/SQL + -- Steven Feuerstein, Copyright 2000, All rights reserved + -- steven@stevenfeuerstein.com + +/* +Modification history +Date Who What +07/2001 SEF Add onerow for V2 suite management. +09/08/2000 SEF NVL on updates of executions and failures +*/ + + /* Test suite API */ + + c_name CONSTANT CHAR (18) := 'TEST SUITE PACKAGE'; + c_abbrev CONSTANT CHAR (5) := 'SUITE'; + + FUNCTION name_from_id (id_in IN ut_suite.id%TYPE) + RETURN ut_suite.name%TYPE; + + FUNCTION id_from_name (name_in IN ut_suite.name%TYPE) + RETURN ut_suite.id%TYPE; + + FUNCTION onerow (name_in IN ut_suite.name%TYPE) + RETURN ut_suite%ROWTYPE; + + PROCEDURE ADD ( + name_in IN ut_suite.name%TYPE, + desc_in IN VARCHAR2 := NULL, + rem_if_exists_in IN BOOLEAN := TRUE, + per_method_setup_in in ut_suite.per_method_setup%type := null + + ); + + PROCEDURE rem (name_in IN ut_suite.name%TYPE); + + PROCEDURE rem (id_in IN ut_suite.id%TYPE); + + PROCEDURE upd ( + name_in IN ut_suite.name%TYPE, + start_in DATE, + end_in DATE, + successful_in BOOLEAN, + per_method_setup_in in ut_suite.per_method_setup%type := null + ); + + PROCEDURE upd ( + id_in IN ut_suite.id%TYPE, + start_in DATE, + end_in DATE, + successful_in BOOLEAN, + per_method_setup_in in ut_suite.per_method_setup%type := null + ); + + FUNCTION suites ( + name_like_in IN VARCHAR2 := '%' + ) + RETURN utconfig.refcur_t; +END utsuite; +/ diff --git a/source/ut_suite.tab b/source/ut_suite.tab new file mode 100644 index 000000000..7fc835a23 --- /dev/null +++ b/source/ut_suite.tab @@ -0,0 +1,19 @@ +CREATE TABLE ut_suite ( + id INTEGER, + name VARCHAR2(200), + description VARCHAR2(2000), + frequency VARCHAR2(2000), + created_by VARCHAR2(30), + created_on DATE, + executions INTEGER, -- V2 no longer used. see utr_suite + failures INTEGER, -- V2 no longer used. see utr_suite + last_status VARCHAR2(20), -- V2 no longer used. see utr_suite + last_start DATE, -- V2 no longer used. see utr_suite + last_end DATE, -- V2 no longer used. see utr_suite + per_method_setup char(1), -- 2.0.8.1 + CONSTRAINT ut_suite_pk PRIMARY KEY (id) +); + +CREATE unique index ut_suite_idx1 ON + ut_suite (name); + diff --git a/source/ut_suite_seq.seq b/source/ut_suite_seq.seq new file mode 100644 index 000000000..61195ee47 --- /dev/null +++ b/source/ut_suite_seq.seq @@ -0,0 +1 @@ +CREATE sequence ut_suite_seq INCREMENT BY 1 START WITH 1 ORDER NOCACHE; diff --git a/source/ut_suite_utp.tab b/source/ut_suite_utp.tab new file mode 100644 index 000000000..c22a938b5 --- /dev/null +++ b/source/ut_suite_utp.tab @@ -0,0 +1,11 @@ +create table ut_suite_utp ( +suite_id integer, +utp_id integer, +seq integer +); + +ALTER table ut_suite_utp add CONSTRAINT ut_suite_utp_pk + primary key (suite_id, utp_id); + +REM 2.1 - Allow enable/disable of individual packages in the suite. +ALTER table ut_suite_utp add enabled VARCHAR2(1); diff --git a/source/ut_suiteutp.pkb b/source/ut_suiteutp.pkb new file mode 100644 index 000000000..128270fd4 --- /dev/null +++ b/source/ut_suiteutp.pkb @@ -0,0 +1,182 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE BODY utsuiteutp -- &start81 AUTHID CURRENT_USER &end81 +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + -- Unit Test Framework for PL/SQL + -- Steven Feuerstein, Copyright 2000, All rights reserved + -- steven@stevenfeuerstein.com + + FUNCTION defined ( + suite_id_in IN ut_suite.id%TYPE, + utp_id_in IN ut_utp.id%TYPE + ) + RETURN BOOLEAN + IS + l_val CHAR (1); + BEGIN + SELECT 'x' + INTO l_val + FROM ut_suite_utp + WHERE suite_id = suite_id_in + AND utp_id_in = utp_id; + RETURN TRUE; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN FALSE; + END; + + FUNCTION seq ( + suite_id_in IN ut_suite.id%TYPE, + utp_id_in IN ut_utp.id%TYPE + ) + RETURN ut_suite_utp.seq%TYPE + IS + retval ut_suite_utp.seq%TYPE; + BEGIN + SELECT seq + INTO retval + FROM ut_suite_utp + WHERE suite_id = suite_id_in + AND utp_id_in = utp_id; + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END; + + FUNCTION enabled ( + suite_id_in IN ut_suite.id%TYPE, + utp_id_in IN ut_utp.id%TYPE + ) + RETURN ut_suite_utp.enabled%TYPE + IS + l_val ut_suite_utp.enabled%TYPE; + BEGIN + SELECT enabled + INTO l_val + FROM ut_suite_utp + WHERE suite_id = suite_id_in + AND utp_id_in = utp_id; + RETURN l_val; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END; + + PROCEDURE ADD ( + suite_id_in IN ut_suite.id%TYPE, + utp_id_in IN ut_utp.id%TYPE, + seq_in IN ut_suite_utp.seq%TYPE := NULL + ,enabled_in IN ut_suite_utp.enabled%TYPE := NULL + ) + IS + &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + BEGIN + utrerror.assert (suite_id_in IS NOT NULL, 'Suite ID cannot be null.'); + utrerror.assert (utp_id_in IS NOT NULL, 'UTP ID cannot be null.'); + + INSERT INTO ut_suite_utp + (suite_id, utp_id, seq, enabled) + VALUES (suite_id_in, utp_id_in, seq_in, enabled_in); + &start81 COMMIT; &end81 + EXCEPTION + WHEN DUP_VAL_ON_INDEX + THEN + -- already exists. Just ignore. + &start81 ROLLBACK; &end81 + NULL; + WHEN OTHERS + THEN + IF utrerror.uterrcode = utrerror.assertion_failure + THEN + &start81 ROLLBACK; &end81 + raise; + ELSE + + &start81 ROLLBACK; &end81 + utrerror.report_define_error ( + c_abbrev, + 'Suite ' + || suite_id_in + || ' UTP ' + || utp_id_in + ); + end if; + END; + + PROCEDURE rem ( + suite_id_in IN ut_suite.id%TYPE, + utp_id_in IN ut_utp.id%TYPE + ) + IS + &start81 + PRAGMA autonomous_transaction; + &end81 + BEGIN + DELETE FROM ut_suite_utp + WHERE suite_id = suite_id_in + AND utp_id = utp_id_in; + &start81 COMMIT; &end81 + EXCEPTION + WHEN OTHERS + THEN + utplsql.pl ( 'Remove suite-utp error: ' + || SQLERRM); + &start81 ROLLBACK; &end81 + RAISE; + END; + + + FUNCTION utps ( + suite_in in ut_suite.id%TYPE + ) + RETURN utconfig.refcur_t + IS + retval utconfig.refcur_t; + BEGIN + OPEN retval FOR + SELECT u.program, u.name, u.id utp_id, su.enabled + FROM ut_utp u, ut_suite_utp su + WHERE su.suite_id = suite_in + and su.utp_id = u.id; + RETURN retval; + EXCEPTION + WHEN OTHERS + THEN + RETURN retval; + END; + + FUNCTION utps ( + suite_in in ut_suite.name%TYPE + ) + RETURN utconfig.refcur_t + IS + retval utconfig.refcur_t; + BEGIN + return utps (utsuite.id_from_name (suite_in)); + END; +END utsuiteutp; +/ diff --git a/source/ut_suiteutp.pks b/source/ut_suiteutp.pks new file mode 100644 index 000000000..dac67c041 --- /dev/null +++ b/source/ut_suiteutp.pks @@ -0,0 +1,70 @@ +CREATE OR REPLACE PACKAGE utsuiteutp -- &start81 AUTHID CURRENT_USER &end81 +IS +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + -- Unit Test Framework for PL/SQL + -- Steven Feuerstein, Copyright 2000, All rights reserved + -- steven@stevenfeuerstein.com + + c_name CONSTANT CHAR (18) := 'SUITE-UTP PACKAGE'; + c_abbrev CONSTANT CHAR (9) := 'SUITE-UTP'; + + FUNCTION defined ( + suite_id_in IN ut_suite.ID%TYPE + ,utp_id_in IN ut_utp.ID%TYPE + ) + RETURN BOOLEAN; + + FUNCTION seq ( + suite_id_in IN ut_suite.ID%TYPE + ,utp_id_in IN ut_utp.ID%TYPE + ) + RETURN ut_suite_utp.seq%TYPE; + + PROCEDURE ADD ( + suite_id_in IN ut_suite.ID%TYPE + ,utp_id_in IN ut_utp.ID%TYPE + ,seq_in IN ut_suite_utp.seq%TYPE := NULL + ,enabled_in IN ut_suite_utp.enabled%TYPE := NULL + ); + + FUNCTION enabled ( + suite_id_in IN ut_suite.ID%TYPE + ,utp_id_in IN ut_utp.ID%TYPE + ) + RETURN ut_suite_utp.enabled%TYPE; + + PROCEDURE REM ( + suite_id_in IN ut_suite.ID%TYPE + ,utp_id_in IN ut_utp.ID%TYPE + ); + + FUNCTION utps ( + suite_in in ut_suite.name%TYPE + ) + RETURN utconfig.refcur_t; + + FUNCTION utps ( + suite_in in ut_suite.id%TYPE + ) + RETURN utconfig.refcur_t; +END utsuiteutp; +/ diff --git a/source/ut_test.pkb b/source/ut_test.pkb new file mode 100644 index 000000000..98893e56f --- /dev/null +++ b/source/ut_test.pkb @@ -0,0 +1,172 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE BODY uttest +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + FUNCTION name_from_id (id_in IN ut_test.id%TYPE) + RETURN ut_test.name%TYPE + IS + retval ut_test.name%TYPE; + BEGIN + SELECT name + INTO retval + FROM ut_test + WHERE id = id_in; + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END; + + FUNCTION id_from_name (name_in IN ut_test.name%TYPE) + RETURN ut_test.id%TYPE + IS + retval ut_test.id%TYPE; + BEGIN + SELECT name + INTO retval + FROM ut_test + WHERE name = UPPER (name_in); + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END; + + PROCEDURE ADD ( + package_in IN INTEGER, + test_in IN VARCHAR2, + desc_in IN VARCHAR2 := NULL, + seq_in IN PLS_INTEGER := NULL + ) + IS + &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + v_id ut_test.id%TYPE; + BEGIN + &start81 v_id := utplsql.seqval ('ut_test'); &end81 + &start73 SELECT ut_test_seq.NEXTVAL INTO v_id FROM dual; &end73 + + INSERT INTO ut_test + (id, package_id, name, description, + seq) + VALUES (v_id, package_in, UPPER (test_in), desc_in, + NVL (seq_in, 1)); + &start81 COMMIT; &end81 + EXCEPTION + WHEN OTHERS + THEN + utplsql.pl ( 'Add test error: ' + || SQLERRM); + &start81 ROLLBACK; &end81 + RAISE; + END; + + PROCEDURE ADD ( + package_in IN VARCHAR2, + test_in IN VARCHAR2, + desc_in IN VARCHAR2 := NULL, + seq_in IN PLS_INTEGER := NULL + ) + IS + BEGIN + ADD (utpackage.id_from_name (package_in), test_in, desc_in, seq_in); + END; + + PROCEDURE rem (package_in IN INTEGER, test_in IN VARCHAR2) + IS + &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + BEGIN + DELETE FROM ut_test + WHERE package_id = package_in + AND name LIKE UPPER (test_in); + &start81 COMMIT; &end81 + EXCEPTION + WHEN OTHERS + THEN + utplsql.pl ( 'Remove test error: ' + || SQLERRM); + &start81 ROLLBACK; &end81 + RAISE; + END; + + PROCEDURE rem (package_in IN VARCHAR2, test_in IN VARCHAR2) + IS + BEGIN + rem (utpackage.id_from_name (package_in), test_in); + END; + + PROCEDURE upd ( + package_in IN INTEGER, + test_in IN VARCHAR2, + start_in DATE, + end_in DATE, + successful_in BOOLEAN + ) + IS + &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + v_failure PLS_INTEGER := 0; + BEGIN + IF NOT successful_in + THEN + v_failure := 1; + END IF; + + UPDATE ut_test + SET last_start = start_in, + last_end = end_in, + executions = executions + + 1, + failures = failures + + v_failure + WHERE package_id = package_in + AND name = UPPER (test_in); + &start81 COMMIT; &end81 + EXCEPTION + WHEN OTHERS + THEN + utplsql.pl ( 'Update test error: ' + || SQLERRM); + &start81 ROLLBACK; &end81 + RAISE; + END; + + PROCEDURE upd ( + package_in IN VARCHAR2, + test_in IN VARCHAR2, + start_in DATE, + end_in DATE, + successful_in BOOLEAN + ) + IS + BEGIN + upd ( + utpackage.id_from_name (package_in), + test_in, + start_in, + end_in, + successful_in + ); + END; +END uttest; +/ diff --git a/source/ut_test.pks b/source/ut_test.pks new file mode 100644 index 000000000..2715a12b1 --- /dev/null +++ b/source/ut_test.pks @@ -0,0 +1,69 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE uttest -- &start81 AUTHID CURRENT_USER &end81 +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + -- Unit Test Framework for PL/SQL + -- Steven Feuerstein, Copyright 2000, All rights reserved + -- steven@stevenfeuerstein.com + + FUNCTION name_from_id (id_in IN ut_test.id%TYPE) + RETURN ut_test.name%TYPE; + + FUNCTION id_from_name (name_in IN ut_test.name%TYPE) + RETURN ut_test.id%TYPE; + + PROCEDURE ADD ( + package_in IN INTEGER, + test_in IN VARCHAR2, + desc_in IN VARCHAR2 := NULL, + seq_in IN PLS_INTEGER := NULL + ); + + PROCEDURE ADD ( + package_in IN VARCHAR2, + test_in IN VARCHAR2, + desc_in IN VARCHAR2 := NULL, + seq_in IN PLS_INTEGER := NULL + ); + + PROCEDURE rem (package_in IN INTEGER, test_in IN VARCHAR2); + + PROCEDURE rem (package_in IN VARCHAR2, test_in IN VARCHAR2); + + PROCEDURE upd ( + package_in IN INTEGER, + test_in IN VARCHAR2, + start_in DATE, + end_in DATE, + successful_in BOOLEAN + ); + + PROCEDURE upd ( + package_in IN VARCHAR2, + test_in IN VARCHAR2, + start_in DATE, + end_in DATE, + successful_in BOOLEAN + ); +END uttest; +/ diff --git a/source/ut_test.tab b/source/ut_test.tab new file mode 100644 index 000000000..9248386c8 --- /dev/null +++ b/source/ut_test.tab @@ -0,0 +1,19 @@ +CREATE TABLE ut_test ( + id INTEGER , + package_id INTEGER, + name VARCHAR2(200), + description VARCHAR2(2000), + seq INTEGER, + executions INTEGER, + failures INTEGER, + last_start DATE, + last_end DATE, + CONSTRAINT ut_test_pk PRIMARY KEY (id) +); + +CREATE unique index ut_test_idx1 ON + ut_test (name); + +ALTER table ut_test add CONSTRAINT ut_test_package_fk + FOREIGN KEY (package_id) REFERENCES ut_package; + diff --git a/source/ut_test_seq.seq b/source/ut_test_seq.seq new file mode 100644 index 000000000..86b102997 --- /dev/null +++ b/source/ut_test_seq.seq @@ -0,0 +1 @@ +CREATE sequence ut_test_seq INCREMENT BY 1 START WITH 1 ORDER NOCACHE; diff --git a/source/ut_testcase.pkb b/source/ut_testcase.pkb new file mode 100644 index 000000000..b556dc178 --- /dev/null +++ b/source/ut_testcase.pkb @@ -0,0 +1,171 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE BODY uttestcase +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + FUNCTION name_from_id (id_in IN ut_testcase.id%TYPE) + RETURN ut_testcase.name%TYPE + IS + retval ut_testcase.name%TYPE; + BEGIN + SELECT name + INTO retval + FROM ut_testcase + WHERE id = id_in; + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END; + + FUNCTION id_from_name (name_in IN ut_testcase.name%TYPE) + RETURN ut_testcase.id%TYPE + IS + retval ut_testcase.id%TYPE; + BEGIN + SELECT name + INTO retval + FROM ut_testcase + WHERE name = UPPER (name_in); + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END; + + PROCEDURE ADD ( + test_in IN INTEGER, + testcase_in IN VARCHAR2, + desc_in IN VARCHAR2 := NULL, + seq_in IN PLS_INTEGER := NULL + ) + IS + &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + v_id ut_testcase.id%TYPE; + BEGIN + &start81 v_id := utplsql.seqval ('ut_testcase'); &end81 + &start73 SELECT ut_testcase_seq.NEXTVAL INTO v_id FROM dual; &end73 + INSERT INTO ut_testcase + (id, test_id, name, description, + seq) + VALUES (v_id, test_in, UPPER (testcase_in), desc_in, + NVL (seq_in, 1)); + &start81 COMMIT; &end81 + EXCEPTION + WHEN OTHERS + THEN + utplsql.pl ( 'Add test error: ' + || SQLERRM); + &start81 ROLLBACK; &end81 + RAISE; + END; + + PROCEDURE ADD ( + test_in IN VARCHAR2, + testcase_in IN VARCHAR2, + desc_in IN VARCHAR2 := NULL, + seq_in IN PLS_INTEGER := NULL + ) + IS + BEGIN + ADD (uttest.id_from_name (test_in), testcase_in, desc_in, seq_in); + END; + + PROCEDURE rem (test_in IN INTEGER, testcase_in IN VARCHAR2) + IS + &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + BEGIN + DELETE FROM ut_testcase + WHERE test_id = test_in + AND name LIKE UPPER (testcase_in); + &start81 COMMIT; &end81 + EXCEPTION + WHEN OTHERS + THEN + utplsql.pl ( 'Remove test error: ' + || SQLERRM); + &start81 ROLLBACK; &end81 + RAISE; + END; + + PROCEDURE rem (test_in IN VARCHAR2, testcase_in IN VARCHAR2) + IS + BEGIN + rem (uttest.id_from_name (test_in), testcase_in); + END; + + PROCEDURE upd ( + test_in IN INTEGER, + testcase_in IN VARCHAR2, + start_in DATE, + end_in DATE, + successful_in BOOLEAN + ) + IS + &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + v_failure PLS_INTEGER := 0; + BEGIN + IF NOT successful_in + THEN + v_failure := 1; + END IF; + + UPDATE ut_testcase + SET last_start = start_in, + last_end = end_in, + executions = executions + + 1, + failures = failures + + v_failure + WHERE test_id = test_in + AND name = UPPER (testcase_in); + &start81 COMMIT; &end81 + EXCEPTION + WHEN OTHERS + THEN + utplsql.pl ( 'Update test error: ' + || SQLERRM); + &start81 ROLLBACK; &end81 + RAISE; + END; + + PROCEDURE upd ( + test_in IN VARCHAR2, + testcase_in IN VARCHAR2, + start_in DATE, + end_in DATE, + successful_in BOOLEAN + ) + IS + BEGIN + upd ( + uttest.id_from_name (test_in), + testcase_in, + start_in, + end_in, + successful_in + ); + END; +END uttestcase; +/ diff --git a/source/ut_testcase.pks b/source/ut_testcase.pks new file mode 100644 index 000000000..92faaf180 --- /dev/null +++ b/source/ut_testcase.pks @@ -0,0 +1,72 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE uttestcase -- &start81 AUTHID CURRENT_USER &end81 +IS + +/* +GNU General Public License for utPLSQL + +Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + -- Unit Test Framework for PL/SQL + -- Steven Feuerstein, Copyright 2000, All rights reserved + -- steven@stevenfeuerstein.com + + c_name CONSTANT CHAR (9) := 'TEST CASE'; + c_abbrev CONSTANT CHAR (3) := 'TC'; + + FUNCTION name_from_id (id_in IN ut_testcase.id%TYPE) + RETURN ut_testcase.name%TYPE; + + FUNCTION id_from_name (name_in IN ut_testcase.name%TYPE) + RETURN ut_testcase.id%TYPE; + + PROCEDURE ADD ( + test_in IN INTEGER, + testcase_in IN VARCHAR2, + desc_in IN VARCHAR2 := NULL, + seq_in IN PLS_INTEGER := NULL + ); + + PROCEDURE ADD ( + test_in IN VARCHAR2, + testcase_in IN VARCHAR2, + desc_in IN VARCHAR2 := NULL, + seq_in IN PLS_INTEGER := NULL + ); + + PROCEDURE rem (test_in IN INTEGER, testcase_in IN VARCHAR2); + + PROCEDURE rem (test_in IN VARCHAR2, testcase_in IN VARCHAR2); + + PROCEDURE upd ( + test_in IN INTEGER, + testcase_in IN VARCHAR2, + start_in DATE, + end_in DATE, + successful_in BOOLEAN + ); + + PROCEDURE upd ( + test_in IN VARCHAR2, + testcase_in IN VARCHAR2, + start_in DATE, + end_in DATE, + successful_in BOOLEAN + ); +END uttestcase; +/ diff --git a/source/ut_testcase.tab b/source/ut_testcase.tab new file mode 100644 index 000000000..258e96f9d --- /dev/null +++ b/source/ut_testcase.tab @@ -0,0 +1,31 @@ +CREATE TABLE ut_testcase ( + id INTEGER, + unittest_id INTEGER, + name VARCHAR2(200), + seq integer DEFAULT 1, + description VARCHAR2(2000), + status VARCHAR2(20), /* ENABLED or DISABLED */ + declarations varchar2(2000), + setup varchar2(2000), + teardown varchar2(2000), + exceptions varchar2(2000), + /* From here down, for v1 compatibility only */ + test_id INTEGER, + prefix VARCHAR2(200), + assertion VARCHAR2(100), + inline_assertion_call CHAR(1) DEFAULT 'N', + executions INTEGER, + failures INTEGER, + last_start DATE, + last_end DATE, + CONSTRAINT ut_testcase_pk PRIMARY KEY (id) +) +/ + +CREATE unique index ut_testcase_idx1 ON + ut_testcase (name); + +ALTER table ut_testcase add CONSTRAINT ut_testcase_unitest_fk + FOREIGN KEY (unittest_id) REFERENCES ut_unittest; + + diff --git a/source/ut_testcase_seq.seq b/source/ut_testcase_seq.seq new file mode 100644 index 000000000..4b608a9a6 --- /dev/null +++ b/source/ut_testcase_seq.seq @@ -0,0 +1 @@ +CREATE sequence ut_testcase_seq INCREMENT BY 1 START WITH 1 ORDER NOCACHE; diff --git a/source/ut_testprep.pkb b/source/ut_testprep.pkb new file mode 100644 index 000000000..3ffc8d3cf --- /dev/null +++ b/source/ut_testprep.pkb @@ -0,0 +1,18 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE BODY uttestprep +IS + FUNCTION setup_program (utp_in IN ut_utp%ROWTYPE) + RETURN VARCHAR2 + IS + BEGIN + return null; + END setup_program; + + FUNCTION teardown_program (utp_in IN ut_utp%ROWTYPE) + RETURN VARCHAR2 + IS + BEGIN + return null; + END teardown_program; +END; +/ diff --git a/source/ut_testprep.pks b/source/ut_testprep.pks new file mode 100644 index 000000000..92438ddc6 --- /dev/null +++ b/source/ut_testprep.pks @@ -0,0 +1,11 @@ +/* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE uttestprep +-- NO LONGER USED. +IS + FUNCTION setup_program (utp_in IN ut_utp%ROWTYPE) + RETURN VARCHAR2; + + FUNCTION teardown_program (utp_in IN ut_utp%ROWTYPE) + RETURN VARCHAR2; +END; +/ diff --git a/source/ut_testprep.tab b/source/ut_testprep.tab new file mode 100644 index 000000000..225e0a129 --- /dev/null +++ b/source/ut_testprep.tab @@ -0,0 +1,13 @@ +CREATE TABLE ut_testprep ( +id integer, +type varchar2(20), +name varchar2(200), +action_level varchar2(10), +prep_id integer, +declarations varchar2 (2000), +setup varchar2 (2000), +teardown varchar2 (2000), + CONSTRAINT ut_testprep_pk PRIMARY KEY (id) +); + + diff --git a/source/ut_unittest.pkb b/source/ut_unittest.pkb new file mode 100644 index 000000000..9d55f6b21 --- /dev/null +++ b/source/ut_unittest.pkb @@ -0,0 +1,166 @@ +/* Formatted on 2001/07/14 08:45 (RevealNet Formatter v4.4.1) */ + +CREATE OR REPLACE PACKAGE BODY utunittest +IS + FUNCTION name ( + ut_in IN ut_unittest%ROWTYPE + ) + RETURN VARCHAR2 + IS + BEGIN + RETURN c_abbrev || utconfig.delimiter || ut_in.id; + END name; + + FUNCTION name ( + id_in IN ut_unittest.id%TYPE + ) + RETURN VARCHAR2 is rec ut_unittest%rowtype; + begin + rec := onerow (id_in); + return name (rec); end; + + +FUNCTION full_name ( + utp_in IN ut_utp%ROWTYPE, + ut_in IN ut_unittest%ROWTYPE + ) + RETURN VARCHAR2 + IS + BEGIN + RETURN ututp.qualified_name (utp_in) || '.' + || name (ut_in.id); + END full_name; + + FUNCTION onerow (id_in IN ut_unittest.id%TYPE) + RETURN ut_unittest%ROWTYPE + IS + retval ut_unittest%ROWTYPE; + empty_rec ut_unittest%ROWTYPE; + BEGIN + SELECT * + INTO retval + FROM ut_unittest + WHERE id = id_in; + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN empty_rec; + END; + + FUNCTION program_name (id_in IN ut_unittest.id%TYPE) + RETURN ut_unittest.program_name%TYPE + IS + retval ut_unittest.program_name%TYPE; + BEGIN + SELECT program_name + INTO retval + FROM ut_unittest + WHERE id = id_in; + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + END; + + FUNCTION id (name_in IN VARCHAR2) + RETURN ut_unittest.id%TYPE + IS + l_delimiter ut_config.delimiter%TYPE := utconfig.delimiter; + l_loc PLS_INTEGER; + retval ut_unittest.id%TYPE; + BEGIN + l_loc := INSTR (name_in, l_delimiter); + + IF l_loc = 0 + THEN + RETURN NULL; + ELSE + RETURN to_number (SUBSTR (name_in, l_loc + + LENGTH (l_delimiter)) + ); + END IF; + end; + + PROCEDURE ADD ( + utp_id_in IN ut_unittest.utp_id%TYPE, + program_name_in IN ut_unittest.program_name%TYPE, + seq_in IN ut_unittest.seq%TYPE := NULL, + description_in IN ut_unittest.description%TYPE + := NULL + ) + IS + &start81 + PRAGMA autonomous_transaction; + &end81 + l_id ut_unittest.id%TYPE; + BEGIN + SELECT ut_unittest_seq.NEXTVAL + INTO l_id + FROM DUAL; + + INSERT INTO ut_unittest + (id, program_name, seq, + description) + VALUES (l_id, UPPER (program_name_in), seq_in, description_in); + + &start81 + COMMIT; + &end81 + EXCEPTION + WHEN OTHERS + THEN + IF utrerror.uterrcode = utrerror.assertion_failure + THEN + &start81 ROLLBACK; &end81 + RAISE; + ELSE + &start81 ROLLBACK; &end81 + utrerror.report_define_error ( + c_abbrev, + 'Unittest for ' + || program_name_in + || ' UTP ID ' + || utp_id_in + ); + END IF; + END; + + PROCEDURE rem ( + name_in IN varchar2 + ) + IS begin rem (id (name_in)); + END; + + PROCEDURE rem (id_in IN ut_unittest.id%TYPE) + IS + &start81 + PRAGMA autonomous_transaction; + &end81 + BEGIN + DELETE FROM ut_unittest + WHERE id = id_in; + + &start81 + COMMIT; + &end81 + EXCEPTION + WHEN OTHERS + THEN + IF utrerror.uterrcode = utrerror.assertion_failure + THEN + &start81 ROLLBACK; &end81 + RAISE; + ELSE + &start81 ROLLBACK; &end81 + utrerror.report_define_error ( + c_abbrev, + 'Unittest ID ' + || id_in + ); + END IF; + END; +END utunittest; +/ + diff --git a/source/ut_unittest.pks b/source/ut_unittest.pks new file mode 100644 index 000000000..048b90f1e --- /dev/null +++ b/source/ut_unittest.pks @@ -0,0 +1,49 @@ +/* Formatted on 2001/07/13 17:50 (RevealNet Formatter v4.4.0) */ +CREATE OR REPLACE PACKAGE utunittest +IS + c_name CONSTANT CHAR (9) := 'UNIT TEST'; + c_abbrev CONSTANT CHAR (2) := 'UT'; + + /* UT##NNN */ + FUNCTION name ( + ut_in IN ut_unittest%ROWTYPE + ) + RETURN VARCHAR2; + + /* SCHEMA.UTP##NNN.UT##NNN */ + FUNCTION full_name ( + utp_in IN ut_utp%ROWTYPE, + ut_in IN ut_unittest%ROWTYPE + ) + RETURN VARCHAR2; + + FUNCTION name ( + id_in IN ut_unittest.id%TYPE + ) + RETURN VARCHAR2; + + FUNCTION onerow (id_in IN ut_unittest.id%TYPE) + RETURN ut_unittest%ROWTYPE; + + FUNCTION program_name (id_in IN ut_unittest.id%TYPE) + RETURN ut_unittest.program_name%TYPE; + + FUNCTION id (name_in IN VARCHAR2) + RETURN ut_unittest.id%TYPE; + + PROCEDURE ADD ( + utp_id_in IN ut_unittest.utp_id%TYPE, + program_name_in IN ut_unittest.program_name%TYPE, + seq_in IN ut_unittest.seq%TYPE := NULL, + description_in IN ut_unittest.description%TYPE + := NULL + ); + + PROCEDURE rem ( + name_in IN VARCHAR2 + ); + + PROCEDURE rem (id_in IN ut_unittest.id%TYPE); +END; +/ + diff --git a/source/ut_unittest.tab b/source/ut_unittest.tab new file mode 100644 index 000000000..236deff91 --- /dev/null +++ b/source/ut_unittest.tab @@ -0,0 +1,19 @@ +CREATE TABLE ut_unittest ( +id INTEGER, +utp_id INTEGER, +program_name VARCHAR2(30), +overload INTEGER, /* overloading in the package definition */ +seq INTEGER, +description VARCHAR2(2000), +status VARCHAR2(20), /* ENABLED or DISABLED */ +is_deterministic CHAR(1), +declarations varchar2(2000), +setup varchar2(2000), +teardown varchar2(2000), +exceptions varchar2(2000), + CONSTRAINT ut_unittest_pk PRIMARY KEY (id) +); + +ALTER TABLE ut_unittest ADD CONSTRAINT ut_unittest_utp_fk + FOREIGN KEY (utp_id) REFERENCES ut_utp; + diff --git a/source/ut_unittest_seq.seq b/source/ut_unittest_seq.seq new file mode 100644 index 000000000..f84bfe20b --- /dev/null +++ b/source/ut_unittest_seq.seq @@ -0,0 +1 @@ +CREATE sequence ut_unittest_seq INCREMENT BY 1 START WITH 1 ORDER NOCACHE; diff --git a/source/ut_utoutput.pkb b/source/ut_utoutput.pkb new file mode 100644 index 000000000..5da9d10a4 --- /dev/null +++ b/source/ut_utoutput.pkb @@ -0,0 +1,193 @@ +CREATE OR REPLACE PACKAGE BODY ut_utoutput +IS + + PROCEDURE clear_buffer + IS + lines number; + buffer DBMS_OUTPUT.CHARARR; + BEGIN + lines := 1000000; + dbms_output.get_lines(buffer, lines); + END; + + PROCEDURE ut_setup + IS + BEGIN + NULL; + END; + + PROCEDURE ut_teardown + IS + BEGIN + NULL; + END; + + PROCEDURE ut_count + IS + BEGIN + + clear_buffer; + + utassert.eq('Count Empty buffer', utoutput.count, 0); + + dbms_output.put_line('XYZ'); + + utassert.eq('Count Single Line', utoutput.count, 1); + + utassert.eq('Count Single Line Still Present', utoutput.count, 1); + + dbms_output.put_line('ABC'); + + utassert.eq('Count Two Lines', utoutput.count, 2); + + clear_buffer; + + END ut_count; + + PROCEDURE ut_extract + IS + + buf dbms_output.CHARARR; + buf2 dbms_output.CHARARR; + + BEGIN + + utoutput.replace; + clear_buffer; + + dbms_output.put_line('Alpha'); + dbms_output.put_line('Beta'); + dbms_output.put_line('Gamma'); + + utoutput.save; + utassert.eq('Pull one line', utoutput.extract(max_lines_in => 1, + save_in => FALSE), 1); + utassert.eq('Pull two lines', utoutput.extract(buffer_out => buf, + max_lines_in => 2, + save_in => FALSE), 2); + utassert.eq('How Many Lines Pulled', buf.COUNT, 2); + utassert.eq('First Line Pulled', buf(buf.FIRST), 'Beta'); + utassert.eq('Second Line Pulled', buf(buf.NEXT(buf.FIRST)), 'Gamma'); + + clear_buffer; + + dbms_output.put_line('Al'); + dbms_output.put_line('Ben'); + dbms_output.put_line('Carol'); + dbms_output.put_line('Donna'); + + utoutput.extract(max_lines_in => 1); + utoutput.extract(buffer_out => buf); + + utassert.eq('2: How Many Lines Pulled', buf.COUNT, 3); + utassert.eq('2: First Line Pulled', buf(buf.FIRST), 'Ben'); + utassert.eq('2: Second Line Pulled', buf(buf.NEXT(buf.FIRST)), 'Carol'); + utassert.eq('2: Third Line Pulled', buf(buf.NEXT(buf.NEXT(buf.FIRST))), 'Donna'); + + utoutput.replace; + + utassert.eq('Count Lines Collected and Replaced', utoutput.COUNT, 4); + + clear_buffer; + + END ut_extract; + + PROCEDURE ut_nextline + IS + BEGIN + + clear_buffer; + + utassert.isnull('NextLine Empty Buffer', utoutput.nextline(raise_exc_in => FALSE, save_in => FALSE)); + utassert.throws('NextLine Empty Buffer with Exception', + 'declare + v varchar2(2000); + begin + v := utoutput.nextline(raise_exc_in => TRUE, save_in => FALSE); + end;', + 'utoutput.EMPTY_OUTPUT_BUFFER'); + + dbms_output.put_line('DEF'); + dbms_output.put_line('GHI'); + + utassert.eq('NextLine Typical 1', utoutput.nextline(raise_exc_in => FALSE, save_in => FALSE), 'DEF'); + utassert.eq('NextLine Typical 2', utoutput.nextline(raise_exc_in => FALSE, save_in => FALSE), 'GHI'); + + utassert.isnull('NextLine Empty Buffer Again', utoutput.nextline(raise_exc_in => FALSE, save_in => FALSE)); + + clear_buffer; + + END ut_nextline; + + PROCEDURE ut_replace + IS + + dummy VARCHAR2(2000); + + BEGIN + + utoutput.replace; + clear_buffer; + + --Put in some text, extract, then replace it + dbms_output.put_line('JKL'); + dummy := utoutput.nextline(raise_exc_in => FALSE, save_in => TRUE); + utoutput.replace; + + --Extract again, but don't save + dummy := utoutput.nextline(raise_exc_in => FALSE, save_in => FALSE); + utassert.eq('NextLine after replace', dummy, 'JKL'); + + --Try replacing when there should be nothing to replace + utoutput.replace; + + dummy := utoutput.nextline(raise_exc_in => FALSE, save_in => FALSE); + utassert.isnull('NextLine after empty replace', dummy); + + dbms_output.put_line('MNO'); + dbms_output.put_line('PQR'); + + --Pull out all the data, but save it + utoutput.save; + utoutput.extract(max_lines_in => 1000); + utoutput.nosave; + + --It should be empty now + dummy := utoutput.nextline(raise_exc_in => FALSE); + utassert.isnull('NextLine after full extract', dummy); + + --Put it back + utoutput.replace; + + utassert.eq('Count after multi-replace', utoutput.count, 2); + + utassert.eq('NextLine after multi-replace', utoutput.nextline, 'MNO'); + utassert.eq('NextLine again after multi-replace', utoutput.nextline, 'PQR'); + + --Make sure all is clear + utoutput.replace; + clear_buffer; + + END ut_replace; + + PROCEDURE ut_saving + IS + BEGIN + + utoutput.save; + + utassert.this('Saving Turned On', utoutput.saving); + + utoutput.nosave; + + utassert.this('Saving Turned Off', NOT utoutput.saving); + + utoutput.save; + + utassert.this('Saving Turned Back On', utoutput.saving); + + END ut_saving; + +END ut_utoutput; + +/ diff --git a/source/ut_utoutput.pks b/source/ut_utoutput.pks new file mode 100644 index 000000000..582896d8b --- /dev/null +++ b/source/ut_utoutput.pks @@ -0,0 +1,14 @@ +CREATE OR REPLACE PACKAGE ut_utoutput +IS + PROCEDURE ut_setup; + PROCEDURE ut_teardown; + + -- For each program to test... + PROCEDURE ut_count; + PROCEDURE ut_extract; + PROCEDURE ut_nextline; + PROCEDURE ut_replace; + PROCEDURE ut_saving; + +END ut_utoutput; +/ diff --git a/source/ut_utp.pkb b/source/ut_utp.pkb new file mode 100644 index 000000000..473e7e817 --- /dev/null +++ b/source/ut_utp.pkb @@ -0,0 +1,382 @@ +/* Formatted on 2001/09/14 10:34 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE BODY ututp +IS + /* UTP##NNN */ + FUNCTION name (utp_in IN ut_utp%ROWTYPE) + RETURN VARCHAR2 + IS + BEGIN + RETURN c_abbrev + || utconfig.delimiter + || utp_in.id; + END; + + FUNCTION name (id_in IN ut_utp.id%TYPE) + RETURN VARCHAR2 + IS + rec ut_utp%ROWTYPE; + BEGIN + rec := onerow (id_in); + RETURN name (rec); + END; + + /* schema.UTP##NNN */ + FUNCTION qualified_name (utp_in IN ut_utp%ROWTYPE) + RETURN VARCHAR2 + IS + BEGIN + RETURN utp_in.owner + || '.' + || name (utp_in); + END; + + FUNCTION qualified_name (id_in IN ut_utp.id%TYPE) + RETURN VARCHAR2 + IS + rec ut_utp%ROWTYPE; + BEGIN + rec := onerow (id_in); + RETURN qualified_name (rec); + END; + + FUNCTION setup_procedure (utp_in IN ut_utp%ROWTYPE) + RETURN VARCHAR2 + IS + BEGIN + RETURN utp_in.owner + || '.' + || name (utp_in) + || '.' + || utplsql.c_setup; + END; + + FUNCTION teardown_procedure (utp_in IN ut_utp%ROWTYPE) + RETURN VARCHAR2 + IS + BEGIN + RETURN utp_in.owner + || '.' + || name (utp_in) + || '.' + || utplsql.c_teardown; + END; + + FUNCTION prefix (utp_in IN ut_utp%ROWTYPE) + RETURN VARCHAR2 + IS + BEGIN + RETURN utp_in.prefix; + END; + + FUNCTION onerow ( + owner_in IN ut_utp.owner%TYPE, + program_in IN ut_utp.program%TYPE + ) + RETURN ut_utp%ROWTYPE + IS + retval ut_utp%ROWTYPE; + empty_rec ut_utp%ROWTYPE; + BEGIN + SELECT * + INTO retval + FROM ut_utp + WHERE owner = NVL (UPPER (owner_in), USER) + AND program = UPPER (program_in); + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN empty_rec; + END; + + PROCEDURE get_onerow ( + owner_in IN ut_utp.owner%TYPE + ,program_in IN ut_utp.program%TYPE + ,id_out OUT ut_utp.ID%TYPE + ,description_out OUT ut_utp.description%TYPE + ,filename_out OUT ut_utp.filename%TYPE + ,program_directory_out OUT ut_utp.program_directory%TYPE + ,directory_out OUT ut_utp.DIRECTORY%TYPE + ,name_out OUT ut_utp.NAME%TYPE + ,utp_owner_out OUT ut_utp.utp_owner%TYPE + ,prefix_out OUT ut_utp.prefix%TYPE + ) + is + rec ut_utp%rowtype; + begin + rec := onerow (owner_in, program_in); + id_out := rec.id; + if rec.id is not null then +description_out := rec.description; +filename_out := rec.filename; +program_directory_out := rec.program_directory; +directory_out := rec.directory; +name_out := rec.name; +utp_owner_out := rec.utp_owner; +prefix_out := rec.prefix; + + end if; + end get_onerow; + + FUNCTION exists ( + owner_in IN ut_utp.owner%TYPE, + program_in IN ut_utp.program%TYPE + ) + RETURN Boolean + IS + retval char(1); + + BEGIN + SELECT 'x' + INTO retval + FROM ut_utp + WHERE owner = NVL (UPPER (owner_in), USER) + AND program = UPPER (program_in); + RETURN true; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN false; + END; + + FUNCTION onerow (utp_id_in IN ut_utp.id%TYPE) + RETURN ut_utp%ROWTYPE + IS + retval ut_utp%ROWTYPE; + empty_rec ut_utp%ROWTYPE; + BEGIN + SELECT * + INTO retval + FROM ut_utp + WHERE id = utp_id_in; + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN empty_rec; + END; + + FUNCTION id (name_in IN VARCHAR2) + RETURN ut_utp.id%TYPE + IS + l_delimiter ut_config.delimiter%TYPE := utconfig.delimiter; + l_loc PLS_INTEGER; + retval ut_utp.id%TYPE; + BEGIN + l_loc := INSTR (name_in, l_delimiter); + + IF l_loc = 0 + THEN + RETURN NULL; + ELSE + RETURN to_number (SUBSTR (name_in, l_loc + + LENGTH (l_delimiter)) + ); + END IF; + /* Use new formula; no query required + SELECT id + INTO retval + FROM ut_utp + WHERE name = UPPER (name_in); + RETURN retval; + EXCEPTION + WHEN NO_DATA_FOUND + THEN + RETURN NULL; + */ + END; + + PROCEDURE ADD ( + program_in IN ut_utp.program%TYPE := NULL, + owner_in IN ut_utp.owner%TYPE := NULL, + description_in IN ut_utp.description%TYPE := NULL, + filename_in IN ut_utp.filename%TYPE := NULL, + frequency_in IN ut_utp.frequency%TYPE := NULL, + program_map_in IN ut_utp.program_map%TYPE := NULL, + declarations_in IN ut_utp.declarations%TYPE + := NULL, + setup_in IN ut_utp.setup%TYPE := NULL, + teardown_in IN ut_utp.teardown%TYPE := NULL, + exceptions_in IN ut_utp.exceptions%TYPE := NULL, + program_directory_in IN ut_utp.program_directory%TYPE := NULL, + directory_in IN ut_utp.directory%TYPE := NULL, + name_in IN ut_utp.name%TYPE := NULL, + utp_owner_in IN ut_utp.utp_owner%TYPE := NULL, + prefix_in IN ut_utp.prefix%TYPE := NULL, + id_out OUT ut_utp.id%TYPE + ) + IS + &start81 + PRAGMA autonomous_transaction; + &end81 + l_id ut_utp.id%TYPE; + l_program ut_utp.name%type := program_in; + BEGIN + if l_program not like '"%' then l_program := upper (l_program); end if; + SELECT ut_utp_seq.NEXTVAL + INTO l_id + FROM DUAL; + + INSERT INTO ut_utp + (id, program, + owner, description, filename, + frequency, program_map, declarations, + setup, teardown, program_directory, directory, + name, utp_owner, prefix + ) + VALUES (l_id, l_program, + NVL (owner_in, USER), description_in, filename_in, + frequency_in, program_map_in, declarations_in, + setup_in, teardown_in, program_directory_in, directory_in, + name_in, utp_owner_in, prefix_in + ); + + &start81 + COMMIT; + + &end81 + id_out := l_id; + EXCEPTION + WHEN OTHERS + THEN + IF utrerror.uterrcode = utrerror.assertion_failure + THEN + &start81 ROLLBACK; &end81 + RAISE; + ELSE + &start81 ROLLBACK; &end81 + utrerror.report_define_error ( + c_abbrev, + 'UTP for ' + || program_in + || ' Owner ' + || owner_in + ); + END IF; + END; + + PROCEDURE ADD ( + program_in IN ut_utp.program%TYPE := NULL, + owner_in IN ut_utp.owner%TYPE := NULL, + description_in IN ut_utp.description%TYPE := NULL, + filename_in IN ut_utp.filename%TYPE := NULL, + frequency_in IN ut_utp.frequency%TYPE := NULL, + program_map_in IN ut_utp.program_map%TYPE := NULL, + declarations_in IN ut_utp.declarations%TYPE + := NULL, + setup_in IN ut_utp.setup%TYPE := NULL, + teardown_in IN ut_utp.teardown%TYPE := NULL, + exceptions_in IN ut_utp.exceptions%TYPE := NULL, + program_directory_in IN ut_utp.program_directory%TYPE := NULL, + directory_in IN ut_utp.directory%TYPE := NULL, + name_in IN ut_utp.name%TYPE := NULL, + utp_owner_in IN ut_utp.utp_owner%TYPE := NULL, + prefix_in IN ut_utp.prefix%TYPE := NULL + ) is l_id ut_utp.id%TYPE; begin + add (program_in => program_in, + owner_in => owner_in, + description_in => description_in, + filename_in => filename_in, + frequency_in => frequency_in, + program_map_in => program_map_in, + declarations_in => declarations_in, + setup_in => setup_in, + teardown_in => teardown_in, + exceptions_in => exceptions_in, + program_directory_in => program_directory_in, + directory_in => directory_in, + name_in => name_in, + utp_owner_in => utp_owner_in, + prefix_in => prefix_in, + id_out => l_id); + end; + + PROCEDURE rem (name_in IN VARCHAR2) + IS + BEGIN + rem (id (name_in)); + END; + + PROCEDURE rem (id_in IN ut_utp.id%TYPE) + IS + &start81 + PRAGMA autonomous_transaction; + &end81 + BEGIN + DELETE FROM ut_utp + WHERE id = id_in; + + &start81 + COMMIT; + &end81 + EXCEPTION + WHEN OTHERS + THEN + IF utrerror.uterrcode = utrerror.assertion_failure + THEN + &start81 ROLLBACK; &end81 + RAISE; + ELSE + &start81 ROLLBACK; &end81 + utrerror.report_define_error (c_abbrev, 'UTP ' + || id_in); + END IF; + END; + + PROCEDURE upd ( + id_in IN ut_utp.id%TYPE, + program_directory_in IN ut_utp.program_directory%TYPE := NULL, + directory_in IN ut_utp.directory%TYPE := NULL, + name_in IN ut_utp.name%TYPE := NULL, + utp_owner_in IN ut_utp.utp_owner%TYPE := NULL, + filename_in IN ut_utp.filename%TYPE := NULL, + prefix_in IN ut_utp.prefix%TYPE := NULL + ) + IS + &start81 + PRAGMA autonomous_transaction; + &end81 + l_name ut_utp.name%type := name_in; + BEGIN + if l_name not like '"%' then l_name := upper (l_name); end if; + update ut_utp + set filename = filename_in, + program_directory = program_directory_in, + directory = directory_in, + name = l_name, + utp_owner = utp_owner_in, + prefix = prefix_in + where id = id_in; + &start81 + COMMIT; + + &end81 + EXCEPTION + WHEN OTHERS + THEN + &start81 ROLLBACK; &end81 + utrerror.report_define_error ( + c_abbrev, + 'UTP update for UTP ' + || id_in + ); + END; + + FUNCTION utps (program_like_in IN VARCHAR2 := '%') + RETURN utconfig.refcur_t + IS + retval utconfig.refcur_t; + BEGIN + OPEN retval FOR + SELECT * + FROM ut_utp + WHERE program LIKE UPPER (program_like_in); + RETURN retval; + EXCEPTION + WHEN OTHERS + THEN + RETURN retval; + END; +END ututp; +/ + diff --git a/source/ut_utp.pks b/source/ut_utp.pks new file mode 100644 index 000000000..b7508311b --- /dev/null +++ b/source/ut_utp.pks @@ -0,0 +1,110 @@ +CREATE OR REPLACE PACKAGE ututp +IS + c_name CONSTANT CHAR (18) := 'UNIT TEST PACKAGE'; + c_abbrev CONSTANT CHAR (3) := 'UTP'; + + /* UTP##NNN */ + FUNCTION NAME (utp_in IN ut_utp%ROWTYPE) + RETURN VARCHAR2; + + FUNCTION NAME (id_in IN ut_utp.ID%TYPE) + RETURN VARCHAR2; + + /* schema.UTP##NNN */ + FUNCTION qualified_name (utp_in IN ut_utp%ROWTYPE) + RETURN VARCHAR2; + + FUNCTION qualified_name (id_in IN ut_utp.ID%TYPE) + RETURN VARCHAR2; + + FUNCTION setup_procedure (utp_in IN ut_utp%ROWTYPE) + RETURN VARCHAR2; + + FUNCTION teardown_procedure (utp_in IN ut_utp%ROWTYPE) + RETURN VARCHAR2; + + /* V1 compatibility */ + FUNCTION prefix (utp_in IN ut_utp%ROWTYPE) + RETURN VARCHAR2; + + FUNCTION onerow ( + owner_in IN ut_utp.owner%TYPE + ,program_in IN ut_utp.program%TYPE + ) + RETURN ut_utp%ROWTYPE; + + FUNCTION onerow (utp_id_in IN ut_utp.ID%TYPE) + RETURN ut_utp%ROWTYPE; + + PROCEDURE get_onerow ( + owner_in IN ut_utp.owner%TYPE + ,program_in IN ut_utp.program%TYPE + ,id_out OUT ut_utp.ID%TYPE + ,description_out OUT ut_utp.description%TYPE + ,filename_out OUT ut_utp.filename%TYPE + ,program_directory_out OUT ut_utp.program_directory%TYPE + ,directory_out OUT ut_utp.DIRECTORY%TYPE + ,name_out OUT ut_utp.NAME%TYPE + ,utp_owner_out OUT ut_utp.utp_owner%TYPE + ,prefix_out OUT ut_utp.prefix%TYPE + ); + + FUNCTION EXISTS ( + owner_in IN ut_utp.owner%TYPE + ,program_in IN ut_utp.program%TYPE + ) + RETURN BOOLEAN; + + FUNCTION ID (NAME_IN IN VARCHAR2) + RETURN ut_utp.ID%TYPE; + + PROCEDURE ADD ( + -- 2.0.7 name_in IN ut_utp.name%TYPE, + program_in IN ut_utp.program%TYPE := NULL + ,owner_in IN ut_utp.owner%TYPE := NULL + ,description_in IN ut_utp.description%TYPE := NULL + ,filename_in IN ut_utp.filename%TYPE := NULL + ,frequency_in IN ut_utp.frequency%TYPE := NULL + ,program_map_in IN ut_utp.program_map%TYPE := NULL + ,declarations_in IN ut_utp.declarations%TYPE := NULL + ,setup_in IN ut_utp.setup%TYPE := NULL + ,teardown_in IN ut_utp.teardown%TYPE := NULL + ,exceptions_in IN ut_utp.EXCEPTIONS%TYPE := NULL + ,program_directory_in IN ut_utp.program_directory%TYPE := NULL + ,directory_in IN ut_utp.DIRECTORY%TYPE := NULL + ,NAME_IN IN ut_utp.NAME%TYPE := NULL + ,utp_owner_in IN ut_utp.utp_owner%TYPE := NULL + ,prefix_in IN ut_utp.prefix%TYPE := NULL + -- V1 prefix_in IN ut_utp.prefix%TYPE := utconfig.c_prefix + ); + + PROCEDURE ADD ( + program_in IN ut_utp.program%TYPE := NULL + ,owner_in IN ut_utp.owner%TYPE := NULL + ,description_in IN ut_utp.description%TYPE := NULL + ,filename_in IN ut_utp.filename%TYPE := NULL + ,frequency_in IN ut_utp.frequency%TYPE := NULL + ,program_map_in IN ut_utp.program_map%TYPE := NULL + ,declarations_in IN ut_utp.declarations%TYPE := NULL + ,setup_in IN ut_utp.setup%TYPE := NULL + ,teardown_in IN ut_utp.teardown%TYPE := NULL + ,exceptions_in IN ut_utp.EXCEPTIONS%TYPE := NULL + ,program_directory_in IN ut_utp.program_directory%TYPE := NULL + ,directory_in IN ut_utp.DIRECTORY%TYPE := NULL + ,NAME_IN IN ut_utp.NAME%TYPE := NULL + ,utp_owner_in IN ut_utp.utp_owner%TYPE := NULL + ,prefix_in IN ut_utp.prefix%TYPE := NULL + ,id_out OUT ut_utp.ID%TYPE + ); + + PROCEDURE REM (NAME_IN IN VARCHAR2); + + PROCEDURE REM (id_in IN ut_utp.ID%TYPE); + + FUNCTION utps ( + program_like_in IN VARCHAR2 := '%' + ) + RETURN utconfig.refcur_t; + +END ututp; +/ diff --git a/source/ut_utp.tab b/source/ut_utp.tab new file mode 100644 index 000000000..766f065d5 --- /dev/null +++ b/source/ut_utp.tab @@ -0,0 +1,31 @@ +CREATE TABLE ut_utp ( + name VARCHAR2(30), /* V2: now constructed as UTPid */ + id INTEGER, + description VARCHAR2(2000), + prefix VARCHAR2(10), /* V1 compatibility. V2: use ut_config.delimiter to construct names. */ + program VARCHAR2(30), /* name of program being tested */ + owner VARCHAR2(30), /* owner of program */ + filename VARCHAR2(2000), /* name of file containing source code for UTP */ + frequency VARCHAR2(2000), + program_map VARCHAR2(2000), + /* XML document representing parsed version of package. Should be LOB. */ + declarations varchar2(2000), + setup varchar2(2000), + teardown varchar2(2000), + exceptions varchar2(2000), + CONSTRAINT ut_utp_pk PRIMARY KEY (id) +); + +REM 2.0.8.1 +ALTER TABLE ut_utp ADD per_method_setup char(1); + +REM 2.1.1 +REM /* Owner of UTP */ +ALTER TABLE ut_utp ADD utp_owner VARCHAR2(30); +REM File containing source code of program +ALTER TABLE ut_utp ADD program_filename VARCHAR2(30); +REM-- Location of UTP source file +ALTER TABLE ut_utp ADD directory VARCHAR2(30); +REM-- Location of program +ALTER TABLE ut_utp ADD program_directory VARCHAR2(30); + diff --git a/source/ut_utp_seq.seq b/source/ut_utp_seq.seq new file mode 100644 index 000000000..2f0799bbf --- /dev/null +++ b/source/ut_utp_seq.seq @@ -0,0 +1 @@ +CREATE sequence ut_utp_seq INCREMENT BY 1 START WITH 1 ORDER NOCACHE; diff --git a/source/ut_vvalue.pkb b/source/ut_vvalue.pkb new file mode 100644 index 000000000..347cc3e7e --- /dev/null +++ b/source/ut_vvalue.pkb @@ -0,0 +1,880 @@ +/* Formatted on 2001/09/15 09:27 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE BODY utvvalue +--//----------------------------------------------------------------------- +--// ** PL/Generator Table Encapsulator for "UTV_VALUE" +--//----------------------------------------------------------------------- +--// (c) COPYRIGHT Personnel Policies, Inc. 2001. +--// All rights reserved. +--// +--// No part of this copyrighted work may be reproduced, modified, +--// or distributed in any form or by any means without the prior +--// written permission of Personnel Policies, Inc.. +--//----------------------------------------------------------------------- +--// This software was generated by RevealNet's PL/Generator (TM). +--// +--// For more information, visit www.revealnet.com or call 1.800.REVEAL4 +--//----------------------------------------------------------------------- +--// Stored In: utvvalue.pkb +--// Created On: September 15, 2001 09:21:04 +--// Created By: SCOTT +--// PL/Generator Version: PRO-2000.2.9 +--//----------------------------------------------------------------------- +IS + --// Package name and program name globals --// + c_pkgname VARCHAR2 (30) := 'utvvalue'; + g_progname VARCHAR2 (30) := NULL; + + --// Update Flag private data structures. --// + TYPE frcflg_rt IS RECORD ( + data_type CHAR (1), + data_type_name CHAR (1), + is_expression CHAR (1), + VALUE CHAR (1), + record_id CHAR (1), + object_id CHAR (1), + collection_id CHAR (1), + uri_id CHAR (1), + xml_id CHAR (1), + lob_id CHAR (1)); + + frcflg frcflg_rt; + emptyfrc frcflg_rt; + c_set CHAR (1) := 'Y'; + c_noset CHAR (1) := 'N'; + + FUNCTION version + RETURN VARCHAR2 + IS + BEGIN + RETURN '7.09'; + END; + + +--// Private Modules //-- + + --// For Dynamic SQL operations; currently unused. //-- + PROCEDURE initcur (cur_inout IN OUT INTEGER) + IS + BEGIN + IF NOT DBMS_SQL.is_open (cur_inout) + THEN + cur_inout := DBMS_SQL.open_cursor; + END IF; + EXCEPTION + WHEN INVALID_CURSOR + THEN + cur_inout := DBMS_SQL.open_cursor; + END; + + PROCEDURE start_program (nm IN VARCHAR2, msg IN VARCHAR2 := NULL) + IS + BEGIN + g_progname := nm; + END; + + PROCEDURE end_program + IS + BEGIN + g_progname := NULL; + END; + + +--// Cursor management procedures //-- + + --// Open the cursors with some options. //-- + PROCEDURE open_allforpky_cur ( + id_in IN utv_value.id%TYPE, + close_if_open IN BOOLEAN := TRUE + ) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + start_program ('open_allforpky_cur'); + + IF allforpky_cur%ISOPEN + AND v_close + THEN + CLOSE allforpky_cur; + ELSIF allforpky_cur%ISOPEN + AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN allforpky_cur (id_in); + END IF; + + end_program; + END; + + PROCEDURE open_allbypky_cur (close_if_open IN BOOLEAN := TRUE) + IS + v_close BOOLEAN := NVL (close_if_open, TRUE); + v_open BOOLEAN := TRUE; + BEGIN + IF allbypky_cur%ISOPEN + AND v_close + THEN + CLOSE allbypky_cur; + ELSIF allbypky_cur%ISOPEN + AND NOT v_close + THEN + v_open := FALSE; + END IF; + + IF v_open + THEN + OPEN allbypky_cur; + END IF; + END; + + --// Close the cursors if they are open. //-- + PROCEDURE close_allforpky_cur + IS + BEGIN + IF allforpky_cur%ISOPEN + THEN + CLOSE allforpky_cur; + END IF; + END; + + PROCEDURE close_allbypky_cur + IS + BEGIN + IF allbypky_cur%ISOPEN + THEN + CLOSE allbypky_cur; + END IF; + END; + + PROCEDURE closeall + IS + BEGIN + close_allforpky_cur; + close_allbypky_cur; + END; + + +--// Emulate aggregate-level record operations. //-- + + FUNCTION recseq (rec1 IN allcols_rt, rec2 IN allcols_rt) + RETURN BOOLEAN + IS + unequal_records EXCEPTION; + retval BOOLEAN; + BEGIN + retval := rec1.id = rec2.id + OR ( rec1.id IS NULL + AND rec2.id IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := rec1.data_type = rec2.data_type + OR ( rec1.data_type IS NULL + AND rec2.data_type IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := rec1.data_type_name = rec2.data_type_name + OR ( rec1.data_type_name IS NULL + AND rec2.data_type_name IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := rec1.is_expression = rec2.is_expression + OR ( rec1.is_expression IS NULL + AND rec2.is_expression IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := rec1.VALUE = rec2.VALUE + OR ( rec1.VALUE IS NULL + AND rec2.VALUE IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := rec1.record_id = rec2.record_id + OR ( rec1.record_id IS NULL + AND rec2.record_id IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := rec1.object_id = rec2.object_id + OR ( rec1.object_id IS NULL + AND rec2.object_id IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := rec1.collection_id = rec2.collection_id + OR ( rec1.collection_id IS NULL + AND rec2.collection_id IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := rec1.uri_id = rec2.uri_id + OR ( rec1.uri_id IS NULL + AND rec2.uri_id IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := rec1.xml_id = rec2.xml_id + OR ( rec1.xml_id IS NULL + AND rec2.xml_id IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + retval := rec1.lob_id = rec2.lob_id + OR ( rec1.lob_id IS NULL + AND rec2.lob_id IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + RETURN TRUE; + EXCEPTION + WHEN unequal_records + THEN + RETURN FALSE; + END; + + FUNCTION recseq (rec1 IN pky_rt, rec2 IN pky_rt) + RETURN BOOLEAN + IS + unequal_records EXCEPTION; + retval BOOLEAN; + BEGIN + retval := rec1.id = rec2.id + OR ( rec1.id IS NULL + AND rec2.id IS NULL + ); + + IF NOT NVL (retval, FALSE) + THEN + RAISE unequal_records; + END IF; + + RETURN TRUE; + EXCEPTION + WHEN unequal_records + THEN + RETURN FALSE; + END; + + +--// Is the primary key NOT NULL? //-- + + FUNCTION isnullpky (rec_in IN allcols_rt) + RETURN BOOLEAN + IS + BEGIN + RETURN rec_in.id IS NULL; + END; + + FUNCTION isnullpky (rec_in IN pky_rt) + RETURN BOOLEAN + IS + BEGIN + RETURN rec_in.id IS NULL; + END; + + +--// Query Processing --// + + FUNCTION onerow_internal (id_in IN utv_value.id%TYPE) + RETURN allcols_rt + IS + CURSOR onerow_cur + IS + SELECT id, data_type, data_type_name, is_expression, VALUE, + record_id, object_id, collection_id, uri_id, xml_id, + lob_id + FROM utv_value + WHERE id = id_in; + + onerow_rec allcols_rt; + BEGIN + OPEN onerow_cur; + FETCH onerow_cur INTO onerow_rec; + CLOSE onerow_cur; + RETURN onerow_rec; + END onerow_internal; + + FUNCTION onerow (id_in IN utv_value.id%TYPE) + RETURN allcols_rt + IS + retval allcols_rt; + BEGIN + retval := onerow_internal (id_in); + RETURN retval; + END onerow; + + --// Count of all rows in table and for each foreign key. //-- + FUNCTION rowcount + RETURN INTEGER + IS + retval INTEGER; + BEGIN + SELECT COUNT (*) + INTO retval + FROM utv_value; + RETURN retval; + END; + + FUNCTION pkyrowcount (id_in IN utv_value.id%TYPE) + RETURN INTEGER + IS + retval INTEGER; + BEGIN + SELECT COUNT (*) + INTO retval + FROM utv_value + WHERE id = id_in; + RETURN retval; + END; + + --// Generate the next primary key: single column PKYs only --// + FUNCTION nextpky + RETURN utv_value.id%TYPE + IS + retval utv_value.id%TYPE; + BEGIN + SELECT utv_value_seq.NEXTVAL + INTO retval + FROM DUAL; + RETURN retval; + END; + + +--// Update Processing --// + + PROCEDURE reset$frc + IS + BEGIN + frcflg := emptyfrc; + END reset$frc; + + FUNCTION data_type$frc ( + data_type_in IN utv_value.data_type%TYPE DEFAULT NULL + ) + RETURN utv_value.data_type%TYPE + IS + BEGIN + frcflg.data_type := c_set; + RETURN data_type_in; + END data_type$frc; + + FUNCTION data_type_name$frc ( + data_type_name_in IN utv_value.data_type_name%TYPE + DEFAULT NULL + ) + RETURN utv_value.data_type_name%TYPE + IS + BEGIN + frcflg.data_type_name := c_set; + RETURN data_type_name_in; + END data_type_name$frc; + + FUNCTION is_expression$frc ( + is_expression_in IN utv_value.is_expression%TYPE DEFAULT NULL + ) + RETURN utv_value.is_expression%TYPE + IS + BEGIN + frcflg.is_expression := c_set; + RETURN is_expression_in; + END is_expression$frc; + + FUNCTION value$frc (value_in IN utv_value.VALUE%TYPE DEFAULT NULL) + RETURN utv_value.VALUE%TYPE + IS + BEGIN + frcflg.VALUE := c_set; + RETURN value_in; + END value$frc; + + FUNCTION record_id$frc ( + record_id_in IN utv_value.record_id%TYPE DEFAULT NULL + ) + RETURN utv_value.record_id%TYPE + IS + BEGIN + frcflg.record_id := c_set; + RETURN record_id_in; + END record_id$frc; + + FUNCTION object_id$frc ( + object_id_in IN utv_value.object_id%TYPE DEFAULT NULL + ) + RETURN utv_value.object_id%TYPE + IS + BEGIN + frcflg.object_id := c_set; + RETURN object_id_in; + END object_id$frc; + + FUNCTION collection_id$frc ( + collection_id_in IN utv_value.collection_id%TYPE DEFAULT NULL + ) + RETURN utv_value.collection_id%TYPE + IS + BEGIN + frcflg.collection_id := c_set; + RETURN collection_id_in; + END collection_id$frc; + + FUNCTION uri_id$frc ( + uri_id_in IN utv_value.uri_id%TYPE DEFAULT NULL + ) + RETURN utv_value.uri_id%TYPE + IS + BEGIN + frcflg.uri_id := c_set; + RETURN uri_id_in; + END uri_id$frc; + + FUNCTION xml_id$frc ( + xml_id_in IN utv_value.xml_id%TYPE DEFAULT NULL + ) + RETURN utv_value.xml_id%TYPE + IS + BEGIN + frcflg.xml_id := c_set; + RETURN xml_id_in; + END xml_id$frc; + + FUNCTION lob_id$frc ( + lob_id_in IN utv_value.lob_id%TYPE DEFAULT NULL + ) + RETURN utv_value.lob_id%TYPE + IS + BEGIN + frcflg.lob_id := c_set; + RETURN lob_id_in; + END lob_id$frc; + + PROCEDURE upd ( + id_in IN utv_value.id%TYPE, + data_type_in IN utv_value.data_type%TYPE + DEFAULT NULL, + data_type_name_in IN utv_value.data_type_name%TYPE + DEFAULT NULL, + is_expression_in IN utv_value.is_expression%TYPE + DEFAULT NULL, + value_in IN utv_value.VALUE%TYPE DEFAULT NULL, + record_id_in IN utv_value.record_id%TYPE + DEFAULT NULL, + object_id_in IN utv_value.object_id%TYPE + DEFAULT NULL, + collection_id_in IN utv_value.collection_id%TYPE + DEFAULT NULL, + uri_id_in IN utv_value.uri_id%TYPE DEFAULT NULL, + xml_id_in IN utv_value.xml_id%TYPE DEFAULT NULL, + lob_id_in IN utv_value.lob_id%TYPE DEFAULT NULL, + rowcount_out OUT INTEGER, + reset_in IN BOOLEAN DEFAULT TRUE + ) + IS + BEGIN + UPDATE utv_value + SET data_type = DECODE ( + frcflg.data_type, + c_set, data_type_in, + NVL (data_type_in, data_type) + ), + data_type_name = DECODE ( + frcflg.data_type_name, + c_set, data_type_name_in, + NVL ( + data_type_name_in, + data_type_name + ) + ), + is_expression = DECODE ( + frcflg.is_expression, + c_set, is_expression_in, + NVL (is_expression_in, is_expression) + ), + VALUE = DECODE ( + frcflg.VALUE, + c_set, value_in, + NVL (value_in, VALUE) + ), + record_id = DECODE ( + frcflg.record_id, + c_set, record_id_in, + NVL (record_id_in, record_id) + ), + object_id = DECODE ( + frcflg.object_id, + c_set, object_id_in, + NVL (object_id_in, object_id) + ), + collection_id = DECODE ( + frcflg.collection_id, + c_set, collection_id_in, + NVL (collection_id_in, collection_id) + ), + uri_id = DECODE ( + frcflg.uri_id, + c_set, uri_id_in, + NVL (uri_id_in, uri_id) + ), + xml_id = DECODE ( + frcflg.xml_id, + c_set, xml_id_in, + NVL (xml_id_in, xml_id) + ), + lob_id = DECODE ( + frcflg.lob_id, + c_set, lob_id_in, + NVL (lob_id_in, lob_id) + ) + WHERE id = id_in; + + rowcount_out := SQL%ROWCOUNT; + + IF reset_in + THEN + reset$frc; + END IF; + EXCEPTION + WHEN OTHERS + THEN + RAISE; + END upd; + + --// Record-based Update --// + PROCEDURE upd ( + rec_in IN allcols_rt, + rowcount_out OUT INTEGER, + reset_in IN BOOLEAN DEFAULT TRUE + ) + IS + BEGIN + upd ( + rec_in.id, + rec_in.data_type, + rec_in.data_type_name, + rec_in.is_expression, + rec_in.VALUE, + rec_in.record_id, + rec_in.object_id, + rec_in.collection_id, + rec_in.uri_id, + rec_in.xml_id, + rec_in.lob_id, + rowcount_out, + reset_in + ); + END upd; + + +--// Insert Processing --// + + --// Initialize record with default values. --// + FUNCTION initrec (allnull IN BOOLEAN := FALSE) + RETURN allcols_rt + IS + retval allcols_rt; + BEGIN + IF allnull + THEN + NULL; /* Default values are NULL already. */ + ELSE + retval.id := NULL; + retval.data_type := NULL; + retval.data_type_name := NULL; + retval.is_expression := NULL; + retval.VALUE := NULL; + retval.record_id := NULL; + retval.object_id := NULL; + retval.collection_id := NULL; + retval.uri_id := NULL; + retval.xml_id := NULL; + retval.lob_id := NULL; + END IF; + + RETURN retval; + END; + + --// Initialize record with default values. --// + PROCEDURE initrec ( + rec_inout IN OUT allcols_rt, + allnull IN BOOLEAN := FALSE + ) + IS + BEGIN + rec_inout := initrec; + END; + + PROCEDURE ins$ins ( + id_in IN utv_value.id%TYPE, + data_type_in IN utv_value.data_type%TYPE DEFAULT NULL, + data_type_name_in IN utv_value.data_type_name%TYPE + DEFAULT NULL, + is_expression_in IN utv_value.is_expression%TYPE + DEFAULT NULL, + value_in IN utv_value.VALUE%TYPE DEFAULT NULL, + record_id_in IN utv_value.record_id%TYPE DEFAULT NULL, + object_id_in IN utv_value.object_id%TYPE DEFAULT NULL, + collection_id_in IN utv_value.collection_id%TYPE + DEFAULT NULL, + uri_id_in IN utv_value.uri_id%TYPE DEFAULT NULL, + xml_id_in IN utv_value.xml_id%TYPE DEFAULT NULL, + lob_id_in IN utv_value.lob_id%TYPE DEFAULT NULL, + upd_on_dup IN BOOLEAN := FALSE + ) + IS + BEGIN + INSERT INTO utv_value + (id, data_type, data_type_name, + is_expression, VALUE, record_id, + object_id, collection_id, uri_id, + xml_id, lob_id) + VALUES (id_in, data_type_in, data_type_name_in, + is_expression_in, value_in, record_id_in, + object_id_in, collection_id_in, uri_id_in, + xml_id_in, lob_id_in); + EXCEPTION + WHEN DUP_VAL_ON_INDEX + THEN + IF NOT NVL (upd_on_dup, FALSE) + THEN + RAISE; + ELSE + DECLARE + v_errm VARCHAR2 (2000) := SQLERRM; + v_rowcount INTEGER; + dotloc INTEGER; + leftloc INTEGER; + c_owner all_constraints.owner%TYPE; + c_name all_constraints.constraint_name%TYPE; + BEGIN + dotloc := INSTR (v_errm, '.'); + leftloc := INSTR (v_errm, '('); + c_owner := SUBSTR ( + v_errm, + leftloc + + 1, + dotloc + - leftloc + - 1 + ); + c_name := SUBSTR ( + v_errm, + dotloc + + 1, + INSTR (v_errm, ')') + - dotloc + - 1 + ); + + --// Duplicate based on primary key //-- + IF 'SYS_C004468' = c_name + AND /* 2000.2 'SCOTT' */ USER = c_owner + THEN + upd ( + id_in, + data_type_in, + data_type_name_in, + is_expression_in, + value_in, + record_id_in, + object_id_in, + collection_id_in, + uri_id_in, + xml_id_in, + lob_id_in, + v_rowcount, + FALSE + ); + ELSE + --// Unique index violation. Cannot recover... //-- + RAISE; + END IF; + END; + END IF; + WHEN OTHERS + THEN + RAISE; + END ins$ins; + + --// Insert 1: with individual fields and return primary key //-- + PROCEDURE ins ( + data_type_in IN utv_value.data_type%TYPE + DEFAULT NULL, + data_type_name_in IN utv_value.data_type_name%TYPE + DEFAULT NULL, + is_expression_in IN utv_value.is_expression%TYPE + DEFAULT NULL, + value_in IN utv_value.VALUE%TYPE DEFAULT NULL, + record_id_in IN utv_value.record_id%TYPE + DEFAULT NULL, + object_id_in IN utv_value.object_id%TYPE + DEFAULT NULL, + collection_id_in IN utv_value.collection_id%TYPE + DEFAULT NULL, + uri_id_in IN utv_value.uri_id%TYPE DEFAULT NULL, + xml_id_in IN utv_value.xml_id%TYPE DEFAULT NULL, + lob_id_in IN utv_value.lob_id%TYPE DEFAULT NULL, + id_out IN OUT utv_value.id%TYPE, + upd_on_dup IN BOOLEAN := FALSE + ) + IS + v_pky INTEGER := nextpky; + BEGIN + ins$ins ( + v_pky, + data_type_in, + data_type_name_in, + is_expression_in, + value_in, + record_id_in, + object_id_in, + collection_id_in, + uri_id_in, + xml_id_in, + lob_id_in, + upd_on_dup + ); + id_out := v_pky; + END; + + -- Simple insert for expressions/scalars only. + PROCEDURE ins ( + data_type_in IN utv_value.data_type%TYPE DEFAULT NULL, + is_expression_in IN BOOLEAN, + value_in IN utv_value.VALUE%TYPE DEFAULT NULL, + id_out IN OUT utv_value.id%TYPE, + upd_on_dup IN BOOLEAN := FALSE + ) + IS + BEGIN + ins ( + data_type_in=> data_type_in, + is_expression_in=> utplsql.ifelse ( + is_expression_in, + utplsql.c_yes, + utplsql.c_no + ), + value_in=> value_in, + id_out=> id_out, + upd_on_dup=> upd_on_dup + ); + END; + + --// Insert 2: with record, returning primary key. //-- + PROCEDURE ins ( + rec_in IN allcols_rt, + id_out IN OUT utv_value.id%TYPE, + upd_on_dup IN BOOLEAN := FALSE + ) + IS + v_pky INTEGER := nextpky; + BEGIN + ins$ins ( + v_pky, + rec_in.data_type, + rec_in.data_type_name, + rec_in.is_expression, + rec_in.VALUE, + rec_in.record_id, + rec_in.object_id, + rec_in.collection_id, + rec_in.uri_id, + rec_in.xml_id, + rec_in.lob_id, + upd_on_dup + ); + id_out := v_pky; + END; + + +--// Delete Processing --// + + PROCEDURE del (id_in IN utv_value.id%TYPE, rowcount_out OUT INTEGER) + IS + BEGIN + DELETE FROM utv_value + WHERE id = id_in; + + rowcount_out := SQL%ROWCOUNT; + EXCEPTION + WHEN OTHERS + THEN + RAISE; + END del; + + --// Record-based delete --// + PROCEDURE del (rec_in IN pky_rt, rowcount_out OUT INTEGER) + IS + BEGIN + del (rec_in.id, rowcount_out); + END del; + + PROCEDURE del (rec_in IN allcols_rt, rowcount_out OUT INTEGER) + IS + BEGIN + del (rec_in.id, rowcount_out); + END del; + + --// Program called by database initialization script to pin the package. //-- + PROCEDURE pinme + IS + BEGIN + --// Doesn't do anything except cause the package to be loaded. //-- + NULL; + END; + +--// Initialization section for the package. --// +BEGIN + NULL; -- Placeholder. +END utvvalue; +/ + diff --git a/source/ut_vvalue.pks b/source/ut_vvalue.pks new file mode 100644 index 000000000..2db2c2b8b --- /dev/null +++ b/source/ut_vvalue.pks @@ -0,0 +1,274 @@ +/* Formatted on 2001/09/15 09:25 (RevealNet Formatter v4.4.1) */ +CREATE OR REPLACE PACKAGE utvvalue +--//----------------------------------------------------------------------- +--// ** PL/Generator Table Encapsulator for "UTV_VALUE" +--//----------------------------------------------------------------------- +--// (c) COPYRIGHT Personnel Policies, Inc. 2001. +--// All rights reserved. +--// +--// No part of this copyrighted work may be reproduced, modified, +--// or distributed in any form or by any means without the prior +--// written permission of Personnel Policies, Inc.. +--//----------------------------------------------------------------------- +--// This software was generated by RevealNet's PL/Generator (TM). +--// +--// For more information, visit www.revealnet.com or call 1.800.REVEAL4 +--//----------------------------------------------------------------------- +--// Stored In: utvvalue.pks +--// Created On: September 15, 2001 09:21:01 +--// Created By: SCOTT +--// PL/Generator Version: PRO-2000.2.9 +--//----------------------------------------------------------------------- +IS + +--// Data Structures //-- + TYPE pky_rt IS RECORD ( + id utv_value.id%TYPE); + + --// Modified version of %ROWTYPE for table with subset of columns //-- + TYPE allcols_rt IS RECORD ( + id utv_value.id%TYPE, + data_type utv_value.data_type%TYPE, + data_type_name utv_value.data_type_name%TYPE, + is_expression utv_value.is_expression%TYPE, + VALUE utv_value.VALUE%TYPE, + record_id utv_value.record_id%TYPE, + object_id utv_value.object_id%TYPE, + collection_id utv_value.collection_id%TYPE, + uri_id utv_value.uri_id%TYPE, + xml_id utv_value.xml_id%TYPE, + lob_id utv_value.lob_id%TYPE); + + TYPE cv_t IS REF CURSOR; + + +--// Cursors //-- + + CURSOR allbypky_cur + IS + SELECT id, data_type, data_type_name, is_expression, VALUE, + record_id, object_id, collection_id, uri_id, xml_id, + lob_id + FROM utv_value + ORDER BY id; + + CURSOR allforpky_cur (id_in IN utv_value.id%TYPE) + IS + SELECT id, data_type, data_type_name, is_expression, VALUE, + record_id, object_id, collection_id, uri_id, xml_id, + lob_id + FROM utv_value + WHERE id = allforpky_cur.id_in; + + +--// Cursor management procedures //-- + + --// Open the cursors with some options. //-- + PROCEDURE open_allforpky_cur ( + id_in IN utv_value.id%TYPE, + close_if_open IN BOOLEAN := TRUE + ); + + PROCEDURE open_allbypky_cur (close_if_open IN BOOLEAN := TRUE); + + --// Close the cursors if they are open. //-- + PROCEDURE close_allforpky_cur; + + PROCEDURE close_allbypky_cur; + + PROCEDURE closeall; + + +--// Analyze presence of primary key: is it NOT NULL? //-- + + FUNCTION isnullpky (rec_in IN allcols_rt) + RETURN BOOLEAN; + + FUNCTION isnullpky (rec_in IN pky_rt) + RETURN BOOLEAN; + + +--// Emulate aggregate-level record operations. //-- + + FUNCTION recseq (rec1 IN allcols_rt, rec2 IN allcols_rt) + RETURN BOOLEAN; + + FUNCTION recseq (rec1 IN pky_rt, rec2 IN pky_rt) + RETURN BOOLEAN; + + +--// Fetch Data //-- + + --// Fetch one row of data for a primary key. //-- + FUNCTION onerow (id_in IN utv_value.id%TYPE) + RETURN allcols_rt; + + --// Count of all rows in table and for each foreign key. //-- + FUNCTION rowcount + RETURN INTEGER; + + FUNCTION pkyrowcount (id_in IN utv_value.id%TYPE) + RETURN INTEGER; + + +--// Update Processing //-- + + PROCEDURE reset$frc; + + --// Force setting of NULL values //-- + + FUNCTION data_type$frc ( + data_type_in IN utv_value.data_type%TYPE DEFAULT NULL + ) + RETURN utv_value.data_type%TYPE; + + FUNCTION data_type_name$frc ( + data_type_name_in IN utv_value.data_type_name%TYPE + DEFAULT NULL + ) + RETURN utv_value.data_type_name%TYPE; + + FUNCTION is_expression$frc ( + is_expression_in IN utv_value.is_expression%TYPE + DEFAULT NULL + ) + RETURN utv_value.is_expression%TYPE; + + FUNCTION value$frc (value_in IN utv_value.VALUE%TYPE DEFAULT NULL) + RETURN utv_value.VALUE%TYPE; + + FUNCTION record_id$frc ( + record_id_in IN utv_value.record_id%TYPE DEFAULT NULL + ) + RETURN utv_value.record_id%TYPE; + + FUNCTION object_id$frc ( + object_id_in IN utv_value.object_id%TYPE DEFAULT NULL + ) + RETURN utv_value.object_id%TYPE; + + FUNCTION collection_id$frc ( + collection_id_in IN utv_value.collection_id%TYPE + DEFAULT NULL + ) + RETURN utv_value.collection_id%TYPE; + + FUNCTION uri_id$frc ( + uri_id_in IN utv_value.uri_id%TYPE DEFAULT NULL + ) + RETURN utv_value.uri_id%TYPE; + + FUNCTION xml_id$frc ( + xml_id_in IN utv_value.xml_id%TYPE DEFAULT NULL + ) + RETURN utv_value.xml_id%TYPE; + + FUNCTION lob_id$frc ( + lob_id_in IN utv_value.lob_id%TYPE DEFAULT NULL + ) + RETURN utv_value.lob_id%TYPE; + + PROCEDURE upd ( + id_in IN utv_value.id%TYPE, + data_type_in IN utv_value.data_type%TYPE + DEFAULT NULL, + data_type_name_in IN utv_value.data_type_name%TYPE + DEFAULT NULL, + is_expression_in IN utv_value.is_expression%TYPE + DEFAULT NULL, + value_in IN utv_value.VALUE%TYPE DEFAULT NULL, + record_id_in IN utv_value.record_id%TYPE + DEFAULT NULL, + object_id_in IN utv_value.object_id%TYPE + DEFAULT NULL, + collection_id_in IN utv_value.collection_id%TYPE + DEFAULT NULL, + uri_id_in IN utv_value.uri_id%TYPE DEFAULT NULL, + xml_id_in IN utv_value.xml_id%TYPE DEFAULT NULL, + lob_id_in IN utv_value.lob_id%TYPE DEFAULT NULL, + rowcount_out OUT INTEGER, + reset_in IN BOOLEAN DEFAULT TRUE + ); + + --// Record-based Update //-- + + PROCEDURE upd ( + rec_in IN allcols_rt, + rowcount_out OUT INTEGER, + reset_in IN BOOLEAN DEFAULT TRUE + ); + + +--// Insert Processing //-- + + --// Initialize record with default values. //-- + FUNCTION initrec (allnull IN BOOLEAN := FALSE) + RETURN allcols_rt; + + --// Initialize record with default values. //-- + PROCEDURE initrec ( + rec_inout IN OUT allcols_rt, + allnull IN BOOLEAN := FALSE + ); + + --// Generate next primary key: for single column PKs only. //-- + FUNCTION nextpky + RETURN utv_value.id%TYPE; + + PROCEDURE ins ( + data_type_in IN utv_value.data_type%TYPE + DEFAULT NULL, + data_type_name_in IN utv_value.data_type_name%TYPE + DEFAULT NULL, + is_expression_in IN utv_value.is_expression%TYPE + DEFAULT NULL, + value_in IN utv_value.VALUE%TYPE DEFAULT NULL, + record_id_in IN utv_value.record_id%TYPE + DEFAULT NULL, + object_id_in IN utv_value.object_id%TYPE + DEFAULT NULL, + collection_id_in IN utv_value.collection_id%TYPE + DEFAULT NULL, + uri_id_in IN utv_value.uri_id%TYPE DEFAULT NULL, + xml_id_in IN utv_value.xml_id%TYPE DEFAULT NULL, + lob_id_in IN utv_value.lob_id%TYPE DEFAULT NULL, + id_out IN OUT utv_value.id%TYPE, + upd_on_dup IN BOOLEAN := FALSE + ); + + -- Simple insert for expressions/scalars only. + PROCEDURE ins ( + data_type_in IN utv_value.data_type%TYPE + DEFAULT NULL, + is_expression_in IN BOOLEAN, + value_in IN utv_value.VALUE%TYPE DEFAULT NULL, + id_out IN OUT utv_value.id%TYPE, + upd_on_dup IN BOOLEAN := FALSE + ); + + PROCEDURE ins ( + rec_in IN allcols_rt, + id_out IN OUT utv_value.id%TYPE, + upd_on_dup IN BOOLEAN := FALSE + ); + + +--// Delete Processing //-- + PROCEDURE del ( + id_in IN utv_value.id%TYPE, + rowcount_out OUT INTEGER + ); + + --// Record-based delete //-- + PROCEDURE del (rec_in IN pky_rt, rowcount_out OUT INTEGER); + + PROCEDURE del (rec_in IN allcols_rt, rowcount_out OUT INTEGER); + + --// Program called by database initialization script to pin the package. //-- + PROCEDURE pinme; + + FUNCTION version + RETURN VARCHAR2; +END utvvalue; +/ + diff --git a/source/uta_eq.tab b/source/uta_eq.tab new file mode 100644 index 000000000..3e3f7d87a --- /dev/null +++ b/source/uta_eq.tab @@ -0,0 +1,17 @@ +CREATE TABLE uta_eq ( + id INTEGER , + outcome_id INTEGER, + data_type VARCHAR2(100), + check_value_id INTEGER, + against_value_id INTEGER, + CONSTRAINT uta_eq_pk PRIMARY KEY (id) +); + +ALTER TABLE uta_eq ADD CONSTRAINT uta_eq_outcome_fk + FOREIGN KEY (outcome_id) REFERENCES ut_outcome; + +ALTER TABLE uta_eq ADD CONSTRAINT uta_eq_check_fk + FOREIGN KEY (check_value_id) REFERENCES utv_value; + +ALTER TABLE uta_eq ADD CONSTRAINT uta_eq_against_fk + FOREIGN KEY (against_value_id) REFERENCES utv_value; diff --git a/source/uta_eq_seq.seq b/source/uta_eq_seq.seq new file mode 100644 index 000000000..905abb25d --- /dev/null +++ b/source/uta_eq_seq.seq @@ -0,0 +1 @@ +CREATE sequence uta_eq_seq INCREMENT BY 1 START WITH 1 ORDER NOCACHE; diff --git a/source/utr_error.tab b/source/utr_error.tab new file mode 100644 index 000000000..8181239cf --- /dev/null +++ b/source/utr_error.tab @@ -0,0 +1,28 @@ +CREATE TABLE utr_error ( + run_id INTEGER, + suite_id INTEGER, + utp_id INTEGER, + unittest_id INTEGER, + testcase_id INTEGER, + outcome_id INTEGER, + errlevel varchar2(100), + occurred_on DATE, + errcode integer, + errtext varchar2(1000), + description varchar2(2000)); + +ALTER TABLE utr_error ADD CONSTRAINT utr_error_suite_fk + FOREIGN KEY (suite_id) REFERENCES ut_suite; + +ALTER TABLE utr_error ADD CONSTRAINT utr_error_utp_fk + FOREIGN KEY (utp_id) REFERENCES ut_utp; + +ALTER TABLE utr_error ADD CONSTRAINT utr_error_unittest_fk + FOREIGN KEY (unittest_id) REFERENCES ut_unittest; + +ALTER TABLE utr_error ADD CONSTRAINT utr_error_testcase_fk + FOREIGN KEY (testcase_id) REFERENCES ut_testcase; + +ALTER TABLE utr_error ADD CONSTRAINT utr_error_outcome_fk + FOREIGN KEY (outcome_id) REFERENCES ut_outcome; + diff --git a/source/utr_outcome.tab b/source/utr_outcome.tab new file mode 100644 index 000000000..e85eb2a28 --- /dev/null +++ b/source/utr_outcome.tab @@ -0,0 +1,23 @@ +/* Formatted by PL/Formatter v3.1.2.1 on 2001/04/12 10:49 */ + +CREATE TABLE utr_outcome ( + run_id INTEGER, + outcome_id integer, + start_on date, + end_on date, + status varchar2(100), + description varchar2(2000) +); + +REM 2.0.9.1 Record order of execution of test. +ALTER TABLE utr_outcome ADD tc_run_id INTEGER; + +ALTER table utr_outcome add CONSTRAINT utr_outcome_pk + primary key (run_id, outcome_id); + +-- Turn off to support V1 compatibility +--ALTER table utr_outcome add CONSTRAINT utr_outcome_fk1 +-- FOREIGN KEY (outcome_id) REFERENCES ut_outcome; + + + diff --git a/source/utr_suite.tab b/source/utr_suite.tab new file mode 100644 index 000000000..e3610b478 --- /dev/null +++ b/source/utr_suite.tab @@ -0,0 +1,17 @@ +/* Formatted by PL/Formatter v3.1.2.1 on 2001/02/09 16:21 */ + +CREATE TABLE utr_suite ( + run_id INTEGER, + run_by VARCHAR2(30), + profiler_run_id INTEGER, + suite_id integer, + start_on date, + end_on date, + status varchar2(100)); + +ALTER table utr_suite add CONSTRAINT utr_suite_pk + primary key (run_id, suite_id); + +ALTER table utr_suite add CONSTRAINT utr_suite_fk1 + FOREIGN KEY (suite_id) REFERENCES ut_suite; + diff --git a/source/utr_testcase.tab b/source/utr_testcase.tab new file mode 100644 index 000000000..e000cabcb --- /dev/null +++ b/source/utr_testcase.tab @@ -0,0 +1,16 @@ +/* Formatted by PL/Formatter v3.1.2.1 on 2001/04/12 10:49 */ + +CREATE TABLE utr_testcase ( + run_id INTEGER, + testcase_id integer, + start_on date, + end_on date, + status varchar2(100)); + +ALTER table utr_testcase add CONSTRAINT utr_testcase_pk + primary key (run_id, testcase_id); + +ALTER table utr_testcase add CONSTRAINT utr_testcase_fk1 + FOREIGN KEY (testcase_id) REFERENCES ut_testcase; + + diff --git a/source/utr_unittest.tab b/source/utr_unittest.tab new file mode 100644 index 000000000..ef3279c32 --- /dev/null +++ b/source/utr_unittest.tab @@ -0,0 +1,16 @@ +/* Formatted by PL/Formatter v3.1.2.1 on 2001/04/12 10:49 */ + +CREATE TABLE utr_unittest ( + run_id INTEGER, + unittest_id integer, + start_on date, + end_on date, + status varchar2(100)); + +ALTER table utr_unittest add CONSTRAINT utr_unittest_pk + primary key (run_id, unittest_id); + +ALTER table utr_unittest add CONSTRAINT utr_unittest_fk1 + FOREIGN KEY (unittest_id) REFERENCES ut_unittest; + + diff --git a/source/utr_utp.tab b/source/utr_utp.tab new file mode 100644 index 000000000..6e042b543 --- /dev/null +++ b/source/utr_utp.tab @@ -0,0 +1,17 @@ +/* Formatted by PL/Formatter v3.1.2.1 on 2001/02/09 16:21 */ + +CREATE TABLE utr_utp ( + run_id INTEGER, + run_by VARCHAR2(30), + profiler_run_id INTEGER, + utp_id integer, + start_on date, + end_on date, + status varchar2(100)); + +ALTER table utr_utp add CONSTRAINT utr_utp_pk + primary key (run_id, utp_id); + +ALTER table utr_utp add CONSTRAINT utr_utp_fk1 + FOREIGN KEY (utp_id) REFERENCES ut_utp; + diff --git a/source/utv_last_run.sql b/source/utv_last_run.sql new file mode 100644 index 000000000..f9604c075 --- /dev/null +++ b/source/utv_last_run.sql @@ -0,0 +1,9 @@ +CREATE OR REPLACE VIEW utv_last_run +AS + SELECT a.id utp_id, program, run_id last_run_id + FROM ut_utp a, + (SELECT utp_id, MAX (run_id) run_id + FROM utv_result_full + GROUP BY utp_id) b + WHERE a.id = b.utp_id(+); + diff --git a/source/utv_result_full.sql b/source/utv_result_full.sql new file mode 100644 index 000000000..484879f0e --- /dev/null +++ b/source/utv_result_full.sql @@ -0,0 +1,14 @@ +CREATE OR REPLACE VIEW utv_result_full +AS + SELECT utp.id utp_id, program, ut.id unittest_id, + tc.id testcase_id, utr.outcome_id, run_id, + start_on, end_on, utr.status, utr.description + FROM ut_utp utp, + ut_unittest ut, + ut_testcase tc, + ut_outcome oc, + utr_outcome utr + WHERE utp.id = ut.utp_id + AND ut.id = tc.unittest_id + AND tc.id = oc.testcase_id + AND oc.id = utr.outcome_id; diff --git a/source/utv_value.tab b/source/utv_value.tab new file mode 100644 index 000000000..c7fd91991 --- /dev/null +++ b/source/utv_value.tab @@ -0,0 +1,17 @@ +/* Formatted on 2001/09/15 08:08 (RevealNet Formatter v4.4.1) */ +CREATE TABLE utv_value ( +id INTEGER, +data_type varchar2(100), +data_type_name varchar2(100), +is_expression char(1), +value varchar2(2000), +record_id integer, +object_id integer, +collection_id integer, +uri_id integer, +xml_id integer, +lob_id integer, + CONSTRAINT utv_value_pk PRIMARY KEY (id) +); + + diff --git a/source/utv_value_seq.seq b/source/utv_value_seq.seq new file mode 100644 index 000000000..a535cc149 --- /dev/null +++ b/source/utv_value_seq.seq @@ -0,0 +1 @@ +CREATE sequence utv_value_seq INCREMENT BY 1 START WITH 1 ORDER NOCACHE; From f5c428b5e06f131422300361b2acf3b6c617f2b8 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 28 May 2003 08:28:09 +0000 Subject: [PATCH 043/143] More "discriminating" version of uninstall script --- source/ut_i_uninstall.sql | 217 +++++++++++++++++++++----------------- 1 file changed, 121 insertions(+), 96 deletions(-) diff --git a/source/ut_i_uninstall.sql b/source/ut_i_uninstall.sql index 2197e2918..4774f3c32 100644 --- a/source/ut_i_uninstall.sql +++ b/source/ut_i_uninstall.sql @@ -8,102 +8,127 @@ SET DEFINE ON TTITLE OFF SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED -DEFINE uscript='ut_i_spool_temp.sql' - -COLUMN col NOPRINT NEW_VALUE ut_owner -SELECT USER col FROM DUAL; - -DEFINE line1='-------------------------------------------------------------' -DEFINE line2='=============================================================' -DEFINE finished='. Finished' - - -SPOOL &uscript - -REM synonyms: -------------------------------------------------------------- - -COLUMN col NOPRINT NEW_VALUE fine -SELECT COUNT (PRIVILEGE) col - FROM session_privs - WHERE PRIVILEGE = 'DROP PUBLIC SYNONYM'; - -SELECT DECODE (&fine - , 0, '' - , 'PROMPT Dropping &UT public synonyms...' - ) - FROM DUAL; - -SELECT DECODE (&fine - , 0, '' - , 'drop public synonym ' || o1.object_name || ';' - ) - FROM all_objects o1, all_objects o2 - WHERE o1.owner = 'PUBLIC' - AND o1.object_type = 'SYNONYM' - AND o1.object_name = o2.object_name - AND o1.object_name LIKE 'UT%' - AND o2.object_type IN ('PACKAGE', 'TABLE', 'VIEW','SEQUENCE') - AND o2.owner = '&ut_owner'; - -SELECT DECODE (&fine, 0, '', 'PROMPT &finished') - FROM DUAL; - -REM tables: ---------------------------------------------------------------- - -SELECT 'PROMPT Dropping &UT tables...' - FROM DUAL; - -SELECT 'drop table ' || object_name || ' cascade constraints;' - FROM all_objects - WHERE owner = '&ut_owner' - AND object_name LIKE 'UT%' - AND object_type = 'TABLE'; - -SELECT 'PROMPT &finished' - FROM DUAL; - -REM views: ---------------------------------------------------------------- - -SELECT 'PROMPT Dropping &UT views...' - FROM DUAL; - -SELECT 'drop view ' || object_name || ' cascade constraints;' - FROM all_objects - WHERE owner = '&ut_owner' - AND object_name LIKE 'UT%' - AND object_type = 'VIEW'; - -SELECT 'PROMPT &finished' - FROM DUAL; - -REM sequences: -------------------------------------------------------------- - -SELECT 'PROMPT Dropping &UT sequences...' - FROM DUAL; - -SELECT 'drop sequence ' || object_name || ';' - FROM all_objects - WHERE owner = '&ut_owner' - AND object_name LIKE 'UT%' - AND object_type = 'SEQUENCE'; - -SELECT 'PROMPT &finished' - FROM DUAL; - -REM sequences: -------------------------------------------------------------- - -SELECT 'PROMPT Dropping &UT packages...' - FROM DUAL; - -SELECT 'drop package ' || object_name || ';' - FROM all_objects - WHERE owner = '&ut_owner' - AND object_name LIKE 'UT%' - AND object_type = 'PACKAGE'; - -SELECT 'PROMPT &finished' - FROM DUAL; - +drop package UTAEQ; +drop package UTASSERT2; +drop package UTASSERT; +drop package UTCONFIG; +drop package UTGEN; +drop package UTOUTCOME; +drop package UTOUTPUT; +drop package UTPACKAGE; +drop package UTPLSQL2; +drop package UTPLSQL; +drop package UTPLSQL_UTIL; +drop package UTRECEQ; +drop package UTRERROR; +drop package UTRESULT2; +drop package UTRESULT; +drop package UTROUTCOME; +drop package UTRSUITE; +drop package UTRTESTCASE; +drop package UTRUNITTEST; +drop package UTRUTP; +drop package UTSUITE; +drop package UTSUITEUTP; +drop package UTTEST; +drop package UTTESTCASE; +drop package UTTESTPREP; +drop package UTUNITTEST; +drop package UTUTP; +drop package UTVVALUE; +drop public synonym UTAEQ; +drop public synonym UTASSERT2; +drop public synonym UTASSERT; +drop public synonym UTA_EQ; +drop public synonym UTCONFIG; +drop public synonym UTGEN; +drop public synonym UTOUTCOME; +drop public synonym UTOUTPUT; +drop public synonym UTPACKAGE; +drop public synonym UTPLSQL2; +drop public synonym UTPLSQL; +drop public synonym UTPLSQL_UTIL; +drop public synonym UTRECEQ; +drop public synonym UTRERROR; +drop public synonym UTRESULT2; +drop public synonym UTRESULT; +drop public synonym UTROUTCOME; +drop public synonym UTRSUITE; +drop public synonym UTRTESTCASE; +drop public synonym UTRUNITTEST; +drop public synonym UTRUTP; +drop public synonym UTR_ERROR; +drop public synonym UTR_OUTCOME; +drop public synonym UTR_SUITE; +drop public synonym UTR_TESTCASE; +drop public synonym UTR_UNITTEST; +drop public synonym UTR_UTP; +drop public synonym UTSUITE; +drop public synonym UTSUITEUTP; +drop public synonym UTTEST; +drop public synonym UTTESTCASE; +drop public synonym UTTESTPREP; +drop public synonym UTUNITTEST; +drop public synonym UTUTP; +drop public synonym UTVVALUE; +drop public synonym UTV_VALUE; +drop public synonym UT_ARGUMENT; +drop public synonym UT_ASSERTION; +drop public synonym UT_CONFIG; +drop public synonym UT_DETERMINISTIC; +drop public synonym UT_DETERMINISTIC_ARG; +drop public synonym UT_EQ; +drop public synonym UT_GRID; +drop public synonym UT_OUTCOME; +drop public synonym UT_PACKAGE; +drop public synonym UT_RECEQ; +drop public synonym UT_RECEQ_PKG; +drop public synonym UT_SUITE; +drop public synonym UT_SUITE_UTP; +drop public synonym UT_TEST; +drop public synonym UT_TESTCASE; +drop public synonym UT_TESTPREP; +drop public synonym UT_UNITTEST; +drop public synonym UT_UTOUTPUT; +drop public synonym UT_UTP; +drop sequence UTA_EQ_SEQ; +drop sequence UTPLSQL_RUNNUM_SEQ; +drop sequence UTV_VALUE_SEQ; +drop sequence UT_ASSERTION_SEQ; +drop sequence UT_PACKAGE_SEQ; +drop sequence UT_RECEQ_SEQ; +drop sequence UT_REFCURSOR_RESULTS_SEQ; +drop sequence UT_SUITE_SEQ; +drop sequence UT_TESTCASE_SEQ; +drop sequence UT_TEST_SEQ; +drop sequence UT_UNITTEST_SEQ; +drop sequence UT_UTP_SEQ; +drop table UTA_EQ cascade constraints; +drop table UTR_ERROR cascade constraints; +drop table UTR_OUTCOME cascade constraints; +drop table UTR_SUITE cascade constraints; +drop table UTR_TESTCASE cascade constraints; +drop table UTR_UNITTEST cascade constraints; +drop table UTR_UTP cascade constraints; +drop table UTV_VALUE cascade constraints; +drop table UT_ARGUMENT cascade constraints; +drop table UT_ASSERTION cascade constraints; +drop table UT_CONFIG cascade constraints; +drop table UT_DETERMINISTIC cascade constraints; +drop table UT_DETERMINISTIC_ARG cascade constraints; +drop table UT_EQ cascade constraints; +drop table UT_GRID cascade constraints; +drop table UT_OUTCOME cascade constraints; +drop table UT_PACKAGE cascade constraints; +drop table UT_RECEQ cascade constraints; +drop table UT_RECEQ_PKG cascade constraints; +drop table UT_SUITE cascade constraints; +drop table UT_SUITE_UTP cascade constraints; +drop table UT_TEST cascade constraints; +drop table UT_TESTCASE cascade constraints; +drop table UT_TESTPREP cascade constraints; +drop table UT_UNITTEST cascade constraints; +drop table UT_UTP cascade constraints; SPOOL OFF SET TERMOUT ON From a3e93cf59193a6e00044599e88f652bb1c967c21 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 28 May 2003 14:29:50 +0000 Subject: [PATCH 044/143] Added avail file --- CVSROOT/avail | 8 ++++++++ CVSROOT/checkoutlist | 1 + 2 files changed, 9 insertions(+) create mode 100755 CVSROOT/avail diff --git a/CVSROOT/avail b/CVSROOT/avail new file mode 100755 index 000000000..2df8312e6 --- /dev/null +++ b/CVSROOT/avail @@ -0,0 +1,8 @@ +unavail +avail|chrisrimmer +avail|patch72 +avail|plsqlguy +avail|billp +avail|cmarac +avail|wtoddl +avail|thalanki_naveen diff --git a/CVSROOT/checkoutlist b/CVSROOT/checkoutlist index b04b3501f..5719ec3d9 100755 --- a/CVSROOT/checkoutlist +++ b/CVSROOT/checkoutlist @@ -11,3 +11,4 @@ # [] # # comment lines begin with '#' +avail From f0938b7dbe2df8aa174a771371e193ae88c50ccf Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 28 May 2003 14:33:32 +0000 Subject: [PATCH 045/143] Added cvs_acl --- CVSROOT/commitinfo | 1 + 1 file changed, 1 insertion(+) diff --git a/CVSROOT/commitinfo b/CVSROOT/commitinfo index b19e7b7a6..c81f202ef 100755 --- a/CVSROOT/commitinfo +++ b/CVSROOT/commitinfo @@ -13,3 +13,4 @@ # # If the name "ALL" appears as a regular expression it is always used # in addition to the first matching regex or "DEFAULT". +ALL /cvsroot/sitedocs/CVSROOT/cvstools/cvs_acls From cdf5e6dc24e46ef0a4391edf02bcfd2b0aaf6cd3 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 28 May 2003 14:37:27 +0000 Subject: [PATCH 046/143] tweak --- source/ut_utp.pkb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ut_utp.pkb b/source/ut_utp.pkb index 473e7e817..60c3cf175 100644 --- a/source/ut_utp.pkb +++ b/source/ut_utp.pkb @@ -324,7 +324,7 @@ prefix_out := rec.prefix; END; PROCEDURE upd ( - id_in IN ut_utp.id%TYPE, + id_in IN ut_utp.id%TYPE, program_directory_in IN ut_utp.program_directory%TYPE := NULL, directory_in IN ut_utp.directory%TYPE := NULL, name_in IN ut_utp.name%TYPE := NULL, From c02475af240bf94e279f7c9fbfcbb6bd41948831 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 29 May 2003 07:50:17 +0000 Subject: [PATCH 047/143] Removed cmarac from list --- CVSROOT/avail | 1 - 1 file changed, 1 deletion(-) diff --git a/CVSROOT/avail b/CVSROOT/avail index 2df8312e6..c7ad6c7fc 100755 --- a/CVSROOT/avail +++ b/CVSROOT/avail @@ -3,6 +3,5 @@ avail|chrisrimmer avail|patch72 avail|plsqlguy avail|billp -avail|cmarac avail|wtoddl avail|thalanki_naveen From ed9e544530e9d034dd9a3b0dff7ef5cefe12b615 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 30 May 2003 07:49:45 +0000 Subject: [PATCH 048/143] Removed a temporary spool file from repository --- source/ut_i_spool_temp.sql | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 source/ut_i_spool_temp.sql diff --git a/source/ut_i_spool_temp.sql b/source/ut_i_spool_temp.sql deleted file mode 100644 index 52730ab0f..000000000 --- a/source/ut_i_spool_temp.sql +++ /dev/null @@ -1,31 +0,0 @@ -PROMPT Recompiling... -alter package UTCONFIG compile package; -alter package UTPLSQL compile package; -alter package UTRESULT compile package; -alter package UTPLSQL_UTIL compile package; -alter package UTASSERT2 compile package; -alter package UTASSERT compile package; -alter package UTPLSQL2 compile package; -alter package UTUTP compile package; -alter package UTRESULT2 compile package; -alter package UTOUTCOME compile package; -alter package UTUNITTEST compile package; -alter package UTTESTPREP compile package; -alter package UTTESTCASE compile package; -alter package UTPACKAGE compile package; -alter package UTSUITEUTP compile package; -alter package UTSUITE compile package; -alter package UTTEST compile package; -alter package UTAEQ compile package; -alter package UTGEN compile package; -alter package UTROUTCOME compile package; -alter package UTVVALUE compile package; -alter package UTRTESTCASE compile package; -alter package UTRUTP compile package; -alter package UTRUNITTEST compile package; -alter package UTRSUITE compile package; -alter package UTRERROR compile package; -alter package UTOUTPUT compile package; -alter package UTRECEQ compile package; -alter package UT_UTOUTPUT compile package; -PROMPT . Finished From a163a145066513e32a5eab587677a6d6beb476ed Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 30 May 2003 07:50:37 +0000 Subject: [PATCH 049/143] Fixed so that upgrade from 2.0.10.2 works --- source/ut_utp.tab | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/ut_utp.tab b/source/ut_utp.tab index 766f065d5..9f7a9720d 100644 --- a/source/ut_utp.tab +++ b/source/ut_utp.tab @@ -1,5 +1,4 @@ CREATE TABLE ut_utp ( - name VARCHAR2(30), /* V2: now constructed as UTPid */ id INTEGER, description VARCHAR2(2000), prefix VARCHAR2(10), /* V1 compatibility. V2: use ut_config.delimiter to construct names. */ @@ -19,6 +18,8 @@ CREATE TABLE ut_utp ( REM 2.0.8.1 ALTER TABLE ut_utp ADD per_method_setup char(1); +ALTER TABLE ut_utp ADD name VARCHAR2(30); + REM 2.1.1 REM /* Owner of UTP */ ALTER TABLE ut_utp ADD utp_owner VARCHAR2(30); From 4e33a1518b1ed5de8840d347acb8e0e86df49ddb Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 30 May 2003 07:52:08 +0000 Subject: [PATCH 050/143] Removed reference to OUNIT --- source/ut_i_install.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/ut_i_install.sql b/source/ut_i_install.sql index a494424c7..c97d01b08 100644 --- a/source/ut_i_install.sql +++ b/source/ut_i_install.sql @@ -41,7 +41,7 @@ DEFINE prompt_text='Creating &UT view ' ----------------------------------------------------PACKAGE HEADERS SET TERMOUT ON PROMPT &line1 -PROMPT CREATING OUNIT PACKAGE HEADERS +PROMPT CREATING utPLSQL PACKAGE HEADERS PROMPT &line1 DEFINE prompt_text='Creating &UT package specification ' @@ -51,7 +51,7 @@ DEFINE prompt_text='Creating &UT package specification ' ----------------------------------------------------PACKAGE BODIES SET TERMOUT ON PROMPT &line1 -PROMPT CREATING OUNIT PACKAGE BODIES +PROMPT CREATING utPLSQL PACKAGE BODIES PROMPT &line1 DEFINE prompt_text='Creating &UT package body ' From 1427f27e6ee3d541616e9637076b548413124bd8 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 30 May 2003 07:54:22 +0000 Subject: [PATCH 051/143] Fixed to recognise 9i --- source/ut_i_do.sql | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/source/ut_i_do.sql b/source/ut_i_do.sql index 0a81402ed..ac23f400b 100644 --- a/source/ut_i_do.sql +++ b/source/ut_i_do.sql @@ -23,7 +23,6 @@ DEFINE line2='=============================================================' DEFINE finished='. Finished' DEFINE UT='UT' ------- [PBA] this will not work when we don't have DBA rights or grant select on V$SESSION COLUMN col NOPRINT NEW_VALUE ut_owner select USER col from dual; @@ -48,30 +47,55 @@ SELECT SUBSTR(version,1,3) col FROM product_component_version WHERE UPPER(PRODUCT) LIKE 'ORACLE7%' OR UPPER(PRODUCT) LIKE 'PERSONAL ORACLE%' - OR UPPER(PRODUCT) LIKE 'ORACLE8%'; + OR UPPER(PRODUCT) LIKE 'ORACLE8%' + OR UPPER(PRODUCT) LIKE 'ORACLE9%'; +COLUMN col NOPRINT NEW_VALUE start92 +SELECT DECODE (UPPER('&v_orcl_vers'), + '9.2', '/* Use 9i code! */', + '/* Ignore 9i code') col + FROM dual; + +COLUMN col NOPRINT NEW_VALUE end92 +SELECT DECODE (upper('&v_orcl_vers'), + '9.2', '/* Use 9i code! */', + 'Ignore 9i code */') col + FROM dual; + COLUMN col NOPRINT NEW_VALUE start81 SELECT DECODE (UPPER('&v_orcl_vers'), '8.1', '/* Use 8i code! */', - '/* Ignore 8i code') col + '9.0', '/* Use 8i code! */', + '9.1', '/* Use 8i code! */', + '9.2', '/* Use 8i code! */', + '/* Ignore 8i code') col FROM dual; COLUMN col NOPRINT NEW_VALUE end81 SELECT DECODE (upper('&v_orcl_vers'), '8.1', '/* Use 8i code! */', - 'Ignore 8i code */') col + '9.0', '/* Use 8i code! */', + '9.1', '/* Use 8i code! */', + '9.2', '/* Use 8i code! */', + 'Ignore 8i code */') col FROM dual; COLUMN col NOPRINT NEW_VALUE start73 SELECT DECODE (UPPER('&v_orcl_vers'), '8.1', '/* Ignore Oracle7 code! ', - '/* Use Oracle7 code */') col + '9.0', '/* Ignore Oracle7 code! ', + '9.1', '/* Ignore Oracle7 code! ', + '9.2', '/* Ignore Oracle7 code! ', + '/* Use Oracle7 code */') col FROM dual; COLUMN col NOPRINT NEW_VALUE end73 SELECT DECODE (UPPER('&v_orcl_vers'), '8.1', 'Ignore Oracle7 code! */', - '/* Use Oracle7 code */') col + '9.0', 'Ignore Oracle7 code! */', + '9.1', 'Ignore Oracle7 code! */', + '9.2', 'Ignore Oracle7 code! */', + '/* Use Oracle7 code */') col FROM dual; ------------------------------------------------------ From becc21fe5ec600e7dd6395d9274ff3727ff948da Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Mon, 2 Jun 2003 16:29:14 +0000 Subject: [PATCH 052/143] Removed thalanki_naveen --- CVSROOT/avail | 1 - 1 file changed, 1 deletion(-) diff --git a/CVSROOT/avail b/CVSROOT/avail index c7ad6c7fc..51aa060b2 100755 --- a/CVSROOT/avail +++ b/CVSROOT/avail @@ -4,4 +4,3 @@ avail|patch72 avail|plsqlguy avail|billp avail|wtoddl -avail|thalanki_naveen From c2a8fac0049ed6a55cbf4d6ed35e47af0d692c87 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 4 Jun 2003 14:57:30 +0000 Subject: [PATCH 053/143] Removed billp and wtoddl --- CVSROOT/avail | 2 -- 1 file changed, 2 deletions(-) diff --git a/CVSROOT/avail b/CVSROOT/avail index 51aa060b2..8ae4257d5 100755 --- a/CVSROOT/avail +++ b/CVSROOT/avail @@ -2,5 +2,3 @@ unavail avail|chrisrimmer avail|patch72 avail|plsqlguy -avail|billp -avail|wtoddl From 8c58878421ddc25f9b77abbe4d8f6a778aad1021 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Mon, 9 Jun 2003 16:19:46 +0000 Subject: [PATCH 054/143] Replaced numbers with words to determine install type --- source/ut_i_do.sql | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/source/ut_i_do.sql b/source/ut_i_do.sql index ac23f400b..1f8820654 100644 --- a/source/ut_i_do.sql +++ b/source/ut_i_do.sql @@ -10,35 +10,38 @@ SET DEFINE ON ---------------------------------------------------- -- ou installator -- --- paprameter 1 values: +-- parameter 1 values: -- --- 1 - UT full installation --- 2 - Recompile UT code base --- 3 - Create public synonyms for UT --- 4 - Deinstall UT +-- install - UT full installation +-- recompile - Recompile UT code base +-- synonyms - Create public synonyms for UT +-- uninstall - Deinstall UT ---------------------------------------------------- DEFINE line1='-------------------------------------------------------------' DEFINE line2='=============================================================' DEFINE finished='. Finished' -DEFINE UT='UT' +DEFINE UT='utPLSQL' COLUMN col NOPRINT NEW_VALUE ut_owner select USER col from dual; COLUMN col NOPRINT NEW_VALUE next_script -select decode(&1,1,'ut_i_install', - 2,'ut_i_recompile', - 3,'ut_i_synonyms', - 4,'ut_i_uninstall', +select decode(LOWER('&1'),'install','ut_i_install', + 'recompile','ut_i_recompile', + 'compile','ut_i_recompile', + 'synonyms','ut_i_synonyms', + 'synonym','ut_i_synonyms', + 'uninstall','ut_i_uninstall', + 'deinstall','ut_i_uninstall', 'ERROR') col from dual; COLUMN col NOPRINT NEW_VALUE txt_prompt -select decode(&1,1,'I N S T A L L A T I O N', - 2,'R E C O M P I L A T I O N', - 3,'S Y N O N Y M S', - 4,'D E I N S T A L L A T I O N', +select decode('&next_script','ut_i_install','I N S T A L L A T I O N', + 'ut_i_recompile','R E C O M P I L A T I O N', + 'ut_i_synonyms','S Y N O N Y M S', + 'ut_i_uninstall','D E I N S T A L L A T I O N', 'ERROR') col from dual; ------------------------------------------------------ COLUMN col NOPRINT NEW_VALUE v_orcl_vers From c43e939471f38d7169ed91034887cd7e44a1338d Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Mon, 9 Jun 2003 16:21:24 +0000 Subject: [PATCH 055/143] Minor Tweak --- source/ut_i_install.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/ut_i_install.sql b/source/ut_i_install.sql index c97d01b08..94830dd7b 100644 --- a/source/ut_i_install.sql +++ b/source/ut_i_install.sql @@ -41,7 +41,7 @@ DEFINE prompt_text='Creating &UT view ' ----------------------------------------------------PACKAGE HEADERS SET TERMOUT ON PROMPT &line1 -PROMPT CREATING utPLSQL PACKAGE HEADERS +PROMPT CREATING &UT PACKAGE HEADERS PROMPT &line1 DEFINE prompt_text='Creating &UT package specification ' @@ -51,7 +51,7 @@ DEFINE prompt_text='Creating &UT package specification ' ----------------------------------------------------PACKAGE BODIES SET TERMOUT ON PROMPT &line1 -PROMPT CREATING utPLSQL PACKAGE BODIES +PROMPT CREATING &UT PACKAGE BODIES PROMPT &line1 DEFINE prompt_text='Creating &UT package body ' From 7b5ce66aa1fca52ad32841214243fb8c571e1e2f Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Mon, 9 Jun 2003 16:22:40 +0000 Subject: [PATCH 056/143] Minor Tweaks --- source/ut_i_synonyms.sql | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/ut_i_synonyms.sql b/source/ut_i_synonyms.sql index 9de029fa8..33c202e12 100644 --- a/source/ut_i_synonyms.sql +++ b/source/ut_i_synonyms.sql @@ -21,11 +21,12 @@ COLUMN col NOPRINT NEW_VALUE fine select count(privilege) col from session_privs where privilege='CREATE PUBLIC SYNONYM'; SPOOL &uscript -select decode(&fine,0,'','PROMPT Creating synonyms for packages...') from dual; +select decode(&fine,0,'','PROMPT Creating synonyms ...') from dual; select decode(&fine,0,'','create public synonym '||object_name||' for '||object_name||';') from all_objects -where owner='&ut_owner' and object_name like 'UT%' and - object_type in ('PACKAGE','TABLE','VIEW','SEQUENCE'); +where owner='&ut_owner' +and object_name like 'UT%' +and object_type IN ('PACKAGE', 'TABLE', 'VIEW', 'SEQUENCE'); select decode(&fine,0,'','PROMPT &finished') from dual; select decode(&fine,1,'','PROMPT Skipped - user has no rights to create public synonyms') from dual; From 3e7ab2d2c5e49003288b11d4da81fe52b3e1d4cd Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Mon, 9 Jun 2003 16:23:47 +0000 Subject: [PATCH 057/143] Added in missing synonyms --- source/ut_i_uninstall.sql | 41 +++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/source/ut_i_uninstall.sql b/source/ut_i_uninstall.sql index 4774f3c32..4b834efd4 100644 --- a/source/ut_i_uninstall.sql +++ b/source/ut_i_uninstall.sql @@ -8,6 +8,11 @@ SET DEFINE ON TTITLE OFF SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED +SET TERMOUT ON +PROMPT &line1 +PROMPT DROPPING &UT PACKAGES +PROMPT &line1 + drop package UTAEQ; drop package UTASSERT2; drop package UTASSERT; @@ -36,6 +41,12 @@ drop package UTTESTPREP; drop package UTUNITTEST; drop package UTUTP; drop package UTVVALUE; + +SET TERMOUT ON +PROMPT &line1 +PROMPT DROPPING &UT PUBLIC SYNONYMS +PROMPT &line1 + drop public synonym UTAEQ; drop public synonym UTASSERT2; drop public synonym UTASSERT; @@ -91,6 +102,26 @@ drop public synonym UT_TESTPREP; drop public synonym UT_UNITTEST; drop public synonym UT_UTOUTPUT; drop public synonym UT_UTP; +drop public synonym UTA_EQ_SEQ; +drop public synonym UTPLSQL_RUNNUM_SEQ; +drop public synonym UTV_VALUE_SEQ; +drop public synonym UT_ASSERTION_SEQ; +drop public synonym UT_PACKAGE_SEQ; +drop public synonym UT_RECEQ_SEQ; +drop public synonym UT_REFCURSOR_RESULTS_SEQ; +drop public synonym UT_SUITE_SEQ; +drop public synonym UT_TESTCASE_SEQ; +drop public synonym UT_TEST_SEQ; +drop public synonym UT_UNITTEST_SEQ; +drop public synonym UT_UTP_SEQ; +drop public synonym UTV_LAST_RUN; +drop public synonym UTV_RESULT_FULL; + +SET TERMOUT ON +PROMPT &line1 +PROMPT DROPPING &UT SEQUENCES +PROMPT &line1 + drop sequence UTA_EQ_SEQ; drop sequence UTPLSQL_RUNNUM_SEQ; drop sequence UTV_VALUE_SEQ; @@ -103,6 +134,12 @@ drop sequence UT_TESTCASE_SEQ; drop sequence UT_TEST_SEQ; drop sequence UT_UNITTEST_SEQ; drop sequence UT_UTP_SEQ; + +SET TERMOUT ON +PROMPT &line1 +PROMPT DROPPING &UT TABLES +PROMPT &line1 + drop table UTA_EQ cascade constraints; drop table UTR_ERROR cascade constraints; drop table UTR_OUTCOME cascade constraints; @@ -130,7 +167,3 @@ drop table UT_TESTPREP cascade constraints; drop table UT_UNITTEST cascade constraints; drop table UT_UTP cascade constraints; -SPOOL OFF -SET TERMOUT ON - -@@&uscript From 4c9711035a357ebdefc3def155c4a896ffd3c6b5 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 10 Jun 2003 11:26:31 +0000 Subject: [PATCH 058/143] Added new installation instructions --- documentation/src/fourstep.html | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/documentation/src/fourstep.html b/documentation/src/fourstep.html index 2f5ba497c..8971ced45 100644 --- a/documentation/src/fourstep.html +++ b/documentation/src/fourstep.html @@ -24,7 +24,6 @@

      Step 1. Install (and Upgrade) utPLSQL.

      over the existing installation, please follow the steps below for removing utPLSQL.

      -

      Connect via SQL*Plus to the session that will own the utPLSQL components. If you do not already have a schema defined, then you must create it. The utPLSQL schema must have the authority to:

      @@ -52,34 +51,34 @@

      Step 1. Install (and Upgrade) utPLSQL.

      grant execute on dbms_pipe to utp;

    Note If the schema in question does not have the ability to create and drop public synonyms, you -will get error messages when installing. However, utPLSQL will still function correctly.

    +may get error messages when installing. However, utPLSQL will still function correctly.

    -

    Once you have connected to the schema, run the utplsql_install.sql -file to install all utPLSQL objects. If the working directory of your SQL*Plus -session is the directory holding the utPLSQL files, you can issue this command:

    +

    Once you have connected to the schema, run the ut_i_do.sql +file with the parameter "install" to install all utPLSQL objects. If the working directory of your SQL*Plus +session is the directory holding the utPLSQL files, you can issue this as follows:

    -
    SQL> @utplsql_install
     
    +
    SQL> @ut_i_do install
     

    If the working directory of your SQL*Plus session is not the directory holding the utPLSQL files, you can issue this command:

    -
    SQL> @<directory>utplsql_install
     
    +
    SQL> @<directory>ut_i_do install
     

    as in:

    -
    SQL> @c:\utplsql\utplsql_install
     
    +
    SQL> @c:\utplsql\ut_i_do install
     

    or

    -
    SQL> @/orautils/utplsql/utplsql_install
     
    +
    SQL> @/orautils/utplsql/ut_i_do install
     

    This file will remove the existing installation of utPLSQL and then create all tables and packages needed.

    @@ -87,22 +86,22 @@

    Step 1. Install (and Upgrade) utPLSQL.

    To check the installation of utPLSQL, examine the -utplsql_install.log file.

    +ut_i_install.log file.

    Removing utPLSQL

    -

    To de-install the product, run the utplsql_uninstall.sql -script, as in:

    +

    To de-install the product, run the ut_i_do.sql +script again, but with the parameter "uninstall", as in:

    -
    SQL> @utplsql_uninstall
     
    +
    SQL> @ut_i_do uninstall
     

    or

    -
    SQL> @<directory>utplsql_uninstall
    +
    SQL> @<directory>ut_i_do uninstall

    Step 2. Choose a program to test and identify the test cases.

    From 550b93cee36703baf4a39fed612c6a61bd8d5036 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 10 Jun 2003 14:31:21 +0000 Subject: [PATCH 059/143] Fixed so that dbms_output is turned on automatically --- source/ut_utoutput.pkb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/ut_utoutput.pkb b/source/ut_utoutput.pkb index 5da9d10a4..7afefcc16 100644 --- a/source/ut_utoutput.pkb +++ b/source/ut_utoutput.pkb @@ -13,7 +13,7 @@ IS PROCEDURE ut_setup IS BEGIN - NULL; + dbms_output.enable(1000000); END; PROCEDURE ut_teardown From 4956bfa574ab4c2f4457e64e1bc9bc95147d570b Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 18 Jun 2003 13:00:15 +0000 Subject: [PATCH 060/143] Removed utgen.exe documentation --- documentation/src/map.txt | 1 - documentation/src/utgen_frontend.html | 68 -------------------------- documentation/utgen_function.jpg | Bin 104138 -> 0 bytes documentation/utgen_package.jpg | Bin 112458 -> 0 bytes documentation/utgen_procedure.jpg | Bin 89232 -> 0 bytes 5 files changed, 69 deletions(-) delete mode 100644 documentation/src/utgen_frontend.html delete mode 100644 documentation/utgen_function.jpg delete mode 100644 documentation/utgen_package.jpg delete mode 100644 documentation/utgen_procedure.jpg diff --git a/documentation/src/map.txt b/documentation/src/map.txt index 18bc7d8d4..fe73c9ca4 100644 --- a/documentation/src/map.txt +++ b/documentation/src/map.txt @@ -28,7 +28,6 @@ fileout.html,Configuring File Output utresult.html,utResult Package utassert.html,utAssert Package utgen.html,utGen Package -utgen_frontend.html,utGen Front-End utoutput.html,utOutput Package utreceq.html,utRecEq Package defsuite.html,Define Test Suites diff --git a/documentation/src/utgen_frontend.html b/documentation/src/utgen_frontend.html deleted file mode 100644 index 2286b5a96..000000000 --- a/documentation/src/utgen_frontend.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - -

    -utGen Front End -

    -

    -Introduction -

    -With the utGen package it is possible to generate a test package based on the information in the table ut_grid:
    -
    -  PROCEDURE testpkg_from_table (
    -      package_in       IN   VARCHAR2,
    -      program_in       IN   VARCHAR2 := '%',
    -      samepackage_in   IN   BOOLEAN := FALSE,
    -      prefix_in        IN   VARCHAR2 := NULL,
    -      schema_in        IN   VARCHAR2 := NULL,
    -      output_type_in   IN   PLS_INTEGER := c_screen,
    -      dir_in           IN   VARCHAR2 := NULL,
    -      date_format_in       IN   VARCHAR2
    -            := 'MM/DD/YYYY'
    -  );
    -
    -This procedure is based on the testpkg_from_string procedure. -You can fill this table with test cases using the Windows frontend utgen.exe provided in the utplsql framework.
    -
    -The frontend looks like this:
    - -

    -Objects -

    -This is the object browser for utgen.exe. I retrieves all Functions, Procedures and Packages from the database. Select the Function, Procedure or Package you want to create testcases for.
    -

    -Procedures -

    -If you selected a Package then the package contents are displayed here. If a function or procedure in the package is overloaded then they will display the overload number Oracle gives it prefixed by a colon (:)
    -Here you can select the function of procedure from the package you want to create testcases for.
    -

    -Parameters -

    -When you have selected a function or procedure then here the parameters are displayed. In the last column you can enter the values for these parameters.
    -Using the button [set argument list] you can set the values in the testcase.
    -Using the button [get argument list] you can get the values from a selected testcase from the database
    -

    -utPL/SQL info -

    -On this line you can enter your test case name (tcname), a (unique) message for the testcase and the assertion type (currently only supports EQ and ISNULL)
    -

    -Testcases -

    -Here you can see the defined testcases for the selected function or procedure.
    -Select one of these cases and press [Modify] to modify this case (to modify the arguments list use the [get arguments list] button).
    -Select one of these cases and press [Delete] to delete this case from the database.
    - -

    -Procedure -

    -This is how the screen looks when you select a procedure - -

    -Package -

    -This is how the screen looks when you select a procedure - - - - diff --git a/documentation/utgen_function.jpg b/documentation/utgen_function.jpg deleted file mode 100644 index 499bf3c28d7c0f481603483e60725cf824eb3bb8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 104138 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 nuS!C8F^XulLc%HwI^uXLF#-s){O#AOZpc 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 Z%RQ!#J?FunUMPRYAxPP@=jdakaciMOD7%)V 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 From 431db55a38c2e0d55a1b84a366a6e9f8f599725a Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 18 Jun 2003 13:02:28 +0000 Subject: [PATCH 061/143] Removed broken links, added 2.1.1 release notes --- documentation/src/admin.html | 6 ------ documentation/src/release.html | 17 +++++++++++++++-- documentation/src/utplsql.html | 2 +- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/documentation/src/admin.html b/documentation/src/admin.html index fa599833a..ea420f111 100644 --- a/documentation/src/admin.html +++ b/documentation/src/admin.html @@ -14,12 +14,6 @@

    -

    -Components

    - -

    -File Descriptions

    -

    Administrative Topics

    diff --git a/documentation/src/release.html b/documentation/src/release.html index 82a0a54b1..a8886bab1 100644 --- a/documentation/src/release.html +++ b/documentation/src/release.html @@ -22,6 +22,19 @@

    utPLSQL version 2.x

    Change History

    +

    utPLSQL version 2.1.1

    +
      +
    • +This version has a variety of small fixes and is released to coincide +with OUnit version 1.0. +
    • +
    • +The installation procedure has been changed and a variety of bugs with it have been fixed. +
    • +
    • +utGen.exe has been removed from the "core" utPLSQL distribution. The functionallity it supplied will be included in a future version of Ounit. +
    • +

    utPLSQL version 2.0.10.1

    • @@ -579,8 +592,8 @@

      assertions.

      -You can also now request that utAssert show the -results of a test immediately +You can also now request that utAssert show the +results of a test immediately after execution. This allows you to build small test scripts without have to create a test package and run it through the utPLSQL test engine.

      diff --git a/documentation/src/utplsql.html b/documentation/src/utplsql.html index 79d3d9473..20e816950 100644 --- a/documentation/src/utplsql.html +++ b/documentation/src/utplsql.html @@ -273,7 +273,7 @@

      Recording and Accessing Test Statistics

      the test
    -

    All of this is done for you automatically. You can then write queries and reports against the +

    All of this is done for you automatically. You can then write queries and reports against the ut_package and ut_suite tables.

    Register a Unit Test

    From b899af37986af62d596e30fd3ed0983f2f8e8bf3 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 18 Jun 2003 13:17:53 +0000 Subject: [PATCH 062/143] Added to CVS --- documentation/readme.txt | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 documentation/readme.txt diff --git a/documentation/readme.txt b/documentation/readme.txt new file mode 100644 index 000000000..f383fe3fc --- /dev/null +++ b/documentation/readme.txt @@ -0,0 +1,36 @@ +==================================================================== +Welcome to utPLSQL, the unit testing framework for PL/SQL +==================================================================== + +Copyright (c) 2000-2003, Steven Feuerstein and the utPLSQL Project + +You have downloaded utPLSQL. + +It is not warranted to be free of bugs. + +Use it at your own risk (but, believe me, there's nothing very risky about it). + +TO INSTALL + +1. Unzip the software into the directory of your choice. It will create three +sub-directories: Code, Examples and Doc. + +2. Open the Doc/index.html file and follow instructions in the Getting Started +document for either installing or upgrading utPLSQL. + +TO USE + +Review the on-line documentation. Start with Getting Started, then check out +Build Test Packages and dip into the User Guide as needed. + +Any questions? Go to the utPLSQL Forum at + +http://utplsql.oracledeveloper.nl + +and let us know about it. + + +Thanks, +Steven Feuerstein + +$Id$ From f740036d0a54982a652856befad5ee174e315d01 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 27 Jun 2003 15:49:39 +0000 Subject: [PATCH 063/143] Added in GPL License File --- source/license.txt | 281 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 source/license.txt diff --git a/source/license.txt b/source/license.txt new file mode 100644 index 000000000..8f5b408d9 --- /dev/null +++ b/source/license.txt @@ -0,0 +1,281 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 + Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS From 0bbad8513826c6dc8453710298c70902f9259bb2 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 27 Jun 2003 15:50:29 +0000 Subject: [PATCH 064/143] Added in missing definition of setfiledir --- source/ut_config.pks | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/ut_config.pks b/source/ut_config.pks index 6ea21bf3f..8a3378b73 100644 --- a/source/ut_config.pks +++ b/source/ut_config.pks @@ -106,7 +106,12 @@ IS /* end 2.0.10.1 additions */ - -- RMM start + -- Set the directory for file output + PROCEDURE setfiledir ( + dir_in IN VARCHAR2 := NULL + ,username_in IN VARCHAR2 := NULL + ); + -- Get the directory for file output FUNCTION filedir (username_in IN VARCHAR2 := NULL) RETURN VARCHAR2; From 14485a5110673916429682e95f1b8ff92d59951a Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 27 Jun 2003 15:51:45 +0000 Subject: [PATCH 065/143] Removed UTAEQ and UTVVALUE tables, associated packages and sequences. --- source/ut_aeq.pkb | 742 ------------------------------- source/ut_aeq.pks | 251 ----------- source/ut_i_packages.sql | 2 - source/ut_i_packages_b.sql | 2 - source/ut_i_sequences.sql | 2 - source/ut_i_tables.sql | 2 - source/ut_i_uninstall.sql | 12 - source/ut_vvalue.pkb | 880 ------------------------------------- source/ut_vvalue.pks | 274 ------------ source/uta_eq.tab | 17 - source/uta_eq_seq.seq | 1 - source/utv_value.tab | 17 - source/utv_value_seq.seq | 1 - 13 files changed, 2203 deletions(-) delete mode 100644 source/ut_aeq.pkb delete mode 100644 source/ut_aeq.pks delete mode 100644 source/ut_vvalue.pkb delete mode 100644 source/ut_vvalue.pks delete mode 100644 source/uta_eq.tab delete mode 100644 source/uta_eq_seq.seq delete mode 100644 source/utv_value.tab delete mode 100644 source/utv_value_seq.seq diff --git a/source/ut_aeq.pkb b/source/ut_aeq.pkb deleted file mode 100644 index 35dbc037e..000000000 --- a/source/ut_aeq.pkb +++ /dev/null @@ -1,742 +0,0 @@ -/* Formatted on 2001/09/15 08:57 (RevealNet Formatter v4.4.1) */ -CREATE OR REPLACE PACKAGE BODY utaeq ---//----------------------------------------------------------------------- ---// ** PL/Generator Table Encapsulator for "UTA_EQ" ---//----------------------------------------------------------------------- ---// (c) COPYRIGHT Personnel Policies, Inc. 2001. ---// All rights reserved. ---// ---// No part of this copyrighted work may be reproduced, modified, ---// or distributed in any form or by any means without the prior ---// written permission of Personnel Policies, Inc.. ---//----------------------------------------------------------------------- ---// This software was generated by RevealNet's PL/Generator (TM). ---// ---// For more information, visit www.revealnet.com or call 1.800.REVEAL4 ---//----------------------------------------------------------------------- ---// Stored In: utaeq.pkb ---// Created On: September 15, 2001 08:44:51 ---// Created By: SCOTT ---// PL/Generator Version: PRO-2000.2.9 ---//----------------------------------------------------------------------- -IS - --// Package name and program name globals --// - c_pkgname VARCHAR2 (30) := 'utaeq'; - g_progname VARCHAR2 (30) := NULL; - - --// Update Flag private data structures. --// - TYPE frcflg_rt IS RECORD ( - outcome_id CHAR (1), - data_type CHAR (1), - check_value_id CHAR (1), - against_value_id CHAR (1)); - - frcflg frcflg_rt; - emptyfrc frcflg_rt; - c_set CHAR (1) := 'Y'; - c_noset CHAR (1) := 'N'; - - FUNCTION version - RETURN VARCHAR2 - IS - BEGIN - RETURN '7.09'; - END; - - ---// Private Modules //-- - - --// For Dynamic SQL operations; currently unused. //-- - PROCEDURE initcur (cur_inout IN OUT INTEGER) - IS - BEGIN - IF NOT DBMS_SQL.is_open (cur_inout) - THEN - cur_inout := DBMS_SQL.open_cursor; - END IF; - EXCEPTION - WHEN INVALID_CURSOR - THEN - cur_inout := DBMS_SQL.open_cursor; - END; - - PROCEDURE start_program (nm IN VARCHAR2, msg IN VARCHAR2 := NULL) - IS - BEGIN - g_progname := nm; - END; - - PROCEDURE end_program - IS - BEGIN - g_progname := NULL; - END; - - ---// Cursor management procedures //-- - - --// Open the cursors with some options. //-- - PROCEDURE open_allforpky_cur ( - id_in IN uta_eq.id%TYPE, - close_if_open IN BOOLEAN := TRUE - ) - IS - v_close BOOLEAN := NVL (close_if_open, TRUE); - v_open BOOLEAN := TRUE; - BEGIN - start_program ('open_allforpky_cur'); - - IF allforpky_cur%ISOPEN - AND v_close - THEN - CLOSE allforpky_cur; - ELSIF allforpky_cur%ISOPEN - AND NOT v_close - THEN - v_open := FALSE; - END IF; - - IF v_open - THEN - OPEN allforpky_cur (id_in); - END IF; - - end_program; - END; - - PROCEDURE open_allbypky_cur (close_if_open IN BOOLEAN := TRUE) - IS - v_close BOOLEAN := NVL (close_if_open, TRUE); - v_open BOOLEAN := TRUE; - BEGIN - IF allbypky_cur%ISOPEN - AND v_close - THEN - CLOSE allbypky_cur; - ELSIF allbypky_cur%ISOPEN - AND NOT v_close - THEN - v_open := FALSE; - END IF; - - IF v_open - THEN - OPEN allbypky_cur; - END IF; - END; - - PROCEDURE open_uta_eq_outcome_fk_all_cur ( - outcome_id_in IN uta_eq.outcome_id%TYPE, - close_if_open IN BOOLEAN := TRUE - ) - IS - v_close BOOLEAN := NVL (close_if_open, TRUE); - v_open BOOLEAN := TRUE; - BEGIN - IF uta_eq_outcome_fk_all_cur%ISOPEN - AND v_close - THEN - CLOSE uta_eq_outcome_fk_all_cur; - ELSIF uta_eq_outcome_fk_all_cur%ISOPEN - AND NOT v_close - THEN - v_open := FALSE; - END IF; - - IF v_open - THEN - OPEN uta_eq_outcome_fk_all_cur (outcome_id_in); - END IF; - END; - - --// Close the cursors if they are open. //-- - PROCEDURE close_allforpky_cur - IS - BEGIN - IF allforpky_cur%ISOPEN - THEN - CLOSE allforpky_cur; - END IF; - END; - - PROCEDURE close_allbypky_cur - IS - BEGIN - IF allbypky_cur%ISOPEN - THEN - CLOSE allbypky_cur; - END IF; - END; - - PROCEDURE close_uta_eq_outcome_fk_all_cu - IS - BEGIN - IF uta_eq_outcome_fk_all_cur%ISOPEN - THEN - CLOSE uta_eq_outcome_fk_all_cur; - END IF; - END; - - PROCEDURE closeall - IS - BEGIN - close_allforpky_cur; - close_allbypky_cur; - close_uta_eq_outcome_fk_all_cu; - END; - - ---// Emulate aggregate-level record operations. //-- - - FUNCTION recseq (rec1 IN allcols_rt, rec2 IN allcols_rt) - RETURN BOOLEAN - IS - unequal_records EXCEPTION; - retval BOOLEAN; - BEGIN - retval := rec1.id = rec2.id - OR ( rec1.id IS NULL - AND rec2.id IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - retval := rec1.outcome_id = rec2.outcome_id - OR ( rec1.outcome_id IS NULL - AND rec2.outcome_id IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - retval := rec1.data_type = rec2.data_type - OR ( rec1.data_type IS NULL - AND rec2.data_type IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - retval := rec1.check_value_id = rec2.check_value_id - OR ( rec1.check_value_id IS NULL - AND rec2.check_value_id IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - retval := rec1.against_value_id = rec2.against_value_id - OR ( rec1.against_value_id IS NULL - AND rec2.against_value_id IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - RETURN TRUE; - EXCEPTION - WHEN unequal_records - THEN - RETURN FALSE; - END; - - FUNCTION recseq (rec1 IN pky_rt, rec2 IN pky_rt) - RETURN BOOLEAN - IS - unequal_records EXCEPTION; - retval BOOLEAN; - BEGIN - retval := rec1.id = rec2.id - OR ( rec1.id IS NULL - AND rec2.id IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - RETURN TRUE; - EXCEPTION - WHEN unequal_records - THEN - RETURN FALSE; - END; - - ---// Is the primary key NOT NULL? //-- - - FUNCTION isnullpky (rec_in IN allcols_rt) - RETURN BOOLEAN - IS - BEGIN - RETURN rec_in.id IS NULL; - END; - - FUNCTION isnullpky (rec_in IN pky_rt) - RETURN BOOLEAN - IS - BEGIN - RETURN rec_in.id IS NULL; - END; - - ---// Query Processing --// - - FUNCTION onerow_internal (id_in IN uta_eq.id%TYPE) - RETURN allcols_rt - IS - CURSOR onerow_cur - IS - SELECT id, outcome_id, data_type, check_value_id, - against_value_id - FROM uta_eq - WHERE id = id_in; - - onerow_rec allcols_rt; - BEGIN - OPEN onerow_cur; - FETCH onerow_cur INTO onerow_rec; - CLOSE onerow_cur; - RETURN onerow_rec; - END onerow_internal; - - FUNCTION onerow (id_in IN uta_eq.id%TYPE) - RETURN allcols_rt - IS - retval allcols_rt; - BEGIN - retval := onerow_internal (id_in); - RETURN retval; - END onerow; - - --// Count of all rows in table and for each foreign key. //-- - FUNCTION rowcount - RETURN INTEGER - IS - retval INTEGER; - BEGIN - SELECT COUNT (*) - INTO retval - FROM uta_eq; - RETURN retval; - END; - - FUNCTION pkyrowcount (id_in IN uta_eq.id%TYPE) - RETURN INTEGER - IS - retval INTEGER; - BEGIN - SELECT COUNT (*) - INTO retval - FROM uta_eq - WHERE id = id_in; - RETURN retval; - END; - - FUNCTION uta_eq_outcome_fkrowcount ( - outcome_id_in IN uta_eq.outcome_id%TYPE - ) - RETURN INTEGER - IS - retval INTEGER; - BEGIN - SELECT COUNT (*) - INTO retval - FROM uta_eq - WHERE outcome_id = uta_eq_outcome_fkrowcount.outcome_id_in; - RETURN retval; - END; - - --// Generate the next primary key: single column PKYs only --// - FUNCTION nextpky - RETURN uta_eq.id%TYPE - IS - retval uta_eq.id%TYPE; - BEGIN - SELECT uta_eq_seq.NEXTVAL - INTO retval - FROM DUAL; - RETURN retval; - END; - - ---// Update Processing --// - - PROCEDURE reset$frc - IS - BEGIN - frcflg := emptyfrc; - END reset$frc; - - FUNCTION outcome_id$frc ( - outcome_id_in IN uta_eq.outcome_id%TYPE DEFAULT NULL - ) - RETURN uta_eq.outcome_id%TYPE - IS - BEGIN - frcflg.outcome_id := c_set; - RETURN outcome_id_in; - END outcome_id$frc; - - FUNCTION data_type$frc ( - data_type_in IN uta_eq.data_type%TYPE DEFAULT NULL - ) - RETURN uta_eq.data_type%TYPE - IS - BEGIN - frcflg.data_type := c_set; - RETURN data_type_in; - END data_type$frc; - - FUNCTION check_value_id$frc ( - check_value_id_in IN uta_eq.check_value_id%TYPE DEFAULT NULL - ) - RETURN uta_eq.check_value_id%TYPE - IS - BEGIN - frcflg.check_value_id := c_set; - RETURN check_value_id_in; - END check_value_id$frc; - - FUNCTION against_value_id$frc ( - against_value_id_in IN uta_eq.against_value_id%TYPE - DEFAULT NULL - ) - RETURN uta_eq.against_value_id%TYPE - IS - BEGIN - frcflg.against_value_id := c_set; - RETURN against_value_id_in; - END against_value_id$frc; - - PROCEDURE upd ( - id_in IN uta_eq.id%TYPE, - outcome_id_in IN uta_eq.outcome_id%TYPE - DEFAULT NULL, - data_type_in IN uta_eq.data_type%TYPE DEFAULT NULL, - check_value_id_in IN uta_eq.check_value_id%TYPE - DEFAULT NULL, - against_value_id_in IN uta_eq.against_value_id%TYPE - DEFAULT NULL, - rowcount_out OUT INTEGER, - reset_in IN BOOLEAN DEFAULT TRUE - ) - IS - BEGIN - UPDATE uta_eq - SET outcome_id = DECODE ( - frcflg.outcome_id, - c_set, outcome_id_in, - NVL (outcome_id_in, outcome_id) - ), - data_type = DECODE ( - frcflg.data_type, - c_set, data_type_in, - NVL (data_type_in, data_type) - ), - check_value_id = DECODE ( - frcflg.check_value_id, - c_set, check_value_id_in, - NVL ( - check_value_id_in, - check_value_id - ) - ), - against_value_id = DECODE ( - frcflg.against_value_id, - c_set, against_value_id_in, - NVL ( - against_value_id_in, - against_value_id - ) - ) - WHERE id = id_in; - - rowcount_out := SQL%ROWCOUNT; - - IF reset_in - THEN - reset$frc; - END IF; - EXCEPTION - WHEN OTHERS - THEN - RAISE; - END upd; - - --// Record-based Update --// - PROCEDURE upd ( - rec_in IN allcols_rt, - rowcount_out OUT INTEGER, - reset_in IN BOOLEAN DEFAULT TRUE - ) - IS - BEGIN - upd ( - rec_in.id, - rec_in.outcome_id, - rec_in.data_type, - rec_in.check_value_id, - rec_in.against_value_id, - rowcount_out, - reset_in - ); - END upd; - - ---// Insert Processing --// - - --// Initialize record with default values. --// - FUNCTION initrec (allnull IN BOOLEAN := FALSE) - RETURN allcols_rt - IS - retval allcols_rt; - BEGIN - IF allnull - THEN - NULL; /* Default values are NULL already. */ - ELSE - retval.id := NULL; - retval.outcome_id := NULL; - retval.data_type := NULL; - retval.check_value_id := NULL; - retval.against_value_id := NULL; - END IF; - - RETURN retval; - END; - - --// Initialize record with default values. --// - PROCEDURE initrec ( - rec_inout IN OUT allcols_rt, - allnull IN BOOLEAN := FALSE - ) - IS - BEGIN - rec_inout := initrec; - END; - - PROCEDURE ins$ins ( - id_in IN uta_eq.id%TYPE, - outcome_id_in IN uta_eq.outcome_id%TYPE DEFAULT NULL, - data_type_in IN uta_eq.data_type%TYPE DEFAULT NULL, - check_value_id_in IN uta_eq.check_value_id%TYPE - DEFAULT NULL, - against_value_id_in IN uta_eq.against_value_id%TYPE - DEFAULT NULL, - upd_on_dup IN BOOLEAN := FALSE - ) - IS - BEGIN - INSERT INTO uta_eq - (id, outcome_id, data_type, - check_value_id, against_value_id) - VALUES (id_in, outcome_id_in, data_type_in, - check_value_id_in, against_value_id_in); - EXCEPTION - WHEN DUP_VAL_ON_INDEX - THEN - IF NOT NVL (upd_on_dup, FALSE) - THEN - RAISE; - ELSE - DECLARE - v_errm VARCHAR2 (2000) := SQLERRM; - v_rowcount INTEGER; - dotloc INTEGER; - leftloc INTEGER; - c_owner all_constraints.owner%TYPE; - c_name all_constraints.constraint_name%TYPE; - BEGIN - dotloc := INSTR (v_errm, '.'); - leftloc := INSTR (v_errm, '('); - c_owner := SUBSTR ( - v_errm, - leftloc - + 1, - dotloc - - leftloc - - 1 - ); - c_name := SUBSTR ( - v_errm, - dotloc - + 1, - INSTR (v_errm, ')') - - dotloc - - 1 - ); - - --// Duplicate based on primary key //-- - IF 'SYS_C004438' = c_name - AND /* 2000.2 'SCOTT' */ USER = c_owner - THEN - upd ( - id_in, - outcome_id_in, - data_type_in, - check_value_id_in, - against_value_id_in, - v_rowcount, - FALSE - ); - ELSE - --// Unique index violation. Cannot recover... //-- - RAISE; - END IF; - END; - END IF; - WHEN OTHERS - THEN - RAISE; - END ins$ins; - - --// Insert 1: with individual fields and return primary key //-- - PROCEDURE ins ( - outcome_id_in IN uta_eq.outcome_id%TYPE - DEFAULT NULL, - data_type_in IN uta_eq.data_type%TYPE DEFAULT NULL, - check_value_id_in IN uta_eq.check_value_id%TYPE - DEFAULT NULL, - against_value_id_in IN uta_eq.against_value_id%TYPE - DEFAULT NULL, - id_out IN OUT uta_eq.id%TYPE, - upd_on_dup IN BOOLEAN := FALSE - ) - IS - v_pky INTEGER := nextpky; - BEGIN - ins$ins ( - v_pky, - outcome_id_in, - data_type_in, - check_value_id_in, - against_value_id_in, - upd_on_dup - ); - id_out := v_pky; - END; - - PROCEDURE ins ( - outcome_id_in IN uta_eq.outcome_id%TYPE - DEFAULT NULL, - data_type_in IN uta_eq.data_type%TYPE - DEFAULT NULL, - check_value_in IN VARCHAR2, - check_is_expression_in IN BOOLEAN, - against_value_in IN VARCHAR2, - id_out IN OUT uta_eq.id%TYPE, - upd_on_dup IN BOOLEAN := FALSE - ) - IS - l_id uta_eq.id%TYPE; - l_check utv_value.id%TYPE; - l_against utv_value.id%TYPE; - BEGIN - utvvalue.ins ( - data_type_in => data_type_in, - is_expression_in => check_is_expression_in, - value_in => check_value_in, - id_out => l_check); - - utvvalue.ins ( - data_type_in => data_type_in, - is_expression_in => TRUE, - value_in => against_value_in, - id_out => l_against); - - ins (outcome_id_in, data_type_in, l_check, l_against, id_out, upd_on_dup); - END; - - --// Insert 2: with record, returning primary key. //-- - PROCEDURE ins ( - rec_in IN allcols_rt, - id_out IN OUT uta_eq.id%TYPE, - upd_on_dup IN BOOLEAN := FALSE - ) - IS - v_pky INTEGER := nextpky; - BEGIN - ins$ins ( - v_pky, - rec_in.outcome_id, - rec_in.data_type, - rec_in.check_value_id, - rec_in.against_value_id, - upd_on_dup - ); - id_out := v_pky; - END; - - ---// Delete Processing --// - - PROCEDURE del (id_in IN uta_eq.id%TYPE, rowcount_out OUT INTEGER) - IS - BEGIN - DELETE FROM uta_eq - WHERE id = id_in; - - rowcount_out := SQL%ROWCOUNT; - EXCEPTION - WHEN OTHERS - THEN - RAISE; - END del; - - --// Record-based delete --// - PROCEDURE del (rec_in IN pky_rt, rowcount_out OUT INTEGER) - IS - BEGIN - del (rec_in.id, rowcount_out); - END del; - - PROCEDURE del (rec_in IN allcols_rt, rowcount_out OUT INTEGER) - IS - BEGIN - del (rec_in.id, rowcount_out); - END del; - - --// Delete all records for foreign key UTA_EQ_OUTCOME_FK. //-- - PROCEDURE delby_uta_eq_outcome_fk ( - outcome_id_in IN uta_eq.outcome_id%TYPE, - rowcount_out OUT INTEGER - ) - IS - BEGIN - DELETE FROM uta_eq - WHERE outcome_id = delby_uta_eq_outcome_fk.outcome_id_in; - - rowcount_out := SQL%ROWCOUNT; - EXCEPTION - WHEN OTHERS - THEN - RAISE; - END delby_uta_eq_outcome_fk; - - --// Program called by database initialization script to pin the package. //-- - PROCEDURE pinme - IS - BEGIN - --// Doesn't do anything except cause the package to be loaded. //-- - NULL; - END; - ---// Initialization section for the package. --// -BEGIN - NULL; -- Placeholder. -END utaeq; -/ - diff --git a/source/ut_aeq.pks b/source/ut_aeq.pks deleted file mode 100644 index 0ba472670..000000000 --- a/source/ut_aeq.pks +++ /dev/null @@ -1,251 +0,0 @@ -CREATE OR REPLACE PACKAGE utaeq ---//----------------------------------------------------------------------- ---// ** PL/Generator Table Encapsulator for "UTA_EQ" ---//----------------------------------------------------------------------- ---// (c) COPYRIGHT Personnel Policies, Inc. 2001. ---// All rights reserved. ---// ---// No part of this copyrighted work may be reproduced, modified, ---// or distributed in any form or by any means without the prior ---// written permission of Personnel Policies, Inc.. ---//----------------------------------------------------------------------- ---// This software was generated by RevealNet's PL/Generator (TM). ---// ---// For more information, visit www.revealnet.com or call 1.800.REVEAL4 ---//----------------------------------------------------------------------- ---// Stored In: utaeq.pks ---// Created On: September 15, 2001 08:44:48 ---// Created By: SCOTT ---// PL/Generator Version: PRO-2000.2.9 ---//----------------------------------------------------------------------- -IS ---// Data Structures //-- - TYPE pky_rt IS RECORD ( - id UTA_EQ.ID%TYPE - ); - - --// Modified version of %ROWTYPE for table with subset of columns //-- - TYPE allcols_rt IS RECORD ( - id UTA_EQ.ID%TYPE, - outcome_id UTA_EQ.OUTCOME_ID%TYPE, - data_type UTA_EQ.DATA_TYPE%TYPE, - check_value_id UTA_EQ.CHECK_VALUE_ID%TYPE, - against_value_id UTA_EQ.AGAINST_VALUE_ID%TYPE - ); - - TYPE cv_t IS REF CURSOR; - ---// Cursors //-- - - CURSOR allbypky_cur - IS - SELECT - ID, - OUTCOME_ID, - DATA_TYPE, - CHECK_VALUE_ID, - AGAINST_VALUE_ID - FROM UTA_EQ - ORDER BY - ID - ; - - CURSOR allforpky_cur ( - id_in IN UTA_EQ.ID%TYPE - ) - IS - SELECT - ID, - OUTCOME_ID, - DATA_TYPE, - CHECK_VALUE_ID, - AGAINST_VALUE_ID - FROM UTA_EQ - WHERE - ID = allforpky_cur.id_in - ; - - --// Specified columns, all rows for this foreign key. //-- - CURSOR uta_eq_outcome_fk_all_cur ( - outcome_id_in IN UTA_EQ.OUTCOME_ID%TYPE - ) - IS - SELECT - ID, - OUTCOME_ID, - DATA_TYPE, - CHECK_VALUE_ID, - AGAINST_VALUE_ID - FROM UTA_EQ - WHERE - OUTCOME_ID = uta_eq_outcome_fk_all_cur.outcome_id_in - ; - ---// Cursor management procedures //-- - - --// Open the cursors with some options. //-- - PROCEDURE open_allforpky_cur ( - id_in IN UTA_EQ.ID%TYPE, - close_if_open IN BOOLEAN := TRUE - ); - - PROCEDURE open_allbypky_cur ( - close_if_open IN BOOLEAN := TRUE - ); - - PROCEDURE open_uta_eq_outcome_fk_all_cur ( - outcome_id_in IN UTA_EQ.OUTCOME_ID%TYPE, - close_if_open IN BOOLEAN := TRUE - ); - - --// Close the cursors if they are open. //-- - PROCEDURE close_allforpky_cur; - PROCEDURE close_allbypky_cur; - PROCEDURE close_uta_eq_outcome_fk_all_cu; - PROCEDURE closeall; - ---// Analyze presence of primary key: is it NOT NULL? //-- - - FUNCTION isnullpky ( - rec_in IN allcols_rt - ) - RETURN BOOLEAN; - - FUNCTION isnullpky ( - rec_in IN pky_rt - ) - RETURN BOOLEAN; - ---// Emulate aggregate-level record operations. //-- - - FUNCTION recseq (rec1 IN allcols_rt, rec2 IN allcols_rt) - RETURN BOOLEAN; - - FUNCTION recseq (rec1 IN pky_rt, rec2 IN pky_rt) - RETURN BOOLEAN; - ---// Fetch Data //-- - - --// Fetch one row of data for a primary key. //-- - FUNCTION onerow ( - id_in IN UTA_EQ.ID%TYPE - ) - RETURN allcols_rt; - - - --// Count of all rows in table and for each foreign key. //-- - FUNCTION rowcount RETURN INTEGER; - FUNCTION pkyrowcount ( - id_in IN UTA_EQ.ID%TYPE - ) - RETURN INTEGER; - FUNCTION uta_eq_outcome_fkrowcount ( - outcome_id_in IN UTA_EQ.OUTCOME_ID%TYPE - ) - RETURN INTEGER; ---// Update Processing //-- - - PROCEDURE reset$frc; - - --// Force setting of NULL values //-- - - FUNCTION outcome_id$frc - (outcome_id_in IN UTA_EQ.OUTCOME_ID%TYPE DEFAULT NULL) - RETURN UTA_EQ.OUTCOME_ID%TYPE; - - FUNCTION data_type$frc - (data_type_in IN UTA_EQ.DATA_TYPE%TYPE DEFAULT NULL) - RETURN UTA_EQ.DATA_TYPE%TYPE; - - FUNCTION check_value_id$frc - (check_value_id_in IN UTA_EQ.CHECK_VALUE_ID%TYPE DEFAULT NULL) - RETURN UTA_EQ.CHECK_VALUE_ID%TYPE; - - FUNCTION against_value_id$frc - (against_value_id_in IN UTA_EQ.AGAINST_VALUE_ID%TYPE DEFAULT NULL) - RETURN UTA_EQ.AGAINST_VALUE_ID%TYPE; - - PROCEDURE upd ( - id_in IN UTA_EQ.ID%TYPE, - outcome_id_in IN UTA_EQ.OUTCOME_ID%TYPE DEFAULT NULL, - data_type_in IN UTA_EQ.DATA_TYPE%TYPE DEFAULT NULL, - check_value_id_in IN UTA_EQ.CHECK_VALUE_ID%TYPE DEFAULT NULL, - against_value_id_in IN UTA_EQ.AGAINST_VALUE_ID%TYPE DEFAULT NULL, - rowcount_out OUT INTEGER, - reset_in IN BOOLEAN DEFAULT TRUE - ); - - --// Record-based Update //-- - - PROCEDURE upd (rec_in IN allcols_rt, - rowcount_out OUT INTEGER, - reset_in IN BOOLEAN DEFAULT TRUE); - ---// Insert Processing //-- - - --// Initialize record with default values. //-- - FUNCTION initrec (allnull IN BOOLEAN := FALSE) RETURN allcols_rt; - - --// Initialize record with default values. //-- - PROCEDURE initrec ( - rec_inout IN OUT allcols_rt, - allnull IN BOOLEAN := FALSE); - - - --// Generate next primary key: for single column PKs only. //-- - FUNCTION nextpky RETURN UTA_EQ.id%TYPE; - - PROCEDURE ins ( - outcome_id_in IN UTA_EQ.OUTCOME_ID%TYPE DEFAULT NULL, - data_type_in IN UTA_EQ.DATA_TYPE%TYPE DEFAULT NULL, - check_value_id_in IN UTA_EQ.CHECK_VALUE_ID%TYPE DEFAULT NULL, - against_value_id_in IN UTA_EQ.AGAINST_VALUE_ID%TYPE DEFAULT NULL, - id_out IN OUT UTA_EQ.ID%TYPE, - upd_on_dup IN BOOLEAN := FALSE - ); - - -- Insert values entered by user, create value rows and then - -- insert the uta_eq row. - -- ?? Provide lots of overloading or put the conversion logic - -- inside this procedure based on data_type? For now will - -- opt for the conversion, first implementing simply for - -- VARCHAR2. Obviously this would not work for special - -- datatypes like BLOB. - PROCEDURE ins ( - outcome_id_in IN UTA_EQ.OUTCOME_ID%TYPE DEFAULT NULL, - data_type_in IN UTA_EQ.DATA_TYPE%TYPE DEFAULT NULL, - check_value_in IN VARCHAR2, - check_is_expression_in in BOOLEAN, - against_value_in IN VARCHAR2, - id_out IN OUT UTA_EQ.ID%TYPE, - upd_on_dup IN BOOLEAN := FALSE - ); - - PROCEDURE ins (rec_in IN allcols_rt, - id_out IN OUT UTA_EQ.ID%TYPE, - upd_on_dup IN BOOLEAN := FALSE - ); - ---// Delete Processing //-- - PROCEDURE del ( - id_in IN UTA_EQ.ID%TYPE, - rowcount_out OUT INTEGER); - - --// Record-based delete //-- - PROCEDURE del (rec_in IN pky_rt, - rowcount_out OUT INTEGER); - - PROCEDURE del (rec_in IN allcols_rt, - rowcount_out OUT INTEGER); - - --// Delete all records for this UTA_EQ_OUTCOME_FK foreign key. //-- - PROCEDURE delby_uta_eq_outcome_fk ( - outcome_id_in IN UTA_EQ.OUTCOME_ID%TYPE, - rowcount_out OUT INTEGER - ); - - --// Program called by database initialization script to pin the package. //-- - PROCEDURE pinme; - FUNCTION version RETURN VARCHAR2; -END utaeq; -/ diff --git a/source/ut_i_packages.sql b/source/ut_i_packages.sql index f95f4ae14..dd5dc7137 100644 --- a/source/ut_i_packages.sql +++ b/source/ut_i_packages.sql @@ -22,8 +22,6 @@ @@ut_i_run ut_rtestcase.pks @@ut_i_run ut_routcome.pks @@ut_i_run ut_rerror.pks -@@ut_i_run ut_vvalue.pks -@@ut_i_run ut_aeq.pks @@ut_i_run ut_receq.pks @@ut_i_run ut_output.pks @@ut_i_run ut_utoutput.pks diff --git a/source/ut_i_packages_b.sql b/source/ut_i_packages_b.sql index ea8c4f065..2486f55ef 100644 --- a/source/ut_i_packages_b.sql +++ b/source/ut_i_packages_b.sql @@ -22,8 +22,6 @@ @@ut_i_run ut_rtestcase.pkb @@ut_i_run ut_routcome.pkb @@ut_i_run ut_rerror.pkb -@@ut_i_run ut_vvalue.pkb -@@ut_i_run ut_aeq.pkb @@ut_i_run ut_receq.pkb @@ut_i_run ut_output.pkb @@ut_i_run ut_utoutput.pkb diff --git a/source/ut_i_sequences.sql b/source/ut_i_sequences.sql index 9e48f2e13..e8bafc906 100644 --- a/source/ut_i_sequences.sql +++ b/source/ut_i_sequences.sql @@ -5,8 +5,6 @@ @@ut_i_run ut_unittest_seq.seq @@ut_i_run ut_testcase_seq.seq @@ut_i_run ut_plsql_runnum_seq.seq -@@ut_i_run uta_eq_seq.seq -@@ut_i_run utv_value_seq.seq @@ut_i_run ut_assertion_seq.seq @@ut_i_run ut_receq_seq.seq @@ut_i_run ut_refcursor_results_seq.seq diff --git a/source/ut_i_tables.sql b/source/ut_i_tables.sql index a5f9f79d4..f79a804af 100644 --- a/source/ut_i_tables.sql +++ b/source/ut_i_tables.sql @@ -19,7 +19,5 @@ @@ut_i_run utr_error.tab @@ut_i_run ut_deterministic.tab @@ut_i_run ut_deterministic_arg.tab -@@ut_i_run utv_value.tab -@@ut_i_run uta_eq.tab @@ut_i_run ut_receq.tab @@ut_i_run ut_grid.tab diff --git a/source/ut_i_uninstall.sql b/source/ut_i_uninstall.sql index 4b834efd4..7549871a2 100644 --- a/source/ut_i_uninstall.sql +++ b/source/ut_i_uninstall.sql @@ -13,7 +13,6 @@ PROMPT &line1 PROMPT DROPPING &UT PACKAGES PROMPT &line1 -drop package UTAEQ; drop package UTASSERT2; drop package UTASSERT; drop package UTCONFIG; @@ -40,17 +39,14 @@ drop package UTTESTCASE; drop package UTTESTPREP; drop package UTUNITTEST; drop package UTUTP; -drop package UTVVALUE; SET TERMOUT ON PROMPT &line1 PROMPT DROPPING &UT PUBLIC SYNONYMS PROMPT &line1 -drop public synonym UTAEQ; drop public synonym UTASSERT2; drop public synonym UTASSERT; -drop public synonym UTA_EQ; drop public synonym UTCONFIG; drop public synonym UTGEN; drop public synonym UTOUTCOME; @@ -81,8 +77,6 @@ drop public synonym UTTESTCASE; drop public synonym UTTESTPREP; drop public synonym UTUNITTEST; drop public synonym UTUTP; -drop public synonym UTVVALUE; -drop public synonym UTV_VALUE; drop public synonym UT_ARGUMENT; drop public synonym UT_ASSERTION; drop public synonym UT_CONFIG; @@ -102,9 +96,7 @@ drop public synonym UT_TESTPREP; drop public synonym UT_UNITTEST; drop public synonym UT_UTOUTPUT; drop public synonym UT_UTP; -drop public synonym UTA_EQ_SEQ; drop public synonym UTPLSQL_RUNNUM_SEQ; -drop public synonym UTV_VALUE_SEQ; drop public synonym UT_ASSERTION_SEQ; drop public synonym UT_PACKAGE_SEQ; drop public synonym UT_RECEQ_SEQ; @@ -122,9 +114,7 @@ PROMPT &line1 PROMPT DROPPING &UT SEQUENCES PROMPT &line1 -drop sequence UTA_EQ_SEQ; drop sequence UTPLSQL_RUNNUM_SEQ; -drop sequence UTV_VALUE_SEQ; drop sequence UT_ASSERTION_SEQ; drop sequence UT_PACKAGE_SEQ; drop sequence UT_RECEQ_SEQ; @@ -140,14 +130,12 @@ PROMPT &line1 PROMPT DROPPING &UT TABLES PROMPT &line1 -drop table UTA_EQ cascade constraints; drop table UTR_ERROR cascade constraints; drop table UTR_OUTCOME cascade constraints; drop table UTR_SUITE cascade constraints; drop table UTR_TESTCASE cascade constraints; drop table UTR_UNITTEST cascade constraints; drop table UTR_UTP cascade constraints; -drop table UTV_VALUE cascade constraints; drop table UT_ARGUMENT cascade constraints; drop table UT_ASSERTION cascade constraints; drop table UT_CONFIG cascade constraints; diff --git a/source/ut_vvalue.pkb b/source/ut_vvalue.pkb deleted file mode 100644 index 347cc3e7e..000000000 --- a/source/ut_vvalue.pkb +++ /dev/null @@ -1,880 +0,0 @@ -/* Formatted on 2001/09/15 09:27 (RevealNet Formatter v4.4.1) */ -CREATE OR REPLACE PACKAGE BODY utvvalue ---//----------------------------------------------------------------------- ---// ** PL/Generator Table Encapsulator for "UTV_VALUE" ---//----------------------------------------------------------------------- ---// (c) COPYRIGHT Personnel Policies, Inc. 2001. ---// All rights reserved. ---// ---// No part of this copyrighted work may be reproduced, modified, ---// or distributed in any form or by any means without the prior ---// written permission of Personnel Policies, Inc.. ---//----------------------------------------------------------------------- ---// This software was generated by RevealNet's PL/Generator (TM). ---// ---// For more information, visit www.revealnet.com or call 1.800.REVEAL4 ---//----------------------------------------------------------------------- ---// Stored In: utvvalue.pkb ---// Created On: September 15, 2001 09:21:04 ---// Created By: SCOTT ---// PL/Generator Version: PRO-2000.2.9 ---//----------------------------------------------------------------------- -IS - --// Package name and program name globals --// - c_pkgname VARCHAR2 (30) := 'utvvalue'; - g_progname VARCHAR2 (30) := NULL; - - --// Update Flag private data structures. --// - TYPE frcflg_rt IS RECORD ( - data_type CHAR (1), - data_type_name CHAR (1), - is_expression CHAR (1), - VALUE CHAR (1), - record_id CHAR (1), - object_id CHAR (1), - collection_id CHAR (1), - uri_id CHAR (1), - xml_id CHAR (1), - lob_id CHAR (1)); - - frcflg frcflg_rt; - emptyfrc frcflg_rt; - c_set CHAR (1) := 'Y'; - c_noset CHAR (1) := 'N'; - - FUNCTION version - RETURN VARCHAR2 - IS - BEGIN - RETURN '7.09'; - END; - - ---// Private Modules //-- - - --// For Dynamic SQL operations; currently unused. //-- - PROCEDURE initcur (cur_inout IN OUT INTEGER) - IS - BEGIN - IF NOT DBMS_SQL.is_open (cur_inout) - THEN - cur_inout := DBMS_SQL.open_cursor; - END IF; - EXCEPTION - WHEN INVALID_CURSOR - THEN - cur_inout := DBMS_SQL.open_cursor; - END; - - PROCEDURE start_program (nm IN VARCHAR2, msg IN VARCHAR2 := NULL) - IS - BEGIN - g_progname := nm; - END; - - PROCEDURE end_program - IS - BEGIN - g_progname := NULL; - END; - - ---// Cursor management procedures //-- - - --// Open the cursors with some options. //-- - PROCEDURE open_allforpky_cur ( - id_in IN utv_value.id%TYPE, - close_if_open IN BOOLEAN := TRUE - ) - IS - v_close BOOLEAN := NVL (close_if_open, TRUE); - v_open BOOLEAN := TRUE; - BEGIN - start_program ('open_allforpky_cur'); - - IF allforpky_cur%ISOPEN - AND v_close - THEN - CLOSE allforpky_cur; - ELSIF allforpky_cur%ISOPEN - AND NOT v_close - THEN - v_open := FALSE; - END IF; - - IF v_open - THEN - OPEN allforpky_cur (id_in); - END IF; - - end_program; - END; - - PROCEDURE open_allbypky_cur (close_if_open IN BOOLEAN := TRUE) - IS - v_close BOOLEAN := NVL (close_if_open, TRUE); - v_open BOOLEAN := TRUE; - BEGIN - IF allbypky_cur%ISOPEN - AND v_close - THEN - CLOSE allbypky_cur; - ELSIF allbypky_cur%ISOPEN - AND NOT v_close - THEN - v_open := FALSE; - END IF; - - IF v_open - THEN - OPEN allbypky_cur; - END IF; - END; - - --// Close the cursors if they are open. //-- - PROCEDURE close_allforpky_cur - IS - BEGIN - IF allforpky_cur%ISOPEN - THEN - CLOSE allforpky_cur; - END IF; - END; - - PROCEDURE close_allbypky_cur - IS - BEGIN - IF allbypky_cur%ISOPEN - THEN - CLOSE allbypky_cur; - END IF; - END; - - PROCEDURE closeall - IS - BEGIN - close_allforpky_cur; - close_allbypky_cur; - END; - - ---// Emulate aggregate-level record operations. //-- - - FUNCTION recseq (rec1 IN allcols_rt, rec2 IN allcols_rt) - RETURN BOOLEAN - IS - unequal_records EXCEPTION; - retval BOOLEAN; - BEGIN - retval := rec1.id = rec2.id - OR ( rec1.id IS NULL - AND rec2.id IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - retval := rec1.data_type = rec2.data_type - OR ( rec1.data_type IS NULL - AND rec2.data_type IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - retval := rec1.data_type_name = rec2.data_type_name - OR ( rec1.data_type_name IS NULL - AND rec2.data_type_name IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - retval := rec1.is_expression = rec2.is_expression - OR ( rec1.is_expression IS NULL - AND rec2.is_expression IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - retval := rec1.VALUE = rec2.VALUE - OR ( rec1.VALUE IS NULL - AND rec2.VALUE IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - retval := rec1.record_id = rec2.record_id - OR ( rec1.record_id IS NULL - AND rec2.record_id IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - retval := rec1.object_id = rec2.object_id - OR ( rec1.object_id IS NULL - AND rec2.object_id IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - retval := rec1.collection_id = rec2.collection_id - OR ( rec1.collection_id IS NULL - AND rec2.collection_id IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - retval := rec1.uri_id = rec2.uri_id - OR ( rec1.uri_id IS NULL - AND rec2.uri_id IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - retval := rec1.xml_id = rec2.xml_id - OR ( rec1.xml_id IS NULL - AND rec2.xml_id IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - retval := rec1.lob_id = rec2.lob_id - OR ( rec1.lob_id IS NULL - AND rec2.lob_id IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - RETURN TRUE; - EXCEPTION - WHEN unequal_records - THEN - RETURN FALSE; - END; - - FUNCTION recseq (rec1 IN pky_rt, rec2 IN pky_rt) - RETURN BOOLEAN - IS - unequal_records EXCEPTION; - retval BOOLEAN; - BEGIN - retval := rec1.id = rec2.id - OR ( rec1.id IS NULL - AND rec2.id IS NULL - ); - - IF NOT NVL (retval, FALSE) - THEN - RAISE unequal_records; - END IF; - - RETURN TRUE; - EXCEPTION - WHEN unequal_records - THEN - RETURN FALSE; - END; - - ---// Is the primary key NOT NULL? //-- - - FUNCTION isnullpky (rec_in IN allcols_rt) - RETURN BOOLEAN - IS - BEGIN - RETURN rec_in.id IS NULL; - END; - - FUNCTION isnullpky (rec_in IN pky_rt) - RETURN BOOLEAN - IS - BEGIN - RETURN rec_in.id IS NULL; - END; - - ---// Query Processing --// - - FUNCTION onerow_internal (id_in IN utv_value.id%TYPE) - RETURN allcols_rt - IS - CURSOR onerow_cur - IS - SELECT id, data_type, data_type_name, is_expression, VALUE, - record_id, object_id, collection_id, uri_id, xml_id, - lob_id - FROM utv_value - WHERE id = id_in; - - onerow_rec allcols_rt; - BEGIN - OPEN onerow_cur; - FETCH onerow_cur INTO onerow_rec; - CLOSE onerow_cur; - RETURN onerow_rec; - END onerow_internal; - - FUNCTION onerow (id_in IN utv_value.id%TYPE) - RETURN allcols_rt - IS - retval allcols_rt; - BEGIN - retval := onerow_internal (id_in); - RETURN retval; - END onerow; - - --// Count of all rows in table and for each foreign key. //-- - FUNCTION rowcount - RETURN INTEGER - IS - retval INTEGER; - BEGIN - SELECT COUNT (*) - INTO retval - FROM utv_value; - RETURN retval; - END; - - FUNCTION pkyrowcount (id_in IN utv_value.id%TYPE) - RETURN INTEGER - IS - retval INTEGER; - BEGIN - SELECT COUNT (*) - INTO retval - FROM utv_value - WHERE id = id_in; - RETURN retval; - END; - - --// Generate the next primary key: single column PKYs only --// - FUNCTION nextpky - RETURN utv_value.id%TYPE - IS - retval utv_value.id%TYPE; - BEGIN - SELECT utv_value_seq.NEXTVAL - INTO retval - FROM DUAL; - RETURN retval; - END; - - ---// Update Processing --// - - PROCEDURE reset$frc - IS - BEGIN - frcflg := emptyfrc; - END reset$frc; - - FUNCTION data_type$frc ( - data_type_in IN utv_value.data_type%TYPE DEFAULT NULL - ) - RETURN utv_value.data_type%TYPE - IS - BEGIN - frcflg.data_type := c_set; - RETURN data_type_in; - END data_type$frc; - - FUNCTION data_type_name$frc ( - data_type_name_in IN utv_value.data_type_name%TYPE - DEFAULT NULL - ) - RETURN utv_value.data_type_name%TYPE - IS - BEGIN - frcflg.data_type_name := c_set; - RETURN data_type_name_in; - END data_type_name$frc; - - FUNCTION is_expression$frc ( - is_expression_in IN utv_value.is_expression%TYPE DEFAULT NULL - ) - RETURN utv_value.is_expression%TYPE - IS - BEGIN - frcflg.is_expression := c_set; - RETURN is_expression_in; - END is_expression$frc; - - FUNCTION value$frc (value_in IN utv_value.VALUE%TYPE DEFAULT NULL) - RETURN utv_value.VALUE%TYPE - IS - BEGIN - frcflg.VALUE := c_set; - RETURN value_in; - END value$frc; - - FUNCTION record_id$frc ( - record_id_in IN utv_value.record_id%TYPE DEFAULT NULL - ) - RETURN utv_value.record_id%TYPE - IS - BEGIN - frcflg.record_id := c_set; - RETURN record_id_in; - END record_id$frc; - - FUNCTION object_id$frc ( - object_id_in IN utv_value.object_id%TYPE DEFAULT NULL - ) - RETURN utv_value.object_id%TYPE - IS - BEGIN - frcflg.object_id := c_set; - RETURN object_id_in; - END object_id$frc; - - FUNCTION collection_id$frc ( - collection_id_in IN utv_value.collection_id%TYPE DEFAULT NULL - ) - RETURN utv_value.collection_id%TYPE - IS - BEGIN - frcflg.collection_id := c_set; - RETURN collection_id_in; - END collection_id$frc; - - FUNCTION uri_id$frc ( - uri_id_in IN utv_value.uri_id%TYPE DEFAULT NULL - ) - RETURN utv_value.uri_id%TYPE - IS - BEGIN - frcflg.uri_id := c_set; - RETURN uri_id_in; - END uri_id$frc; - - FUNCTION xml_id$frc ( - xml_id_in IN utv_value.xml_id%TYPE DEFAULT NULL - ) - RETURN utv_value.xml_id%TYPE - IS - BEGIN - frcflg.xml_id := c_set; - RETURN xml_id_in; - END xml_id$frc; - - FUNCTION lob_id$frc ( - lob_id_in IN utv_value.lob_id%TYPE DEFAULT NULL - ) - RETURN utv_value.lob_id%TYPE - IS - BEGIN - frcflg.lob_id := c_set; - RETURN lob_id_in; - END lob_id$frc; - - PROCEDURE upd ( - id_in IN utv_value.id%TYPE, - data_type_in IN utv_value.data_type%TYPE - DEFAULT NULL, - data_type_name_in IN utv_value.data_type_name%TYPE - DEFAULT NULL, - is_expression_in IN utv_value.is_expression%TYPE - DEFAULT NULL, - value_in IN utv_value.VALUE%TYPE DEFAULT NULL, - record_id_in IN utv_value.record_id%TYPE - DEFAULT NULL, - object_id_in IN utv_value.object_id%TYPE - DEFAULT NULL, - collection_id_in IN utv_value.collection_id%TYPE - DEFAULT NULL, - uri_id_in IN utv_value.uri_id%TYPE DEFAULT NULL, - xml_id_in IN utv_value.xml_id%TYPE DEFAULT NULL, - lob_id_in IN utv_value.lob_id%TYPE DEFAULT NULL, - rowcount_out OUT INTEGER, - reset_in IN BOOLEAN DEFAULT TRUE - ) - IS - BEGIN - UPDATE utv_value - SET data_type = DECODE ( - frcflg.data_type, - c_set, data_type_in, - NVL (data_type_in, data_type) - ), - data_type_name = DECODE ( - frcflg.data_type_name, - c_set, data_type_name_in, - NVL ( - data_type_name_in, - data_type_name - ) - ), - is_expression = DECODE ( - frcflg.is_expression, - c_set, is_expression_in, - NVL (is_expression_in, is_expression) - ), - VALUE = DECODE ( - frcflg.VALUE, - c_set, value_in, - NVL (value_in, VALUE) - ), - record_id = DECODE ( - frcflg.record_id, - c_set, record_id_in, - NVL (record_id_in, record_id) - ), - object_id = DECODE ( - frcflg.object_id, - c_set, object_id_in, - NVL (object_id_in, object_id) - ), - collection_id = DECODE ( - frcflg.collection_id, - c_set, collection_id_in, - NVL (collection_id_in, collection_id) - ), - uri_id = DECODE ( - frcflg.uri_id, - c_set, uri_id_in, - NVL (uri_id_in, uri_id) - ), - xml_id = DECODE ( - frcflg.xml_id, - c_set, xml_id_in, - NVL (xml_id_in, xml_id) - ), - lob_id = DECODE ( - frcflg.lob_id, - c_set, lob_id_in, - NVL (lob_id_in, lob_id) - ) - WHERE id = id_in; - - rowcount_out := SQL%ROWCOUNT; - - IF reset_in - THEN - reset$frc; - END IF; - EXCEPTION - WHEN OTHERS - THEN - RAISE; - END upd; - - --// Record-based Update --// - PROCEDURE upd ( - rec_in IN allcols_rt, - rowcount_out OUT INTEGER, - reset_in IN BOOLEAN DEFAULT TRUE - ) - IS - BEGIN - upd ( - rec_in.id, - rec_in.data_type, - rec_in.data_type_name, - rec_in.is_expression, - rec_in.VALUE, - rec_in.record_id, - rec_in.object_id, - rec_in.collection_id, - rec_in.uri_id, - rec_in.xml_id, - rec_in.lob_id, - rowcount_out, - reset_in - ); - END upd; - - ---// Insert Processing --// - - --// Initialize record with default values. --// - FUNCTION initrec (allnull IN BOOLEAN := FALSE) - RETURN allcols_rt - IS - retval allcols_rt; - BEGIN - IF allnull - THEN - NULL; /* Default values are NULL already. */ - ELSE - retval.id := NULL; - retval.data_type := NULL; - retval.data_type_name := NULL; - retval.is_expression := NULL; - retval.VALUE := NULL; - retval.record_id := NULL; - retval.object_id := NULL; - retval.collection_id := NULL; - retval.uri_id := NULL; - retval.xml_id := NULL; - retval.lob_id := NULL; - END IF; - - RETURN retval; - END; - - --// Initialize record with default values. --// - PROCEDURE initrec ( - rec_inout IN OUT allcols_rt, - allnull IN BOOLEAN := FALSE - ) - IS - BEGIN - rec_inout := initrec; - END; - - PROCEDURE ins$ins ( - id_in IN utv_value.id%TYPE, - data_type_in IN utv_value.data_type%TYPE DEFAULT NULL, - data_type_name_in IN utv_value.data_type_name%TYPE - DEFAULT NULL, - is_expression_in IN utv_value.is_expression%TYPE - DEFAULT NULL, - value_in IN utv_value.VALUE%TYPE DEFAULT NULL, - record_id_in IN utv_value.record_id%TYPE DEFAULT NULL, - object_id_in IN utv_value.object_id%TYPE DEFAULT NULL, - collection_id_in IN utv_value.collection_id%TYPE - DEFAULT NULL, - uri_id_in IN utv_value.uri_id%TYPE DEFAULT NULL, - xml_id_in IN utv_value.xml_id%TYPE DEFAULT NULL, - lob_id_in IN utv_value.lob_id%TYPE DEFAULT NULL, - upd_on_dup IN BOOLEAN := FALSE - ) - IS - BEGIN - INSERT INTO utv_value - (id, data_type, data_type_name, - is_expression, VALUE, record_id, - object_id, collection_id, uri_id, - xml_id, lob_id) - VALUES (id_in, data_type_in, data_type_name_in, - is_expression_in, value_in, record_id_in, - object_id_in, collection_id_in, uri_id_in, - xml_id_in, lob_id_in); - EXCEPTION - WHEN DUP_VAL_ON_INDEX - THEN - IF NOT NVL (upd_on_dup, FALSE) - THEN - RAISE; - ELSE - DECLARE - v_errm VARCHAR2 (2000) := SQLERRM; - v_rowcount INTEGER; - dotloc INTEGER; - leftloc INTEGER; - c_owner all_constraints.owner%TYPE; - c_name all_constraints.constraint_name%TYPE; - BEGIN - dotloc := INSTR (v_errm, '.'); - leftloc := INSTR (v_errm, '('); - c_owner := SUBSTR ( - v_errm, - leftloc - + 1, - dotloc - - leftloc - - 1 - ); - c_name := SUBSTR ( - v_errm, - dotloc - + 1, - INSTR (v_errm, ')') - - dotloc - - 1 - ); - - --// Duplicate based on primary key //-- - IF 'SYS_C004468' = c_name - AND /* 2000.2 'SCOTT' */ USER = c_owner - THEN - upd ( - id_in, - data_type_in, - data_type_name_in, - is_expression_in, - value_in, - record_id_in, - object_id_in, - collection_id_in, - uri_id_in, - xml_id_in, - lob_id_in, - v_rowcount, - FALSE - ); - ELSE - --// Unique index violation. Cannot recover... //-- - RAISE; - END IF; - END; - END IF; - WHEN OTHERS - THEN - RAISE; - END ins$ins; - - --// Insert 1: with individual fields and return primary key //-- - PROCEDURE ins ( - data_type_in IN utv_value.data_type%TYPE - DEFAULT NULL, - data_type_name_in IN utv_value.data_type_name%TYPE - DEFAULT NULL, - is_expression_in IN utv_value.is_expression%TYPE - DEFAULT NULL, - value_in IN utv_value.VALUE%TYPE DEFAULT NULL, - record_id_in IN utv_value.record_id%TYPE - DEFAULT NULL, - object_id_in IN utv_value.object_id%TYPE - DEFAULT NULL, - collection_id_in IN utv_value.collection_id%TYPE - DEFAULT NULL, - uri_id_in IN utv_value.uri_id%TYPE DEFAULT NULL, - xml_id_in IN utv_value.xml_id%TYPE DEFAULT NULL, - lob_id_in IN utv_value.lob_id%TYPE DEFAULT NULL, - id_out IN OUT utv_value.id%TYPE, - upd_on_dup IN BOOLEAN := FALSE - ) - IS - v_pky INTEGER := nextpky; - BEGIN - ins$ins ( - v_pky, - data_type_in, - data_type_name_in, - is_expression_in, - value_in, - record_id_in, - object_id_in, - collection_id_in, - uri_id_in, - xml_id_in, - lob_id_in, - upd_on_dup - ); - id_out := v_pky; - END; - - -- Simple insert for expressions/scalars only. - PROCEDURE ins ( - data_type_in IN utv_value.data_type%TYPE DEFAULT NULL, - is_expression_in IN BOOLEAN, - value_in IN utv_value.VALUE%TYPE DEFAULT NULL, - id_out IN OUT utv_value.id%TYPE, - upd_on_dup IN BOOLEAN := FALSE - ) - IS - BEGIN - ins ( - data_type_in=> data_type_in, - is_expression_in=> utplsql.ifelse ( - is_expression_in, - utplsql.c_yes, - utplsql.c_no - ), - value_in=> value_in, - id_out=> id_out, - upd_on_dup=> upd_on_dup - ); - END; - - --// Insert 2: with record, returning primary key. //-- - PROCEDURE ins ( - rec_in IN allcols_rt, - id_out IN OUT utv_value.id%TYPE, - upd_on_dup IN BOOLEAN := FALSE - ) - IS - v_pky INTEGER := nextpky; - BEGIN - ins$ins ( - v_pky, - rec_in.data_type, - rec_in.data_type_name, - rec_in.is_expression, - rec_in.VALUE, - rec_in.record_id, - rec_in.object_id, - rec_in.collection_id, - rec_in.uri_id, - rec_in.xml_id, - rec_in.lob_id, - upd_on_dup - ); - id_out := v_pky; - END; - - ---// Delete Processing --// - - PROCEDURE del (id_in IN utv_value.id%TYPE, rowcount_out OUT INTEGER) - IS - BEGIN - DELETE FROM utv_value - WHERE id = id_in; - - rowcount_out := SQL%ROWCOUNT; - EXCEPTION - WHEN OTHERS - THEN - RAISE; - END del; - - --// Record-based delete --// - PROCEDURE del (rec_in IN pky_rt, rowcount_out OUT INTEGER) - IS - BEGIN - del (rec_in.id, rowcount_out); - END del; - - PROCEDURE del (rec_in IN allcols_rt, rowcount_out OUT INTEGER) - IS - BEGIN - del (rec_in.id, rowcount_out); - END del; - - --// Program called by database initialization script to pin the package. //-- - PROCEDURE pinme - IS - BEGIN - --// Doesn't do anything except cause the package to be loaded. //-- - NULL; - END; - ---// Initialization section for the package. --// -BEGIN - NULL; -- Placeholder. -END utvvalue; -/ - diff --git a/source/ut_vvalue.pks b/source/ut_vvalue.pks deleted file mode 100644 index 2db2c2b8b..000000000 --- a/source/ut_vvalue.pks +++ /dev/null @@ -1,274 +0,0 @@ -/* Formatted on 2001/09/15 09:25 (RevealNet Formatter v4.4.1) */ -CREATE OR REPLACE PACKAGE utvvalue ---//----------------------------------------------------------------------- ---// ** PL/Generator Table Encapsulator for "UTV_VALUE" ---//----------------------------------------------------------------------- ---// (c) COPYRIGHT Personnel Policies, Inc. 2001. ---// All rights reserved. ---// ---// No part of this copyrighted work may be reproduced, modified, ---// or distributed in any form or by any means without the prior ---// written permission of Personnel Policies, Inc.. ---//----------------------------------------------------------------------- ---// This software was generated by RevealNet's PL/Generator (TM). ---// ---// For more information, visit www.revealnet.com or call 1.800.REVEAL4 ---//----------------------------------------------------------------------- ---// Stored In: utvvalue.pks ---// Created On: September 15, 2001 09:21:01 ---// Created By: SCOTT ---// PL/Generator Version: PRO-2000.2.9 ---//----------------------------------------------------------------------- -IS - ---// Data Structures //-- - TYPE pky_rt IS RECORD ( - id utv_value.id%TYPE); - - --// Modified version of %ROWTYPE for table with subset of columns //-- - TYPE allcols_rt IS RECORD ( - id utv_value.id%TYPE, - data_type utv_value.data_type%TYPE, - data_type_name utv_value.data_type_name%TYPE, - is_expression utv_value.is_expression%TYPE, - VALUE utv_value.VALUE%TYPE, - record_id utv_value.record_id%TYPE, - object_id utv_value.object_id%TYPE, - collection_id utv_value.collection_id%TYPE, - uri_id utv_value.uri_id%TYPE, - xml_id utv_value.xml_id%TYPE, - lob_id utv_value.lob_id%TYPE); - - TYPE cv_t IS REF CURSOR; - - ---// Cursors //-- - - CURSOR allbypky_cur - IS - SELECT id, data_type, data_type_name, is_expression, VALUE, - record_id, object_id, collection_id, uri_id, xml_id, - lob_id - FROM utv_value - ORDER BY id; - - CURSOR allforpky_cur (id_in IN utv_value.id%TYPE) - IS - SELECT id, data_type, data_type_name, is_expression, VALUE, - record_id, object_id, collection_id, uri_id, xml_id, - lob_id - FROM utv_value - WHERE id = allforpky_cur.id_in; - - ---// Cursor management procedures //-- - - --// Open the cursors with some options. //-- - PROCEDURE open_allforpky_cur ( - id_in IN utv_value.id%TYPE, - close_if_open IN BOOLEAN := TRUE - ); - - PROCEDURE open_allbypky_cur (close_if_open IN BOOLEAN := TRUE); - - --// Close the cursors if they are open. //-- - PROCEDURE close_allforpky_cur; - - PROCEDURE close_allbypky_cur; - - PROCEDURE closeall; - - ---// Analyze presence of primary key: is it NOT NULL? //-- - - FUNCTION isnullpky (rec_in IN allcols_rt) - RETURN BOOLEAN; - - FUNCTION isnullpky (rec_in IN pky_rt) - RETURN BOOLEAN; - - ---// Emulate aggregate-level record operations. //-- - - FUNCTION recseq (rec1 IN allcols_rt, rec2 IN allcols_rt) - RETURN BOOLEAN; - - FUNCTION recseq (rec1 IN pky_rt, rec2 IN pky_rt) - RETURN BOOLEAN; - - ---// Fetch Data //-- - - --// Fetch one row of data for a primary key. //-- - FUNCTION onerow (id_in IN utv_value.id%TYPE) - RETURN allcols_rt; - - --// Count of all rows in table and for each foreign key. //-- - FUNCTION rowcount - RETURN INTEGER; - - FUNCTION pkyrowcount (id_in IN utv_value.id%TYPE) - RETURN INTEGER; - - ---// Update Processing //-- - - PROCEDURE reset$frc; - - --// Force setting of NULL values //-- - - FUNCTION data_type$frc ( - data_type_in IN utv_value.data_type%TYPE DEFAULT NULL - ) - RETURN utv_value.data_type%TYPE; - - FUNCTION data_type_name$frc ( - data_type_name_in IN utv_value.data_type_name%TYPE - DEFAULT NULL - ) - RETURN utv_value.data_type_name%TYPE; - - FUNCTION is_expression$frc ( - is_expression_in IN utv_value.is_expression%TYPE - DEFAULT NULL - ) - RETURN utv_value.is_expression%TYPE; - - FUNCTION value$frc (value_in IN utv_value.VALUE%TYPE DEFAULT NULL) - RETURN utv_value.VALUE%TYPE; - - FUNCTION record_id$frc ( - record_id_in IN utv_value.record_id%TYPE DEFAULT NULL - ) - RETURN utv_value.record_id%TYPE; - - FUNCTION object_id$frc ( - object_id_in IN utv_value.object_id%TYPE DEFAULT NULL - ) - RETURN utv_value.object_id%TYPE; - - FUNCTION collection_id$frc ( - collection_id_in IN utv_value.collection_id%TYPE - DEFAULT NULL - ) - RETURN utv_value.collection_id%TYPE; - - FUNCTION uri_id$frc ( - uri_id_in IN utv_value.uri_id%TYPE DEFAULT NULL - ) - RETURN utv_value.uri_id%TYPE; - - FUNCTION xml_id$frc ( - xml_id_in IN utv_value.xml_id%TYPE DEFAULT NULL - ) - RETURN utv_value.xml_id%TYPE; - - FUNCTION lob_id$frc ( - lob_id_in IN utv_value.lob_id%TYPE DEFAULT NULL - ) - RETURN utv_value.lob_id%TYPE; - - PROCEDURE upd ( - id_in IN utv_value.id%TYPE, - data_type_in IN utv_value.data_type%TYPE - DEFAULT NULL, - data_type_name_in IN utv_value.data_type_name%TYPE - DEFAULT NULL, - is_expression_in IN utv_value.is_expression%TYPE - DEFAULT NULL, - value_in IN utv_value.VALUE%TYPE DEFAULT NULL, - record_id_in IN utv_value.record_id%TYPE - DEFAULT NULL, - object_id_in IN utv_value.object_id%TYPE - DEFAULT NULL, - collection_id_in IN utv_value.collection_id%TYPE - DEFAULT NULL, - uri_id_in IN utv_value.uri_id%TYPE DEFAULT NULL, - xml_id_in IN utv_value.xml_id%TYPE DEFAULT NULL, - lob_id_in IN utv_value.lob_id%TYPE DEFAULT NULL, - rowcount_out OUT INTEGER, - reset_in IN BOOLEAN DEFAULT TRUE - ); - - --// Record-based Update //-- - - PROCEDURE upd ( - rec_in IN allcols_rt, - rowcount_out OUT INTEGER, - reset_in IN BOOLEAN DEFAULT TRUE - ); - - ---// Insert Processing //-- - - --// Initialize record with default values. //-- - FUNCTION initrec (allnull IN BOOLEAN := FALSE) - RETURN allcols_rt; - - --// Initialize record with default values. //-- - PROCEDURE initrec ( - rec_inout IN OUT allcols_rt, - allnull IN BOOLEAN := FALSE - ); - - --// Generate next primary key: for single column PKs only. //-- - FUNCTION nextpky - RETURN utv_value.id%TYPE; - - PROCEDURE ins ( - data_type_in IN utv_value.data_type%TYPE - DEFAULT NULL, - data_type_name_in IN utv_value.data_type_name%TYPE - DEFAULT NULL, - is_expression_in IN utv_value.is_expression%TYPE - DEFAULT NULL, - value_in IN utv_value.VALUE%TYPE DEFAULT NULL, - record_id_in IN utv_value.record_id%TYPE - DEFAULT NULL, - object_id_in IN utv_value.object_id%TYPE - DEFAULT NULL, - collection_id_in IN utv_value.collection_id%TYPE - DEFAULT NULL, - uri_id_in IN utv_value.uri_id%TYPE DEFAULT NULL, - xml_id_in IN utv_value.xml_id%TYPE DEFAULT NULL, - lob_id_in IN utv_value.lob_id%TYPE DEFAULT NULL, - id_out IN OUT utv_value.id%TYPE, - upd_on_dup IN BOOLEAN := FALSE - ); - - -- Simple insert for expressions/scalars only. - PROCEDURE ins ( - data_type_in IN utv_value.data_type%TYPE - DEFAULT NULL, - is_expression_in IN BOOLEAN, - value_in IN utv_value.VALUE%TYPE DEFAULT NULL, - id_out IN OUT utv_value.id%TYPE, - upd_on_dup IN BOOLEAN := FALSE - ); - - PROCEDURE ins ( - rec_in IN allcols_rt, - id_out IN OUT utv_value.id%TYPE, - upd_on_dup IN BOOLEAN := FALSE - ); - - ---// Delete Processing //-- - PROCEDURE del ( - id_in IN utv_value.id%TYPE, - rowcount_out OUT INTEGER - ); - - --// Record-based delete //-- - PROCEDURE del (rec_in IN pky_rt, rowcount_out OUT INTEGER); - - PROCEDURE del (rec_in IN allcols_rt, rowcount_out OUT INTEGER); - - --// Program called by database initialization script to pin the package. //-- - PROCEDURE pinme; - - FUNCTION version - RETURN VARCHAR2; -END utvvalue; -/ - diff --git a/source/uta_eq.tab b/source/uta_eq.tab deleted file mode 100644 index 3e3f7d87a..000000000 --- a/source/uta_eq.tab +++ /dev/null @@ -1,17 +0,0 @@ -CREATE TABLE uta_eq ( - id INTEGER , - outcome_id INTEGER, - data_type VARCHAR2(100), - check_value_id INTEGER, - against_value_id INTEGER, - CONSTRAINT uta_eq_pk PRIMARY KEY (id) -); - -ALTER TABLE uta_eq ADD CONSTRAINT uta_eq_outcome_fk - FOREIGN KEY (outcome_id) REFERENCES ut_outcome; - -ALTER TABLE uta_eq ADD CONSTRAINT uta_eq_check_fk - FOREIGN KEY (check_value_id) REFERENCES utv_value; - -ALTER TABLE uta_eq ADD CONSTRAINT uta_eq_against_fk - FOREIGN KEY (against_value_id) REFERENCES utv_value; diff --git a/source/uta_eq_seq.seq b/source/uta_eq_seq.seq deleted file mode 100644 index 905abb25d..000000000 --- a/source/uta_eq_seq.seq +++ /dev/null @@ -1 +0,0 @@ -CREATE sequence uta_eq_seq INCREMENT BY 1 START WITH 1 ORDER NOCACHE; diff --git a/source/utv_value.tab b/source/utv_value.tab deleted file mode 100644 index c7fd91991..000000000 --- a/source/utv_value.tab +++ /dev/null @@ -1,17 +0,0 @@ -/* Formatted on 2001/09/15 08:08 (RevealNet Formatter v4.4.1) */ -CREATE TABLE utv_value ( -id INTEGER, -data_type varchar2(100), -data_type_name varchar2(100), -is_expression char(1), -value varchar2(2000), -record_id integer, -object_id integer, -collection_id integer, -uri_id integer, -xml_id integer, -lob_id integer, - CONSTRAINT utv_value_pk PRIMARY KEY (id) -); - - diff --git a/source/utv_value_seq.seq b/source/utv_value_seq.seq deleted file mode 100644 index a535cc149..000000000 --- a/source/utv_value_seq.seq +++ /dev/null @@ -1 +0,0 @@ -CREATE sequence utv_value_seq INCREMENT BY 1 START WITH 1 ORDER NOCACHE; From a5cdcbad1de3cb177379d129a82a00369fadeca6 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 1 Jul 2003 19:36:47 +0000 Subject: [PATCH 066/143] Added Standard Headers --- source/ut_assert.pkb | 17 ++++++------- source/ut_assert.pks | 18 ++++++-------- source/ut_assert2.pkb | 53 ++++++++++++++++++---------------------- source/ut_assert2.pks | 19 ++++++-------- source/ut_config.pkb | 19 ++++++-------- source/ut_config.pks | 31 ++++++++++++++++++----- source/ut_gen.pkb | 36 +++++++++++++++------------ source/ut_gen.pks | 20 +++++++-------- source/ut_i_do.sql | 9 +++---- source/ut_outcome.pkb | 25 +++++++++++++++++++ source/ut_outcome.pks | 25 +++++++++++++++++++ source/ut_output.pkb | 48 ++++++++++++++++++------------------ source/ut_output.pks | 17 ++++++------- source/ut_package.pkb | 10 +++++--- source/ut_package.pks | 19 ++++++-------- source/ut_plsql.pkb | 23 ++++++----------- source/ut_plsql.pks | 10 +++++--- source/ut_plsql2.pkb | 21 ++++++---------- source/ut_plsql2.pks | 10 +++++--- source/ut_plsql_util.pkb | 25 +++++++++++++++++++ source/ut_plsql_util.pks | 29 +++++++++++++++++----- source/ut_receq.pkb | 27 ++++++++++++++++---- source/ut_receq.pks | 30 ++++++++++++++++++----- source/ut_rerror.pkb | 25 +++++++++++++++++++ source/ut_rerror.pks | 25 +++++++++++++++++++ source/ut_result.pkb | 11 ++++++--- source/ut_result.pks | 10 +++++--- source/ut_result2.pkb | 12 ++++++--- source/ut_result2.pks | 12 ++++++--- source/ut_routcome.pkb | 26 +++++++++++++++++++- source/ut_routcome.pks | 25 +++++++++++++++++++ source/ut_rsuite.pkb | 25 +++++++++++++++++++ source/ut_rsuite.pks | 25 +++++++++++++++++++ source/ut_rtestcase.pkb | 25 +++++++++++++++++++ source/ut_rtestcase.pks | 25 +++++++++++++++++++ source/ut_runittest.pkb | 25 +++++++++++++++++++ source/ut_runittest.pks | 25 +++++++++++++++++++ source/ut_rutp.pkb | 25 +++++++++++++++++++ source/ut_rutp.pks | 26 +++++++++++++++++++- source/ut_suite.pkb | 10 +++++--- source/ut_suite.pks | 21 ++++++---------- source/ut_suiteutp.pkb | 14 +++++------ source/ut_suiteutp.pks | 15 ++++++------ source/ut_test.pkb | 10 +++++--- source/ut_test.pks | 14 +++++------ source/ut_testcase.pkb | 10 +++++--- source/ut_testcase.pks | 14 +++++------ source/ut_testprep.pkb | 25 +++++++++++++++++++ source/ut_testprep.pks | 25 +++++++++++++++++++ source/ut_unittest.pkb | 26 +++++++++++++++++++- source/ut_unittest.pks | 25 +++++++++++++++++++ source/ut_utoutput.pkb | 24 ++++++++++++++++++ source/ut_utoutput.pks | 26 +++++++++++++++++++- source/ut_utp.pkb | 25 +++++++++++++++++++ source/ut_utp.pks | 25 +++++++++++++++++++ 55 files changed, 920 insertions(+), 277 deletions(-) diff --git a/source/ut_assert.pkb b/source/ut_assert.pkb index ee9bd3d11..5436301d2 100644 --- a/source/ut_assert.pkb +++ b/source/ut_assert.pkb @@ -2,12 +2,12 @@ CREATE OR REPLACE PACKAGE BODY utassert IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 -Steven Feuerstein, steven@stevenfeuerstein.com -Chris Rimmer, chris@sunset.force9.co.uk +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,11 +22,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -/*Modification History: -studious:01/20/2002:Assertion for object existance -Venky:08-AUG-2002:Addes refcursor Assertions -*/ +************************************************************************ +$Log$ +************************************************************************/ g_showresults BOOLEAN := FALSE; @@ -663,4 +661,3 @@ Description: Checking whether object exists */ END utassert; / -REM SHO ERR diff --git a/source/ut_assert.pks b/source/ut_assert.pks index f8fc24954..f8315885c 100644 --- a/source/ut_assert.pks +++ b/source/ut_assert.pks @@ -2,12 +2,12 @@ CREATE OR REPLACE PACKAGE utassert &start81 AUTHID CURRENT_USER &end81 IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 -Steven Feuerstein, steven@stevenfeuerstein.com -Chris Rimmer, chris@sunset.force9.co.uk +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,13 +22,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -/* -MODIFICATION HISTORY -Who When What -chrisrimmer 19-Feb-2002 Added previous_passed and previous_failed -Venky 08-Aug-2002 Added refcursor assertions -*/ +************************************************************************ +$Log$ +************************************************************************/ test_failure EXCEPTION; /* On Error behaviors */ diff --git a/source/ut_assert2.pkb b/source/ut_assert2.pkb index fa613890f..ab27afa7b 100644 --- a/source/ut_assert2.pkb +++ b/source/ut_assert2.pkb @@ -1,33 +1,29 @@ CREATE OR REPLACE PACKAGE BODY utassert2 IS - /* - GNU General Public License for utPLSQL - - Copyright (C) 2000 - Steven Feuerstein, steven@stevenfeuerstein.com - Chris Rimmer, chris@sunset.force9.co.uk - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program (see license.txt); if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - /*Modification History: - chrisrimmer 19-Feb-2002 Added g_previous_pass, previous_passed - and previous_failed - studious:01/20/2002:Assertion for object existance - chrisrimmer 10-Jun-2002 Added eqoutput assertions - Venky 08-AUG-2002 Added refcursor assertions 12345 - */ + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ /* START chrisrimmer 42694 */ g_previous_pass BOOLEAN; @@ -3733,5 +3729,4 @@ UNION END utassert2; / -REM SHO ERR diff --git a/source/ut_assert2.pks b/source/ut_assert2.pks index acde4ee5f..466314363 100644 --- a/source/ut_assert2.pks +++ b/source/ut_assert2.pks @@ -3,12 +3,12 @@ CREATE OR REPLACE PACKAGE utassert2 &start81 AUTHID CURRENT_USER &end81 IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (outcome_in in ut_outcome.id%TYPE,C) 2000 -Steven Feuerstein, steven@stevenfeuerstein.com -Chris Rimmer, chris@sunset.force9.co.uk +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,14 +21,11 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with this program (outcome_in in ut_outcome.id%TYPE,see license.txt); if not, write to the Free Software +along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -/*Modification History: -studious:01/20/2002:Assertion for object existance -chrisrimmer 19-Feb-2002 Added previous_passed and previous_failed -Venky 08-AUG-2002 Added refcursor assertions -*/ +************************************************************************ +$Log$ +************************************************************************/ test_failure EXCEPTION; /* On Error behaviors */ diff --git a/source/ut_config.pkb b/source/ut_config.pkb index 8bffe9faa..f0e4a5506 100644 --- a/source/ut_config.pkb +++ b/source/ut_config.pkb @@ -1,11 +1,11 @@ CREATE OR REPLACE PACKAGE BODY utconfig IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 -Steven Feuerstein, steven@stevenfeuerstein.com -Chris Rimmer, chris@sunset.force9.co.uk +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +20,10 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ +************************************************************************ +$Log$ +************************************************************************/ + ------------------------------------------------------------------------------- --Description ------------------------------------------------------------------------------- @@ -29,12 +32,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --by default is set by calling settester. Wherever a username is passed as NULL, --it is assumed to be that user. This defaults initially to the current user. ------------------------------------------------------------------------------- ---Modification History -------------------------------------------------------------------------------- ---WHO WHEN WHAT -------------------------------------------------------------------------------- ---Chris Rimmer 22 Oct 2000 Created from utplsql package -------------------------------------------------------------------------------- ---------------------------------------------------------------------------- --This record holds the default configuration diff --git a/source/ut_config.pks b/source/ut_config.pks index 8a3378b73..8d5f5a609 100644 --- a/source/ut_config.pks +++ b/source/ut_config.pks @@ -1,5 +1,30 @@ CREATE OR REPLACE PACKAGE utconfig &start81 AUTHID CURRENT_USER &end81 IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + ------------------------------------------------------------------------------- --Description ------------------------------------------------------------------------------- @@ -7,12 +32,6 @@ IS --settings for different users. The configuration data to be used by utPLSQL --by default is set by calling settester. Wherever a username is passed as NULL, --it is assumed to be that user. This defaults initially to the current user. -------------------------------------------------------------------------------- ---Modification History -------------------------------------------------------------------------------- ---WHO WHEN WHAT -------------------------------------------------------------------------------- ---Chris Rimmer 22 Oct 2000 Created from utplsql package ------------------------------------------------------------------------------- --The default prefix diff --git a/source/ut_gen.pkb b/source/ut_gen.pkb index 03332bc92..b6b78efd2 100644 --- a/source/ut_gen.pkb +++ b/source/ut_gen.pkb @@ -1,24 +1,30 @@ CREATE OR REPLACE PACKAGE BODY utgen IS - /* - GNU General Public License for utPLSQL - Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +/************************************************************************ +GNU General Public License for utPLSQL - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ - You should have received a copy of the GNU General Public License - along with this program (see license.txt); if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ g_pkgstring VARCHAR2 (32767); g_currrow PLS_INTEGER := NULL; g_firstbodyrow PLS_INTEGER := NULL; diff --git a/source/ut_gen.pks b/source/ut_gen.pks index 88676eba7..560ad2e8b 100644 --- a/source/ut_gen.pks +++ b/source/ut_gen.pks @@ -1,13 +1,13 @@ CREATE OR REPLACE PACKAGE utgen -&start81 -AUTHID CURRENT_USER -&end81 +&start81 AUTHID CURRENT_USER &end81 IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,12 +22,10 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -/* -11/2001 SEF Add receq_package based on functionality provided by Dan Spencer. -09/2002 PBA Add testpkg_from_table functionality. Depends upon table ut_grid for - input. -*/ +************************************************************************ +$Log$ +************************************************************************/ + c_screen CONSTANT PLS_INTEGER := 1; c_string CONSTANT PLS_INTEGER := 2; c_file CONSTANT PLS_INTEGER := 3; diff --git a/source/ut_i_do.sql b/source/ut_i_do.sql index 1f8820654..4ea94e755 100644 --- a/source/ut_i_do.sql +++ b/source/ut_i_do.sql @@ -106,11 +106,10 @@ SET TERMOUT ON PROMPT &line2 PROMPT GNU General Public License for utPLSQL -PROMPT -PROMPT Copyright (C) 2000 -PROMPT Steven Feuerstein, steven@stevenfeuerstein.com -PROMPT Chris Rimmer, chris@sunset.force9.co.uk -PROMPT +PROMPT +PROMPT Copyright (C) 2000-2003 +PROMPT Steven Feuerstein and the utPLSQL Project +PROMPT (steven@stevenfeuerstein.com) PROMPT PROMPT This program is free software; you can redistribute it and/or modify PROMPT it under the terms of the GNU General Public License as published by diff --git a/source/ut_outcome.pkb b/source/ut_outcome.pkb index b63c46418..fd18be095 100644 --- a/source/ut_outcome.pkb +++ b/source/ut_outcome.pkb @@ -1,5 +1,30 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ CREATE OR REPLACE PACKAGE BODY utoutcome + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + IS FUNCTION name (outcome_id_in IN ut_outcome.id%TYPE) RETURN ut_outcome.name%TYPE diff --git a/source/ut_outcome.pks b/source/ut_outcome.pks index b6470539a..a88fd8a7f 100644 --- a/source/ut_outcome.pks +++ b/source/ut_outcome.pks @@ -1,6 +1,31 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ CREATE OR REPLACE PACKAGE utoutcome IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + c_name CONSTANT CHAR (7) := 'OUTCOME'; c_abbrev CONSTANT CHAR (2) := 'OC'; diff --git a/source/ut_output.pkb b/source/ut_output.pkb index f776a6621..78b5de98c 100644 --- a/source/ut_output.pkb +++ b/source/ut_output.pkb @@ -1,29 +1,29 @@ CREATE OR REPLACE PACKAGE BODY utoutput IS - /* - GNU General Public License for utPLSQL - - Copyright (C) 2000 - Steven Feuerstein, steven@stevenfeuerstein.com - Chris Rimmer, chris@sunset.force9.co.uk - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program (see license.txt); if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - /*Modification History: - chrisrimmer 03-Apr-2002 Created - */ + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ g_temp_buffer DBMS_OUTPUT.CHARARR; g_save_buffer DBMS_OUTPUT.CHARARR; diff --git a/source/ut_output.pks b/source/ut_output.pks index e6c67e064..086f2ec82 100644 --- a/source/ut_output.pks +++ b/source/ut_output.pks @@ -2,12 +2,12 @@ CREATE OR REPLACE PACKAGE utoutput &start81 AUTHID CURRENT_USER &end81 IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 -Steven Feuerstein, steven@stevenfeuerstein.com -Chris Rimmer, chris@sunset.force9.co.uk +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,11 +22,10 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -/*Modification History: -chrisrimmer 03-Apr-2002 Created -*/ - +************************************************************************ +$Log$ +************************************************************************/ + EMPTY_OUTPUT_BUFFER EXCEPTION; FUNCTION saving RETURN BOOLEAN; diff --git a/source/ut_package.pkb b/source/ut_package.pkb index f6dfd71fb..a1f155fa5 100644 --- a/source/ut_package.pkb +++ b/source/ut_package.pkb @@ -2,10 +2,12 @@ CREATE OR REPLACE PACKAGE BODY utpackage IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +22,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ +************************************************************************ +$Log$ +************************************************************************/ FUNCTION name_from_id (id_in IN ut_package.id%TYPE) RETURN ut_package.name%TYPE diff --git a/source/ut_package.pks b/source/ut_package.pks index 3a8226ad6..5da49ce00 100644 --- a/source/ut_package.pks +++ b/source/ut_package.pks @@ -2,10 +2,12 @@ CREATE OR REPLACE PACKAGE utpackage -- &start81 AUTHID CURRENT_USER &end81 IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,16 +22,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - - -- Unit Test Framework for PL/SQL - -- Steven Feuerstein, Copyright 2000, All rights reserved - -- steven@stevenfeuerstein.com -/* -Modification history -Date Who What -09/08/2000 SEF NVL on updates of executions and failures -*/ +************************************************************************ +$Log$ +************************************************************************/ c_success CONSTANT VARCHAR2 (7) := 'SUCCESS'; c_failure CONSTANT VARCHAR2 (7) := 'FAILURE'; diff --git a/source/ut_plsql.pkb b/source/ut_plsql.pkb index 71d85f434..c837e0b1b 100644 --- a/source/ut_plsql.pkb +++ b/source/ut_plsql.pkb @@ -2,12 +2,12 @@ CREATE OR REPLACE PACKAGE BODY utplsql IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 -Steven Feuerstein, steven@stevenfeuerstein.com -Chris Rimmer, chris@sunset.force9.co.uk +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,18 +22,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -------------------------------------------------------------------------------- ---Modification History -------------------------------------------------------------------------------- ---WHO WHEN WHAT -------------------------------------------------------------------------------- ---Dan Spencer 27 DEc 01 Added record comparison logic. ---Steven F 3 Dec 2001 Revamp setpkg logic to populate the test --- array later in the process. ---Steven F 15 Nov 2001 Add per_method_setup logic ---Chris Rimmer 08 Nov 2000 Changed to use new utConfig package -------------------------------------------------------------------------------- +************************************************************************ +$Log$ +************************************************************************/ g_trc BOOLEAN := FALSE; g_version VARCHAR2 (100) := '2.1.1'; diff --git a/source/ut_plsql.pks b/source/ut_plsql.pks index 2c8aa845f..e43cc31a1 100644 --- a/source/ut_plsql.pks +++ b/source/ut_plsql.pks @@ -2,10 +2,12 @@ CREATE OR REPLACE PACKAGE utplsql &start81 AUTHID CURRENT_USER &end81 IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +22,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ +************************************************************************ +$Log$ +************************************************************************/ c_success CONSTANT VARCHAR2 (7) := 'SUCCESS'; c_failure CONSTANT VARCHAR2 (7) := 'FAILURE'; diff --git a/source/ut_plsql2.pkb b/source/ut_plsql2.pkb index 815406d21..939845ca0 100644 --- a/source/ut_plsql2.pkb +++ b/source/ut_plsql2.pkb @@ -2,12 +2,12 @@ CREATE OR REPLACE PACKAGE BODY utplsql2 IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 -Steven Feuerstein, steven@stevenfeuerstein.com -Chris Rimmer, chris@sunset.force9.co.uk +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,16 +22,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -------------------------------------------------------------------------------- ---Modification History -------------------------------------------------------------------------------- ---WHO WHEN WHAT -------------------------------------------------------------------------------- ---SEF 15 Nov 2001 2.0.8.1: Add support for unit test level --- setup/teardown ---Chris Rimmer 08 Nov 2000 Changed to use new utConfig package -------------------------------------------------------------------------------- +************************************************************************ +$Log$ +************************************************************************/ g_trc BOOLEAN := FALSE; g_version VARCHAR2 (100) := '1.5.6'; diff --git a/source/ut_plsql2.pks b/source/ut_plsql2.pks index 2ba445fc4..a76435524 100644 --- a/source/ut_plsql2.pks +++ b/source/ut_plsql2.pks @@ -2,10 +2,12 @@ CREATE OR REPLACE PACKAGE utplsql2 &start81 AUTHID CURRENT_USER &end81 IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +22,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ +************************************************************************ +$Log$ +************************************************************************/ V2_naming_mode constant char(2) := 'V1'; V1_naming_mode constant char(2) := 'V2'; diff --git a/source/ut_plsql_util.pkb b/source/ut_plsql_util.pkb index 01171c4a3..fe7880aaf 100644 --- a/source/ut_plsql_util.pkb +++ b/source/ut_plsql_util.pkb @@ -1,4 +1,29 @@ CREATE OR REPLACE PACKAGE BODY utplsql_util + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + AS ver_no VARCHAR2 (10) := '1.0.0'; diff --git a/source/ut_plsql_util.pks b/source/ut_plsql_util.pks index 2f10ad3f2..12cb7f333 100644 --- a/source/ut_plsql_util.pks +++ b/source/ut_plsql_util.pks @@ -1,13 +1,30 @@ CREATE OR REPLACE PACKAGE utplsql_util ---&start81 AUTHID CURRENT_USER --&end81 AS -/* - This package is custom build for UTPLSQL custom test project - Author : Venky Mangapillai - Created : May'2000 +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ -*/ TYPE SQLDATA IS RECORD ( col_name VARCHAR2 (50), col_type PLS_INTEGER, diff --git a/source/ut_receq.pkb b/source/ut_receq.pkb index a70670a8d..d8ab85def 100644 --- a/source/ut_receq.pkb +++ b/source/ut_receq.pkb @@ -1,13 +1,30 @@ --- register tables and view that will have record comparison functions created +CREATE OR REPLACE PACKAGE BODY utreceq +IS --- 26 Dec 2001 Dan Spencer Created +/************************************************************************ +GNU General Public License for utPLSQL --- 31 Jul 2002 Chris Rimmer Fixed so that records in foreign schemas work +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ -CREATE OR REPLACE PACKAGE BODY utreceq -IS PROCEDURE delete_receq (id_in ut_receq.id%TYPE) IS v_cur PLS_INTEGER := DBMS_SQL.open_cursor; diff --git a/source/ut_receq.pks b/source/ut_receq.pks index a5b5e51be..af7bbc7ea 100644 --- a/source/ut_receq.pks +++ b/source/ut_receq.pks @@ -1,12 +1,30 @@ --- 26 Dec 2001 Dan Spencer Created - --- 31 Jul 2002 Chris Rimmer Fixed so that records in foreign schemas work - - - CREATE OR REPLACE PACKAGE utreceq &start81 AUTHID CURRENT_USER &end81 IS +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + PROCEDURE add( pkg_name_in IN ut_package.name%TYPE , diff --git a/source/ut_rerror.pkb b/source/ut_rerror.pkb index 03aeaa78f..c5d92f919 100644 --- a/source/ut_rerror.pkb +++ b/source/ut_rerror.pkb @@ -1,6 +1,31 @@ /* Formatted on 2001/07/13 12:30 (RevealNet Formatter v4.4.1) */ CREATE OR REPLACE PACKAGE BODY utrerror IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + FUNCTION uterrcode (errmsg_in IN VARCHAR2 := NULL) RETURN INTEGER IS diff --git a/source/ut_rerror.pks b/source/ut_rerror.pks index 0e286af0d..dedbc58f4 100644 --- a/source/ut_rerror.pks +++ b/source/ut_rerror.pks @@ -1,6 +1,31 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ CREATE OR REPLACE PACKAGE utrerror &start81 AUTHID CURRENT_USER &end81 IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + c_error_indicator CONSTANT VARCHAR2 (7) := 'UT-300%'; general_error CONSTANT INTEGER := 300000; no_utp_for_program CONSTANT INTEGER := 300001; diff --git a/source/ut_result.pkb b/source/ut_result.pkb index d8fd380ce..7a1704612 100644 --- a/source/ut_result.pkb +++ b/source/ut_result.pkb @@ -1,10 +1,12 @@ CREATE OR REPLACE PACKAGE BODY utresult IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,7 +21,10 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ +************************************************************************ +$Log$ +************************************************************************/ + resultindx PLS_INTEGER; g_header_shown BOOLEAN := FALSE ; g_include_successes BOOLEAN := TRUE ; diff --git a/source/ut_result.pks b/source/ut_result.pks index 82fa75198..2e08a103a 100644 --- a/source/ut_result.pks +++ b/source/ut_result.pks @@ -2,10 +2,12 @@ CREATE OR REPLACE PACKAGE utresult IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +22,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ +************************************************************************ +$Log$ +************************************************************************/ /* Test result record structure */ TYPE result_rt IS RECORD ( diff --git a/source/ut_result2.pkb b/source/ut_result2.pkb index 825e45f26..2b3d917e7 100644 --- a/source/ut_result2.pkb +++ b/source/ut_result2.pkb @@ -1,9 +1,12 @@ CREATE OR REPLACE PACKAGE BODY utresult2 IS -/* + +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,7 +21,10 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ +************************************************************************ +$Log$ +************************************************************************/ + PROCEDURE report ( outcome_in IN ut_outcome.ID%TYPE ,description_in IN VARCHAR2 diff --git a/source/ut_result2.pks b/source/ut_result2.pks index d96b81475..3d10eb474 100644 --- a/source/ut_result2.pks +++ b/source/ut_result2.pks @@ -1,9 +1,12 @@ CREATE OR REPLACE PACKAGE utresult2 IS -/* + +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,7 +21,10 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ +************************************************************************ +$Log$ +************************************************************************/ + c_success CONSTANT CHAR (7) := 'SUCCESS'; c_failure CONSTANT CHAR (7) := 'FAILURE'; diff --git a/source/ut_routcome.pkb b/source/ut_routcome.pkb index d044fba17..3d5d8fe92 100644 --- a/source/ut_routcome.pkb +++ b/source/ut_routcome.pkb @@ -1,6 +1,30 @@ - CREATE OR REPLACE PACKAGE BODY utroutcome IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + PROCEDURE initiate ( run_id_in IN utr_outcome.run_id%TYPE , outcome_id_in IN utr_outcome.outcome_id%TYPE diff --git a/source/ut_routcome.pks b/source/ut_routcome.pks index 6b9352dfa..0fdabe236 100644 --- a/source/ut_routcome.pks +++ b/source/ut_routcome.pks @@ -1,5 +1,30 @@ CREATE OR REPLACE PACKAGE utroutcome IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + PROCEDURE RECORD ( run_id_in IN utr_outcome.run_id%TYPE , tc_run_id_in IN PLS_INTEGER diff --git a/source/ut_rsuite.pkb b/source/ut_rsuite.pkb index 6e81ef069..87d360f54 100644 --- a/source/ut_rsuite.pkb +++ b/source/ut_rsuite.pkb @@ -1,6 +1,31 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ CREATE OR REPLACE PACKAGE BODY utrsuite IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + PROCEDURE initiate ( run_id_in IN utr_suite.run_id%TYPE, suite_id_in IN utr_suite.suite_id%TYPE, diff --git a/source/ut_rsuite.pks b/source/ut_rsuite.pks index 9cd9d994f..198004755 100644 --- a/source/ut_rsuite.pks +++ b/source/ut_rsuite.pks @@ -1,6 +1,31 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ CREATE OR REPLACE PACKAGE utrsuite IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + PROCEDURE terminate ( run_id_in IN utr_suite.run_id%TYPE, suite_id_in IN utr_suite.suite_id%TYPE, diff --git a/source/ut_rtestcase.pkb b/source/ut_rtestcase.pkb index 52ae2b2de..93014c548 100644 --- a/source/ut_rtestcase.pkb +++ b/source/ut_rtestcase.pkb @@ -1,6 +1,31 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ CREATE OR REPLACE PACKAGE BODY utrtestcase IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + PROCEDURE initiate ( run_id_in IN utr_testcase.run_id%TYPE, testcase_id_in IN utr_testcase.testcase_id%TYPE, diff --git a/source/ut_rtestcase.pks b/source/ut_rtestcase.pks index 1f6177099..6608cd32f 100644 --- a/source/ut_rtestcase.pks +++ b/source/ut_rtestcase.pks @@ -1,6 +1,31 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ CREATE OR REPLACE PACKAGE utrtestcase IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + PROCEDURE terminate ( run_id_in IN utr_testcase.run_id%TYPE, testcase_id_in IN utr_testcase.testcase_id%TYPE, diff --git a/source/ut_runittest.pkb b/source/ut_runittest.pkb index 67b38f105..f1a4495f2 100644 --- a/source/ut_runittest.pkb +++ b/source/ut_runittest.pkb @@ -1,6 +1,31 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ CREATE OR REPLACE PACKAGE BODY utrunittest IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + PROCEDURE initiate ( run_id_in IN utr_unittest.run_id%TYPE, unittest_id_in IN utr_unittest.unittest_id%TYPE, diff --git a/source/ut_runittest.pks b/source/ut_runittest.pks index 8ce731917..5cf0752ad 100644 --- a/source/ut_runittest.pks +++ b/source/ut_runittest.pks @@ -1,6 +1,31 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ CREATE OR REPLACE PACKAGE utrunittest IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + PROCEDURE terminate ( run_id_in IN utr_unittest.run_id%TYPE, unittest_id_in IN utr_unittest.unittest_id%TYPE, diff --git a/source/ut_rutp.pkb b/source/ut_rutp.pkb index c47977e4e..69a386113 100644 --- a/source/ut_rutp.pkb +++ b/source/ut_rutp.pkb @@ -1,6 +1,31 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ CREATE OR REPLACE PACKAGE BODY utrutp IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + PROCEDURE initiate ( run_id_in IN utr_utp.run_id%TYPE, utp_id_in IN utr_utp.utp_id%TYPE, diff --git a/source/ut_rutp.pks b/source/ut_rutp.pks index 45f4029b1..57e7eda94 100644 --- a/source/ut_rutp.pks +++ b/source/ut_rutp.pks @@ -1,6 +1,30 @@ - CREATE OR REPLACE PACKAGE utrutp IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + PROCEDURE TERMINATE ( run_id_in IN utr_utp.run_id%TYPE , utp_id_in IN utr_utp.utp_id%TYPE diff --git a/source/ut_suite.pkb b/source/ut_suite.pkb index 61a55f0ca..1260ecd10 100644 --- a/source/ut_suite.pkb +++ b/source/ut_suite.pkb @@ -2,10 +2,12 @@ CREATE OR REPLACE PACKAGE BODY utsuite IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +22,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ +************************************************************************ +$Log$ +************************************************************************/ FUNCTION name_from_id (id_in IN ut_suite.id%TYPE) RETURN ut_suite.name%TYPE diff --git a/source/ut_suite.pks b/source/ut_suite.pks index 796d85ab9..e3564f980 100644 --- a/source/ut_suite.pks +++ b/source/ut_suite.pks @@ -2,10 +2,12 @@ CREATE OR REPLACE PACKAGE utsuite -- &start81 AUTHID CURRENT_USER &end81 IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,18 +22,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - - -- Unit Test Framework for PL/SQL - -- Steven Feuerstein, Copyright 2000, All rights reserved - -- steven@stevenfeuerstein.com - -/* -Modification history -Date Who What -07/2001 SEF Add onerow for V2 suite management. -09/08/2000 SEF NVL on updates of executions and failures -*/ +************************************************************************ +$Log$ +************************************************************************/ /* Test suite API */ diff --git a/source/ut_suiteutp.pkb b/source/ut_suiteutp.pkb index 128270fd4..92b2390ca 100644 --- a/source/ut_suiteutp.pkb +++ b/source/ut_suiteutp.pkb @@ -2,10 +2,12 @@ CREATE OR REPLACE PACKAGE BODY utsuiteutp -- &start81 AUTHID CURRENT_USER &end81 IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,11 +22,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - - -- Unit Test Framework for PL/SQL - -- Steven Feuerstein, Copyright 2000, All rights reserved - -- steven@stevenfeuerstein.com +************************************************************************ +$Log$ +************************************************************************/ FUNCTION defined ( suite_id_in IN ut_suite.id%TYPE, diff --git a/source/ut_suiteutp.pks b/source/ut_suiteutp.pks index dac67c041..464e526d7 100644 --- a/source/ut_suiteutp.pks +++ b/source/ut_suiteutp.pks @@ -1,9 +1,12 @@ CREATE OR REPLACE PACKAGE utsuiteutp -- &start81 AUTHID CURRENT_USER &end81 IS -/* + +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,11 +21,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - - -- Unit Test Framework for PL/SQL - -- Steven Feuerstein, Copyright 2000, All rights reserved - -- steven@stevenfeuerstein.com +************************************************************************ +$Log$ +************************************************************************/ c_name CONSTANT CHAR (18) := 'SUITE-UTP PACKAGE'; c_abbrev CONSTANT CHAR (9) := 'SUITE-UTP'; diff --git a/source/ut_test.pkb b/source/ut_test.pkb index 98893e56f..51e1b03e0 100644 --- a/source/ut_test.pkb +++ b/source/ut_test.pkb @@ -2,10 +2,12 @@ CREATE OR REPLACE PACKAGE BODY uttest IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +22,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ +************************************************************************ +$Log$ +************************************************************************/ FUNCTION name_from_id (id_in IN ut_test.id%TYPE) RETURN ut_test.name%TYPE diff --git a/source/ut_test.pks b/source/ut_test.pks index 2715a12b1..e0caf03b8 100644 --- a/source/ut_test.pks +++ b/source/ut_test.pks @@ -2,10 +2,12 @@ CREATE OR REPLACE PACKAGE uttest -- &start81 AUTHID CURRENT_USER &end81 IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,11 +22,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - - -- Unit Test Framework for PL/SQL - -- Steven Feuerstein, Copyright 2000, All rights reserved - -- steven@stevenfeuerstein.com +************************************************************************ +$Log$ +************************************************************************/ FUNCTION name_from_id (id_in IN ut_test.id%TYPE) RETURN ut_test.name%TYPE; diff --git a/source/ut_testcase.pkb b/source/ut_testcase.pkb index b556dc178..2df210cf4 100644 --- a/source/ut_testcase.pkb +++ b/source/ut_testcase.pkb @@ -2,10 +2,12 @@ CREATE OR REPLACE PACKAGE BODY uttestcase IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,7 +22,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ +************************************************************************ +$Log$ +************************************************************************/ FUNCTION name_from_id (id_in IN ut_testcase.id%TYPE) RETURN ut_testcase.name%TYPE diff --git a/source/ut_testcase.pks b/source/ut_testcase.pks index 92faaf180..dc2527480 100644 --- a/source/ut_testcase.pks +++ b/source/ut_testcase.pks @@ -2,10 +2,12 @@ CREATE OR REPLACE PACKAGE uttestcase -- &start81 AUTHID CURRENT_USER &end81 IS -/* +/************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000 Steven Feuerstein, steven@stevenfeuerstein.com +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,11 +22,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - - -- Unit Test Framework for PL/SQL - -- Steven Feuerstein, Copyright 2000, All rights reserved - -- steven@stevenfeuerstein.com +************************************************************************ +$Log$ +************************************************************************/ c_name CONSTANT CHAR (9) := 'TEST CASE'; c_abbrev CONSTANT CHAR (3) := 'TC'; diff --git a/source/ut_testprep.pkb b/source/ut_testprep.pkb index 3ffc8d3cf..aec5262be 100644 --- a/source/ut_testprep.pkb +++ b/source/ut_testprep.pkb @@ -1,6 +1,31 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ CREATE OR REPLACE PACKAGE BODY uttestprep IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + FUNCTION setup_program (utp_in IN ut_utp%ROWTYPE) RETURN VARCHAR2 IS diff --git a/source/ut_testprep.pks b/source/ut_testprep.pks index 92438ddc6..256867ad4 100644 --- a/source/ut_testprep.pks +++ b/source/ut_testprep.pks @@ -2,6 +2,31 @@ CREATE OR REPLACE PACKAGE uttestprep -- NO LONGER USED. IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + FUNCTION setup_program (utp_in IN ut_utp%ROWTYPE) RETURN VARCHAR2; diff --git a/source/ut_unittest.pkb b/source/ut_unittest.pkb index 9d55f6b21..864f0ec23 100644 --- a/source/ut_unittest.pkb +++ b/source/ut_unittest.pkb @@ -1,7 +1,31 @@ /* Formatted on 2001/07/14 08:45 (RevealNet Formatter v4.4.1) */ - CREATE OR REPLACE PACKAGE BODY utunittest IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + FUNCTION name ( ut_in IN ut_unittest%ROWTYPE ) diff --git a/source/ut_unittest.pks b/source/ut_unittest.pks index 048b90f1e..ff5598358 100644 --- a/source/ut_unittest.pks +++ b/source/ut_unittest.pks @@ -1,6 +1,31 @@ /* Formatted on 2001/07/13 17:50 (RevealNet Formatter v4.4.0) */ CREATE OR REPLACE PACKAGE utunittest IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + c_name CONSTANT CHAR (9) := 'UNIT TEST'; c_abbrev CONSTANT CHAR (2) := 'UT'; diff --git a/source/ut_utoutput.pkb b/source/ut_utoutput.pkb index 7afefcc16..108d3f790 100644 --- a/source/ut_utoutput.pkb +++ b/source/ut_utoutput.pkb @@ -1,6 +1,30 @@ CREATE OR REPLACE PACKAGE BODY ut_utoutput IS +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + PROCEDURE clear_buffer IS lines number; diff --git a/source/ut_utoutput.pks b/source/ut_utoutput.pks index 582896d8b..4f5aa81e3 100644 --- a/source/ut_utoutput.pks +++ b/source/ut_utoutput.pks @@ -1,9 +1,33 @@ CREATE OR REPLACE PACKAGE ut_utoutput IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + PROCEDURE ut_setup; PROCEDURE ut_teardown; - -- For each program to test... PROCEDURE ut_count; PROCEDURE ut_extract; PROCEDURE ut_nextline; diff --git a/source/ut_utp.pkb b/source/ut_utp.pkb index 60c3cf175..c7596eb4e 100644 --- a/source/ut_utp.pkb +++ b/source/ut_utp.pkb @@ -1,6 +1,31 @@ /* Formatted on 2001/09/14 10:34 (RevealNet Formatter v4.4.1) */ CREATE OR REPLACE PACKAGE BODY ututp IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + /* UTP##NNN */ FUNCTION name (utp_in IN ut_utp%ROWTYPE) RETURN VARCHAR2 diff --git a/source/ut_utp.pks b/source/ut_utp.pks index b7508311b..8e3a750de 100644 --- a/source/ut_utp.pks +++ b/source/ut_utp.pks @@ -1,5 +1,30 @@ CREATE OR REPLACE PACKAGE ututp IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ +************************************************************************/ + c_name CONSTANT CHAR (18) := 'UNIT TEST PACKAGE'; c_abbrev CONSTANT CHAR (3) := 'UTP'; From 0ce7d9fdb5ded9351ac3468ac6e09802d0261ebb Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 11 Jul 2003 14:24:09 +0000 Subject: [PATCH 067/143] Added an extra note on spool files --- documentation/src/fourstep.html | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/documentation/src/fourstep.html b/documentation/src/fourstep.html index 8971ced45..e0a8b4471 100644 --- a/documentation/src/fourstep.html +++ b/documentation/src/fourstep.html @@ -54,34 +54,19 @@

    Step 1. Install (and Upgrade) utPLSQL.

    may get error messages when installing. However, utPLSQL will still function correctly.

    Once you have connected to the schema, run the ut_i_do.sql -file with the parameter "install" to install all utPLSQL objects. If the working directory of your SQL*Plus -session is the directory holding the utPLSQL files, you can issue this as follows:

    +file with the parameter "install" to install all utPLSQL objects. You should ensure that +the working directory of your SQL*Plus +session is the directory holding the utPLSQL files, then issue this as follows:

    SQL> @ut_i_do install
     
    -

    If the working directory of your SQL*Plus session is not -the directory holding the utPLSQL files, you can issue this command:

    - -

    - -
    SQL> @<directory>ut_i_do install
     
    - -

    as in:

    - -

    - -
    SQL> @c:\utplsql\ut_i_do install
     
    - -

    or

    - -

    - -
    SQL> @/orautils/utplsql/ut_i_do install
     

    This file will remove the existing installation of utPLSQL -and then create all tables and packages needed.

    +and then create all tables and packages needed. Note that the installation script +creates some files dynamically using the SPOOL command. For this reason, it is +necessary that you have write permission in the directory.

    @@ -97,12 +82,6 @@

    Removing utPLSQL

    SQL> @ut_i_do uninstall
     
    -

    or

    - -

    - -
    SQL> @<directory>ut_i_do uninstall
    -

    Step 2. Choose a program to test and identify the test cases.

    From 0d166ce18d56bdd7727196af69c1dba412031977 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 11 Jul 2003 14:32:52 +0000 Subject: [PATCH 068/143] Added 'throws' bugfix from Ivan Desjardins --- source/ut_assert2.pkb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source/ut_assert2.pkb b/source/ut_assert2.pkb index ab27afa7b..ac7d3ae48 100644 --- a/source/ut_assert2.pkb +++ b/source/ut_assert2.pkb @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:46 chrisrimmer +Added Standard Headers + ************************************************************************/ /* START chrisrimmer 42694 */ @@ -2553,7 +2556,7 @@ UNION l_indicator PLS_INTEGER; v_block VARCHAR2 (32767) := 'BEGIN ' - || RTRIM (check_call_in, ';') + || RTRIM (RTRIM (check_call_in), ';') || '; :indicator := 0; EXCEPTION @@ -2636,7 +2639,7 @@ UNION l_indicator PLS_INTEGER; v_block VARCHAR2 (32767) := 'BEGIN ' - || RTRIM (check_call_in, ';') + || RTRIM (RTRIM (check_call_in), ';') || '; :indicator := 0; EXCEPTION From 6006520532978b73b92f2f219e5eda64331455a2 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 21 Nov 2003 16:28:44 +0000 Subject: [PATCH 069/143] Fixed the commented out preprocessor flags, pointed out by Frank Puechl in bug 846639 --- source/ut_plsql_util.pkb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/source/ut_plsql_util.pkb b/source/ut_plsql_util.pkb index fe7880aaf..d0f38c98b 100644 --- a/source/ut_plsql_util.pkb +++ b/source/ut_plsql_util.pkb @@ -22,6 +22,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ AS @@ -960,19 +963,19 @@ AS PROCEDURE execute_ddl (stmt VARCHAR2) IS - --&start73 + &start73 fdbk PLS_INTEGER; cur PLS_INTEGER := DBMS_SQL.open_cursor; - --&end73 + &end73 BEGIN - --&start81 + &start81 EXECUTE IMMEDIATE stmt; - --&end81 - --&start73 + &end81 + &start73 DBMS_SQL.parse (cur, stmt, DBMS_SQL.native); fdbk := DBMS_SQL.EXECUTE (cur); DBMS_SQL.close_cursor (cur); - --&end73 + &end73 EXCEPTION WHEN OTHERS THEN From 38ee275ec2162e86303bc32e66de32dcee72fd5e Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 25 Nov 2003 13:54:49 +0000 Subject: [PATCH 070/143] Added back in AUTHID line --- source/ut_plsql_util.pks | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/ut_plsql_util.pks b/source/ut_plsql_util.pks index 12cb7f333..edf3aa0a6 100644 --- a/source/ut_plsql_util.pks +++ b/source/ut_plsql_util.pks @@ -1,4 +1,5 @@ CREATE OR REPLACE PACKAGE utplsql_util +&start81 AUTHID CURRENT_USER &end81 AS /************************************************************************ @@ -23,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ TYPE SQLDATA IS RECORD ( From 2a962bf6992626fc76468bbc474cdede08f1ef78 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 25 Nov 2003 16:44:23 +0000 Subject: [PATCH 071/143] Added Frank Puechl's documentation on eq_refc_* procedures --- documentation/src/utassert.html | 212 +++++++++++++++++++++++++++++++- 1 file changed, 210 insertions(+), 2 deletions(-) diff --git a/documentation/src/utassert.html b/documentation/src/utassert.html index 0228b453f..5ccee38c4 100644 --- a/documentation/src/utassert.html +++ b/documentation/src/utassert.html @@ -71,7 +71,15 @@

    utAssert Package

    utAssert.objnotexists Check for existence of database objects - + + utAssert.eq_refc_query + Check Equality of RefCursor and Query + + + utAssert.eq_refc_table + Check Equality of RefCursor and Database Table + + The utAssert package provides a set of assertion routines ("assert that the following condition is true") that you will use to register the outcome @@ -675,6 +683,206 @@

    Check for Existence of Database Objects

    So passing 'ANOTHER.THATTHING' will check for the existence of the THATTHING object in the ANOTHER schema.

    +

    Check Equality of RefCursor and Query

    + If you have a procedure or function that returns a REF CURSOR type you often would like to compare the data of the REF CURSOR against a query (if your REF CURSOR returns a complete table you can use utAssert.eq_refc_table below). In this case, you specify the REF CURSOR of the procedure or function and the full SELECT statement as parameters. By using eq_refc_query, you may be able to avoid the huge workload of constructing separate tables with preset data. + +

    Before calling the comparison you have to specifiy the parameters of the procedure or function you are going to use. +This is done with the procedures utPLSQL_Util.reg_In_Param, utPLSQL_Util.reg_InOut_Param or utPLSQL_Util.reg_Out_Param. +The details of the parameters are built up in a variable of type utplsql_util.utplsql_params, which is then passed into eq_refc_query. + +

    +PROCEDURE utPLSQL_Util.reg_In_Param (
    +   par_pos            PLS_INTEGER,
    +   par_val            VARCHAR2 | NUMBER | DATE,
    +   params    IN OUT   utplsql_util.utplsql_params );
    +
    +PROCEDURE utPLSQL_Util.reg_InOut_Param (
    +   par_pos            PLS_INTEGER,
    +   par_val            VARCHAR2 | NUMBER | DATE,
    +   params    IN OUT   utplsql_util.utplsql_params );
    +
    +PROCEDURE utPLSQL_Util.reg_Out_Param (
    +   par_pos            PLS_INTEGER,
    +   par_type           VARCHAR2,
    +   params    IN OUT   utplsql_util.utplsql_params );
    +
    + +

    Having specified all the parameters for the procedure or function returning the REF CURSOR, the comparison can be started. + +

    +PROCEDURE utAssert.eq_refc_query (
    +   p_msg_nm          IN   VARCHAR2,
    +   proc_name         IN   VARCHAR2,
    +   params            IN   utplsql_util.utplsql_params,
    +   cursor_position   IN   PLS_INTEGER,
    +   qry               IN   VARCHAR2 );
    +
    + + where the reg_In_Param, reg_InOut_Param and reg_Out_Param-specific parameters are as follows: + + + + + + + + + + + + + + + + + + + +
    ParameterDescription
    par_pos Defines the parameter position beginning with 1, or 0 specifying the return value +
    par_type Specifies the data type of the return value and must be one out of 'NUMBER', 'VARCHAR', 'CHAR' or 'REFCURSOR' +
    params The local variable to keep the values that is used as a parameter for eq_refc_query +
    + +

    and the eq_refc_query-specific parameters are as follows: + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ParameterDescription
    p_msg_nm The message to be displayed if the test fails +
    proc_name Specifies the procedure or function that delivers the REF CURSOR +
    params The parameter setting for the procedure or function +
    cursor_position Position of the REF CURSOR parameter to be checked, beginning with 1, or 0 to specify the return value of a function +
    qry The SELECT statement to be checked against +
    + +

    Finally, note that only the record itself is compared. These assertions do not care about how the records within the cursor are numbered.

    + + +

    Check Equality of RefCursor and Database Table

    + + If you have a procedure or function that returns a REF CURSOR type that represents a complete table or view you + often would like to compare the data of this REF CURSOR against the table or view + (if your REF CURSOR doesn't return a complete table or view you can use utAssert.eq_refc_query above). + In this case, you specify the REF CURSOR of the procedure or function and the table or view name as parameters. + By using eq_refc_table, you may be able to avoid the huge workload of constructing separate tables with preset data. + +

    Before calling the comparison you have to specifiy the parameters of the procedure or function you are going to use. +This is done with the procedures utPLSQL_Util.reg_In_Param, utPLSQL_Util.reg_InOut_Param or utPLSQL_Util.reg_Out_Param. +The details of the parameters are built up in a variable of type utplsql_util.utplsql_params, which is then passed into eq_refc_query. + +

    +PROCEDURE utPLSQL_Util.reg_In_Param (
    +   par_pos            PLS_INTEGER,
    +   par_val            VARCHAR2 | NUMBER | DATE,
    +   params    IN OUT   utplsql_util.utplsql_params );
    +
    +PROCEDURE utPLSQL_Util.reg_InOut_Param (
    +   par_pos            PLS_INTEGER,
    +   par_val            VARCHAR2 | NUMBER | DATE,
    +   params    IN OUT   utplsql_util.utplsql_params );
    +
    +PROCEDURE utPLSQL_Util.reg_Out_Param (
    +   par_pos            PLS_INTEGER,
    +   par_type           VARCHAR2,
    +   params    IN OUT   utplsql_util.utplsql_params );
    +
    + +

    Having specified all the parameters for the procedure or function returning the REF CURSOR, the comparison can be started. + +

    +PROCEDURE utAssert.eq_refc_table (
    +   p_msg_nm          IN   VARCHAR2,
    +   proc_name         IN   VARCHAR2,
    +   params            IN   utplsql_util.utplsql_params,
    +   cursor_position   IN   PLS_INTEGER,
    +   table_name        IN   VARCHAR2 );
    +
    + + where the reg_In_Param, reg_InOut_Param and reg_Out_Param-specific parameters are as follows: + + + + + + + + + + + + + + + + + + + +
    ParameterDescription
    par_pos Defines the parameter position beginning with 1, or 0 specifying the return value +
    par_type Specifies the data type of the return value and must be one out of 'NUMBER', 'VARCHAR', 'CHAR' or 'REFCURSOR' +
    params The local variable to keep the values that is used as a parameter for eq_refc_query +
    + +

    and the eq_refc_query-specific parameters are as follows: + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ParameterDescription
    p_msg_nm The message to be displayed if the test fails +
    proc_name Specifies the procedure or function that delivers the REF CURSOR +
    params The parameter setting for the procedure or function +
    cursor_position Position of the REF CURSOR parameter to be checked, beginning with 1, or 0 to specify the return value of a function +
    table_name The name of the table name or view to be checked against +
    + +

    Finally, note that only the record itself is compared. These assertions do not care about how the records within the cursor are numbered.

    +

    Building Your Own Assertion

    You may want to build assertion routines that fit your specific needs. If PL/SQL supported inheritance, you could extend the utAssert assertion @@ -688,7 +896,7 @@

    Building Your Own Assertion

             -- Show the results of the test more recently run.
    utresult.showlast;
    END IF;

    IF raise_exc_in
    THEN
    RAISE test_failure;
    END IF;
    END IF;
    END;
    The most important statement to include in your assertion routine is the call to utResult.report, which will log the results of the test. - + From 0a169f721c8eb0bcc0d647d3d6757856c8fe3526 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 23 Dec 2003 15:30:54 +0000 Subject: [PATCH 072/143] Added Jens Schauder's show_suites procedure --- source/ut_suite.pkb | 28 ++++++++++++++++++++++++++++ source/ut_suite.pks | 8 ++++++++ 2 files changed, 36 insertions(+) diff --git a/source/ut_suite.pkb b/source/ut_suite.pkb index 1260ecd10..3cfa944f3 100644 --- a/source/ut_suite.pkb +++ b/source/ut_suite.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ FUNCTION name_from_id (id_in IN ut_suite.id%TYPE) @@ -238,5 +241,30 @@ $Log$ THEN RETURN retval; END; + + --Simply write out the results of the above to dbms_output + PROCEDURE show_suites (name_like_in IN VARCHAR2 := '%') + IS + indent VARCHAR2(20) := ' '; + suites_cur utconfig.refcur_t; + suite ut_suite%ROWTYPE; + + CURSOR packages_cur (pi_id ut_suite.id%TYPE) IS + SELECT * FROM ut_package + WHERE suite_id = pi_id; + + BEGIN + suites_cur := suites(name_like_in); + + LOOP + FETCH suites_cur INTO suite; + EXIT WHEN suites_cur%NOTFOUND; + dbms_output.put_line(suite.name); + FOR pack IN packages_cur(suite.id) LOOP + dbms_output.put_line(indent || pack.name); + END LOOP; + END LOOP; + END show_suites; + END utsuite; / diff --git a/source/ut_suite.pks b/source/ut_suite.pks index e3564f980..7fc711c7e 100644 --- a/source/ut_suite.pks +++ b/source/ut_suite.pks @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ /* Test suite API */ @@ -68,9 +71,14 @@ $Log$ per_method_setup_in in ut_suite.per_method_setup%type := null ); + --Get a ref cursor returning suite details FUNCTION suites ( name_like_in IN VARCHAR2 := '%' ) RETURN utconfig.refcur_t; + + --Simply write out the results of the above to dbms_output + PROCEDURE show_suites (name_like_in IN VARCHAR2 := '%'); + END utsuite; / From 794fcaf7e4c72e1c9a47110db96200335a3f9973 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 14 Jan 2004 16:48:22 +0000 Subject: [PATCH 073/143] Added Jens Scahauder's documentation on run and runsuite --- documentation/src/utplsql.html | 155 +++++++++++++++++++++++++++++++-- 1 file changed, 149 insertions(+), 6 deletions(-) diff --git a/documentation/src/utplsql.html b/documentation/src/utplsql.html index 20e816950..b6b2cc131 100644 --- a/documentation/src/utplsql.html +++ b/documentation/src/utplsql.html @@ -10,7 +10,8 @@

    utPLSQL Package

    + + + + +
    -

    utPLSQL.test

    +

    utPLSQL.test
    + utPLSQL.run

    Run a test

    @@ -18,7 +19,8 @@

    utPLSQL Package

    -

    utPLSQL.testsuite

    +

    utPLSQL.testsuite
    + utPLSQL.runsuite

    Run a test suite

    @@ -82,8 +84,8 @@

    Run a Test or Test Suite

    where the parameters are defined as follows:

    - - +
    + @@ -193,7 +195,19 @@

    Run a Test or Test Suite

    execution as a whole.

    -

    package_in

    + +
    +

    override_package_in

    +
    +

    Override the automatic determination of package names thus removing the + one to one relationship between test package and package to test. + Default is NULL. Instead of using this parameter consider the procedure run.

    +

    Here are some examples of using the utPLSQL.test procedure:

    @@ -225,7 +239,116 @@

    Run a Test or Test Suite

    FAILURE: "betwnstr"
     BETWNSTR: IS NULL: NULL start
    -BETWNSTR: End larger than string length; expected "cdeg", got "cdefg"
    +BETWNSTR: End larger than string length; expected "cdeg", got "cdefg"

    Reporting Bugs and Enhancement Requests

    + + +

    Running a Test the other way

    + +

    The normal usage of the test procedure as described above assumes that for +each package you want to test, say mypackage, has a package for +testing this package having the same name but with an additional prefix: +ut_mypackage. Instead of using this approach, you can use the procedure +run. This procedure runs a test package directly without any further +conditions on the name or other packages. The only condition that still applies +is the naming conventions necessary to make it a valid test package. +

    +
    +PROCEDURE run (
    +    testpackage_in      IN VARCHAR2,
    +    prefix_in           IN VARCHAR2 := NULL,
    +    suite_in            IN VARCHAR2 := NULL,
    +    owner_in            IN VARCHAR2 := NULL,
    +    reset_results_in    IN BOOLEAN  := TRUE,
    +    from_suite_in       IN BOOLEAN  := FALSE,
    +    subprogram_in       IN VARCHAR2 := '%',
    +    per_method_setup_id IN BOOLEAN  := FALSE);
    +
    + +

    where the parameters are defined as follows:
    +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    test_package_in

    +
    +

    The name of the test package to run.

    +
    +

    prefix_in

    +
    +

    The prefix to be appended to package_in to come up with + the name of the test package. If you do not provide a value, NULL is used as + a default. i.e. the package name is used as provided in the first parameter

    +
    +

    suite_in

    +
    +

    The name of the suite that contains the specified test + package. This is an optional value and is used to update statistics + for the test.

    +
    +

    owner_in

    +
    +

    The name of the schema that was specified when the test + suite was defined and the packaged added to the suite. This is an + optional value and is used to update statistics for + the test.

    +
    +

    reset_results_in

    +
    +

    Pass FALSE to tell utPLSQL to not reset the results + information, in which case you will still be able to view results by calling utResult.show . Otherwise, utPLSQL clears the result + data after each test.

    +
    +

    from_suite_in

    +
    +

    Pass TRUE to tell utPLSQL that this test is being run from + within a test suite (for internal use only).

    +
    +

    subprogram_in

    +
    +

    Pass a string to restrict which of the test procedures + will be executed for this run. Default of '%' means all tests will be run.

    +
    +

    per_method_setup_in

    +
    +

    Pass TRUE to run the setup and teardown procedure before + and after each unit test procedure is executed. Default of FALSE means that + these programs will be run once, at the start and end of the package test + execution as a whole.

    +
    + +

    Running a Test Suite

    @@ -257,6 +380,26 @@

    Running a Test Suite

    Before you can test an entire suite, you must define the suite.

    + +

    Running a Test Suite the other way

    + +

    Similiar to the run procedure for single packages, there is the +runsuite procedure to run testsuites. When you use this procedure +there is no relationship assumed between the names of test packages specified in the +test suite and the procedures to be tested. +

    + +
    PROCEDURE utPLSQL.runsuite (
    +   suite_in IN VARCHAR2,
    +   reset_results_in IN BOOLEAN := TRUE
    +   per_method_setup_in in BOOLEAN := FALSE
    +   );
    + +

    +The usage of the parameters is just as in testsuite. +

    + +

    Recording and Accessing Test Statistics

    If you have defined test suites, and packages within those From a5dcbaf1ef574138847a166692e296b03bead7cd Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 11 May 2004 15:33:57 +0000 Subject: [PATCH 074/143] Added 9.2 specific code from Mark Vilrokx --- source/ut_gen.pkb | 69 +++++++++++++++------ source/ut_i_do.sql | 16 +++++ source/ut_plsql.pkb | 145 ++++++++++++++++++++++++++------------------ 3 files changed, 151 insertions(+), 79 deletions(-) diff --git a/source/ut_gen.pkb b/source/ut_gen.pkb index b6b78efd2..cdd2b284f 100644 --- a/source/ut_gen.pkb +++ b/source/ut_gen.pkb @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:46 chrisrimmer +Added Standard Headers + ************************************************************************/ g_pkgstring VARCHAR2 (32767); @@ -172,7 +175,7 @@ $Log$ delim_in IN VARCHAR2 := c_delim, date_format_in IN VARCHAR2 := 'MM/DD/YYYY', only_if_in_grid_in IN BOOLEAN := FALSE, - override_file_in IN VARCHAR2 := NULL + override_file_in IN VARCHAR2 := NULL ) IS fid UTL_FILE.file_type; @@ -186,7 +189,7 @@ $Log$ l_grid grid_tt; CURSOR prog_cur (package_in IN VARCHAR2, program_in IN VARCHAR2) - IS + IS &startnot92 SELECT DISTINCT owner, package_name, object_name, overload, object_name || overload full_name @@ -203,6 +206,34 @@ $Log$ AND package_in IS NULL AND object_name = UPPER (program_in) ); + &endnot92 + &start92 + SELECT owner, object_name package_name, procedure_name object_name, + DECODE ( + ROW_NUMBER () OVER (PARTITION BY procedure_name ORDER BY object_name), + 1, NULL, + ROW_NUMBER () OVER (PARTITION BY procedure_name ORDER BY object_name) + ) overload, + procedure_name + || DECODE ( + ROW_NUMBER () OVER (PARTITION BY procedure_name ORDER BY object_name), + 1, NULL, + ROW_NUMBER () OVER (PARTITION BY procedure_name ORDER BY object_name) + ) full_name + FROM all_procedures + WHERE owner = NVL (UPPER (schema_in), USER) + AND ( object_name = UPPER (package_in) + AND procedure_name LIKE + NVL (UPPER (program_in), '%') + ) + OR ( ( object_name IS NULL + -- 2.0.9.1 9i changes way package_name is set. + OR object_name = UPPER (program_in) + ) + AND package_in IS NULL + AND procedure_name = UPPER (program_in) + ); + &end92 CURSOR arg_cur ( schema_in IN VARCHAR2, @@ -256,7 +287,7 @@ $Log$ fid := UTL_FILE.fopen ( v_dir, - NVL (override_file_in, + NVL (override_file_in, NVL (prefix_in, utconfig.prefix (schema_in)) || package_in || '.' @@ -837,7 +868,7 @@ $Log$ schema_in IN VARCHAR2 := NULL, output_type_in IN PLS_INTEGER := c_screen, dir_in IN VARCHAR2 := NULL, - override_file_in IN VARCHAR2 := NULL + override_file_in IN VARCHAR2 := NULL ) IS l_grid grid_tt; @@ -853,7 +884,7 @@ $Log$ output_type_in, dir_in, only_if_in_grid_in => FALSE, - override_file_in => override_file_in + override_file_in => override_file_in ); END; @@ -878,7 +909,7 @@ $Log$ arg_delim_in IN VARCHAR2 := c_delim, date_format_in IN VARCHAR2 := 'MM/DD/YYYY', only_if_in_grid_in IN BOOLEAN := FALSE, - override_file_in IN VARCHAR2 := NULL + override_file_in IN VARCHAR2 := NULL ) IS c_progname VARCHAR2 (30) := 'testpkg_from_file'; @@ -923,7 +954,7 @@ $Log$ arg_delim_in, date_format_in, only_if_in_grid_in, - override_file_in => override_file_in + override_file_in => override_file_in ); EXCEPTION WHEN UTL_FILE.invalid_path @@ -966,7 +997,7 @@ $Log$ arg_delim_in IN VARCHAR2 := c_delim, date_format_in IN VARCHAR2 := 'MM/DD/YYYY', only_if_in_grid_in IN BOOLEAN := FALSE, - override_file_in IN VARCHAR2 := NULL + override_file_in IN VARCHAR2 := NULL ) IS c_progname VARCHAR2 (30) := 'testpkg_from_string'; @@ -1008,7 +1039,7 @@ $Log$ arg_delim_in, date_format_in, only_if_in_grid_in, - override_file_in => override_file_in + override_file_in => override_file_in ); END IF; END; @@ -1017,7 +1048,7 @@ $Log$ package_in IN VARCHAR2, grid_in IN VARCHAR2, dir_in IN VARCHAR2 := NULL, - override_file_in IN VARCHAR2 := NULL + override_file_in IN VARCHAR2 := NULL ) IS BEGIN @@ -1027,23 +1058,23 @@ $Log$ output_type_in => c_file, dir_in => dir_in, only_if_in_grid_in => TRUE, - override_file_in => override_file_in + override_file_in => override_file_in ); END; PROCEDURE clear_grid ( owner_in IN ut_grid.owner%TYPE - ,package_in IN ut_grid.PACKAGE%TYPE) + ,package_in IN ut_grid.PACKAGE%TYPE) IS BEGIN delete from ut_grid WHERE ut_grid.owner = UPPER (owner_in) - AND ut_grid.PACKAGE = UPPER (package_in); - + AND ut_grid.PACKAGE = UPPER (package_in); + END; PROCEDURE add_to_grid ( owner_in IN ut_grid.owner%TYPE - ,package_in IN ut_grid.PACKAGE%TYPE + ,package_in IN ut_grid.PACKAGE%TYPE ,progname_in IN ut_grid.progname%TYPE ,overload_in IN ut_grid.overload%TYPE ,tcname_in IN ut_grid.tcname%TYPE @@ -1074,18 +1105,18 @@ $Log$ output_type_in IN PLS_INTEGER := c_screen, dir_in IN VARCHAR2 := NULL, date_format_in IN VARCHAR2 := 'MM/DD/YYYY', - override_file_in IN VARCHAR2 := NULL + override_file_in IN VARCHAR2 := NULL ) IS CURSOR c_ut_grid (p_package VARCHAR2, p_owner VARCHAR2) IS SELECT ut_grid.owner, - ut_grid.progname, ut_grid.overload, ut_grid.tcname, + ut_grid.progname, ut_grid.overload, ut_grid.tcname, ut_grid.MESSAGE, ut_grid.arglist, ut_grid.return_value, ut_grid.assertion_type FROM ut_grid WHERE ut_grid.owner = UPPER (p_owner) - AND ut_grid.PACKAGE = UPPER (p_package) + AND ut_grid.PACKAGE = UPPER (p_package) ORDER BY ut_grid.progname; lv_grid utgen.grid_tt; @@ -1137,7 +1168,7 @@ $Log$ , output_type_in => output_type_in , dir_in => dir_in , date_format_in => date_format_in - , override_file_in => override_file_in + , override_file_in => override_file_in ); END IF; -- lv_index > -1 diff --git a/source/ut_i_do.sql b/source/ut_i_do.sql index 4ea94e755..96d5157e1 100644 --- a/source/ut_i_do.sql +++ b/source/ut_i_do.sql @@ -65,6 +65,22 @@ SELECT DECODE (upper('&v_orcl_vers'), 'Ignore 9i code */') col FROM dual; +COLUMN col NOPRINT NEW_VALUE startnot92 +SELECT DECODE (UPPER('&v_orcl_vers'), + '8.1', '/* Use Non 9i code! */', + '9.0', '/* Use Non 9i code! */', + '9.1', '/* Use Non 9i code! */', + '/* Ignore Non 9i code') col + FROM dual; + +COLUMN col NOPRINT NEW_VALUE endnot92 +SELECT DECODE (UPPER('&v_orcl_vers'), + '8.1', '/* Use Non 9i code! */', + '9.0', '/* Use Non 9i code! */', + '9.1', '/* Use Non 9i code! */', + 'Ignore Non 9i code */') col + FROM dual; + COLUMN col NOPRINT NEW_VALUE start81 SELECT DECODE (UPPER('&v_orcl_vers'), '8.1', '/* Use 8i code! */', diff --git a/source/ut_plsql.pkb b/source/ut_plsql.pkb index c837e0b1b..547270940 100644 --- a/source/ut_plsql.pkb +++ b/source/ut_plsql.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ g_trc BOOLEAN := FALSE; @@ -63,19 +66,19 @@ $Log$ fid IN OUT UTL_FILE.FILE_TYPE ) IS - v VARCHAR2(10) := '-- TEST --'; - c_endcmd VARCHAR2(13) := '-- TESTEND --'; + v VARCHAR2(10) := '-- TEST --'; + c_endcmd VARCHAR2(13) := '-- TESTEND --'; dir ut_config.directory%TYPE; - file_dir ut_config.filedir%TYPE; + file_dir ut_config.filedir%TYPE; file_out ut_config.fileout%TYPE; userprefix ut_config.fileuserprefix%TYPE; incprog ut_config.fileincprogname%TYPE; date_formt ut_config.filedateformat%TYPE; - extension ut_config.fileextension%TYPE; - - progname VARCHAR2(35); + extension ut_config.fileextension%TYPE; + + progname VARCHAR2(35); no_dir EXCEPTION; @@ -91,9 +94,9 @@ $Log$ -- open file if not already open -- and write header record IF NOT UTL_FILE.is_open(fid) THEN - - -- Get the output file directory - file_dir := utConfig.filedir (); + + -- Get the output file directory + file_dir := utConfig.filedir (); -- check if NULL IF file_dir IS NULL THEN -- try directory @@ -103,32 +106,32 @@ $Log$ -- redirect output to DBMS_OUTPUT set_pl_to_file (FALSE); raise no_dir; - END IF; + END IF; END IF; - -- Get the userprefix from config - userprefix := utConfig.userprefix(); - IF userprefix IS NULL THEN - -- use the current user if userprefix IS NULL - userprefix := USER; + -- Get the userprefix from config + userprefix := utConfig.userprefix(); + IF userprefix IS NULL THEN + -- use the current user if userprefix IS NULL + userprefix := USER; END IF; - userprefix := userprefix ||'_'; + userprefix := userprefix ||'_'; -- include progname in filename ? - progname := NULL; - IF utConfig.includeprogname() THEN - progname := v_in|| '_'; - END IF; + progname := NULL; + IF utConfig.includeprogname() THEN + progname := v_in|| '_'; + END IF; - -- get the date format - date_formt := utConfig.dateformat; - - -- get the file extension - extension := utConfig.fileextension(); - - fid := UTL_FILE.FOPEN (file_dir, userprefix||progname|| - to_char(sysdate,date_formt)||extension, 'A'); - UTL_FILE.PUT_LINE (fid, '-- '||to_char(sysdate,date_formt)); + -- get the date format + date_formt := utConfig.dateformat; + + -- get the file extension + extension := utConfig.fileextension(); + + fid := UTL_FILE.FOPEN (file_dir, userprefix||progname|| + to_char(sysdate,date_formt)||extension, 'A'); + UTL_FILE.PUT_LINE (fid, '-- '||to_char(sysdate,date_formt)); UTL_FILE.PUT_LINE (fid, v); END IF; @@ -139,9 +142,9 @@ $Log$ -- '-- TESTEND --' gets written to file as well IF v_in = c_endcmd AND UTL_FILE.is_open(fid) THEN -- get the date format - date_formt := utConfig.dateformat; + date_formt := utConfig.dateformat; UTL_FILE.PUT_LINE (fid, '-- '||to_char(sysdate,date_formt)); - UTL_FILE.FCLOSE (fid); + UTL_FILE.FCLOSE (fid); END IF; EXCEPTION @@ -204,7 +207,7 @@ $Log$ THEN DBMS_OUTPUT.put_line (s); -- 2.1.2 PBA we should return here... - RETURN; + RETURN; -- Simple case: s is short. ELSIF LENGTH (s) <= maxlinelen THEN @@ -255,14 +258,14 @@ $Log$ ) IS BEGIN - -- RMM start + -- RMM start IF get_pl_to_file THEN - pl_to_file(str,g_fid); - ELSIF NOT get_pl_to_file - -- RMM end - THEN + pl_to_file(str,g_fid); + ELSIF NOT get_pl_to_file + -- RMM end + THEN show (str, len, expand_in); - END IF; + END IF; END; FUNCTION vc2bool (vc IN VARCHAR2) @@ -346,7 +349,7 @@ $Log$ /* Begin changes to check if v_prog is an object */ DECLARE block VARCHAR2(100) := - 'DECLARE obj ' || v_prog || '; BEGIN NULL; END;'; + 'DECLARE obj ' || v_prog || '; BEGIN NULL; END;'; &start73 cur PLS_INTEGER := DBMS_SQL.open_cursor; fdbk PLS_INTEGER; @@ -465,8 +468,8 @@ $Log$ IF owner_in IS NOT NULL THEN - -- 2.0.10.2: embed owner_in in double quotes to support - -- OS authentication + -- 2.0.10.2: embed owner_in in double quotes to support + -- OS authentication retval := '"' || owner_in || '"' --retval := owner_in || '.' @@ -722,7 +725,7 @@ $Log$ END IF; utresult.init (from_suite_in); - + -- 2.0.1 compatibilty with utPLSQL2 utplsql2.set_runnum; @@ -815,11 +818,11 @@ $Log$ END LOOP; UTL_FILE.fclose (fid); - - if tracing then - pl ('Compiling ' || lines (lines.first)); - end if; - + + if tracing then + pl ('Compiling ' || lines (lines.first)); + end if; + DBMS_SQL.parse ( cur, lines, @@ -916,7 +919,7 @@ $Log$ END; - IF tracing + IF tracing THEN pl ( 'Setpkg to ' || testpkg.pkg); @@ -962,7 +965,8 @@ $Log$ THEN -- Populate test information from ALL_ARGUMENTS FOR rec IN - (SELECT DISTINCT object_name + &startnot92 + (SELECT DISTINCT object_name procedure_name FROM all_arguments WHERE owner = NVL ( @@ -993,10 +997,31 @@ $Log$ || c_teardown ) )) + &endnot92 + &start92 + (SELECT procedure_name + FROM all_procedures + WHERE owner = NVL (UPPER (owner_in), USER) + AND object_name = UPPER (v_pkg) + AND procedure_name LIKE UPPER (prefix_in) + || '%' + AND procedure_name LIKE + UPPER ( prefix_in + || subprogram_in) + AND procedure_name NOT IN (UPPER ( + prefix_in + || c_setup + ), + UPPER ( + prefix_in + || c_teardown + ) + )) + &end92 LOOP addtest ( testpkg_in.pkg, - rec.object_name, + rec.procedure_name, prefix_in, iterations_in=> 1, override_in=> TRUE @@ -1109,8 +1134,8 @@ $Log$ IS indx PLS_INTEGER; v_pkg VARCHAR2 (100); - -- 2.0.10.1: use dir in config - v_dir maxvc2_t := NVL (dir_in, utconfig.dir); + -- 2.0.10.1: use dir in config + v_dir maxvc2_t := NVL (dir_in, utconfig.dir); v_start DATE := SYSDATE; v_prefix ut_config.prefix%TYPE := NVL (prefix_in, utconfig.prefix (owner_in)); @@ -1154,20 +1179,20 @@ $Log$ IF suite_in IS NULL AND get_pl_to_file THEN pl('-- TESTEND --'); END IF; - -- RMM end + -- RMM end END; BEGIN init (v_prefix, v_dir, from_suite_in); -- RMM start g_pl_to_file := utConfig.getfile(); IF g_pl_to_file THEN - IF suite_in IS NOT NULL THEN - -- we run a test suite + IF suite_in IS NOT NULL THEN + -- we run a test suite pl(suite_in); - ELSE + ELSE -- we run a single package test - pl(package_in); - END IF; + pl(package_in); + END IF; END IF; -- RMM end @@ -1212,7 +1237,7 @@ $Log$ END IF; utreceq.COMPILE (package_in); - + COMPILE ( -- 2.0.9.1 Package name without OWNER -- 2.0.9.2 Switch to use of record based info. @@ -1376,7 +1401,7 @@ begin IF get_pl_to_file THEN pl('-- TESTEND --'); END IF; - -- RMM end + -- RMM end END; From d5fed4fbefddfdf8ee71f68101ab3e1f6ffb0255 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 11 May 2004 15:36:58 +0000 Subject: [PATCH 075/143] Added tweak to cursor from Steven F --- source/ut_gen.pkb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/ut_gen.pkb b/source/ut_gen.pkb index cdd2b284f..f656d9e1a 100644 --- a/source/ut_gen.pkb +++ b/source/ut_gen.pkb @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2004/05/11 15:33:56 chrisrimmer +Added 9.2 specific code from Mark Vilrokx + Revision 1.2 2003/07/01 19:36:46 chrisrimmer Added Standard Headers @@ -1115,7 +1118,7 @@ Added Standard Headers ut_grid.MESSAGE, ut_grid.arglist, ut_grid.return_value, ut_grid.assertion_type FROM ut_grid - WHERE ut_grid.owner = UPPER (p_owner) + WHERE NVL(ut_grid.owner, USER) = UPPER (p_owner) AND ut_grid.PACKAGE = UPPER (p_package) ORDER BY ut_grid.progname; From 390f00cff0815b5c42a84ae1780028d1b5e94ae2 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 14 Jul 2004 17:01:57 +0000 Subject: [PATCH 076/143] Added first version of pluggable reporter packages --- source/ut_assert.pkb | 5 +- source/ut_assert2.pkb | 35 ++-- source/ut_config.pkb | 98 +++++----- source/ut_config.pks | 63 +++---- source/ut_config.tab | 25 +-- source/ut_filereporter.pkb | 189 +++++++++++++++++++ source/ut_filereporter.pks | 39 ++++ source/ut_gen.pkb | 11 +- source/ut_htmlreporter.pkb | 143 +++++++++++++++ source/ut_htmlreporter.pks | 44 +++++ source/ut_i_packages.sql | 5 + source/ut_i_packages_b.sql | 5 + source/ut_i_uninstall.sql | 13 ++ source/ut_outputreporter.pkb | 281 ++++++++++++++++++++++++++++ source/ut_outputreporter.pks | 44 +++++ source/ut_package.pkb | 13 +- source/ut_plsql.pkb | 344 +++++------------------------------ source/ut_plsql.pks | 22 +-- source/ut_plsql2.pkb | 11 +- source/ut_receq.pkb | 19 +- source/ut_report.pkb | 203 +++++++++++++++++++++ source/ut_report.pks | 52 ++++++ source/ut_rerror.pkb | 5 +- source/ut_rerror.pks | 3 + source/ut_result.pkb | 157 ++-------------- source/ut_result.pks | 9 +- source/ut_result2.pkb | 17 +- source/ut_suite.pkb | 7 +- source/ut_suiteutp.pkb | 5 +- source/ut_test.pkb | 9 +- source/ut_testcase.pkb | 9 +- 31 files changed, 1275 insertions(+), 610 deletions(-) create mode 100644 source/ut_filereporter.pkb create mode 100644 source/ut_filereporter.pks create mode 100644 source/ut_htmlreporter.pkb create mode 100644 source/ut_htmlreporter.pks create mode 100644 source/ut_outputreporter.pkb create mode 100644 source/ut_outputreporter.pks create mode 100644 source/ut_report.pkb create mode 100644 source/ut_report.pks diff --git a/source/ut_assert.pkb b/source/ut_assert.pkb index 5436301d2..7a4ad9634 100644 --- a/source/ut_assert.pkb +++ b/source/ut_assert.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:46 chrisrimmer +Added Standard Headers + ************************************************************************/ g_showresults BOOLEAN := FALSE; @@ -314,7 +317,7 @@ $Log$ -- which have been defined dynamically? IS BEGIN - utplsql.pl ('utAssert.eqCursor is not yet implemented!'); + utreport.pl ('utAssert.eqCursor is not yet implemented!'); END; PROCEDURE eqfile ( diff --git a/source/ut_assert2.pkb b/source/ut_assert2.pkb index ac7d3ae48..51aa561ee 100644 --- a/source/ut_assert2.pkb +++ b/source/ut_assert2.pkb @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2003/07/11 14:32:52 chrisrimmer +Added 'throws' bugfix from Ivan Desjardins + Revision 1.2 2003/07/01 19:36:46 chrisrimmer Added Standard Headers @@ -134,12 +137,12 @@ Added Standard Headers IF utplsql2.tracing THEN - utplsql.pl ( + utreport.pl ( 'utPLSQL TRACE on Assert: ' || msg_in ); - utplsql.pl ('Results:'); - utplsql.bpl (l_failure); + utreport.pl ('Results:'); + utreport.pl (l_failure); END IF; -- Report results failure and success @@ -278,7 +281,7 @@ Added Standard Headers THEN IF utplsql2.tracing THEN - utplsql.pl ( + utreport.pl ( 'Outcome ' || outcome_in || ' is not defined.' @@ -320,7 +323,7 @@ Added Standard Headers IF utplsql2.tracing THEN -- Optional trace of assertion call. - --utplsql.pl (); + --utreport.pl (); NULL; END IF; @@ -490,7 +493,7 @@ Added Standard Headers IF utplsql2.tracing THEN -- Optional trace of assertion call. - utplsql.pl (); + utreport.pl (); END IF; this ( @@ -531,7 +534,7 @@ Added Standard Headers BEGIN IF utplsql2.tracing THEN - utplsql.pl ( + utreport.pl ( 'EQ Compare "' || check_this_in || '" to "' @@ -590,7 +593,7 @@ Added Standard Headers BEGIN IF utplsql2.tracing THEN - utplsql.pl ( + utreport.pl ( 'Compare "' || b2v (check_this_in) || '" to "' @@ -652,7 +655,7 @@ Added Standard Headers IF utplsql2.tracing THEN - utplsql.pl ( + utreport.pl ( 'Compare "' || v_check || '" to "' @@ -1006,7 +1009,7 @@ UNION BEGIN IF utplsql2.tracing THEN - utplsql.pl ( + utreport.pl ( 'V EQQueryValue Compare "' || check_query_in || '" to "' @@ -1098,7 +1101,7 @@ UNION BEGIN IF utplsql2.tracing THEN - utplsql.pl ( + utreport.pl ( 'D EQQueryValue Compare "' || check_query_in || '" to "' @@ -1199,7 +1202,7 @@ UNION BEGIN IF utplsql2.tracing THEN - utplsql.pl ( + utreport.pl ( 'N EQQueryValue Compare "' || check_query_in || '" to "' @@ -1280,7 +1283,7 @@ UNION -- which have been defined dynamically? IS BEGIN - utplsql.pl ( + utreport.pl ( 'utAssert.eqCursor is not yet implemented!' ); END; @@ -2977,7 +2980,7 @@ UNION -- which have been defined dynamically? IS BEGIN - utplsql.pl ( + utreport.pl ( 'utAssert.eqCursor is not yet implemented!' ); END; @@ -3401,7 +3404,7 @@ UNION IF utplsql2.tracing THEN -- Optional trace of assertion call. - utplsql.pl ( + utreport.pl ( 'verfying that the object "' || check_this_in || '"exists' @@ -3439,7 +3442,7 @@ UNION IF utplsql2.tracing THEN -- Optional trace of assertion call. - utplsql.pl ( + utreport.pl ( 'verifying that the object "' || check_this_in || '"does not exist' diff --git a/source/ut_config.pkb b/source/ut_config.pkb index f0e4a5506..f7a42bab6 100644 --- a/source/ut_config.pkb +++ b/source/ut_config.pkb @@ -1,4 +1,4 @@ -CREATE OR REPLACE PACKAGE BODY utconfig +CREATE OR REPLACE PACKAGE BODY Utconfig IS /************************************************************************ GNU General Public License for utPLSQL @@ -22,6 +22,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:46 chrisrimmer +Added Standard Headers + ************************************************************************/ ------------------------------------------------------------------------------- @@ -42,9 +45,9 @@ $Log$ -- Get the configuration record for a user from the table ---------------------------------------------------------------------------- FUNCTION config (username_in IN VARCHAR2 := USER) - RETURN ut_config%ROWTYPE + RETURN UT_CONFIG%ROWTYPE IS - rec ut_config%ROWTYPE; + rec UT_CONFIG%ROWTYPE; BEGIN --Short cut for current user IF username_in = tester @@ -84,7 +87,7 @@ $Log$ PROCEDURE do_dml (statement_in IN VARCHAR2) IS &start73 cursor_handle INTEGER; &end73 - &start73 rows INTEGER; &end73 + &start73 ROWS INTEGER; &end73 BEGIN --In 8i, just do it &start81 EXECUTE IMMEDIATE statement_in; COMMIT; &end81 @@ -92,17 +95,17 @@ $Log$ --Otherwise use DBMS_SQL &start73 --Open the cursor - cursor_handle := DBMS_SQL.open_cursor; + cursor_handle := DBMS_SQL.OPEN_CURSOR; -- Parse the Statement - DBMS_SQL.parse (cursor_handle, statement_in, DBMS_SQL.native); + DBMS_SQL.PARSE (cursor_handle, statement_in, DBMS_SQL.native); -- Execute the Statement ROWS := DBMS_SQL.EXECUTE (cursor_handle); -- Close the cursor - DBMS_SQL.close_cursor (cursor_handle); + DBMS_SQL.CLOSE_CURSOR (cursor_handle); EXCEPTION WHEN OTHERS THEN - DBMS_SQL.close_cursor (cursor_handle); + DBMS_SQL.CLOSE_CURSOR (cursor_handle); RAISE; &end73 END; @@ -135,7 +138,7 @@ $Log$ WHEN OTHERS THEN --Something else went wrong - utplsql.pl (SQLERRM); + UtOutputreporter.pl (SQLERRM); &start81 ROLLBACK; &end81 RETURN; END; @@ -185,23 +188,21 @@ $Log$ --Get the configuration rec := config (v_user); --Now show it - utplsql.pl ('=============================================================' - ); - utplsql.pl ('utPLSQL Configuration for ' || v_user); - utplsql.pl (' Directory: ' || rec.DIRECTORY); - utplsql.pl (' Autcompile? ' || rec.autocompile); - utplsql.pl (' Manual test registration? ' || rec.registertest); - utplsql.pl (' Prefix = ' || rec.prefix); - utplsql.pl (' ----- File Output settings:'); - utplsql.pl (' Output directory: ' || rec.filedir); - utplsql.pl (' Output flag = ' || rec.fileout); - utplsql.pl (' User prefix = ' || rec.fileuserprefix); - utplsql.pl (' Include progname? ' || rec.fileincprogname); - utplsql.pl (' Date format = ' || rec.filedateformat); - utplsql.pl (' File extension = ' || rec.fileextension); - utplsql.pl (' ----- End File Output settings'); - utplsql.pl ('=============================================================' - ); + utOutputReporter.pl ('============================================================='); + utOutputReporter.pl ('utPLSQL Configuration for ' || v_user); + utOutputReporter.pl (' Directory: ' || rec.DIRECTORY); + utOutputReporter.pl (' Autcompile? ' || rec.autocompile); + utOutputReporter.pl (' Manual test registration? ' || rec.registertest); + utOutputReporter.pl (' Prefix = ' || rec.prefix); + utOutputReporter.pl (' Default reporter = ' || rec.reporter); + utOutputReporter.pl (' ----- File Output settings:'); + utOutputReporter.pl (' Output directory: ' || rec.filedir); + utOutputReporter.pl (' User prefix = ' || rec.fileuserprefix); + utOutputReporter.pl (' Include progname? ' || rec.fileincprogname); + utOutputReporter.pl (' Date format = ' || rec.filedateformat); + utOutputReporter.pl (' File extension = ' || rec.fileextension); + utOutputReporter.pl (' ----- End File Output settings'); + utOutputReporter.pl ('============================================================='); END; ---------------------------------------------------------------------------- @@ -223,7 +224,7 @@ $Log$ RETURN VARCHAR2 IS --Holds the user's config record - rec ut_config%ROWTYPE; + rec UT_CONFIG%ROWTYPE; --Holds the username in question v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); BEGIN @@ -300,7 +301,7 @@ $Log$ PROCEDURE autocompile (onoff_in IN BOOLEAN, username_in IN VARCHAR2 := NULL) IS --Holds the flag as 'Y'/'N' - v_autocompile CHAR (1) := utplsql.bool2vc (onoff_in); + v_autocompile CHAR (1) := Utplsql.bool2vc (onoff_in); --Holds the user to set v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); BEGIN @@ -322,7 +323,7 @@ $Log$ --Pull in the configuration rec := config (v_user); --Return autocompile, defaulting to TRUE if NULL - RETURN NVL (utplsql.vc2bool (rec.autocompile), TRUE); + RETURN NVL (Utplsql.vc2bool (rec.autocompile), TRUE); END; ---------------------------------------------------------------------------- @@ -332,7 +333,7 @@ $Log$ := NULL) IS --Holds the flag as 'Y'/'N' - v_registertest CHAR (1) := utplsql.bool2vc (onoff_in); + v_registertest CHAR (1) := Utplsql.bool2vc (onoff_in); --Holds the username in question v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); BEGIN @@ -354,7 +355,7 @@ $Log$ --Pull in the configuration rec := config (v_user); --Return registertest, defaulting to FALSE if NULL - RETURN NVL (utplsql.vc2bool (rec.registertest), FALSE); + RETURN NVL (Utplsql.vc2bool (rec.registertest), FALSE); END; -- Show failures only? @@ -364,7 +365,7 @@ $Log$ ) IS --Holds the flag as 'Y'/'N' - v_showfailuresonly CHAR (1) := utplsql.bool2vc (onoff_in); + v_showfailuresonly CHAR (1) := Utplsql.bool2vc (onoff_in); --Holds the username in question v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); @@ -384,7 +385,7 @@ $Log$ --Pull in the configuration rec := config (v_user); --Return show_failures_only, defaulting to FALSE if NULL - RETURN NVL (utplsql.vc2bool (rec.show_failures_only), FALSE); + RETURN NVL (Utplsql.vc2bool (rec.show_failures_only), FALSE); END; -- RMM start @@ -421,27 +422,26 @@ $Log$ END; ---------------------------------------------------------------------------- --- Set the file output flag for a user +-- Set the default reporter for a user ---------------------------------------------------------------------------- - PROCEDURE setfile ( - fileout_in IN BOOLEAN := FALSE + PROCEDURE setreporter ( + reporter_in IN VARCHAR2 ,username_in IN VARCHAR2 := NULL ) IS - --Holds the flag as 'Y'/'N' - v_fileout CHAR (1) := utplsql.bool2vc (fileout_in); --Holds the user to set v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); BEGIN --Set the configuration - setconfig ('fileout', v_fileout, v_user); + setconfig ('reporter', reporter_in, v_user); + Utreport.USE(reporter_in); END; ---------------------------------------------------------------------------- --- Get the file output flag for a user +-- Get the default reporter for a user ---------------------------------------------------------------------------- - FUNCTION getfile (username_in IN VARCHAR2 := NULL) - RETURN BOOLEAN + FUNCTION getreporter (username_in IN VARCHAR2 := NULL) + RETURN VARCHAR2 IS --Holds the user's config record rec ut_config%ROWTYPE; @@ -451,7 +451,7 @@ $Log$ --Pull in the configuration rec := config (v_user); --Return autocompile, defaulting to TRUE if NULL - RETURN NVL (utplsql.vc2bool (rec.fileout), FALSE); + RETURN rec.reporter; END; ---------------------------------------------------------------------------- @@ -495,7 +495,7 @@ $Log$ ) IS --Holds the flag as 'Y'/'N' - v_incname CHAR (1) := utplsql.bool2vc (incname_in); + v_incname CHAR (1) := Utplsql.bool2vc (incname_in); --Holds the user to set v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); BEGIN @@ -517,7 +517,7 @@ $Log$ --Pull in the configuration rec := config (v_user); --Return autocompile, defaulting to TRUE if NULL - RETURN NVL (utplsql.vc2bool (rec.fileincprogname), FALSE); + RETURN NVL (Utplsql.vc2bool (rec.fileincprogname), FALSE); END; ---------------------------------------------------------------------------- @@ -588,8 +588,7 @@ $Log$ -- Set all of the file output columns for a user ---------------------------------------------------------------------------- PROCEDURE setfileinfo ( - fileout_in IN BOOLEAN := FALSE - ,dir_in IN VARCHAR2 := NULL + dir_in IN VARCHAR2 := NULL ,userprefix_in IN VARCHAR2 := NULL ,incname_in IN BOOLEAN := FALSE ,dateformat_in IN VARCHAR2 := 'yyyyddmmhh24miss' @@ -598,8 +597,6 @@ $Log$ ) IS BEGIN - NULL; - setfile (fileout_in, username_in); setfiledir (dir_in, username_in); setuserprefix (userprefix_in, username_in); setincludeprogname (incname_in, username_in); @@ -623,7 +620,6 @@ $Log$ --Pull in the configuration rec := config (v_user); --populate the record - fileinfo_rec.fileout := rec.fileout; fileinfo_rec.filedir := rec.filedir; fileinfo_rec.fileuserprefix := rec.fileuserprefix; fileinfo_rec.fileincprogname := rec.fileincprogname; @@ -687,7 +683,7 @@ $Log$ BEGIN OPEN retval FOR SELECT ao.owner, ao.object_name, ao.object_type, ao.created - ,ao.last_ddl_time, utrutp.last_run_status ( + ,ao.last_ddl_time, Utrutp.last_run_status ( ao.owner, ao.object_name) status FROM all_objects ao WHERE ao.owner = UPPER (schema_in) diff --git a/source/ut_config.pks b/source/ut_config.pks index 8d5f5a609..4424fc858 100644 --- a/source/ut_config.pks +++ b/source/ut_config.pks @@ -1,4 +1,4 @@ -CREATE OR REPLACE PACKAGE utconfig &start81 AUTHID CURRENT_USER &end81 +CREATE OR REPLACE PACKAGE Utconfig &start81 AUTHID CURRENT_USER &end81 IS /************************************************************************ @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2003/07/01 19:36:46 chrisrimmer +Added Standard Headers + ************************************************************************/ ------------------------------------------------------------------------------- @@ -42,12 +45,11 @@ $Log$ -- RMM start -- Record definition used by fileinfo function TYPE rec_fileinfo IS RECORD ( - fileout ut_config.fileout%TYPE - ,filedir ut_config.filedir%TYPE - ,fileuserprefix ut_config.fileuserprefix%TYPE - ,fileincprogname ut_config.fileincprogname%TYPE - ,filedateformat ut_config.filedateformat%TYPE - ,fileextension ut_config.filedateformat%TYPE + filedir UT_CONFIG.filedir%TYPE + ,fileuserprefix UT_CONFIG.fileuserprefix%TYPE + ,fileincprogname UT_CONFIG.fileincprogname%TYPE + ,filedateformat UT_CONFIG.filedateformat%TYPE + ,fileextension UT_CONFIG.filedateformat%TYPE ); -- RMM end @@ -59,7 +61,7 @@ $Log$ SELECT owner, object_name, object_type, created, last_ddl_time, status FROM all_objects; - cursor source_cur + CURSOR source_cur IS SELECT line, text FROM all_source; @@ -135,15 +137,15 @@ $Log$ FUNCTION filedir (username_in IN VARCHAR2 := NULL) RETURN VARCHAR2; - -- Set the file output flag - PROCEDURE setfile ( - fileout_in IN BOOLEAN := FALSE + -- Set the default reporter + PROCEDURE setreporter ( + reporter_in IN VARCHAR2 ,username_in IN VARCHAR2 := NULL ); - -- Get the file output flag for a user - FUNCTION getfile (username_in IN VARCHAR2 := NULL) - RETURN BOOLEAN; + -- Get the default reporter for a user + FUNCTION getreporter (username_in IN VARCHAR2 := NULL) + RETURN VARCHAR2; -- Set the file prefix for a user PROCEDURE setuserprefix ( @@ -187,8 +189,7 @@ $Log$ -- Set all of the file output columns for a user PROCEDURE setfileinfo ( - fileout_in IN BOOLEAN := FALSE - ,dir_in IN VARCHAR2 := NULL + dir_in IN VARCHAR2 := NULL ,userprefix_in IN VARCHAR2 := NULL ,incname_in IN BOOLEAN := FALSE ,dateformat_in IN VARCHAR2 := 'yyyyddmmhh24miss' @@ -204,14 +205,14 @@ $Log$ -- 2.1.1: Single update and insert procedure PROCEDURE upd ( - username_in IN ut_config.username%TYPE - ,autocompile_in IN ut_config.autocompile%TYPE - ,prefix_in IN ut_config.prefix%TYPE - ,show_failures_only_in IN ut_config.show_failures_only%TYPE - ,directory_in IN ut_config.DIRECTORY%TYPE - ,filedir_in IN ut_config.filedir%TYPE - ,show_config_info_in IN ut_config.show_config_info%TYPE - ,editor_in IN ut_config.editor%TYPE + username_in IN UT_CONFIG.username%TYPE + ,autocompile_in IN UT_CONFIG.autocompile%TYPE + ,prefix_in IN UT_CONFIG.prefix%TYPE + ,show_failures_only_in IN UT_CONFIG.show_failures_only%TYPE + ,directory_in IN UT_CONFIG.DIRECTORY%TYPE + ,filedir_in IN UT_CONFIG.filedir%TYPE + ,show_config_info_in IN UT_CONFIG.show_config_info%TYPE + ,editor_in IN UT_CONFIG.editor%TYPE ); /* The upd procedure does an insert if no row exists. @@ -260,13 +261,13 @@ $Log$ PROCEDURE get_onerow ( schema_in IN VARCHAR2 ,username_out OUT VARCHAR2 - ,autocompile_out OUT ut_config.autocompile%TYPE - ,prefix_out OUT ut_config.prefix%TYPE - ,show_failures_only_out OUT ut_config.show_failures_only%TYPE - ,directory_out OUT ut_config.DIRECTORY%TYPE - ,filedir_out OUT ut_config.filedir%TYPE - ,show_config_info_out OUT ut_config.show_config_info%TYPE - ,editor_out OUT ut_config.editor%TYPE + ,autocompile_out OUT UT_CONFIG.autocompile%TYPE + ,prefix_out OUT UT_CONFIG.prefix%TYPE + ,show_failures_only_out OUT UT_CONFIG.show_failures_only%TYPE + ,directory_out OUT UT_CONFIG.DIRECTORY%TYPE + ,filedir_out OUT UT_CONFIG.filedir%TYPE + ,show_config_info_out OUT UT_CONFIG.show_config_info%TYPE + ,editor_out OUT UT_CONFIG.editor%TYPE ); END; / diff --git a/source/ut_config.tab b/source/ut_config.tab index 14ef7cf26..c09d79197 100644 --- a/source/ut_config.tab +++ b/source/ut_config.tab @@ -1,30 +1,31 @@ -CREATE TABLE ut_config ( +CREATE TABLE UT_CONFIG ( username VARCHAR2(100), autocompile CHAR(1) DEFAULT 'Y', /* V1 compatibility */ registertest CHAR(1) DEFAULT 'N', /* V1 compatibility */ - directory VARCHAR2(2000), /* V1 compatibility */ + DIRECTORY VARCHAR2(2000), /* V1 compatibility */ naming_mode CHAR(2), /* either V1 or V2 */ prefix VARCHAR2(100) /* V1 name construction */ , CONSTRAINT ut_config_pk PRIMARY KEY (username) ); REM /* V2 name construction */ -ALTER TABLE ut_config ADD delimiter VARCHAR2(10) DEFAULT '##'; +ALTER TABLE UT_CONFIG ADD delimiter VARCHAR2(10) DEFAULT '##'; REM 2.0.10.1 Add show only failure results -ALTER TABLE ut_config ADD show_failures_only CHAR(1) DEFAULT 'N'; +ALTER TABLE UT_CONFIG ADD show_failures_only CHAR(1) DEFAULT 'N'; REM RMM start columns required for file output -ALTER TABLE ut_config ADD filedir VARCHAR2 (2000); -ALTER TABLE ut_config ADD fileout VARCHAR2 (1) DEFAULT 'N'; -ALTER TABLE ut_config ADD fileuserprefix VARCHAR2 (100); -ALTER TABLE ut_config ADD fileincprogname VARCHAR2 (1) DEFAULT 'N'; -ALTER TABLE ut_config ADD filedateformat VARCHAR2 (100) DEFAULT 'yyyyddmmhh24miss'; -ALTER TABLE ut_config ADD fileextension VARCHAR2 (200) DEFAULT '.UTF'; +ALTER TABLE UT_CONFIG ADD filedir VARCHAR2 (2000); +ALTER TABLE UT_CONFIG ADD fileuserprefix VARCHAR2 (100); +ALTER TABLE UT_CONFIG ADD fileincprogname VARCHAR2 (1) DEFAULT 'N'; +ALTER TABLE UT_CONFIG ADD filedateformat VARCHAR2 (100) DEFAULT 'yyyyddmmhh24miss'; +ALTER TABLE UT_CONFIG ADD fileextension VARCHAR2 (200) DEFAULT '.UTF'; REM RMM columns required for file output REM 2.1.1 -ALTER TABLE ut_config ADD show_config_info VARCHAR2 (1) DEFAULT 'Y'; -ALTER TABLE ut_config ADD editor VARCHAR2 (1000); +ALTER TABLE UT_CONFIG ADD show_config_info VARCHAR2 (1) DEFAULT 'Y'; +ALTER TABLE UT_CONFIG ADD editor VARCHAR2 (1000); +ALTER TABLE UT_CONFIG DROP COLUMN fileout; +ALTER TABLE UT_CONFIG ADD reporter VARCHAR2(100); diff --git a/source/ut_filereporter.pkb b/source/ut_filereporter.pkb new file mode 100644 index 000000000..a5ac827e8 --- /dev/null +++ b/source/ut_filereporter.pkb @@ -0,0 +1,189 @@ +CREATE OR REPLACE PACKAGE BODY Utfilereporter +IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ + +************************************************************************/ + + g_fid UTL_FILE.FILE_TYPE; + + PROCEDURE record_error (str IN VARCHAR2) + IS + BEGIN + UtOutputReporter.pl('UTL_FILE error: ' || str); + Utfilereporter.CLOSE(bool_abort => TRUE); + END; + + PROCEDURE open_file(dir VARCHAR2, filename VARCHAR2, filemode VARCHAR2 := 'A') + IS + BEGIN + + IF g_fid.ID IS NOT NULL THEN + close_file; + END IF; + + g_fid := UTL_FILE.FOPEN (dir, filename, filemode); + + EXCEPTION + WHEN UTL_FILE.INVALID_PATH + THEN record_error ('invalid_path'); + RAISE; + WHEN UTL_FILE.INVALID_MODE + THEN record_error ('invalid_mode'); + RAISE; + WHEN UTL_FILE.INVALID_FILEHANDLE + THEN record_error ('invalid_filehandle'); + RAISE; + WHEN UTL_FILE.INVALID_OPERATION + THEN record_error ('invalid_operation'); + RAISE; + WHEN UTL_FILE.READ_ERROR + THEN record_error ('read_error'); + RAISE; + WHEN UTL_FILE.WRITE_ERROR + THEN record_error ('write_error'); + RAISE; + WHEN UTL_FILE.INTERNAL_ERROR + THEN record_error ('internal_error'); + RAISE; + END; + + PROCEDURE close_file + IS + BEGIN + + UTL_FILE.FCLOSE (g_fid); + g_fid.ID := NULL; + + EXCEPTION + WHEN UTL_FILE.INVALID_PATH + THEN record_error ('invalid_path'); + RAISE; + WHEN UTL_FILE.INVALID_MODE + THEN record_error ('invalid_mode'); + RAISE; + WHEN UTL_FILE.INVALID_FILEHANDLE + THEN record_error ('invalid_filehandle'); + RAISE; + WHEN UTL_FILE.INVALID_OPERATION + THEN record_error ('invalid_operation'); + RAISE; + WHEN UTL_FILE.READ_ERROR + THEN record_error ('read_error'); + RAISE; + WHEN UTL_FILE.WRITE_ERROR + THEN record_error ('write_error'); + RAISE; + WHEN UTL_FILE.INTERNAL_ERROR + THEN record_error ('internal_error'); + RAISE; + END; + + PROCEDURE OPEN + IS + + file_dir UT_CONFIG.filedir%TYPE; + userprefix UT_CONFIG.fileuserprefix%TYPE; + incprog UT_CONFIG.fileincprogname%TYPE; + extension UT_CONFIG.fileextension%TYPE; + + no_dir EXCEPTION; + + BEGIN + + -- Get the output file directory + file_dir := Utconfig.filedir (); + -- check if NULL + IF file_dir IS NULL THEN + -- try directory + file_dir := Utconfig.dir (); + -- check if NULL + IF file_dir IS NULL THEN + record_error('No directory specified for file output'); + RAISE no_dir; + END IF; + END IF; + + -- Get the userprefix from config + userprefix := Utconfig.userprefix(); + IF userprefix IS NULL THEN + -- use the current user if userprefix IS NULL + userprefix := USER; + END IF; + userprefix := userprefix ||'_'; + + -- get the file extension + extension := Utconfig.fileextension(); + + open_file (file_dir, userprefix || TO_CHAR(SYSDATE,Utconfig.dateformat)||extension); + + pl('-- '||TO_CHAR(SYSDATE,Utconfig.dateformat)); + + END; + + PROCEDURE CLOSE(bool_abort BOOLEAN := FALSE) + IS + BEGIN + IF NOT bool_abort THEN + pl('-- '||TO_CHAR(SYSDATE,Utconfig.dateformat)); + END IF; + + close_file; + END; + + PROCEDURE pl (str IN VARCHAR2) + IS + BEGIN + + -- write input to file + UTL_FILE.PUT_LINE (g_fid, str); + + EXCEPTION + WHEN UTL_FILE.INVALID_PATH + THEN record_error ('invalid_path'); + RAISE; + WHEN UTL_FILE.INVALID_MODE + THEN record_error ('invalid_mode'); + RAISE; + WHEN UTL_FILE.INVALID_FILEHANDLE + THEN record_error ('invalid_filehandle'); + RAISE; + WHEN UTL_FILE.INVALID_OPERATION + THEN record_error ('invalid_operation'); + RAISE; + WHEN UTL_FILE.READ_ERROR + THEN record_error ('read_error'); + RAISE; + WHEN UTL_FILE.WRITE_ERROR + THEN record_error ('write_error'); + RAISE; + WHEN UTL_FILE.INTERNAL_ERROR + THEN record_error ('internal_error'); + RAISE; + END pl; + +BEGIN + g_fid.ID := NULL; +END; +/ diff --git a/source/ut_filereporter.pks b/source/ut_filereporter.pks new file mode 100644 index 000000000..f94fcd766 --- /dev/null +++ b/source/ut_filereporter.pks @@ -0,0 +1,39 @@ +CREATE OR REPLACE PACKAGE utfilereporter &start81 AUTHID CURRENT_USER &end81 +IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log + +************************************************************************/ + + --The procedures to use this as a reporter + PROCEDURE open; + PROCEDURE pl (str IN VARCHAR2); + PROCEDURE close(bool_abort BOOLEAN := FALSE); + + --Simpler versions to be used by other reporters + PROCEDURE open_file(dir VARCHAR2, filename VARCHAR2, filemode VARCHAR2 := 'A'); + PROCEDURE close_file; + +END; +/ diff --git a/source/ut_gen.pkb b/source/ut_gen.pkb index f656d9e1a..67c46f6c7 100644 --- a/source/ut_gen.pkb +++ b/source/ut_gen.pkb @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.4 2004/05/11 15:36:58 chrisrimmer +Added tweak to cursor from Steven F + Revision 1.3 2004/05/11 15:33:56 chrisrimmer Added 9.2 specific code from Mark Vilrokx @@ -285,7 +288,7 @@ Added Standard Headers IF utplsql.tracing THEN - utplsql.pl (v_dir || '-' || package_in || '.' || ext); + utreport.pl (v_dir || '-' || package_in || '.' || ext); END IF; fid := UTL_FILE.fopen ( @@ -306,7 +309,7 @@ Added Standard Headers BEGIN IF output_type_in = c_screen THEN - utplsql.pl (str); + utOutputReporter.pl(str); ELSIF output_type_in = c_string THEN g_pkgstring := g_pkgstring || '|' || str; @@ -859,7 +862,7 @@ Added Standard Headers IF err_in IS NOT NULL THEN - utplsql.pl (prog_in || ' File IO failure: ' || err_in); + utreport.pl (prog_in || ' File IO failure: ' || err_in); END IF; END; @@ -1313,7 +1316,7 @@ Added Standard Headers FOR indx IN 1 .. countrows LOOP setrow (indx); - utplsql.pl (getrow); + utreport.pl (getrow); END LOOP; END; diff --git a/source/ut_htmlreporter.pkb b/source/ut_htmlreporter.pkb new file mode 100644 index 000000000..dca31242e --- /dev/null +++ b/source/ut_htmlreporter.pkb @@ -0,0 +1,143 @@ +CREATE OR REPLACE PACKAGE BODY uthtmlreporter +IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ + +************************************************************************/ + + + PROCEDURE open + IS + + file_dir UT_CONFIG.filedir%TYPE; + no_dir EXCEPTION; + + BEGIN + + -- Get the output file directory + file_dir := Utconfig.filedir (); + -- check if NULL + IF file_dir IS NULL THEN + Utoutputreporter.pl('UTL_FILE error: No directory specified for file output'); + Utfilereporter.CLOSE(bool_abort => TRUE); + RAISE no_dir; + END IF; + + utfilereporter.open_file (file_dir, TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISS') || '.html', 'W'); + + pl('Test Results'); + + END; + + PROCEDURE close + IS + BEGIN + pl(''); + utfilereporter.close_file; + END; + + PROCEDURE pl (str VARCHAR2) + IS + BEGIN + utfilereporter.pl(str); + END; + + PROCEDURE pl_success + IS + BEGIN + pl('Success'); + END; + + PROCEDURE pl_failure + IS + BEGIN + pl('FAILURE'); + END; + + PROCEDURE before_results(run_id IN utr_outcome.run_id%TYPE) + IS + BEGIN + pl('

    '|| utplsql.currpkg || ': '); + IF utresult.success (run_id) THEN + pl_success; + ELSE + pl_failure; + END IF; + + pl('


    Results:'); + pl(''); + + END; + + PROCEDURE show_failure + IS + BEGIN + pl(''); + END; + + PROCEDURE show_result + IS + BEGIN + pl (''); + END; + + PROCEDURE after_results(run_id IN utr_outcome.run_id%TYPE) + IS + BEGIN + pl('
    StatusDescription
    '); + pl_failure; + pl('' || utreport.outcome.description || '
    '); + + IF utreport.outcome.status = 'SUCCESS' THEN + pl_success; + ELSE + pl_failure; + END IF; + + pl('' || utreport.outcome.description || '
    '); + END; + + PROCEDURE before_errors(run_id IN utr_error.run_id%TYPE) + IS + BEGIN + pl('Errors:
    '); + pl(''); + END; + + PROCEDURE show_error + IS + BEGIN + utreport.pl (''); + END; + + PROCEDURE after_errors(run_id IN utr_error.run_id%TYPE) + IS + BEGIN + pl('
    Error LevelError CodeDescription
    ' || utreport.error.errlevel || + '' || utreport.error.errcode || + '' || utreport.error.errtext || '
    '); + END; + +END uthtmlreporter; +/ diff --git a/source/ut_htmlreporter.pks b/source/ut_htmlreporter.pks new file mode 100644 index 000000000..85320b362 --- /dev/null +++ b/source/ut_htmlreporter.pks @@ -0,0 +1,44 @@ +CREATE OR REPLACE PACKAGE uthtmlreporter +IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log + +************************************************************************/ + + PROCEDURE open; + PROCEDURE pl (str IN VARCHAR2); + + PROCEDURE before_results(run_id IN utr_outcome.run_id%TYPE); + PROCEDURE show_failure; + PROCEDURE show_result; + PROCEDURE after_results(run_id IN utr_outcome.run_id%TYPE); + + PROCEDURE before_errors(run_id IN utr_error.run_id%TYPE); + PROCEDURE show_error; + PROCEDURE after_errors(run_id IN utr_error.run_id%TYPE); + + PROCEDURE close; + +END uthtmlreporter; +/ diff --git a/source/ut_i_packages.sql b/source/ut_i_packages.sql index dd5dc7137..8724d448b 100644 --- a/source/ut_i_packages.sql +++ b/source/ut_i_packages.sql @@ -1,5 +1,9 @@ @@ut_i_run ut_config.pks @@ut_i_run ut_plsql.pks +@@ut_i_run ut_report.pks +@@ut_i_run ut_outputreporter.pks +@@ut_i_run ut_filereporter.pks +@@ut_i_run ut_htmlreporter.pks @@ut_i_run ut_result.pks @@ut_i_run ut_plsql_util.pks @@ut_i_run ut_assert2.pks @@ -24,4 +28,5 @@ @@ut_i_run ut_rerror.pks @@ut_i_run ut_receq.pks @@ut_i_run ut_output.pks + @@ut_i_run ut_utoutput.pks diff --git a/source/ut_i_packages_b.sql b/source/ut_i_packages_b.sql index 2486f55ef..ebec03a69 100644 --- a/source/ut_i_packages_b.sql +++ b/source/ut_i_packages_b.sql @@ -1,5 +1,9 @@ @@ut_i_run ut_config.pkb @@ut_i_run ut_plsql.pkb +@@ut_i_run ut_report.pkb +@@ut_i_run ut_outputreporter.pkb +@@ut_i_run ut_filereporter.pkb +@@ut_i_run ut_htmlreporter.pkb @@ut_i_run ut_result.pkb @@ut_i_run ut_plsql_util.pkb @@ut_i_run ut_assert2.pkb @@ -24,4 +28,5 @@ @@ut_i_run ut_rerror.pkb @@ut_i_run ut_receq.pkb @@ut_i_run ut_output.pkb + @@ut_i_run ut_utoutput.pkb diff --git a/source/ut_i_uninstall.sql b/source/ut_i_uninstall.sql index 7549871a2..4c32c1fac 100644 --- a/source/ut_i_uninstall.sql +++ b/source/ut_i_uninstall.sql @@ -25,6 +25,9 @@ drop package UTPLSQL; drop package UTPLSQL_UTIL; drop package UTRECEQ; drop package UTRERROR; +drop package UTREPORT; +drop package UTOUTPUTREPORTER; +drop package UTFILEREPORTER; drop package UTRESULT2; drop package UTRESULT; drop package UTROUTCOME; @@ -40,6 +43,8 @@ drop package UTTESTPREP; drop package UTUNITTEST; drop package UTUTP; +drop package UT_UTOUTPUT; + SET TERMOUT ON PROMPT &line1 PROMPT DROPPING &UT PUBLIC SYNONYMS @@ -125,6 +130,14 @@ drop sequence UT_TEST_SEQ; drop sequence UT_UNITTEST_SEQ; drop sequence UT_UTP_SEQ; +SET TERMOUT ON +PROMPT &line1 +PROMPT DROPPING &UT VIEWS +PROMPT &line1 + +drop view utv_last_run; +drop view utv_result_full; + SET TERMOUT ON PROMPT &line1 PROMPT DROPPING &UT TABLES diff --git a/source/ut_outputreporter.pkb b/source/ut_outputreporter.pkb new file mode 100644 index 000000000..356b46966 --- /dev/null +++ b/source/ut_outputreporter.pkb @@ -0,0 +1,281 @@ +CREATE OR REPLACE PACKAGE BODY utoutputreporter +IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ + +************************************************************************/ + + norows BOOLEAN; + + PROCEDURE open + IS + BEGIN + NULL; + END; + + PROCEDURE close + IS + BEGIN + NULL; + END; + + -- This is an interface to dbms_output.put_line that tries to + -- sensibly split long lines (which is useful if you want to + -- print large dynamic sql statements). From Alistair Bayley + PROCEDURE show ( + s VARCHAR2, + maxlinelenparm NUMBER := 255, + expand BOOLEAN := TRUE + ) + IS + output_buffer_overflow EXCEPTION; + PRAGMA EXCEPTION_INIT (output_buffer_overflow, -20000); + i NUMBER; + maxlinelen NUMBER + := GREATEST (1, LEAST (255, maxlinelenparm)); + + FUNCTION locatenewline (str VARCHAR2) + RETURN NUMBER + IS + i10 NUMBER; + i13 NUMBER; + BEGIN + i13 := NVL (INSTR (SUBSTR (str, 1, maxlinelen), CHR (13)), 0); + i10 := NVL (INSTR (SUBSTR (str, 1, maxlinelen), CHR (10)), 0); + + IF i13 = 0 + THEN + RETURN i10; + ELSIF i10 = 0 + THEN + RETURN i13; + ELSE + RETURN LEAST (i13, i10); + END IF; + END; + BEGIN + -- 2.1.2 if NULL, abort. + IF s IS NULL + THEN + DBMS_OUTPUT.put_line (s); + -- 2.1.2 PBA we should return here... + RETURN; + -- Simple case: s is short. + ELSIF LENGTH (s) <= maxlinelen + THEN + DBMS_OUTPUT.put_line (s); + RETURN; + END IF; + + -- OK, so it's long. Look for newline chars as a good place to split. + i := locatenewline (s); + + IF i > 0 + THEN -- cool, we can split at a newline + DBMS_OUTPUT.put_line (SUBSTR (s, 1, i - 1)); + show (SUBSTR (s, i + 1), maxlinelen, expand); + ELSE + -- No newlines. Look for a convenient space prior to the 255-char limit. + -- Search backwards from maxLineLen. + i := NVL (INSTR (SUBSTR (s, 1, maxlinelen), ' ', -1), 0); + + IF i > 0 + THEN + DBMS_OUTPUT.put_line (SUBSTR (s, 1, i - 1)); + show (SUBSTR (s, i + 1), maxlinelen, expand); + ELSE + -- No whitespace - split at max line length. + i := maxlinelen; + DBMS_OUTPUT.put_line (SUBSTR (s, 1, i)); + show (SUBSTR (s, i + 1), maxlinelen, expand); + END IF; + END IF; + EXCEPTION + WHEN output_buffer_overflow + THEN + IF NOT expand + THEN + RAISE; + ELSE + DBMS_OUTPUT.ENABLE (1000000); + -- set false so won't expand again + show (s, maxlinelen, FALSE); + END IF; + END; + + PROCEDURE showbanner ( + success_in IN BOOLEAN, + program_in IN VARCHAR2, + run_id_in IN utr_outcome.run_id%TYPE := NULL + ) + IS + BEGIN + IF success_in + THEN + utreport.pl ('. '); + utreport.pl ( + '> SSSS U U CCC CCC EEEEEEE SSSS SSSS ' + ); + utreport.pl ( + '> S S U U C C C C E S S S S ' + ); + utreport.pl ( + '> S U U C C C C E S S ' + ); + utreport.pl ( + '> S U U C C E S S ' + ); + utreport.pl ( + '> SSSS U U C C EEEE SSSS SSSS ' + ); + utreport.pl ( + '> S U U C C E S S ' + ); + utreport.pl ( + '> S U U C C C C E S S ' + ); + utreport.pl ( + '> S S U U C C C C E S S S S ' + ); + utreport.pl ( + '> SSSS UUU CCC CCC EEEEEEE SSSS SSSS ' + ); + ELSE + utreport.pl ('. '); + utreport.pl ( + '> FFFFFFF AA III L U U RRRRR EEEEEEE ' + ); + utreport.pl ( + '> F A A I L U U R R E ' + ); + utreport.pl ( + '> F A A I L U U R R E ' + ); + utreport.pl ( + '> F A A I L U U R R E ' + ); + utreport.pl ( + '> FFFF A A I L U U RRRRRR EEEE ' + ); + utreport.pl ( + '> F AAAAAAAA I L U U R R E ' + ); + utreport.pl ( + '> F A A I L U U R R E ' + ); + utreport.pl ( + '> F A A I L U U R R E ' + ); + utreport.pl ( + '> F A A III LLLLLLL UUU R R EEEEEEE ' + ); + END IF; + + utreport.pl ('. '); + + IF run_id_in IS NOT NULL + THEN + utreport.pl ('. Run ID: ' || run_id_in); + ELSE + IF success_in + THEN + utreport.pl (' SUCCESS: "' || NVL (program_in, 'Unnamed Test') || '"'); + ELSE + utreport.pl (' FAILURE: "' || NVL (program_in, 'Unnamed Test') || '"'); + END IF; + END IF; + + utreport.pl ('. '); + END; + + PROCEDURE pl (str VARCHAR2) + IS + BEGIN + show(str); + END; + + PROCEDURE before_results(run_id IN utr_outcome.run_id%TYPE) + IS + BEGIN + showbanner (utresult.success (run_id), utplsql.currpkg, run_id); + utreport.pl ('> Individual Test Case Results:'); + utreport.pl ('>'); + norows := TRUE; + END; + + PROCEDURE show_failure + IS + BEGIN + utreport.pl (utreport.outcome.description); + utreport.pl ('>'); + norows := FALSE; + END; + + PROCEDURE show_result + IS + BEGIN + utreport.pl (utreport.outcome.status || ' - ' || utreport.outcome.description); + utreport.pl ('>'); + norows := FALSE; + END; + + PROCEDURE after_results(run_id IN utr_outcome.run_id%TYPE) + IS + BEGIN + IF norows AND utconfig.showingfailuresonly + THEN + utreport.pl ('> NO FAILURES FOUND'); + ELSIF norows + THEN + utreport.pl ('> NONE FOUND'); + END IF; + END; + + PROCEDURE before_errors(run_id IN utr_error.run_id%TYPE) + IS + BEGIN + utreport.pl ('>'); + utreport.pl ('> Errors recorded in utPLSQL Error Log:'); + utreport.pl ('>'); + norows := TRUE ; + END; + + PROCEDURE show_error + IS + BEGIN + norows := FALSE ; + utreport.pl (utreport.error.errlevel || ' - ' || utreport.error.errcode || ': ' || utreport.error.errtext); + END; + + PROCEDURE after_errors(run_id IN utr_error.run_id%TYPE) + IS + BEGIN + IF norows + THEN + utreport.pl ('> NONE FOUND'); + END IF; + END; + +END; +/ diff --git a/source/ut_outputreporter.pks b/source/ut_outputreporter.pks new file mode 100644 index 000000000..93dc941b1 --- /dev/null +++ b/source/ut_outputreporter.pks @@ -0,0 +1,44 @@ +CREATE OR REPLACE PACKAGE utoutputreporter &start81 AUTHID CURRENT_USER &end81 +IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log + +************************************************************************/ + + PROCEDURE open; + PROCEDURE pl (str IN VARCHAR2); + + PROCEDURE before_results(run_id IN utr_outcome.run_id%TYPE); + PROCEDURE show_failure; + PROCEDURE show_result; + PROCEDURE after_results(run_id IN utr_outcome.run_id%TYPE); + + PROCEDURE before_errors(run_id IN utr_error.run_id%TYPE); + PROCEDURE show_error; + PROCEDURE after_errors(run_id IN utr_error.run_id%TYPE); + + PROCEDURE close; + +END; +/ diff --git a/source/ut_package.pkb b/source/ut_package.pkb index a1f155fa5..5cc55c82d 100644 --- a/source/ut_package.pkb +++ b/source/ut_package.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ FUNCTION name_from_id (id_in IN ut_package.id%TYPE) @@ -147,7 +150,7 @@ $Log$ IF utplsql.tracing THEN - utplsql.pl ( 'Adding test ' + utreport.pl ( 'Adding test ' || package_in || '.' || v_name); @@ -192,7 +195,7 @@ $Log$ IF utplsql.tracing THEN - utplsql.pl ( 'Adding test ' + utreport.pl ( 'Adding test ' || package_in || '.' || v_name); @@ -222,7 +225,7 @@ $Log$ WHEN OTHERS THEN - utplsql.pl ( 'Add package error: ' + utreport.pl ( 'Add package error: ' || SQLERRM); &start81 ROLLBACK; &end81 RAISE; @@ -274,7 +277,7 @@ $Log$ EXCEPTION WHEN OTHERS THEN - utplsql.pl ( 'Remove package error: ' + utreport.pl ( 'Remove package error: ' || SQLERRM); &start81 ROLLBACK; &end81 RAISE; @@ -347,7 +350,7 @@ $Log$ EXCEPTION WHEN OTHERS THEN - utplsql.pl ( 'Update package error: ' + utreport.pl ( 'Update package error: ' || SQLERRM); &start81 ROLLBACK; &end81 RAISE; diff --git a/source/ut_plsql.pkb b/source/ut_plsql.pkb index 547270940..e674f805e 100644 --- a/source/ut_plsql.pkb +++ b/source/ut_plsql.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2004/05/11 15:33:57 chrisrimmer +Added 9.2 specific code from Mark Vilrokx + Revision 1.2 2003/07/01 19:36:47 chrisrimmer Added Standard Headers @@ -32,242 +35,9 @@ Added Standard Headers g_trc BOOLEAN := FALSE; g_version VARCHAR2 (100) := '2.1.1'; --- RMM start - g_pl_to_file BOOLEAN := FALSE; -- to control pl file output - g_fid UTL_FILE.FILE_TYPE; -- to control pl file output --- RMM end - tests test_tt; testpkg test_rt; - -- Start utility definitions - /* RMM start */ - /* Added this function for file output control*/ - FUNCTION get_pl_to_file RETURN BOOLEAN - IS - BEGIN - RETURN g_pl_to_file; - END; - - /* RMM */ - /* Added this procedure for file output control*/ - PROCEDURE set_pl_to_file ( - val IN BOOLEAN := FALSE - ) - IS - BEGIN - g_pl_to_file := val; - END; - - /* RMM */ - /* Added this procedure for file output*/ - PROCEDURE pl_to_file ( - v_in IN VARCHAR2, - fid IN OUT UTL_FILE.FILE_TYPE - ) IS - - v VARCHAR2(10) := '-- TEST --'; - c_endcmd VARCHAR2(13) := '-- TESTEND --'; - - dir ut_config.directory%TYPE; - - file_dir ut_config.filedir%TYPE; - file_out ut_config.fileout%TYPE; - userprefix ut_config.fileuserprefix%TYPE; - incprog ut_config.fileincprogname%TYPE; - date_formt ut_config.filedateformat%TYPE; - extension ut_config.fileextension%TYPE; - - progname VARCHAR2(35); - - no_dir EXCEPTION; - - PROCEDURE recNgo (str IN VARCHAR2) - IS - BEGIN - DBMS_OUTPUT.PUT_LINE ('UTL_FILE error ' || str); - UTL_FILE.FCLOSE (fid); - END; - - BEGIN - - -- open file if not already open - -- and write header record - IF NOT UTL_FILE.is_open(fid) THEN - - -- Get the output file directory - file_dir := utConfig.filedir (); - -- check if NULL - IF file_dir IS NULL THEN - -- try directory - file_dir := utConfig.dir (); - -- check if NULL - IF file_dir IS NULL THEN - -- redirect output to DBMS_OUTPUT - set_pl_to_file (FALSE); - raise no_dir; - END IF; - END IF; - - -- Get the userprefix from config - userprefix := utConfig.userprefix(); - IF userprefix IS NULL THEN - -- use the current user if userprefix IS NULL - userprefix := USER; - END IF; - userprefix := userprefix ||'_'; - - -- include progname in filename ? - progname := NULL; - IF utConfig.includeprogname() THEN - progname := v_in|| '_'; - END IF; - - -- get the date format - date_formt := utConfig.dateformat; - - -- get the file extension - extension := utConfig.fileextension(); - - fid := UTL_FILE.FOPEN (file_dir, userprefix||progname|| - to_char(sysdate,date_formt)||extension, 'A'); - UTL_FILE.PUT_LINE (fid, '-- '||to_char(sysdate,date_formt)); - UTL_FILE.PUT_LINE (fid, v); - END IF; - - -- write input to file - UTL_FILE.PUT_LINE (fid, v_in); - - -- close file on testend command - -- '-- TESTEND --' gets written to file as well - IF v_in = c_endcmd AND UTL_FILE.is_open(fid) THEN - -- get the date format - date_formt := utConfig.dateformat; - UTL_FILE.PUT_LINE (fid, '-- '||to_char(sysdate,date_formt)); - UTL_FILE.FCLOSE (fid); - END IF; - - EXCEPTION - WHEN UTL_FILE.INVALID_PATH - THEN recNgo ('invalid_path'); - WHEN UTL_FILE.INVALID_MODE - THEN recNgo ('invalid_mode'); - WHEN UTL_FILE.INVALID_FILEHANDLE - THEN recNgo ('invalid_filehandle'); - WHEN UTL_FILE.INVALID_OPERATION - THEN recNgo ('invalid_operation'); - WHEN UTL_FILE.READ_ERROR - THEN recNgo ('read_error'); - WHEN UTL_FILE.WRITE_ERROR - THEN recNgo ('write_error'); - WHEN UTL_FILE.INTERNAL_ERROR - THEN recNgo ('internal_error'); - WHEN no_dir - THEN recNgo ('utPLSQL.pl_to_file: No directory specified for file output'); - END pl_to_file; - /* RMM end */ - - -- This is an interface to dbms_output.put_line that tries to - -- sensibly split long lines (which is useful if you want to - -- print large dynamic sql statements). From Alistair Bayley - PROCEDURE show ( - s VARCHAR2, - maxlinelenparm NUMBER := 255, - expand BOOLEAN := TRUE - ) - IS - output_buffer_overflow EXCEPTION; - PRAGMA EXCEPTION_INIT (output_buffer_overflow, -20000); - i NUMBER; - maxlinelen NUMBER - := GREATEST (1, LEAST (255, maxlinelenparm)); - - FUNCTION locatenewline (str VARCHAR2) - RETURN NUMBER - IS - i10 NUMBER; - i13 NUMBER; - BEGIN - i13 := NVL (INSTR (SUBSTR (str, 1, maxlinelen), CHR (13)), 0); - i10 := NVL (INSTR (SUBSTR (str, 1, maxlinelen), CHR (10)), 0); - - IF i13 = 0 - THEN - RETURN i10; - ELSIF i10 = 0 - THEN - RETURN i13; - ELSE - RETURN LEAST (i13, i10); - END IF; - END; - BEGIN - -- 2.1.2 if NULL, abort. - IF s IS NULL - THEN - DBMS_OUTPUT.put_line (s); - -- 2.1.2 PBA we should return here... - RETURN; - -- Simple case: s is short. - ELSIF LENGTH (s) <= maxlinelen - THEN - DBMS_OUTPUT.put_line (s); - RETURN; - END IF; - - -- OK, so it's long. Look for newline chars as a good place to split. - i := locatenewline (s); - - IF i > 0 - THEN -- cool, we can split at a newline - DBMS_OUTPUT.put_line (SUBSTR (s, 1, i - 1)); - show (SUBSTR (s, i + 1), maxlinelen, expand); - ELSE - -- No newlines. Look for a convenient space prior to the 255-char limit. - -- Search backwards from maxLineLen. - i := NVL (INSTR (SUBSTR (s, 1, maxlinelen), ' ', -1), 0); - - IF i > 0 - THEN - DBMS_OUTPUT.put_line (SUBSTR (s, 1, i - 1)); - show (SUBSTR (s, i + 1), maxlinelen, expand); - ELSE - -- No whitespace - split at max line length. - i := maxlinelen; - DBMS_OUTPUT.put_line (SUBSTR (s, 1, i)); - show (SUBSTR (s, i + 1), maxlinelen, expand); - END IF; - END IF; - EXCEPTION - WHEN output_buffer_overflow - THEN - IF NOT expand - THEN - RAISE; - ELSE - DBMS_OUTPUT.ENABLE (1000000); - -- set false so won't expand again - show (s, maxlinelen, FALSE); - END IF; - END; - - PROCEDURE pl ( - str IN VARCHAR2, - len IN INTEGER := 80, - expand_in IN BOOLEAN := TRUE - ) - IS - BEGIN - -- RMM start - IF get_pl_to_file THEN - pl_to_file(str,g_fid); - ELSIF NOT get_pl_to_file - -- RMM end - THEN - show (str, len, expand_in); - END IF; - END; - FUNCTION vc2bool (vc IN VARCHAR2) RETURN BOOLEAN IS @@ -298,12 +68,6 @@ Added Standard Headers END IF; END; - PROCEDURE bpl (bool IN BOOLEAN) - IS - BEGIN - pl (bool2vc (bool)); - END; - FUNCTION progexists ( prog_in IN VARCHAR2, sch_in IN VARCHAR2 @@ -597,23 +361,23 @@ Added Standard Headers BEGIN IF tracing THEN - pl ( 'Runprog of ' + utreport.pl ( 'Runprog of ' || name_in); - pl ( + utreport.pl ( ' Package and program = ' || v_pkg || '.' || v_name ); - pl ( + utreport.pl ( ' Same package? ' || bool2vc (testpkg.samepkg) ); - pl ( + utreport.pl ( ' Is package? ' || bool2vc (testpkg.ispkg) ); - pl ( ' Prefix = ' + utreport.pl ( ' Prefix = ' || testpkg.prefix); END IF; @@ -640,12 +404,12 @@ Added Standard Headers IF tracing THEN - pl ( + utreport.pl ( 'Compile Error "' || SQLERRM || '" on: ' ); - pl (v_str); + utreport.pl (v_str); END IF; utassert.this ( @@ -706,6 +470,11 @@ Added Standard Headers ) IS BEGIN + + IF NOT NVL(from_suite_in, FALSE) THEN + utreport.open; + END IF; + init_tests; --Removed test for null as utConfig.prefix never returns null @@ -731,7 +500,7 @@ Added Standard Headers IF tracing THEN - pl ('Initialized utPLSQL session...'); + utreport.pl ('Initialized utPLSQL session...'); END IF; END; @@ -750,7 +519,7 @@ Added Standard Headers IS BEGIN UTL_FILE.fclose (fid); - pl ( + utreport.pl ( 'Error compiling ' || file_in || ' located in "' @@ -758,11 +527,11 @@ Added Standard Headers || '": ' || str ); - pl ( + utreport.pl ( ' Please make sure the directory for utPLSQL is set by calling ' || 'utConfig.setdir.' ); - pl ( + utreport.pl ( ' Your test package must reside in this directory.' ); @@ -818,11 +587,11 @@ Added Standard Headers END LOOP; UTL_FILE.fclose (fid); - - if tracing then - pl ('Compiling ' || lines (lines.first)); - end if; - + + if tracing then + utreport.pl ('Compiling ' || lines (lines.first)); + end if; + DBMS_SQL.parse ( cur, lines, @@ -921,21 +690,21 @@ Added Standard Headers IF tracing THEN - pl ( 'Setpkg to ' + utreport.pl ( 'Setpkg to ' || testpkg.pkg); - pl ( + utreport.pl ( ' Package and program = ' || v_pkg ); - pl ( + utreport.pl ( ' Same package? ' || bool2vc (testpkg.samepkg) ); - pl ( + utreport.pl ( ' Is package? ' || bool2vc (testpkg.ispkg) ); - pl ( ' Prefix = ' + utreport.pl ( ' Prefix = ' || testpkg.prefix); END IF; END; @@ -1057,22 +826,22 @@ Added Standard Headers THEN IF tracing THEN - pl ('Addtest'); - pl ( + utreport.pl ('Addtest'); + utreport.pl ( ' Package and program = ' || package_in || '.' || name_in ); - pl ( + utreport.pl ( ' Same package? ' || bool2vc (testpkg.samepkg) ); - pl ( + utreport.pl ( ' Override? ' || bool2vc (override_in) ); - pl ( ' Prefix = ' + utreport.pl ( ' Prefix = ' || prefix_in); END IF; @@ -1174,35 +943,23 @@ Added Standard Headers THEN init_tests; END IF; - -- RMM start - -- close output file if open - IF suite_in IS NULL AND get_pl_to_file THEN - pl('-- TESTEND --'); + + IF suite_in IS NULL THEN + utreport.close; END IF; - -- RMM end + END; BEGIN init (v_prefix, v_dir, from_suite_in); - -- RMM start - g_pl_to_file := utConfig.getfile(); - IF g_pl_to_file THEN - IF suite_in IS NOT NULL THEN - -- we run a test suite - pl(suite_in); - ELSE - -- we run a single package test - pl(package_in); - END IF; - END IF; - -- RMM end IF NOT progexists (package_in, owner_in) THEN - pl ( + utreport.pl ( 'Program named "' || package_in || '" does not exist.' ); + utreport.close; ELSE setpkg ( package_in, @@ -1228,7 +985,7 @@ Added Standard Headers THEN IF tracing THEN - pl ( + utreport.pl ( 'Recompiling ' || v_pkg || ' in ' @@ -1287,11 +1044,11 @@ Added Standard Headers IF indx IS NULL THEN - pl ('Warning!'); - pl ( + utreport.pl ('Warning!'); + utreport.pl ( 'Warning...no tests were identified for execution!' ); - pl ('Warning!'); + utreport.pl ('Warning!'); ELSE LOOP EXIT WHEN indx IS NULL; @@ -1332,6 +1089,9 @@ Added Standard Headers v_pkg_start DATE; v_override VARCHAR2 (1000); BEGIN + + utreport.open; + IF v_suite IS NULL THEN utassert.this ( @@ -1392,17 +1152,13 @@ begin ); END IF; + utreport.close; + IF reset_results_in THEN init; END IF; - -- RMM start - -- close output file if open - IF get_pl_to_file THEN - pl('-- TESTEND --'); - END IF; - -- RMM end - + END; /* Programs used in individual unit test programs. */ diff --git a/source/ut_plsql.pks b/source/ut_plsql.pks index e43cc31a1..f98c37d98 100644 --- a/source/ut_plsql.pks +++ b/source/ut_plsql.pks @@ -23,7 +23,10 @@ You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ -$Log$ +$Log: ut_plsql.pks,v +Revision 1.2 2003/07/01 19:36:47 chrisrimme +Added Standard Header + ************************************************************************/ c_success CONSTANT VARCHAR2 (7) := 'SUCCESS'; @@ -72,23 +75,6 @@ $Log$ currcase testcase_rt; /* Utility programs */ - - -- RMM start - FUNCTION get_pl_to_file RETURN BOOLEAN; - - PROCEDURE set_pl_to_file ( - val IN BOOLEAN := FALSE - ); - -- RMM end - - PROCEDURE pl ( - str IN VARCHAR2, - len IN INTEGER := 80, - expand_in IN BOOLEAN := TRUE - ); - - PROCEDURE bpl (bool IN BOOLEAN); - FUNCTION vc2bool (vc IN VARCHAR2) RETURN BOOLEAN; diff --git a/source/ut_plsql2.pkb b/source/ut_plsql2.pkb index 939845ca0..f5e823255 100644 --- a/source/ut_plsql2.pkb +++ b/source/ut_plsql2.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ g_trc BOOLEAN := FALSE; @@ -150,7 +153,7 @@ $Log$ BEGIN IF tracing THEN - utplsql.pl ( 'Runprog of ' + utreport.pl ( 'Runprog of ' || procedure_in); END IF; @@ -186,12 +189,12 @@ $Log$ IF tracing THEN - utplsql.pl ( + utreport.pl ( 'Procedure execution Error "' || SQLERRM || '" on: ' ); - utplsql.pl (v_str); + utreport.pl (v_str); END IF; IF unittest_id_in IS NOT NULL @@ -341,7 +344,7 @@ $Log$ LOOP IF tracing THEN - utplsql.pl ( + utreport.pl ( 'Unit testing: ' || ut_rec.program_name ); diff --git a/source/ut_receq.pkb b/source/ut_receq.pkb index d8ab85def..513d7b989 100644 --- a/source/ut_receq.pkb +++ b/source/ut_receq.pkb @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ PROCEDURE delete_receq (id_in ut_receq.id%TYPE) @@ -52,9 +55,9 @@ $Log$ EXCEPTION WHEN OTHERS THEN - utplsql.pl (SQLERRM); + utreport.pl (SQLERRM); DBMS_SQL.close_cursor (v_cur); - utplsql.pl ( + utreport.pl ( 'Delete failed - function probably used by another package' ); END; @@ -126,8 +129,8 @@ $Log$ EXCEPTION WHEN VALUE_ERROR THEN - utplsql.pl ('Generated test name is too long'); - utplsql.pl ( + utreport.pl ('Generated test name is too long'); + utreport.pl ( 'Resubmit with a defined test_name_in=>''EQ_your_name''' ); RETURN NULL; @@ -223,7 +226,7 @@ $Log$ IF v_pkg_id IS NULL THEN - utplsql.pl (pkg_name_in || ' does not exist'); + utreport.pl (pkg_name_in || ' does not exist'); ELSIF v_receq_id IS NULL THEN SELECT object_type @@ -243,7 +246,7 @@ $Log$ END IF; utreceq.COMPILE (v_receq_id); - utplsql.pl (v_recname || ' compiled for ' || v_obj_type || ' ' || record_in); + utreport.pl (v_recname || ' compiled for ' || v_obj_type || ' ' || record_in); BEGIN INSERT INTO ut_receq_pkg @@ -251,14 +254,14 @@ $Log$ EXCEPTION WHEN DUP_VAL_ON_INDEX THEN - utplsql.pl ( + utreport.pl ( v_recname || ' already registered for package ' || pkg_name_in ); END; EXCEPTION WHEN NO_DATA_FOUND THEN - utplsql.pl (record_in || ' does not exist in schema ' || rec_owner_in); + utreport.pl (record_in || ' does not exist in schema ' || rec_owner_in); END ADD; PROCEDURE COMPILE (pkg_name_in IN ut_package.NAME%TYPE) diff --git a/source/ut_report.pkb b/source/ut_report.pkb new file mode 100644 index 000000000..85fb7c4b5 --- /dev/null +++ b/source/ut_report.pkb @@ -0,0 +1,203 @@ +/* Formatted on 2002/03/31 23:53 (Formatter Plus v4.5.2) */ +CREATE OR REPLACE PACKAGE BODY Utreport +IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ + +************************************************************************/ + + DEFAULT_REPORTER VARCHAR2(100) := 'Output'; + + DYNAMIC_PLSQL_FAILURE NUMBER(10) := -6550; + + --This is the reporter we have been asked to use + g_reporter VARCHAR2(100); + + --This is the reporter we are actually using + --(this differs from the above in the event of error) + g_actual VARCHAR2(100); + + FUNCTION parse_it(proc IN VARCHAR2, params IN NUMBER, force_reporter IN VARCHAR2) + RETURN INTEGER + IS + dyn_handle INTEGER := NULL; + query VARCHAR2(1000); + BEGIN + dyn_handle := DBMS_SQL.OPEN_CURSOR; + QUERY := 'BEGIN ut' || NVL(force_reporter, g_actual) || 'Reporter.' || proc ; + IF params = 1 THEN + QUERY := QUERY || '(:p)'; + END IF; + QUERY := QUERY || '; END;'; + DBMS_SQL.PARSE(dyn_handle, QUERY, DBMS_SQL.NATIVE); + RETURN dyn_handle; + EXCEPTION + WHEN OTHERS THEN + DBMS_SQL.CLOSE_CURSOR (dyn_handle); + RAISE; + END; + + PROCEDURE execute_it(dyn_handle IN OUT INTEGER) + IS + dyn_result INTEGER; + BEGIN + dyn_result := DBMS_SQL.EXECUTE (dyn_handle); + DBMS_SQL.CLOSE_CURSOR (dyn_handle); + END; + + --We use this to make dynamic calls to reporter packages + PROCEDURE call(proc IN VARCHAR2, + param IN VARCHAR2, + params IN NUMBER := 1, + force_reporter IN VARCHAR2 := NULL, + failover IN BOOLEAN := TRUE) + IS + dyn_handle INTEGER := NULL; + BEGIN + dyn_handle := parse_it(proc, params, force_reporter); + IF params = 1 THEN + DBMS_SQL.BIND_VARIABLE (dyn_handle, 'p', param); + END IF; + execute_it(dyn_handle); + EXCEPTION + WHEN OTHERS THEN + + IF dyn_handle IS NOT NULL THEN + DBMS_SQL.CLOSE_CURSOR (dyn_handle); + END IF; + + IF g_actual <> DEFAULT_REPORTER THEN + + IF NOT failover OR SQLCODE <> DYNAMIC_PLSQL_FAILURE THEN + g_actual := DEFAULT_REPORTER; + pl(SQLERRM); + pl('** REVERTING TO DEFAULT REPORTER **'); + END IF; + + ELSE + RAISE; + END IF; + + call(proc, param, params, force_reporter => DEFAULT_REPORTER); + END; + + PROCEDURE call(proc IN VARCHAR2, + failover IN BOOLEAN := TRUE) + IS + BEGIN + call(proc => proc, + param => '', + params => 0, + failover => failover); + END; + + PROCEDURE use(reporter IN VARCHAR2) + IS + BEGIN + g_reporter := reporter; + END; + + FUNCTION using RETURN VARCHAR2 + IS + BEGIN + RETURN g_reporter; + END; + + PROCEDURE open + IS + BEGIN + g_actual := g_reporter; + call('open', failover => FALSE); + END; + + PROCEDURE pl (str IN VARCHAR2) + IS + BEGIN + call('pl', str); + END; + + PROCEDURE pl (bool IN BOOLEAN) + IS + BEGIN + pl (Utplsql.bool2vc (bool)); + END; + + PROCEDURE before_results(run_id IN utr_outcome.run_id%TYPE) + IS + BEGIN + call('before_results', run_id); + END; + + PROCEDURE show_failure(rec_result IN utr_outcome%ROWTYPE) + IS + BEGIN + outcome := rec_result; + call('show_failure'); + END; + + PROCEDURE show_result(rec_result IN utr_outcome%ROWTYPE) + IS + BEGIN + outcome := rec_result; + call('show_result'); + END; + + PROCEDURE after_results(run_id IN utr_outcome.run_id%TYPE) + IS + BEGIN + call('after_results', run_id); + END; + + PROCEDURE before_errors(run_id IN utr_error.run_id%TYPE) + IS + BEGIN + call('before_errors', run_id); + END; + + PROCEDURE show_error(rec_error IN utr_error%ROWTYPE) + IS + BEGIN + error := rec_error; + call('show_error'); + END; + + PROCEDURE after_errors(run_id IN utr_error.run_id%TYPE) + IS + BEGIN + call('after_errors', run_id); + END; + + PROCEDURE close + IS + BEGIN + call('close'); + END; + +BEGIN + + g_reporter := NVL(utconfig.getreporter, DEFAULT_REPORTER); + g_actual := g_reporter; + +END; +/ diff --git a/source/ut_report.pks b/source/ut_report.pks new file mode 100644 index 000000000..62129a69c --- /dev/null +++ b/source/ut_report.pks @@ -0,0 +1,52 @@ +CREATE OR REPLACE PACKAGE utreport &start81 AUTHID CURRENT_USER &end81 +IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2003 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log + +************************************************************************/ + + outcome utr_outcome%ROWTYPE; + error utr_error%ROWTYPE; + + PROCEDURE use(reporter IN VARCHAR2); + FUNCTION using RETURN VARCHAR2; + + PROCEDURE open; + + PROCEDURE pl (str IN VARCHAR2); + PROCEDURE pl (bool IN BOOLEAN); + + PROCEDURE before_results(run_id IN utr_outcome.run_id%TYPE); + PROCEDURE show_failure(rec_result utr_outcome%ROWTYPE); + PROCEDURE show_result(rec_result utr_outcome%ROWTYPE); + PROCEDURE after_results(run_id IN utr_outcome.run_id%TYPE); + + PROCEDURE before_errors(run_id IN utr_error.run_id%TYPE); + PROCEDURE show_error(rec_error utr_error%ROWTYPE); + PROCEDURE after_errors(run_id IN utr_error.run_id%TYPE); + + PROCEDURE close; + +END; +/ diff --git a/source/ut_rerror.pkb b/source/ut_rerror.pkb index c5d92f919..04b60833f 100644 --- a/source/ut_rerror.pkb +++ b/source/ut_rerror.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ FUNCTION uterrcode (errmsg_in IN VARCHAR2 := NULL) @@ -123,7 +126,7 @@ $Log$ END IF; -- Simply display the error information. - utplsql.pl (l_message); + utreport.pl (l_message); END IF; END IF; diff --git a/source/ut_rerror.pks b/source/ut_rerror.pks index dedbc58f4..2e27ce52c 100644 --- a/source/ut_rerror.pks +++ b/source/ut_rerror.pks @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ c_error_indicator CONSTANT VARCHAR2 (7) := 'UT-300%'; diff --git a/source/ut_result.pkb b/source/ut_result.pkb index 7a1704612..c98ac8013 100644 --- a/source/ut_result.pkb +++ b/source/ut_result.pkb @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ resultindx PLS_INTEGER; @@ -41,112 +44,13 @@ $Log$ g_include_successes := FALSE ; END; - PROCEDURE showresults ( - success_in IN BOOLEAN, - program_in IN VARCHAR2, - run_id_in IN utr_outcome.run_id%TYPE := NULL - ) - IS - BEGIN - IF success_in - THEN - utplsql.pl ('. '); - utplsql.pl ( - '> SSSS U U CCC CCC EEEEEEE SSSS SSSS ' - ); - utplsql.pl ( - '> S S U U C C C C E S S S S ' - ); - utplsql.pl ( - '> S U U C C C C E S S ' - ); - utplsql.pl ( - '> S U U C C E S S ' - ); - utplsql.pl ( - '> SSSS U U C C EEEE SSSS SSSS ' - ); - utplsql.pl ( - '> S U U C C E S S ' - ); - utplsql.pl ( - '> S U U C C C C E S S ' - ); - utplsql.pl ( - '> S S U U C C C C E S S S S ' - ); - utplsql.pl ( - '> SSSS UUU CCC CCC EEEEEEE SSSS SSSS ' - ); - ELSE - utplsql.pl ('. '); - utplsql.pl ( - '> FFFFFFF AA III L U U RRRRR EEEEEEE ' - ); - utplsql.pl ( - '> F A A I L U U R R E ' - ); - utplsql.pl ( - '> F A A I L U U R R E ' - ); - utplsql.pl ( - '> F A A I L U U R R E ' - ); - utplsql.pl ( - '> FFFF A A I L U U RRRRRR EEEE ' - ); - utplsql.pl ( - '> F AAAAAAAA I L U U R R E ' - ); - utplsql.pl ( - '> F A A I L U U R R E ' - ); - utplsql.pl ( - '> F A A I L U U R R E ' - ); - utplsql.pl ( - '> F A A III LLLLLLL UUU R R EEEEEEE ' - ); - END IF; - - utplsql.pl ('. '); - - IF run_id_in IS NOT NULL - THEN - utplsql.pl ('. Run ID: ' || run_id_in); - ELSE - IF success_in - THEN - utplsql.pl (' SUCCESS: "' || NVL (program_in, 'Unnamed Test') || '"'); - ELSE - utplsql.pl (' FAILURE: "' || NVL (program_in, 'Unnamed Test') || '"'); - END IF; - END IF; - - utplsql.pl ('. '); - END; - - PROCEDURE showheader (run_id_in IN utr_outcome.run_id%TYPE := NULL) - IS - BEGIN - IF g_header_shown - THEN - NULL; - ELSE - showresults (success (run_id_in), utplsql.currpkg, run_id_in); - END IF; - - -- Disable selectivity of showing header for now. - g_header_shown := FALSE ; - END; - PROCEDURE showone ( run_id_in IN utr_outcome.run_id%TYPE := NULL, indx_in IN PLS_INTEGER ) IS BEGIN - utplsql.pl (results (indx_in).NAME || ': ' || results (indx_in).msg); + utreport.pl (results (indx_in).NAME || ': ' || results (indx_in).msg); END; PROCEDURE show ( @@ -156,13 +60,10 @@ $Log$ IS indx PLS_INTEGER := results.FIRST; l_id utr_outcome.run_id%TYPE := NVL (run_id_in, utplsql2.runnum); - norows BOOLEAN; BEGIN - showheader (run_id_in); - utplsql.pl ('> Individual Test Case Results:'); - utplsql.pl ('>'); - norows := TRUE ; - + + utreport.before_results(run_id_in); + FOR rec IN (SELECT * FROM utr_outcome WHERE run_id = l_id @@ -180,55 +81,25 @@ $Log$ NULL; ELSIF utconfig.showingfailuresonly THEN - norows := FALSE ; - utplsql.pl (rec.description); - utplsql.pl ('>'); + utreport.show_failure(rec); ELSE - norows := FALSE ; - utplsql.pl ( - rec.status || ' - ' || - rec.description); - utplsql.pl ('>'); + utreport.show_result(rec); END IF; END LOOP; - IF norows AND utconfig.showingfailuresonly - THEN - utplsql.pl ('> NO FAILURES FOUND'); - ELSIF norows - THEN - utplsql.pl ('> NONE FOUND'); - END IF; - - utplsql.pl ('>'); - utplsql.pl ('> Errors recorded in utPLSQL Error Log:'); - utplsql.pl ('>'); - norows := TRUE ; + utreport.after_results(run_id_in); + + utreport.before_errors(run_id_in); FOR rec IN (SELECT * FROM utr_error WHERE run_id = l_id) LOOP - norows := FALSE ; - utplsql.pl (rec.errlevel || ' - ' || rec.errcode || ': ' || rec.errtext); + utreport.show_error(rec); END LOOP; - IF norows - THEN - utplsql.pl ('> NONE FOUND'); - END IF; - + utreport.after_errors(run_id_in); -/*V1 approach - IF failure - THEN - LOOP - EXIT WHEN indx IS NULL; - showone (indx); - indx := results.NEXT (indx); - END LOOP; - END IF; -*/ IF reset_in THEN init; diff --git a/source/ut_result.pks b/source/ut_result.pks index 2e08a103a..23432a2c0 100644 --- a/source/ut_result.pks +++ b/source/ut_result.pks @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ /* Test result record structure */ @@ -52,12 +55,6 @@ $Log$ PROCEDURE showlast (run_id_in IN utr_outcome.run_id%TYPE := NULL); - PROCEDURE showresults ( - success_in IN BOOLEAN, - program_in IN VARCHAR2, - run_id_in IN utr_outcome.run_id%TYPE := NULL - ); - PROCEDURE init (from_suite_in IN BOOLEAN := FALSE); FUNCTION success (run_id_in IN utr_outcome.run_id%TYPE := NULL) diff --git a/source/ut_result2.pkb b/source/ut_result2.pkb index 2b3d917e7..d4e23b155 100644 --- a/source/ut_result2.pkb +++ b/source/ut_result2.pkb @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ PROCEDURE report ( @@ -48,12 +51,12 @@ $Log$ BEGIN IF utplsql2.tracing THEN - utplsql.pl ('Record outcome result:'); - utplsql.pl (utplsql2.runnum); - utplsql.pl (utplsql2.tc_runnum); - utplsql.pl (outcome_in); - utplsql.bpl (test_failed_in); - utplsql.pl (description_in); + utreport.pl ('Record outcome result:'); + utreport.pl (utplsql2.runnum); + utreport.pl (utplsql2.tc_runnum); + utreport.pl (outcome_in); + utreport.pl (test_failed_in); + utreport.pl (description_in); END IF; IF register_in @@ -82,7 +85,7 @@ $Log$ THEN utresult.report (description_in); ELSE - utplsql.pl (description_in); + utreport.pl (description_in); END IF; IF showresults_in AND register_in diff --git a/source/ut_suite.pkb b/source/ut_suite.pkb index 3cfa944f3..c5fce82bd 100644 --- a/source/ut_suite.pkb +++ b/source/ut_suite.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2003/12/23 15:30:53 chrisrimmer +Added Jens Schauder's show_suites procedure + Revision 1.2 2003/07/01 19:36:47 chrisrimmer Added Standard Headers @@ -142,7 +145,7 @@ Added Standard Headers EXCEPTION WHEN OTHERS THEN - utplsql.pl ( 'Remove suite error: ' + utreport.pl ( 'Remove suite error: ' || SQLERRM); &start81 ROLLBACK; &end81 RAISE; @@ -207,7 +210,7 @@ Added Standard Headers EXCEPTION WHEN OTHERS THEN - utplsql.pl ( 'Update suite error: ' + utreport.pl ( 'Update suite error: ' || SQLERRM); &start81 ROLLBACK; &end81 RAISE; diff --git a/source/ut_suiteutp.pkb b/source/ut_suiteutp.pkb index 92b2390ca..f285c52dd 100644 --- a/source/ut_suiteutp.pkb +++ b/source/ut_suiteutp.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ FUNCTION defined ( @@ -143,7 +146,7 @@ $Log$ EXCEPTION WHEN OTHERS THEN - utplsql.pl ( 'Remove suite-utp error: ' + utreport.pl ( 'Remove suite-utp error: ' || SQLERRM); &start81 ROLLBACK; &end81 RAISE; diff --git a/source/ut_test.pkb b/source/ut_test.pkb index 51e1b03e0..462b0216c 100644 --- a/source/ut_test.pkb +++ b/source/ut_test.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ FUNCTION name_from_id (id_in IN ut_test.id%TYPE) @@ -80,7 +83,7 @@ $Log$ EXCEPTION WHEN OTHERS THEN - utplsql.pl ( 'Add test error: ' + utreport.pl ( 'Add test error: ' || SQLERRM); &start81 ROLLBACK; &end81 RAISE; @@ -108,7 +111,7 @@ $Log$ EXCEPTION WHEN OTHERS THEN - utplsql.pl ( 'Remove test error: ' + utreport.pl ( 'Remove test error: ' || SQLERRM); &start81 ROLLBACK; &end81 RAISE; @@ -149,7 +152,7 @@ $Log$ EXCEPTION WHEN OTHERS THEN - utplsql.pl ( 'Update test error: ' + utreport.pl ( 'Update test error: ' || SQLERRM); &start81 ROLLBACK; &end81 RAISE; diff --git a/source/ut_testcase.pkb b/source/ut_testcase.pkb index 2df210cf4..323ecb55e 100644 --- a/source/ut_testcase.pkb +++ b/source/ut_testcase.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ FUNCTION name_from_id (id_in IN ut_testcase.id%TYPE) @@ -79,7 +82,7 @@ $Log$ EXCEPTION WHEN OTHERS THEN - utplsql.pl ( 'Add test error: ' + utreport.pl ( 'Add test error: ' || SQLERRM); &start81 ROLLBACK; &end81 RAISE; @@ -107,7 +110,7 @@ $Log$ EXCEPTION WHEN OTHERS THEN - utplsql.pl ( 'Remove test error: ' + utreport.pl ( 'Remove test error: ' || SQLERRM); &start81 ROLLBACK; &end81 RAISE; @@ -148,7 +151,7 @@ $Log$ EXCEPTION WHEN OTHERS THEN - utplsql.pl ( 'Update test error: ' + utreport.pl ( 'Update test error: ' || SQLERRM); &start81 ROLLBACK; &end81 RAISE; From d665ece5525022405223a3a30b9f184913c07c99 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 16 Nov 2004 09:46:49 +0000 Subject: [PATCH 077/143] Changed to new version detection system. --- source/ut_assert.pkb | 3 + source/ut_assert.pks | 5 +- source/ut_assert2.pkb | 145 ++++++++++++++++++----------------- source/ut_assert2.pks | 5 +- source/ut_config.pkb | 57 +++++++------- source/ut_config.pks | 37 +++++---- source/ut_filereporter.pkb | 5 +- source/ut_filereporter.pks | 2 +- source/ut_gen.pkb | 13 ++-- source/ut_gen.pks | 11 ++- source/ut_htmlreporter.pkb | 5 +- source/ut_i_do.sql | 74 +----------------- source/ut_i_packages.sql | 5 ++ source/ut_i_packages_b.sql | 5 ++ source/ut_i_preprocess.sql | 83 ++++++++++++++++++++ source/ut_i_uninstall.sql | 22 +++--- source/ut_outcome.pkb | 3 + source/ut_outcome.pks | 3 + source/ut_output.pks | 5 +- source/ut_outputreporter.pkb | 5 +- source/ut_outputreporter.pks | 2 +- source/ut_package.pkb | 41 +++++----- source/ut_package.pks | 5 +- source/ut_plsql.pkb | 66 +++++++--------- source/ut_plsql.pks | 17 ++-- source/ut_plsql2.pkb | 19 +++-- source/ut_plsql2.pks | 5 +- source/ut_plsql_util.pkb | 16 ++-- source/ut_plsql_util.pks | 5 +- source/ut_receq.pkb | 3 + source/ut_receq.pks | 5 +- source/ut_report.pkb | 3 + source/ut_report.pks | 2 +- source/ut_rerror.pkb | 12 +-- source/ut_rerror.pks | 2 +- source/ut_result.pkb | 1 + source/ut_result2.pks | 3 + source/ut_routcome.pkb | 55 ++++++------- source/ut_routcome.pks | 3 + source/ut_rsuite.pkb | 31 ++++---- source/ut_rsuite.pks | 3 + source/ut_rtestcase.pkb | 27 ++++--- source/ut_rtestcase.pks | 3 + source/ut_runittest.pkb | 31 ++++---- source/ut_runittest.pks | 3 + source/ut_rutp.pkb | 55 ++++++------- source/ut_rutp.pks | 3 + source/ut_suite.pkb | 31 ++++---- source/ut_suite.pks | 5 +- source/ut_suiteutp.pkb | 23 +++--- source/ut_suiteutp.pks | 5 +- source/ut_test.pkb | 25 +++--- source/ut_test.pks | 5 +- source/ut_testcase.pkb | 25 +++--- source/ut_testcase.pks | 5 +- source/ut_testprep.pkb | 3 + source/ut_testprep.pks | 3 + source/ut_unittest.pkb | 27 ++++--- source/ut_unittest.pks | 3 + source/ut_utoutput.pkb | 3 + source/ut_utoutput.pks | 3 + source/ut_utp.pkb | 37 +++++---- source/ut_utp.pks | 3 + 63 files changed, 643 insertions(+), 477 deletions(-) create mode 100644 source/ut_i_preprocess.sql diff --git a/source/ut_assert.pkb b/source/ut_assert.pkb index 7a4ad9634..0a6c1c1a3 100644 --- a/source/ut_assert.pkb +++ b/source/ut_assert.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + Revision 1.2 2003/07/01 19:36:46 chrisrimmer Added Standard Headers diff --git a/source/ut_assert.pks b/source/ut_assert.pks index f8315885c..e271ce1f9 100644 --- a/source/ut_assert.pks +++ b/source/ut_assert.pks @@ -1,5 +1,5 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ -CREATE OR REPLACE PACKAGE utassert &start81 AUTHID CURRENT_USER &end81 +CREATE OR REPLACE PACKAGE utassert &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:46 chrisrimmer +Added Standard Headers + ************************************************************************/ test_failure EXCEPTION; diff --git a/source/ut_assert2.pkb b/source/ut_assert2.pkb index 51aa561ee..dafe94465 100644 --- a/source/ut_assert2.pkb +++ b/source/ut_assert2.pkb @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.4 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + Revision 1.3 2003/07/11 14:32:52 chrisrimmer Added 'throws' bugfix from Ivan Desjardins @@ -697,11 +700,11 @@ Added Standard Headers raise_exc_in IN BOOLEAN := FALSE ) IS - &start73 + &start_lt_8 fdbk PLS_INTEGER; cur PLS_INTEGER := DBMS_SQL.open_cursor; - &end73 + &end_lt_8 ival PLS_INTEGER; /* 2.0.8 suggested replacement below by Chris Rimmer to avoid duplicate column name issues @@ -746,10 +749,10 @@ UNION CLOSE cur; END;'; BEGIN - &start81 + &start_ge_8_1 EXECUTE IMMEDIATE v_block USING OUT ival; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 DBMS_SQL.parse ( cur, v_block, @@ -768,7 +771,7 @@ UNION ival ); DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 this ( outcome_in, @@ -783,9 +786,9 @@ UNION EXCEPTION WHEN OTHERS THEN - &start73 + &start_lt_8 DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 this ( @@ -995,16 +998,16 @@ UNION l_value VARCHAR2 (2000); l_success BOOLEAN; - &start81 + &start_ge_8_1 TYPE cv_t IS REF CURSOR; cv cv_t; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 cur PLS_INTEGER := DBMS_SQL.open_cursor; fdbk PLS_INTEGER; - &end73 + &end_lt_8 BEGIN IF utplsql2.tracing @@ -1018,12 +1021,12 @@ UNION ); END IF; - &start81 + &start_ge_8_1 OPEN cv FOR check_query_in; FETCH cv INTO l_value; CLOSE cv; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 DBMS_SQL.parse ( cur, check_query_in, @@ -1033,7 +1036,7 @@ UNION fdbk := DBMS_SQL.execute_and_fetch (cur); DBMS_SQL.column_value (cur, 1, l_value); DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 l_success := (l_value = against_value_in) OR ( l_value IS NULL @@ -1087,16 +1090,16 @@ UNION l_value DATE; l_success BOOLEAN; - &start81 + &start_ge_8_1 TYPE cv_t IS REF CURSOR; cv cv_t; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 cur PLS_INTEGER := DBMS_SQL.open_cursor; fdbk PLS_INTEGER; - &end73 + &end_lt_8 BEGIN IF utplsql2.tracing @@ -1110,12 +1113,12 @@ UNION ); END IF; - &start81 + &start_ge_8_1 OPEN cv FOR check_query_in; FETCH cv INTO l_value; CLOSE cv; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 DBMS_SQL.parse ( cur, check_query_in, @@ -1125,7 +1128,7 @@ UNION fdbk := DBMS_SQL.execute_and_fetch (cur); DBMS_SQL.column_value (cur, 1, l_value); DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 l_success := (l_value = against_value_in) OR ( l_value IS NULL @@ -1187,17 +1190,17 @@ UNION l_value NUMBER; l_success BOOLEAN; - &start81 + &start_ge_8_1 TYPE cv_t IS REF CURSOR; cv cv_t; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 cur PLS_INTEGER := DBMS_SQL.open_cursor; fdbk PLS_INTEGER; - &end73 + &end_lt_8 BEGIN IF utplsql2.tracing @@ -1211,12 +1214,12 @@ UNION ); END IF; - &start81 + &start_ge_8_1 OPEN cv FOR check_query_in; FETCH cv INTO l_value; CLOSE cv; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 DBMS_SQL.parse ( cur, check_query_in, @@ -1226,7 +1229,7 @@ UNION fdbk := DBMS_SQL.execute_and_fetch (cur); DBMS_SQL.column_value (cur, 1, l_value); DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 l_success := (l_value = against_value_in) @@ -1365,7 +1368,7 @@ UNION UTL_FILE.fopen ( check_this_dir_in, check_this_in, - 'R' &start81, max_linesize => 32767 &end81 + 'R' &start_ge_8_1, max_linesize => 32767 &start_ge_8_1 ); EXCEPTION WHEN OTHERS @@ -1382,7 +1385,7 @@ UNION ), against_this_in, 'R' - &start81, max_linesize => 32767 &end81 + &start_ge_8_1, max_linesize => 32767 &start_ge_8_1 ); EXCEPTION WHEN OTHERS @@ -1692,17 +1695,17 @@ UNION := 'begin :val := ' || str || '; end;'; - &start73 + &start_lt_8 fdbk PLS_INTEGER; cur PLS_INTEGER := DBMS_SQL.open_cursor; - &end73 + &end_lt_8 retval NUMBER; BEGIN - &start81 + &start_ge_8_1 EXECUTE IMMEDIATE sqlstr USING OUT retval; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 DBMS_SQL.parse ( cur, sqlstr, @@ -1711,14 +1714,14 @@ UNION fdbk := DBMS_SQL.EXECUTE (cur); DBMS_SQL.variable_value (cur, 'val', retval); DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 RETURN retval; EXCEPTION WHEN OTHERS THEN - &start73 + &start_lt_8 DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 RAISE; END; @@ -2095,11 +2098,11 @@ UNION bada PLS_INTEGER; badtext VARCHAR2 (32767); null_and_valid BOOLEAN := FALSE ; - &start73 + &start_lt_8 fdbk PLS_INTEGER; cur PLS_INTEGER := DBMS_SQL.open_cursor; - &end73 + &end_lt_8 BEGIN validatecoll ( @@ -2162,7 +2165,7 @@ UNION 'NEXT', NULL ); - &start81 + &start_ge_8_1 EXECUTE IMMEDIATE dynblock USING IN check_endrow_in, IN against_endrow_in, @@ -2172,8 +2175,8 @@ UNION IN check_startrow_in, IN against_startrow_in, IN v_matchrow; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 DBMS_SQL.parse ( cur, dynblock, @@ -2221,7 +2224,7 @@ UNION badtext ); DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 END IF; this ( @@ -2246,9 +2249,9 @@ UNION EXCEPTION WHEN OTHERS THEN --p.l (sqlerrm); - &start73 + &start_lt_8 DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 this ( outcome_in, @@ -2304,11 +2307,11 @@ UNION valid_interim BOOLEAN; invalid_interim_msg VARCHAR2 (4000); null_and_valid BOOLEAN := FALSE ; - &start73 + &start_lt_8 fdbk PLS_INTEGER; cur PLS_INTEGER := DBMS_SQL.open_cursor; - &end73 + &end_lt_8 BEGIN validatecoll ( @@ -2350,7 +2353,7 @@ UNION nextrowfunc_in, getvalfunc_in ); - &start81 + &start_ge_8_1 EXECUTE IMMEDIATE dynblock USING IN check_endrow_in, IN against_endrow_in, @@ -2360,8 +2363,8 @@ UNION IN check_startrow_in, IN against_startrow_in, IN v_matchrow; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 DBMS_SQL.parse ( cur, dynblock, @@ -2410,7 +2413,7 @@ UNION ); DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 <> this ( @@ -2434,9 +2437,9 @@ UNION EXCEPTION WHEN OTHERS THEN --p.l (sqlerrm); - &start73 + &start_lt_8 DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 this ( outcome_in, @@ -2571,17 +2574,17 @@ UNION || '; WHEN OTHERS THEN :indicator := SQLCODE; END;'; - &start73 + &start_lt_8 cur PLS_INTEGER := DBMS_SQL.open_cursor; ret_val PLS_INTEGER; - &end73 + &end_lt_8 BEGIN --Fire off the dynamic PL/SQL - &start81 + &start_ge_8_1 EXECUTE IMMEDIATE v_block USING OUT l_indicator; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 DBMS_SQL.parse ( cur, v_block, @@ -2595,7 +2598,7 @@ UNION l_indicator ); DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 this ( outcome_in, @@ -2654,17 +2657,17 @@ UNION || ';' || ' ELSE :indicator := SQLCODE; END IF; END;'; - &start73 + &start_lt_8 cur PLS_INTEGER := DBMS_SQL.open_cursor; ret_val PLS_INTEGER; - &end73 + &end_lt_8 BEGIN --Fire off the dynamic PL/SQL - &start81 + &start_ge_8_1 EXECUTE IMMEDIATE v_block USING OUT l_indicator; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 DBMS_SQL.parse ( cur, v_block, @@ -2678,7 +2681,7 @@ UNION l_indicator ); DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 this ( outcome_in, @@ -3304,7 +3307,7 @@ UNION UTL_FILE.fopen ( dir_in, file_in, - 'R' &start81, max_linesize => 32767 &end81 + 'R' &start_ge_8_1, max_linesize => 32767 &start_ge_8_1 ); cleanup (TRUE , msg_in); EXCEPTION diff --git a/source/ut_assert2.pks b/source/ut_assert2.pks index 466314363..096422a5a 100644 --- a/source/ut_assert2.pks +++ b/source/ut_assert2.pks @@ -1,6 +1,6 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ CREATE OR REPLACE PACKAGE utassert2 -&start81 AUTHID CURRENT_USER &end81 +&start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ @@ -25,6 +25,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:46 chrisrimmer +Added Standard Headers + ************************************************************************/ test_failure EXCEPTION; diff --git a/source/ut_config.pkb b/source/ut_config.pkb index f7a42bab6..86609a7d4 100644 --- a/source/ut_config.pkb +++ b/source/ut_config.pkb @@ -1,4 +1,4 @@ -CREATE OR REPLACE PACKAGE BODY Utconfig +CREATE OR REPLACE PACKAGE BODY utconfig IS /************************************************************************ GNU General Public License for utPLSQL @@ -22,6 +22,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + Revision 1.2 2003/07/01 19:36:46 chrisrimmer Added Standard Headers @@ -45,9 +48,9 @@ Added Standard Headers -- Get the configuration record for a user from the table ---------------------------------------------------------------------------- FUNCTION config (username_in IN VARCHAR2 := USER) - RETURN UT_CONFIG%ROWTYPE + RETURN ut_config%ROWTYPE IS - rec UT_CONFIG%ROWTYPE; + rec ut_config%ROWTYPE; BEGIN --Short cut for current user IF username_in = tester @@ -81,33 +84,33 @@ Added Standard Headers ,username_in IN VARCHAR2 := NULL ) IS - &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; &start_ge_8_1 --Local procedure to do dynamic SQL PROCEDURE do_dml (statement_in IN VARCHAR2) IS - &start73 cursor_handle INTEGER; &end73 - &start73 ROWS INTEGER; &end73 + &start_lt_8 cursor_handle INTEGER; &end_lt_8 + &start_lt_8 rows INTEGER; &end_lt_8 BEGIN --In 8i, just do it - &start81 EXECUTE IMMEDIATE statement_in; COMMIT; &end81 + &start_ge_8_1 EXECUTE IMMEDIATE statement_in; COMMIT; &start_ge_8_1 --Otherwise use DBMS_SQL - &start73 + &start_lt_8 --Open the cursor - cursor_handle := DBMS_SQL.OPEN_CURSOR; + cursor_handle := DBMS_SQL.open_cursor; -- Parse the Statement - DBMS_SQL.PARSE (cursor_handle, statement_in, DBMS_SQL.native); + DBMS_SQL.parse (cursor_handle, statement_in, DBMS_SQL.native); -- Execute the Statement ROWS := DBMS_SQL.EXECUTE (cursor_handle); -- Close the cursor - DBMS_SQL.CLOSE_CURSOR (cursor_handle); + DBMS_SQL.close_cursor (cursor_handle); EXCEPTION WHEN OTHERS THEN - DBMS_SQL.CLOSE_CURSOR (cursor_handle); + DBMS_SQL.close_cursor (cursor_handle); RAISE; - &end73 + &end_lt_8 END; BEGIN BEGIN @@ -139,11 +142,11 @@ Added Standard Headers THEN --Something else went wrong UtOutputreporter.pl (SQLERRM); - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RETURN; END; - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 --If it's the current user, force update of package record IF username_in = tester @@ -224,7 +227,7 @@ Added Standard Headers RETURN VARCHAR2 IS --Holds the user's config record - rec UT_CONFIG%ROWTYPE; + rec ut_config%ROWTYPE; --Holds the username in question v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); BEGIN @@ -301,7 +304,7 @@ Added Standard Headers PROCEDURE autocompile (onoff_in IN BOOLEAN, username_in IN VARCHAR2 := NULL) IS --Holds the flag as 'Y'/'N' - v_autocompile CHAR (1) := Utplsql.bool2vc (onoff_in); + v_autocompile CHAR (1) := utplsql.bool2vc (onoff_in); --Holds the user to set v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); BEGIN @@ -323,7 +326,7 @@ Added Standard Headers --Pull in the configuration rec := config (v_user); --Return autocompile, defaulting to TRUE if NULL - RETURN NVL (Utplsql.vc2bool (rec.autocompile), TRUE); + RETURN NVL (utplsql.vc2bool (rec.autocompile), TRUE); END; ---------------------------------------------------------------------------- @@ -333,7 +336,7 @@ Added Standard Headers := NULL) IS --Holds the flag as 'Y'/'N' - v_registertest CHAR (1) := Utplsql.bool2vc (onoff_in); + v_registertest CHAR (1) := utplsql.bool2vc (onoff_in); --Holds the username in question v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); BEGIN @@ -355,7 +358,7 @@ Added Standard Headers --Pull in the configuration rec := config (v_user); --Return registertest, defaulting to FALSE if NULL - RETURN NVL (Utplsql.vc2bool (rec.registertest), FALSE); + RETURN NVL (utplsql.vc2bool (rec.registertest), FALSE); END; -- Show failures only? @@ -365,7 +368,7 @@ Added Standard Headers ) IS --Holds the flag as 'Y'/'N' - v_showfailuresonly CHAR (1) := Utplsql.bool2vc (onoff_in); + v_showfailuresonly CHAR (1) := utplsql.bool2vc (onoff_in); --Holds the username in question v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); @@ -385,7 +388,7 @@ Added Standard Headers --Pull in the configuration rec := config (v_user); --Return show_failures_only, defaulting to FALSE if NULL - RETURN NVL (Utplsql.vc2bool (rec.show_failures_only), FALSE); + RETURN NVL (utplsql.vc2bool (rec.show_failures_only), FALSE); END; -- RMM start @@ -495,7 +498,7 @@ Added Standard Headers ) IS --Holds the flag as 'Y'/'N' - v_incname CHAR (1) := Utplsql.bool2vc (incname_in); + v_incname CHAR (1) := utplsql.bool2vc (incname_in); --Holds the user to set v_user VARCHAR2 (100) := NVL (UPPER (username_in), tester); BEGIN @@ -517,7 +520,7 @@ Added Standard Headers --Pull in the configuration rec := config (v_user); --Return autocompile, defaulting to TRUE if NULL - RETURN NVL (Utplsql.vc2bool (rec.fileincprogname), FALSE); + RETURN NVL (utplsql.vc2bool (rec.fileincprogname), FALSE); END; ---------------------------------------------------------------------------- @@ -642,7 +645,7 @@ Added Standard Headers ,editor_in IN ut_config.editor%TYPE ) IS - &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; &start_ge_8_1 BEGIN INSERT INTO ut_config (username, autocompile, prefix @@ -653,7 +656,7 @@ Added Standard Headers ,show_failures_only_in, directory_in, filedir_in ,show_config_info_in, editor_in ); - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 EXCEPTION WHEN DUP_VAL_ON_INDEX THEN @@ -668,7 +671,7 @@ Added Standard Headers WHERE username = username_in; WHEN OTHERS THEN - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 NULL; -- Present to assist in formatting END; diff --git a/source/ut_config.pks b/source/ut_config.pks index 4424fc858..346523bf7 100644 --- a/source/ut_config.pks +++ b/source/ut_config.pks @@ -1,4 +1,4 @@ -CREATE OR REPLACE PACKAGE Utconfig &start81 AUTHID CURRENT_USER &end81 +CREATE OR REPLACE PACKAGE utconfig &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.4 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + Revision 1.3 2003/07/01 19:36:46 chrisrimmer Added Standard Headers @@ -61,7 +64,7 @@ Added Standard Headers SELECT owner, object_name, object_type, created, last_ddl_time, status FROM all_objects; - CURSOR source_cur + cursor source_cur IS SELECT line, text FROM all_source; @@ -205,14 +208,14 @@ Added Standard Headers -- 2.1.1: Single update and insert procedure PROCEDURE upd ( - username_in IN UT_CONFIG.username%TYPE - ,autocompile_in IN UT_CONFIG.autocompile%TYPE - ,prefix_in IN UT_CONFIG.prefix%TYPE - ,show_failures_only_in IN UT_CONFIG.show_failures_only%TYPE - ,directory_in IN UT_CONFIG.DIRECTORY%TYPE - ,filedir_in IN UT_CONFIG.filedir%TYPE - ,show_config_info_in IN UT_CONFIG.show_config_info%TYPE - ,editor_in IN UT_CONFIG.editor%TYPE + username_in IN ut_config.username%TYPE + ,autocompile_in IN ut_config.autocompile%TYPE + ,prefix_in IN ut_config.prefix%TYPE + ,show_failures_only_in IN ut_config.show_failures_only%TYPE + ,directory_in IN ut_config.DIRECTORY%TYPE + ,filedir_in IN ut_config.filedir%TYPE + ,show_config_info_in IN ut_config.show_config_info%TYPE + ,editor_in IN ut_config.editor%TYPE ); /* The upd procedure does an insert if no row exists. @@ -261,13 +264,13 @@ Added Standard Headers PROCEDURE get_onerow ( schema_in IN VARCHAR2 ,username_out OUT VARCHAR2 - ,autocompile_out OUT UT_CONFIG.autocompile%TYPE - ,prefix_out OUT UT_CONFIG.prefix%TYPE - ,show_failures_only_out OUT UT_CONFIG.show_failures_only%TYPE - ,directory_out OUT UT_CONFIG.DIRECTORY%TYPE - ,filedir_out OUT UT_CONFIG.filedir%TYPE - ,show_config_info_out OUT UT_CONFIG.show_config_info%TYPE - ,editor_out OUT UT_CONFIG.editor%TYPE + ,autocompile_out OUT ut_config.autocompile%TYPE + ,prefix_out OUT ut_config.prefix%TYPE + ,show_failures_only_out OUT ut_config.show_failures_only%TYPE + ,directory_out OUT ut_config.DIRECTORY%TYPE + ,filedir_out OUT ut_config.filedir%TYPE + ,show_config_info_out OUT ut_config.show_config_info%TYPE + ,editor_out OUT ut_config.editor%TYPE ); END; / diff --git a/source/ut_filereporter.pkb b/source/ut_filereporter.pkb index a5ac827e8..3fe330bdb 100644 --- a/source/ut_filereporter.pkb +++ b/source/ut_filereporter.pkb @@ -22,7 +22,10 @@ You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ -$Log$ +$Log$ +Revision 1.1 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + ************************************************************************/ diff --git a/source/ut_filereporter.pks b/source/ut_filereporter.pks index f94fcd766..2ecc30a4a 100644 --- a/source/ut_filereporter.pks +++ b/source/ut_filereporter.pks @@ -1,4 +1,4 @@ -CREATE OR REPLACE PACKAGE utfilereporter &start81 AUTHID CURRENT_USER &end81 +CREATE OR REPLACE PACKAGE utfilereporter &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ diff --git a/source/ut_gen.pkb b/source/ut_gen.pkb index 67c46f6c7..47d06d9df 100644 --- a/source/ut_gen.pkb +++ b/source/ut_gen.pkb @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.5 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + Revision 1.4 2004/05/11 15:36:58 chrisrimmer Added tweak to cursor from Steven F @@ -195,7 +198,7 @@ Added Standard Headers l_grid grid_tt; CURSOR prog_cur (package_in IN VARCHAR2, program_in IN VARCHAR2) - IS &startnot92 + IS &start_lt_9 SELECT DISTINCT owner, package_name, object_name, overload, object_name || overload full_name @@ -212,8 +215,8 @@ Added Standard Headers AND package_in IS NULL AND object_name = UPPER (program_in) ); - &endnot92 - &start92 + &end_lt_9 + &start_ge_9 SELECT owner, object_name package_name, procedure_name object_name, DECODE ( ROW_NUMBER () OVER (PARTITION BY procedure_name ORDER BY object_name), @@ -239,7 +242,7 @@ Added Standard Headers AND package_in IS NULL AND procedure_name = UPPER (program_in) ); - &end92 + &end_ge_9 CURSOR arg_cur ( schema_in IN VARCHAR2, @@ -299,7 +302,7 @@ Added Standard Headers || '.' || ext), 'W' - &start81 , max_linesize => 32767 &end81 + &start_ge_8_1 , max_linesize => 32767 &start_ge_8_1 ); END IF; END; diff --git a/source/ut_gen.pks b/source/ut_gen.pks index 560ad2e8b..4e4b0d0e6 100644 --- a/source/ut_gen.pks +++ b/source/ut_gen.pks @@ -1,5 +1,5 @@ CREATE OR REPLACE PACKAGE utgen -&start81 AUTHID CURRENT_USER &end81 +&start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:46 chrisrimmer +Added Standard Headers + ************************************************************************/ c_screen CONSTANT PLS_INTEGER := 1; @@ -33,14 +36,14 @@ $Log$ c_delim CONSTANT CHAR (1) := ';'; c_comment CONSTANT CHAR (1) := '#'; c_asis CONSTANT CHAR (1) := '!'; - &start81 SUBTYPE codeline_t IS VARCHAR2(200); &end81 + &start_ge_8_1 SUBTYPE codeline_t IS VARCHAR2(200); &end_ge_8_1 - &start73 + &start_lt_8 v_codeline VARCHAR2 (200); SUBTYPE codeline_t IS v_codeline%TYPE; - &end73 + &end_lt_8 -- Each line in the grid represents a test case -- diff --git a/source/ut_htmlreporter.pkb b/source/ut_htmlreporter.pkb index dca31242e..004985186 100644 --- a/source/ut_htmlreporter.pkb +++ b/source/ut_htmlreporter.pkb @@ -22,7 +22,10 @@ You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ -$Log$ +$Log$ +Revision 1.1 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + ************************************************************************/ diff --git a/source/ut_i_do.sql b/source/ut_i_do.sql index 96d5157e1..a7ebd5cf3 100644 --- a/source/ut_i_do.sql +++ b/source/ut_i_do.sql @@ -44,79 +44,6 @@ select decode('&next_script','ut_i_install','I N S T A L L A T I O N', 'ut_i_uninstall','D E I N S T A L L A T I O N', 'ERROR') col from dual; ------------------------------------------------------ -COLUMN col NOPRINT NEW_VALUE v_orcl_vers - -SELECT SUBSTR(version,1,3) col - FROM product_component_version - WHERE UPPER(PRODUCT) LIKE 'ORACLE7%' - OR UPPER(PRODUCT) LIKE 'PERSONAL ORACLE%' - OR UPPER(PRODUCT) LIKE 'ORACLE8%' - OR UPPER(PRODUCT) LIKE 'ORACLE9%'; - -COLUMN col NOPRINT NEW_VALUE start92 -SELECT DECODE (UPPER('&v_orcl_vers'), - '9.2', '/* Use 9i code! */', - '/* Ignore 9i code') col - FROM dual; - -COLUMN col NOPRINT NEW_VALUE end92 -SELECT DECODE (upper('&v_orcl_vers'), - '9.2', '/* Use 9i code! */', - 'Ignore 9i code */') col - FROM dual; - -COLUMN col NOPRINT NEW_VALUE startnot92 -SELECT DECODE (UPPER('&v_orcl_vers'), - '8.1', '/* Use Non 9i code! */', - '9.0', '/* Use Non 9i code! */', - '9.1', '/* Use Non 9i code! */', - '/* Ignore Non 9i code') col - FROM dual; - -COLUMN col NOPRINT NEW_VALUE endnot92 -SELECT DECODE (UPPER('&v_orcl_vers'), - '8.1', '/* Use Non 9i code! */', - '9.0', '/* Use Non 9i code! */', - '9.1', '/* Use Non 9i code! */', - 'Ignore Non 9i code */') col - FROM dual; - -COLUMN col NOPRINT NEW_VALUE start81 -SELECT DECODE (UPPER('&v_orcl_vers'), - '8.1', '/* Use 8i code! */', - '9.0', '/* Use 8i code! */', - '9.1', '/* Use 8i code! */', - '9.2', '/* Use 8i code! */', - '/* Ignore 8i code') col - FROM dual; - -COLUMN col NOPRINT NEW_VALUE end81 -SELECT DECODE (upper('&v_orcl_vers'), - '8.1', '/* Use 8i code! */', - '9.0', '/* Use 8i code! */', - '9.1', '/* Use 8i code! */', - '9.2', '/* Use 8i code! */', - 'Ignore 8i code */') col - FROM dual; - -COLUMN col NOPRINT NEW_VALUE start73 -SELECT DECODE (UPPER('&v_orcl_vers'), - '8.1', '/* Ignore Oracle7 code! ', - '9.0', '/* Ignore Oracle7 code! ', - '9.1', '/* Ignore Oracle7 code! ', - '9.2', '/* Ignore Oracle7 code! ', - '/* Use Oracle7 code */') col - FROM dual; - -COLUMN col NOPRINT NEW_VALUE end73 -SELECT DECODE (UPPER('&v_orcl_vers'), - '8.1', 'Ignore Oracle7 code! */', - '9.0', 'Ignore Oracle7 code! */', - '9.1', 'Ignore Oracle7 code! */', - '9.2', 'Ignore Oracle7 code! */', - '/* Use Oracle7 code */') col - FROM dual; ------------------------------------------------------- SET TERMOUT ON @@ -144,4 +71,5 @@ PROMPT &line2 PROMPT PROMPT [ &txt_prompt ] +@@ut_i_preprocess @@&next_script diff --git a/source/ut_i_packages.sql b/source/ut_i_packages.sql index 8724d448b..8ab13858c 100644 --- a/source/ut_i_packages.sql +++ b/source/ut_i_packages.sql @@ -30,3 +30,8 @@ @@ut_i_run ut_output.pks @@ut_i_run ut_utoutput.pks + +@@ut_i_run ut_filereporter.pks +@@ut_i_run ut_htmlreporter.pks +@@ut_i_run ut_outputreporter.pks +@@ut_i_run ut_report.pks diff --git a/source/ut_i_packages_b.sql b/source/ut_i_packages_b.sql index ebec03a69..25b2b3389 100644 --- a/source/ut_i_packages_b.sql +++ b/source/ut_i_packages_b.sql @@ -30,3 +30,8 @@ @@ut_i_run ut_output.pkb @@ut_i_run ut_utoutput.pkb + +@@ut_i_run ut_filereporter.pkb +@@ut_i_run ut_htmlreporter.pkb +@@ut_i_run ut_outputreporter.pkb +@@ut_i_run ut_report.pkb diff --git a/source/ut_i_preprocess.sql b/source/ut_i_preprocess.sql new file mode 100644 index 000000000..369ccc6e9 --- /dev/null +++ b/source/ut_i_preprocess.sql @@ -0,0 +1,83 @@ +COLUMN major NOPRINT NEW_VALUE major_v +COLUMN minor NOPRINT NEW_VALUE minor_v + +--Get the major and minor versions + +select major, SUBSTR(minor_version,1,instr(minor_version, '.')-1) minor +from +( + select major, substr(version, length(major)+2) minor_version + from + ( + SELECT SUBSTR(version,1,instr(version, '.')-1) major, version + FROM product_component_version p + WHERE UPPER(PRODUCT) LIKE 'ORACLE%' + OR UPPER(PRODUCT) LIKE 'PERSONAL ORACLE%' + ) +); + +--Flags for 9.x code + +COLUMN col NOPRINT NEW_VALUE start_ge_9 + +SELECT decode(greatest(8, &major_v), 8, '/* < v9 ', '/* >= v9 */') col +FROM dual; + +COLUMN col NOPRINT NEW_VALUE end_ge_9 + +SELECT decode(greatest(8, &major_v), 8, '< v9 */', '/* >= v9 */') col +FROM dual; + +COLUMN col NOPRINT NEW_VALUE start_lt_9 + +SELECT decode(greatest(8, &major_v), 8, '/* < v9 */', '/* >= v9 ') col +FROM dual; + +COLUMN col NOPRINT NEW_VALUE end_lt_9 + +SELECT decode(greatest(8, &major_v), 8, '/* < v9 */', ' >= v9 */') col +FROM dual; + +--Flags for 8.1 code + +COLUMN col NOPRINT NEW_VALUE start_ge_8_1 + +SELECT decode(greatest(8, &major_v+(&minor_v/10)), 8, '/* < v8.1 ', '/* >= v8.1 */') col +FROM dual; + +COLUMN col NOPRINT NEW_VALUE end_ge_8_1 + +SELECT decode(greatest(8, &major_v+(&minor_v/10)), 8, ' < v8.1 */', '/* >= v8.1 */') col +FROM dual; + +COLUMN col NOPRINT NEW_VALUE start_lt_8_1 + +SELECT decode(greatest(8, &major_v+(&minor_v/10)), 8, '/* < v8.1 */', '/* >= v8.1 ') col +FROM dual; + +COLUMN col NOPRINT NEW_VALUE end_lt_8_1 + +SELECT decode(greatest(8, &major_v+(&minor_v/10)), 8, '/* < v8.1 */', ' >= v8.1 */') col +FROM dual; + +--Flags for 8.x code + +COLUMN col NOPRINT NEW_VALUE start_ge_8 + +SELECT decode(greatest(7, &major_v), 7, '/* < v8 ', '/* >= v8 */') col +FROM dual; + +COLUMN col NOPRINT NEW_VALUE end_ge_8 + +SELECT decode(greatest(7, &major_v), 7, ' < v8 */', '/* >= v8 */') col +FROM dual; + +COLUMN col NOPRINT NEW_VALUE start_lt_8 + +SELECT decode(greatest(7, &major_v), 7, '/* < v8 */', '/* >= v8 ') col +FROM dual; + +COLUMN col NOPRINT NEW_VALUE end_lt_8 + +SELECT decode(greatest(7, &major_v), 7, '/* < v8 */', ' >= v8 */') col +FROM dual; diff --git a/source/ut_i_uninstall.sql b/source/ut_i_uninstall.sql index 4c32c1fac..ed49fa2ac 100644 --- a/source/ut_i_uninstall.sql +++ b/source/ut_i_uninstall.sql @@ -25,9 +25,6 @@ drop package UTPLSQL; drop package UTPLSQL_UTIL; drop package UTRECEQ; drop package UTRERROR; -drop package UTREPORT; -drop package UTOUTPUTREPORTER; -drop package UTFILEREPORTER; drop package UTRESULT2; drop package UTRESULT; drop package UTROUTCOME; @@ -43,8 +40,14 @@ drop package UTTESTPREP; drop package UTUNITTEST; drop package UTUTP; +drop package UTFILEREPORTER; +drop package UTHTMLREPORTER; +drop package UTOUTPUTREPORTER; +drop package UTREPORT; + drop package UT_UTOUTPUT; + SET TERMOUT ON PROMPT &line1 PROMPT DROPPING &UT PUBLIC SYNONYMS @@ -82,6 +85,10 @@ drop public synonym UTTESTCASE; drop public synonym UTTESTPREP; drop public synonym UTUNITTEST; drop public synonym UTUTP; +drop public synonym UTFILEREPORTER; +drop public synonym UTHTMLREPORTER; +drop public synonym UTOUTPUTREPORTER; +drop public synonym UTREPORT; drop public synonym UT_ARGUMENT; drop public synonym UT_ASSERTION; drop public synonym UT_CONFIG; @@ -130,14 +137,6 @@ drop sequence UT_TEST_SEQ; drop sequence UT_UNITTEST_SEQ; drop sequence UT_UTP_SEQ; -SET TERMOUT ON -PROMPT &line1 -PROMPT DROPPING &UT VIEWS -PROMPT &line1 - -drop view utv_last_run; -drop view utv_result_full; - SET TERMOUT ON PROMPT &line1 PROMPT DROPPING &UT TABLES @@ -168,3 +167,4 @@ drop table UT_TESTPREP cascade constraints; drop table UT_UNITTEST cascade constraints; drop table UT_UTP cascade constraints; + diff --git a/source/ut_outcome.pkb b/source/ut_outcome.pkb index fd18be095..0d66b278d 100644 --- a/source/ut_outcome.pkb +++ b/source/ut_outcome.pkb @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:46 chrisrimmer +Added Standard Headers + ************************************************************************/ IS diff --git a/source/ut_outcome.pks b/source/ut_outcome.pks index a88fd8a7f..9fdbb0c93 100644 --- a/source/ut_outcome.pks +++ b/source/ut_outcome.pks @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:46 chrisrimmer +Added Standard Headers + ************************************************************************/ c_name CONSTANT CHAR (7) := 'OUTCOME'; diff --git a/source/ut_output.pks b/source/ut_output.pks index 086f2ec82..e0245bacf 100644 --- a/source/ut_output.pks +++ b/source/ut_output.pks @@ -1,5 +1,5 @@ CREATE OR REPLACE PACKAGE utoutput -&start81 AUTHID CURRENT_USER &end81 +&start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:46 chrisrimmer +Added Standard Headers + ************************************************************************/ EMPTY_OUTPUT_BUFFER EXCEPTION; diff --git a/source/ut_outputreporter.pkb b/source/ut_outputreporter.pkb index 356b46966..93707134f 100644 --- a/source/ut_outputreporter.pkb +++ b/source/ut_outputreporter.pkb @@ -22,7 +22,10 @@ You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ -$Log$ +$Log$ +Revision 1.1 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + ************************************************************************/ diff --git a/source/ut_outputreporter.pks b/source/ut_outputreporter.pks index 93dc941b1..201eaaf58 100644 --- a/source/ut_outputreporter.pks +++ b/source/ut_outputreporter.pks @@ -1,4 +1,4 @@ -CREATE OR REPLACE PACKAGE utoutputreporter &start81 AUTHID CURRENT_USER &end81 +CREATE OR REPLACE PACKAGE utoutputreporter &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ diff --git a/source/ut_package.pkb b/source/ut_package.pkb index 5cc55c82d..1b7200c27 100644 --- a/source/ut_package.pkb +++ b/source/ut_package.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + Revision 1.2 2003/07/01 19:36:47 chrisrimmer Added Standard Headers @@ -78,7 +81,7 @@ Added Standard Headers test_overloads_in IN BOOLEAN := FALSE ) IS - &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; &start_ge_8_1 v_owner VARCHAR2 (30) := NVL (owner_in, USER); v_id ut_package.id%TYPE; v_same ut_package.samepackage%TYPE := utplsql.c_yes; @@ -90,8 +93,8 @@ Added Standard Headers v_same := utplsql.c_no; END IF; - &start81 v_id := utplsql.seqval ('ut_package'); &end81 - &start73 SELECT ut_package_seq.NEXTVAL INTO v_id FROM dual; &end73 + &start_ge_8_1 v_id := utplsql.seqval ('ut_package'); &start_ge_8_1 + &start_lt_8 SELECT ut_package_seq.NEXTVAL INTO v_id FROM dual; &end_lt_8 INSERT INTO ut_package (id, suite_id, name, @@ -102,8 +105,8 @@ Added Standard Headers 0, 0); IF id_from_name( UPPER (package_in),owner_in) IS NULL THEN - &start81 v_id := utplsql.seqval ('ut_package'); &end81 - &start73 SELECT ut_package_seq.NEXTVAL INTO v_id FROM dual; &end73 + &start_ge_8_1 v_id := utplsql.seqval ('ut_package'); &start_ge_8_1 + &start_lt_8 SELECT ut_package_seq.NEXTVAL INTO v_id FROM dual; &end_lt_8 INSERT INTO ut_package (id, suite_id, name, @@ -114,13 +117,13 @@ Added Standard Headers 0, 0); - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 END IF; IF add_tests_in THEN -- For each program in ALL_ARGUMENTS, add a test. - &start81 + &start_ge_8_1 -- 8i NDS implementation DECLARE TYPE cv_t IS REF CURSOR; @@ -163,8 +166,8 @@ Added Standard Headers CLOSE cv; END; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 -- 7.3 DBMS_SQL Implementation DECLARE cur PLS_INTEGER := DBMS_SQL.open_cursor; @@ -207,9 +210,9 @@ Added Standard Headers DBMS_SQL.close_cursor (cur); END; - &end73 + &end_lt_8 END IF; - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 EXCEPTION WHEN DUP_VAL_ON_INDEX THEN @@ -221,13 +224,13 @@ Added Standard Headers WHERE owner = UPPER (v_owner) AND name = UPPER (package_in) AND suite_id = suite_in; - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 WHEN OTHERS THEN utreport.pl ( 'Add package error: ' || SQLERRM); - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; END; @@ -263,7 +266,7 @@ Added Standard Headers owner_in IN VARCHAR2 := NULL ) IS - &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; &start_ge_8_1 BEGIN DELETE FROM ut_package WHERE ( suite_id = UPPER (suite_in) @@ -273,13 +276,13 @@ Added Standard Headers ) AND name = UPPER (package_in) AND owner = NVL (UPPER (owner_in), USER); - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 EXCEPTION WHEN OTHERS THEN utreport.pl ( 'Remove package error: ' || SQLERRM); - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; END; @@ -303,7 +306,7 @@ Added Standard Headers ) IS l_status VARCHAR2 (100) := utplsql.c_success; - &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; &start_ge_8_1 v_failure PLS_INTEGER := 0; PROCEDURE do_upd @@ -346,13 +349,13 @@ Added Standard Headers ); do_upd; END IF; - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 EXCEPTION WHEN OTHERS THEN utreport.pl ( 'Update package error: ' || SQLERRM); - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; END; diff --git a/source/ut_package.pks b/source/ut_package.pks index 5da49ce00..dda916ec5 100644 --- a/source/ut_package.pks +++ b/source/ut_package.pks @@ -1,5 +1,5 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ -CREATE OR REPLACE PACKAGE utpackage -- &start81 AUTHID CURRENT_USER &end81 +CREATE OR REPLACE PACKAGE utpackage -- &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ c_success CONSTANT VARCHAR2 (7) := 'SUCCESS'; diff --git a/source/ut_plsql.pkb b/source/ut_plsql.pkb index e674f805e..486a4ef03 100644 --- a/source/ut_plsql.pkb +++ b/source/ut_plsql.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.4 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + Revision 1.3 2004/05/11 15:33:57 chrisrimmer Added 9.2 specific code from Mark Vilrokx @@ -114,16 +117,16 @@ Added Standard Headers DECLARE block VARCHAR2(100) := 'DECLARE obj ' || v_prog || '; BEGIN NULL; END;'; - &start73 + &start_lt_8 cur PLS_INTEGER := DBMS_SQL.open_cursor; fdbk PLS_INTEGER; - &end73 + &end_lt_8 BEGIN - &start81 + &start_ge_8_1 EXECUTE IMMEDIATE block; - &end81 + &start_ge_8_1 - &start73 + &start_lt_8 DBMS_SQL.parse ( cur, block, @@ -133,15 +136,15 @@ Added Standard Headers fdbk := DBMS_SQL.EXECUTE(cur); DBMS_SQL.close_cursor(cur); - &end73 + &end_lt_8 RETURN TRUE; EXCEPTION WHEN OTHERS THEN - &start73 + &start_lt_8 DBMS_SQL.close_cursor(cur); - &end73 + &end_lt_8 RETURN FALSE; END; /* End changes to check if v_prog is an object */ @@ -353,11 +356,11 @@ Added Standard Headers := progname (NAME_IN, testpkg.samepkg, testpkg.prefix); */ v_str VARCHAR2 (32767); - &start73 + &start_lt_8 fdbk PLS_INTEGER; cur PLS_INTEGER := DBMS_SQL.open_cursor; - &end73 + &end_lt_8 BEGIN IF tracing THEN @@ -386,21 +389,21 @@ Added Standard Headers || '.' || v_name || '; END;'; - &start81 + &start_ge_8_1 EXECUTE IMMEDIATE v_str; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 DBMS_SQL.parse (cur, v_str, DBMS_SQL.native); fdbk := DBMS_SQL.EXECUTE (cur); DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 EXCEPTION WHEN OTHERS THEN - &start73 + &start_lt_8 DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 IF tracing THEN @@ -470,11 +473,6 @@ Added Standard Headers ) IS BEGIN - - IF NOT NVL(from_suite_in, FALSE) THEN - utreport.open; - END IF; - init_tests; --Removed test for null as utConfig.prefix never returns null @@ -549,9 +547,9 @@ Added Standard Headers UTL_FILE.fopen ( v_dir, file_in, - 'R' &start81 + 'R' &start_ge_8_1 , - max_linesize=> 32767 &end81 + max_linesize=> 32767 &start_ge_8_1 ); LOOP @@ -734,7 +732,7 @@ Added Standard Headers THEN -- Populate test information from ALL_ARGUMENTS FOR rec IN - &startnot92 + &start_lt_9 (SELECT DISTINCT object_name procedure_name FROM all_arguments WHERE owner = @@ -766,8 +764,8 @@ Added Standard Headers || c_teardown ) )) - &endnot92 - &start92 + &end_lt_9 + &start_ge_9 (SELECT procedure_name FROM all_procedures WHERE owner = NVL (UPPER (owner_in), USER) @@ -786,7 +784,7 @@ Added Standard Headers || c_teardown ) )) - &end92 + &end_ge_9 LOOP addtest ( testpkg_in.pkg, @@ -959,7 +957,6 @@ Added Standard Headers || package_in || '" does not exist.' ); - utreport.close; ELSE setpkg ( package_in, @@ -1089,9 +1086,6 @@ Added Standard Headers v_pkg_start DATE; v_override VARCHAR2 (1000); BEGIN - - utreport.open; - IF v_suite IS NULL THEN utassert.this ( @@ -1152,8 +1146,6 @@ begin ); END IF; - utreport.close; - IF reset_results_in THEN init; @@ -1224,12 +1216,12 @@ begin fdbk PLS_INTEGER; retval PLS_INTEGER; BEGIN - &start81 + &start_ge_8_1 EXECUTE IMMEDIATE sqlstr INTO retval; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 DECLARE fdbk PLS_INTEGER; cur PLS_INTEGER @@ -1251,7 +1243,7 @@ begin RAISE; END; - &end73 + &end_lt_8 RETURN retval; END; diff --git a/source/ut_plsql.pks b/source/ut_plsql.pks index f98c37d98..fb9ea2658 100644 --- a/source/ut_plsql.pks +++ b/source/ut_plsql.pks @@ -1,5 +1,5 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ -CREATE OR REPLACE PACKAGE utplsql &start81 AUTHID CURRENT_USER &end81 +CREATE OR REPLACE PACKAGE utplsql &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ @@ -23,9 +23,9 @@ You should have received a copy of the GNU General Public License along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ -$Log: ut_plsql.pks,v -Revision 1.2 2003/07/01 19:36:47 chrisrimme -Added Standard Header +$Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers ************************************************************************/ @@ -37,13 +37,13 @@ Added Standard Header c_teardown CONSTANT CHAR (8) := 'TEARDOWN'; c_enabled CONSTANT CHAR (7) := 'ENABLED'; c_disabled CONSTANT CHAR (8) := 'DISABLED'; - &start73 + &start_lt_8 dbmaxvc2 VARCHAR2 (2000); - &end73 - &start81 + &end_lt_8 + &start_ge_8_1 dbmaxvc2 VARCHAR2 (4000); - &end81 + &end_ge_8_1 SUBTYPE dbmaxvc2_t IS dbmaxvc2%TYPE; maxvc2 VARCHAR2 (32767); @@ -241,3 +241,4 @@ Added Standard Header RETURN VARCHAR2; END; / + diff --git a/source/ut_plsql2.pkb b/source/ut_plsql2.pkb index f5e823255..6de93bc46 100644 --- a/source/ut_plsql2.pkb +++ b/source/ut_plsql2.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + Revision 1.2 2003/07/01 19:36:47 chrisrimmer Added Standard Headers @@ -146,10 +149,10 @@ Added Standard Headers IS v_name VARCHAR2 (100) := procedure_in; v_str VARCHAR2 (32767); - &start73 + &start_lt_8 fdbk PLS_INTEGER; cur PLS_INTEGER := DBMS_SQL.open_cursor; - &end73 + &end_lt_8 BEGIN IF tracing THEN @@ -171,21 +174,21 @@ Added Standard Headers || ';' ) || ' END;'; - &start81 + &start_ge_8_1 EXECUTE IMMEDIATE v_str; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 DBMS_SQL.parse (cur, v_str, DBMS_SQL.native); fdbk := DBMS_SQL.EXECUTE (cur); DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 EXCEPTION WHEN OTHERS THEN - &start73 + &start_lt_8 DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 IF tracing THEN diff --git a/source/ut_plsql2.pks b/source/ut_plsql2.pks index a76435524..3d7d11ab8 100644 --- a/source/ut_plsql2.pks +++ b/source/ut_plsql2.pks @@ -1,5 +1,5 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ -CREATE OR REPLACE PACKAGE utplsql2 &start81 AUTHID CURRENT_USER &end81 +CREATE OR REPLACE PACKAGE utplsql2 &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ V2_naming_mode constant char(2) := 'V1'; diff --git a/source/ut_plsql_util.pkb b/source/ut_plsql_util.pkb index d0f38c98b..1ce255374 100644 --- a/source/ut_plsql_util.pkb +++ b/source/ut_plsql_util.pkb @@ -22,6 +22,10 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2003/11/21 16:28:44 chrisrimmer +Fixed the commented out preprocessor flags, pointed out by Frank Puechl +in bug 846639 + Revision 1.2 2003/07/01 19:36:47 chrisrimmer Added Standard Headers @@ -963,19 +967,19 @@ AS PROCEDURE execute_ddl (stmt VARCHAR2) IS - &start73 + &start_lt_8 fdbk PLS_INTEGER; cur PLS_INTEGER := DBMS_SQL.open_cursor; - &end73 + &end_lt_8 BEGIN - &start81 + &start_ge_8_1 EXECUTE IMMEDIATE stmt; - &end81 - &start73 + &start_ge_8_1 + &start_lt_8 DBMS_SQL.parse (cur, stmt, DBMS_SQL.native); fdbk := DBMS_SQL.EXECUTE (cur); DBMS_SQL.close_cursor (cur); - &end73 + &end_lt_8 EXCEPTION WHEN OTHERS THEN diff --git a/source/ut_plsql_util.pks b/source/ut_plsql_util.pks index edf3aa0a6..139a15072 100644 --- a/source/ut_plsql_util.pks +++ b/source/ut_plsql_util.pks @@ -1,5 +1,5 @@ CREATE OR REPLACE PACKAGE utplsql_util -&start81 AUTHID CURRENT_USER &end81 +&start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 AS /************************************************************************ @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2003/11/25 13:54:49 chrisrimmer +Added back in AUTHID line + Revision 1.2 2003/07/01 19:36:47 chrisrimmer Added Standard Headers diff --git a/source/ut_receq.pkb b/source/ut_receq.pkb index 513d7b989..5037e47bb 100644 --- a/source/ut_receq.pkb +++ b/source/ut_receq.pkb @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + Revision 1.2 2003/07/01 19:36:47 chrisrimmer Added Standard Headers diff --git a/source/ut_receq.pks b/source/ut_receq.pks index af7bbc7ea..a5d4ca008 100644 --- a/source/ut_receq.pks +++ b/source/ut_receq.pks @@ -1,4 +1,4 @@ -CREATE OR REPLACE PACKAGE utreceq &start81 AUTHID CURRENT_USER &end81 +CREATE OR REPLACE PACKAGE utreceq &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ PROCEDURE add( diff --git a/source/ut_report.pkb b/source/ut_report.pkb index 85fb7c4b5..ba6601353 100644 --- a/source/ut_report.pkb +++ b/source/ut_report.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.1 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + ************************************************************************/ diff --git a/source/ut_report.pks b/source/ut_report.pks index 62129a69c..a6c123d1c 100644 --- a/source/ut_report.pks +++ b/source/ut_report.pks @@ -1,4 +1,4 @@ -CREATE OR REPLACE PACKAGE utreport &start81 AUTHID CURRENT_USER &end81 +CREATE OR REPLACE PACKAGE utreport &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ diff --git a/source/ut_rerror.pkb b/source/ut_rerror.pkb index 04b60833f..a568bf281 100644 --- a/source/ut_rerror.pkb +++ b/source/ut_rerror.pkb @@ -85,9 +85,9 @@ Added Standard Headers ) IS l_message VARCHAR2 (2000); - &start81 + &start_ge_8_1 PRAGMA autonomous_transaction; - &end81 + &start_ge_8_1 BEGIN -- If error already recorded, simply re-raise. @@ -130,22 +130,22 @@ Added Standard Headers END IF; END IF; - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 IF raiseexc THEN raise_error (errcode_in, errtext_in); END IF; - &start81 + &start_ge_8_1 EXCEPTION WHEN OTHERS THEN ROLLBACK; RAISE; - &end81 + &start_ge_8_1 END; PROCEDURE report ( diff --git a/source/ut_rerror.pks b/source/ut_rerror.pks index 2e27ce52c..add3bf61a 100644 --- a/source/ut_rerror.pks +++ b/source/ut_rerror.pks @@ -1,5 +1,5 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ -CREATE OR REPLACE PACKAGE utrerror &start81 AUTHID CURRENT_USER &end81 +CREATE OR REPLACE PACKAGE utrerror &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ diff --git a/source/ut_result.pkb b/source/ut_result.pkb index c98ac8013..e5153c4fc 100644 --- a/source/ut_result.pkb +++ b/source/ut_result.pkb @@ -60,6 +60,7 @@ Added Standard Headers IS indx PLS_INTEGER := results.FIRST; l_id utr_outcome.run_id%TYPE := NVL (run_id_in, utplsql2.runnum); + norows BOOLEAN; BEGIN utreport.before_results(run_id_in); diff --git a/source/ut_result2.pks b/source/ut_result2.pks index 3d10eb474..f9b56e456 100644 --- a/source/ut_result2.pks +++ b/source/ut_result2.pks @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ c_success CONSTANT CHAR (7) := 'SUCCESS'; diff --git a/source/ut_routcome.pkb b/source/ut_routcome.pkb index 3d5d8fe92..fb91d8f8a 100644 --- a/source/ut_routcome.pkb +++ b/source/ut_routcome.pkb @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ PROCEDURE initiate ( @@ -31,9 +34,9 @@ $Log$ , start_on_in IN DATE := SYSDATE ) IS - &start81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; - &end81 + &start_ge_8_1 BEGIN utplsql2.set_current_outcome (outcome_id_in); @@ -43,22 +46,22 @@ $Log$ VALUES (run_id_in, outcome_id_in, start_on_in ); - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 EXCEPTION WHEN DUP_VAL_ON_INDEX THEN -- Run has already been initiated. Ignore... NULL; - &start81 + &start_ge_8_1 ROLLBACK; - &end81 + &start_ge_8_1 WHEN OTHERS THEN - &start81 + &start_ge_8_1 ROLLBACK; - &end81 + &start_ge_8_1 utrerror.oc_report (run_id_in , outcome_id_in , SQLCODE @@ -79,10 +82,10 @@ $Log$ , end_on_in IN DATE := SYSDATE ) IS - &start81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; - &end81 + &start_ge_8_1 CURSOR start_cur (id_in IN utr_outcome.outcome_id%TYPE) IS @@ -128,15 +131,15 @@ $Log$ END IF; CLOSE start_cur; - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 EXCEPTION WHEN OTHERS THEN - &start81 + &start_ge_8_1 ROLLBACK; - &end81 + &start_ge_8_1 utrerror.oc_report (run_id_in , outcome_id_in , SQLCODE @@ -164,16 +167,16 @@ $Log$ PROCEDURE clear_results (run_id_in IN utr_outcome.run_id%TYPE) IS - &start81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; - &end81 + &start_ge_8_1 BEGIN DELETE FROM utr_outcome WHERE run_id = run_id_in; - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 END; PROCEDURE clear_results ( @@ -182,9 +185,9 @@ $Log$ , start_from_in IN DATE ) IS - &start81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; - &end81 + &start_ge_8_1 BEGIN DELETE FROM utr_outcome WHERE start_on >= start_from_in @@ -195,16 +198,16 @@ $Log$ AND u.owner = owner_in AND u.program = program_in); - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 END; PROCEDURE clear_all_but_last (owner_in IN VARCHAR2, program_in IN VARCHAR2) IS - &start81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; - &end81 + &start_ge_8_1 BEGIN DELETE FROM utr_outcome WHERE start_on < @@ -220,9 +223,9 @@ $Log$ WHERE r.utp_id = u.ID AND u.owner = owner_in AND u.program = program_in); - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 END; END utroutcome; / diff --git a/source/ut_routcome.pks b/source/ut_routcome.pks index 0fdabe236..3c474038c 100644 --- a/source/ut_routcome.pks +++ b/source/ut_routcome.pks @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ PROCEDURE RECORD ( diff --git a/source/ut_rsuite.pkb b/source/ut_rsuite.pkb index 87d360f54..1b14112b8 100644 --- a/source/ut_rsuite.pkb +++ b/source/ut_rsuite.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ PROCEDURE initiate ( @@ -32,9 +35,9 @@ $Log$ start_on_in IN DATE := SYSDATE ) IS - &start81 + &start_ge_8_1 PRAGMA autonomous_transaction; - &end81 + &start_ge_8_1 BEGIN utplsql2.set_current_suite (suite_id_in); @@ -43,22 +46,22 @@ $Log$ (run_id, suite_id, start_on) VALUES (run_id_in, suite_id_in, start_on_in); - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 EXCEPTION WHEN DUP_VAL_ON_INDEX THEN -- Run has already been initiated. Ignore... NULL; - &start81 + &start_ge_8_1 ROLLBACK; - &end81 + &start_ge_8_1 WHEN OTHERS THEN - &start81 + &start_ge_8_1 ROLLBACK; - &end81 + &start_ge_8_1 utrerror.suite_report ( run_id_in, suite_id_in, @@ -77,10 +80,10 @@ $Log$ end_on_in IN DATE := SYSDATE ) IS - &start81 + &start_ge_8_1 PRAGMA autonomous_transaction; - &end81 + &start_ge_8_1 CURSOR start_cur IS @@ -115,15 +118,15 @@ $Log$ VALUES (run_id_in, suite_id_in, l_status, end_on_in); END IF; - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 EXCEPTION WHEN OTHERS THEN - &start81 + &start_ge_8_1 ROLLBACK; - &end81 + &start_ge_8_1 utrerror.suite_report ( run_id_in, suite_id_in, diff --git a/source/ut_rsuite.pks b/source/ut_rsuite.pks index 198004755..ad39fe58f 100644 --- a/source/ut_rsuite.pks +++ b/source/ut_rsuite.pks @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ PROCEDURE terminate ( diff --git a/source/ut_rtestcase.pkb b/source/ut_rtestcase.pkb index 93014c548..b86d262db 100644 --- a/source/ut_rtestcase.pkb +++ b/source/ut_rtestcase.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ PROCEDURE initiate ( @@ -32,9 +35,9 @@ $Log$ start_on_in IN DATE := SYSDATE ) IS - &start81 + &start_ge_8_1 PRAGMA autonomous_transaction; - &end81 + &start_ge_8_1 BEGIN INSERT INTO utr_testcase (run_id, testcase_id, start_on) @@ -44,14 +47,14 @@ $Log$ THEN -- Run has already been initiated. Ignore... NULL; - &start81 + &start_ge_8_1 ROLLBACK; - &end81 + &start_ge_8_1 WHEN OTHERS THEN - &start81 + &start_ge_8_1 ROLLBACK; - &end81 + &start_ge_8_1 utrerror.tc_report ( run_id_in, testcase_id_in, @@ -70,10 +73,10 @@ $Log$ end_on_in IN DATE := SYSDATE ) IS - &start81 + &start_ge_8_1 PRAGMA autonomous_transaction; - &end81 + &start_ge_8_1 CURSOR start_cur IS SELECT start_on, end_on @@ -109,15 +112,15 @@ $Log$ CLOSE start_cur; CLOSE start_cur; - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 EXCEPTION WHEN OTHERS THEN - &start81 + &start_ge_8_1 ROLLBACK; - &end81 + &start_ge_8_1 utrerror.oc_report ( run_id_in, testcase_id_in, diff --git a/source/ut_rtestcase.pks b/source/ut_rtestcase.pks index 6608cd32f..bebc37e8b 100644 --- a/source/ut_rtestcase.pks +++ b/source/ut_rtestcase.pks @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ PROCEDURE terminate ( diff --git a/source/ut_runittest.pkb b/source/ut_runittest.pkb index f1a4495f2..c5cfc23f0 100644 --- a/source/ut_runittest.pkb +++ b/source/ut_runittest.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ PROCEDURE initiate ( @@ -32,9 +35,9 @@ $Log$ start_on_in IN DATE := SYSDATE ) IS - &start81 + &start_ge_8_1 PRAGMA autonomous_transaction; - &end81 + &start_ge_8_1 BEGIN utplsql2.set_current_unittest (unittest_id_in); @@ -42,22 +45,22 @@ $Log$ (run_id, unittest_id, start_on) VALUES (run_id_in, unittest_id_in, start_on_in); - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 EXCEPTION WHEN DUP_VAL_ON_INDEX THEN -- Run has already been initiated. Ignore... NULL; - &start81 + &start_ge_8_1 ROLLBACK; - &end81 + &start_ge_8_1 WHEN OTHERS THEN - &start81 + &start_ge_8_1 ROLLBACK; - &end81 + &start_ge_8_1 utrerror.ut_report ( run_id_in, unittest_id_in, @@ -76,10 +79,10 @@ $Log$ end_on_in IN DATE := SYSDATE ) IS - &start81 + &start_ge_8_1 PRAGMA autonomous_transaction; - &end81 + &start_ge_8_1 CURSOR start_cur IS @@ -117,15 +120,15 @@ $Log$ END IF; CLOSE start_cur; - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 EXCEPTION WHEN OTHERS THEN - &start81 + &start_ge_8_1 ROLLBACK; - &end81 + &start_ge_8_1 utrerror.ut_report ( run_id_in, unittest_id_in, diff --git a/source/ut_runittest.pks b/source/ut_runittest.pks index 5cf0752ad..51042bb1f 100644 --- a/source/ut_runittest.pks +++ b/source/ut_runittest.pks @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ PROCEDURE terminate ( diff --git a/source/ut_rutp.pkb b/source/ut_rutp.pkb index 69a386113..cb6bbbd60 100644 --- a/source/ut_rutp.pkb +++ b/source/ut_rutp.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ PROCEDURE initiate ( @@ -32,9 +35,9 @@ $Log$ start_on_in IN DATE := SYSDATE ) IS - &start81 + &start_ge_8_1 PRAGMA autonomous_transaction; - &end81 + &start_ge_8_1 BEGIN utplsql2.set_current_utp (utp_id_in); @@ -43,22 +46,22 @@ $Log$ (run_id, utp_id, start_on) VALUES (run_id_in, utp_id_in, start_on_in); - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 EXCEPTION WHEN DUP_VAL_ON_INDEX THEN -- Run has already been initiated. Ignore... NULL; - &start81 + &start_ge_8_1 ROLLBACK; - &end81 + &start_ge_8_1 WHEN OTHERS THEN - &start81 + &start_ge_8_1 ROLLBACK; - &end81 + &start_ge_8_1 utrerror.utp_report ( run_id_in, utp_id_in, @@ -77,10 +80,10 @@ $Log$ end_on_in IN DATE := SYSDATE ) IS - &start81 + &start_ge_8_1 PRAGMA autonomous_transaction; - &end81 + &start_ge_8_1 CURSOR start_cur IS @@ -116,15 +119,15 @@ $Log$ END IF; CLOSE start_cur; - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 EXCEPTION WHEN OTHERS THEN - &start81 + &start_ge_8_1 ROLLBACK; - &end81 + &start_ge_8_1 utrerror.utp_report ( run_id_in, utp_id_in, @@ -139,16 +142,16 @@ $Log$ PROCEDURE clear_results (run_id_in IN utr_utp.run_id%TYPE) IS - &start81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; - &end81 + &start_ge_8_1 BEGIN DELETE FROM utr_utp WHERE run_id = run_id_in; - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 END; PROCEDURE clear_results ( @@ -157,9 +160,9 @@ $Log$ , start_from_in IN DATE ) IS - &start81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; - &end81 + &start_ge_8_1 BEGIN DELETE FROM utr_utp WHERE start_on >= start_from_in @@ -170,16 +173,16 @@ $Log$ AND u.owner = owner_in AND u.program = program_in); - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 END; PROCEDURE clear_all_but_last (owner_in IN VARCHAR2, program_in IN VARCHAR2) IS - &start81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; - &end81 + &start_ge_8_1 BEGIN DELETE FROM utr_utp WHERE start_on < @@ -194,9 +197,9 @@ $Log$ WHERE r.utp_id = u.ID AND u.owner = owner_in AND u.program = program_in); - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 END; FUNCTION last_run_status (owner_in IN VARCHAR2, program_in IN VARCHAR2) diff --git a/source/ut_rutp.pks b/source/ut_rutp.pks index 57e7eda94..95d5f292e 100644 --- a/source/ut_rutp.pks +++ b/source/ut_rutp.pks @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ PROCEDURE TERMINATE ( diff --git a/source/ut_suite.pkb b/source/ut_suite.pkb index c5fce82bd..ef34a496c 100644 --- a/source/ut_suite.pkb +++ b/source/ut_suite.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.4 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + Revision 1.3 2003/12/23 15:30:53 chrisrimmer Added Jens Schauder's show_suites procedure @@ -87,18 +90,18 @@ Added Standard Headers per_method_setup_in in ut_suite.per_method_setup%type := null ) IS - &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; &start_ge_8_1 v_id ut_suite.id%TYPE; BEGIN utrerror.assert (name_in IS NOT NULL, 'Suite names cannot be null.'); - &start81 v_id := utplsql.seqval ('ut_suite'); &end81 - &start73 SELECT ut_suite_seq.NEXTVAL INTO v_id FROM dual; &end73 + &start_ge_8_1 v_id := utplsql.seqval ('ut_suite'); &start_ge_8_1 + &start_lt_8 SELECT ut_suite_seq.NEXTVAL INTO v_id FROM dual; &end_lt_8 INSERT INTO ut_suite (id, name, description, executions, failures,per_method_setup) VALUES (v_id, UPPER (name_in), desc_in, 0, 0,per_method_setup_in); - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 EXCEPTION WHEN DUP_VAL_ON_INDEX THEN @@ -107,7 +110,7 @@ Added Standard Headers rem (name_in); ADD (name_in, desc_in, per_method_setup_in => per_method_setup_in); ELSE - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; END IF; WHEN OTHERS @@ -115,10 +118,10 @@ Added Standard Headers IF utrerror.uterrcode = utrerror.assertion_failure THEN - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 raise; ELSE - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 utrerror.report_define_error ( c_abbrev, 'Suite ' @@ -130,7 +133,7 @@ Added Standard Headers PROCEDURE rem (id_in IN ut_suite.id%TYPE) IS - &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; &start_ge_8_1 BEGIN -- V1 compatibility DELETE FROM ut_package @@ -141,19 +144,19 @@ Added Standard Headers DELETE FROM ut_suite WHERE id = id_in; - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 EXCEPTION WHEN OTHERS THEN utreport.pl ( 'Remove suite error: ' || SQLERRM); - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; END; PROCEDURE rem (name_in IN ut_suite.name%TYPE) IS - &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; &start_ge_8_1 v_id ut_suite.id%TYPE; BEGIN rem (id_from_name (name_in)); @@ -167,7 +170,7 @@ Added Standard Headers per_method_setup_in in ut_suite.per_method_setup%type := null ) IS - &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; &start_ge_8_1 l_status VARCHAR2 (100) := utplsql.c_success; v_failure PLS_INTEGER := 0; @@ -206,13 +209,13 @@ Added Standard Headers ); do_upd; END IF; - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 EXCEPTION WHEN OTHERS THEN utreport.pl ( 'Update suite error: ' || SQLERRM); - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; END; diff --git a/source/ut_suite.pks b/source/ut_suite.pks index 7fc711c7e..90da3f0c1 100644 --- a/source/ut_suite.pks +++ b/source/ut_suite.pks @@ -1,5 +1,5 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ -CREATE OR REPLACE PACKAGE utsuite -- &start81 AUTHID CURRENT_USER &end81 +CREATE OR REPLACE PACKAGE utsuite -- &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2003/12/23 15:30:54 chrisrimmer +Added Jens Schauder's show_suites procedure + Revision 1.2 2003/07/01 19:36:47 chrisrimmer Added Standard Headers diff --git a/source/ut_suiteutp.pkb b/source/ut_suiteutp.pkb index f285c52dd..7e219032b 100644 --- a/source/ut_suiteutp.pkb +++ b/source/ut_suiteutp.pkb @@ -1,5 +1,5 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ -CREATE OR REPLACE PACKAGE BODY utsuiteutp -- &start81 AUTHID CURRENT_USER &end81 +CREATE OR REPLACE PACKAGE BODY utsuiteutp -- &start_ge_8_1 AUTHID CURRENT_USER &start_ge_8_1 IS /************************************************************************ @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + Revision 1.2 2003/07/01 19:36:47 chrisrimmer Added Standard Headers @@ -96,7 +99,7 @@ Added Standard Headers ,enabled_in IN ut_suite_utp.enabled%TYPE := NULL ) IS - &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; &start_ge_8_1 BEGIN utrerror.assert (suite_id_in IS NOT NULL, 'Suite ID cannot be null.'); utrerror.assert (utp_id_in IS NOT NULL, 'UTP ID cannot be null.'); @@ -104,22 +107,22 @@ Added Standard Headers INSERT INTO ut_suite_utp (suite_id, utp_id, seq, enabled) VALUES (suite_id_in, utp_id_in, seq_in, enabled_in); - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 EXCEPTION WHEN DUP_VAL_ON_INDEX THEN -- already exists. Just ignore. - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 NULL; WHEN OTHERS THEN IF utrerror.uterrcode = utrerror.assertion_failure THEN - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 raise; ELSE - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 utrerror.report_define_error ( c_abbrev, 'Suite ' @@ -135,20 +138,20 @@ Added Standard Headers utp_id_in IN ut_utp.id%TYPE ) IS - &start81 + &start_ge_8_1 PRAGMA autonomous_transaction; - &end81 + &start_ge_8_1 BEGIN DELETE FROM ut_suite_utp WHERE suite_id = suite_id_in AND utp_id = utp_id_in; - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 EXCEPTION WHEN OTHERS THEN utreport.pl ( 'Remove suite-utp error: ' || SQLERRM); - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; END; diff --git a/source/ut_suiteutp.pks b/source/ut_suiteutp.pks index 464e526d7..c6f53df24 100644 --- a/source/ut_suiteutp.pks +++ b/source/ut_suiteutp.pks @@ -1,4 +1,4 @@ -CREATE OR REPLACE PACKAGE utsuiteutp -- &start81 AUTHID CURRENT_USER &end81 +CREATE OR REPLACE PACKAGE utsuiteutp -- &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ c_name CONSTANT CHAR (18) := 'SUITE-UTP PACKAGE'; diff --git a/source/ut_test.pkb b/source/ut_test.pkb index 462b0216c..19747a324 100644 --- a/source/ut_test.pkb +++ b/source/ut_test.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + Revision 1.2 2003/07/01 19:36:47 chrisrimmer Added Standard Headers @@ -68,24 +71,24 @@ Added Standard Headers seq_in IN PLS_INTEGER := NULL ) IS - &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; &start_ge_8_1 v_id ut_test.id%TYPE; BEGIN - &start81 v_id := utplsql.seqval ('ut_test'); &end81 - &start73 SELECT ut_test_seq.NEXTVAL INTO v_id FROM dual; &end73 + &start_ge_8_1 v_id := utplsql.seqval ('ut_test'); &start_ge_8_1 + &start_lt_8 SELECT ut_test_seq.NEXTVAL INTO v_id FROM dual; &end_lt_8 INSERT INTO ut_test (id, package_id, name, description, seq) VALUES (v_id, package_in, UPPER (test_in), desc_in, NVL (seq_in, 1)); - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 EXCEPTION WHEN OTHERS THEN utreport.pl ( 'Add test error: ' || SQLERRM); - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; END; @@ -102,18 +105,18 @@ Added Standard Headers PROCEDURE rem (package_in IN INTEGER, test_in IN VARCHAR2) IS - &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; &start_ge_8_1 BEGIN DELETE FROM ut_test WHERE package_id = package_in AND name LIKE UPPER (test_in); - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 EXCEPTION WHEN OTHERS THEN utreport.pl ( 'Remove test error: ' || SQLERRM); - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; END; @@ -131,7 +134,7 @@ Added Standard Headers successful_in BOOLEAN ) IS - &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; &start_ge_8_1 v_failure PLS_INTEGER := 0; BEGIN IF NOT successful_in @@ -148,13 +151,13 @@ Added Standard Headers + v_failure WHERE package_id = package_in AND name = UPPER (test_in); - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 EXCEPTION WHEN OTHERS THEN utreport.pl ( 'Update test error: ' || SQLERRM); - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; END; diff --git a/source/ut_test.pks b/source/ut_test.pks index e0caf03b8..fdda008e7 100644 --- a/source/ut_test.pks +++ b/source/ut_test.pks @@ -1,5 +1,5 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ -CREATE OR REPLACE PACKAGE uttest -- &start81 AUTHID CURRENT_USER &end81 +CREATE OR REPLACE PACKAGE uttest -- &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ FUNCTION name_from_id (id_in IN ut_test.id%TYPE) diff --git a/source/ut_testcase.pkb b/source/ut_testcase.pkb index 323ecb55e..642dfb50f 100644 --- a/source/ut_testcase.pkb +++ b/source/ut_testcase.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2004/07/14 17:01:57 chrisrimmer +Added first version of pluggable reporter packages + Revision 1.2 2003/07/01 19:36:47 chrisrimmer Added Standard Headers @@ -68,23 +71,23 @@ Added Standard Headers seq_in IN PLS_INTEGER := NULL ) IS - &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; &start_ge_8_1 v_id ut_testcase.id%TYPE; BEGIN - &start81 v_id := utplsql.seqval ('ut_testcase'); &end81 - &start73 SELECT ut_testcase_seq.NEXTVAL INTO v_id FROM dual; &end73 + &start_ge_8_1 v_id := utplsql.seqval ('ut_testcase'); &start_ge_8_1 + &start_lt_8 SELECT ut_testcase_seq.NEXTVAL INTO v_id FROM dual; &end_lt_8 INSERT INTO ut_testcase (id, test_id, name, description, seq) VALUES (v_id, test_in, UPPER (testcase_in), desc_in, NVL (seq_in, 1)); - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 EXCEPTION WHEN OTHERS THEN utreport.pl ( 'Add test error: ' || SQLERRM); - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; END; @@ -101,18 +104,18 @@ Added Standard Headers PROCEDURE rem (test_in IN INTEGER, testcase_in IN VARCHAR2) IS - &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; &start_ge_8_1 BEGIN DELETE FROM ut_testcase WHERE test_id = test_in AND name LIKE UPPER (testcase_in); - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 EXCEPTION WHEN OTHERS THEN utreport.pl ( 'Remove test error: ' || SQLERRM); - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; END; @@ -130,7 +133,7 @@ Added Standard Headers successful_in BOOLEAN ) IS - &start81 PRAGMA AUTONOMOUS_TRANSACTION; &end81 + &start_ge_8_1 PRAGMA AUTONOMOUS_TRANSACTION; &start_ge_8_1 v_failure PLS_INTEGER := 0; BEGIN IF NOT successful_in @@ -147,13 +150,13 @@ Added Standard Headers + v_failure WHERE test_id = test_in AND name = UPPER (testcase_in); - &start81 COMMIT; &end81 + &start_ge_8_1 COMMIT; &start_ge_8_1 EXCEPTION WHEN OTHERS THEN utreport.pl ( 'Update test error: ' || SQLERRM); - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; END; diff --git a/source/ut_testcase.pks b/source/ut_testcase.pks index dc2527480..c0ce414cc 100644 --- a/source/ut_testcase.pks +++ b/source/ut_testcase.pks @@ -1,5 +1,5 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ -CREATE OR REPLACE PACKAGE uttestcase -- &start81 AUTHID CURRENT_USER &end81 +CREATE OR REPLACE PACKAGE uttestcase -- &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ c_name CONSTANT CHAR (9) := 'TEST CASE'; diff --git a/source/ut_testprep.pkb b/source/ut_testprep.pkb index aec5262be..3be4f99e2 100644 --- a/source/ut_testprep.pkb +++ b/source/ut_testprep.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ FUNCTION setup_program (utp_in IN ut_utp%ROWTYPE) diff --git a/source/ut_testprep.pks b/source/ut_testprep.pks index 256867ad4..922da4b9c 100644 --- a/source/ut_testprep.pks +++ b/source/ut_testprep.pks @@ -25,6 +25,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ FUNCTION setup_program (utp_in IN ut_utp%ROWTYPE) diff --git a/source/ut_unittest.pkb b/source/ut_unittest.pkb index 864f0ec23..7ae66a503 100644 --- a/source/ut_unittest.pkb +++ b/source/ut_unittest.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ FUNCTION name ( @@ -115,9 +118,9 @@ FUNCTION full_name ( := NULL ) IS - &start81 + &start_ge_8_1 PRAGMA autonomous_transaction; - &end81 + &start_ge_8_1 l_id ut_unittest.id%TYPE; BEGIN SELECT ut_unittest_seq.NEXTVAL @@ -129,18 +132,18 @@ FUNCTION full_name ( description) VALUES (l_id, UPPER (program_name_in), seq_in, description_in); - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 EXCEPTION WHEN OTHERS THEN IF utrerror.uterrcode = utrerror.assertion_failure THEN - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; ELSE - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 utrerror.report_define_error ( c_abbrev, 'Unittest for ' @@ -159,25 +162,25 @@ FUNCTION full_name ( PROCEDURE rem (id_in IN ut_unittest.id%TYPE) IS - &start81 + &start_ge_8_1 PRAGMA autonomous_transaction; - &end81 + &start_ge_8_1 BEGIN DELETE FROM ut_unittest WHERE id = id_in; - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 EXCEPTION WHEN OTHERS THEN IF utrerror.uterrcode = utrerror.assertion_failure THEN - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; ELSE - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 utrerror.report_define_error ( c_abbrev, 'Unittest ID ' diff --git a/source/ut_unittest.pks b/source/ut_unittest.pks index ff5598358..05e684ff7 100644 --- a/source/ut_unittest.pks +++ b/source/ut_unittest.pks @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ c_name CONSTANT CHAR (9) := 'UNIT TEST'; diff --git a/source/ut_utoutput.pkb b/source/ut_utoutput.pkb index 108d3f790..59e471cf5 100644 --- a/source/ut_utoutput.pkb +++ b/source/ut_utoutput.pkb @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ PROCEDURE clear_buffer diff --git a/source/ut_utoutput.pks b/source/ut_utoutput.pks index 4f5aa81e3..0dbc5f529 100644 --- a/source/ut_utoutput.pks +++ b/source/ut_utoutput.pks @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ PROCEDURE ut_setup; diff --git a/source/ut_utp.pkb b/source/ut_utp.pkb index c7596eb4e..883487408 100644 --- a/source/ut_utp.pkb +++ b/source/ut_utp.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ /* UTP##NNN */ @@ -231,9 +234,9 @@ prefix_out := rec.prefix; id_out OUT ut_utp.id%TYPE ) IS - &start81 + &start_ge_8_1 PRAGMA autonomous_transaction; - &end81 + &start_ge_8_1 l_id ut_utp.id%TYPE; l_program ut_utp.name%type := program_in; BEGIN @@ -256,20 +259,20 @@ prefix_out := rec.prefix; name_in, utp_owner_in, prefix_in ); - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 id_out := l_id; EXCEPTION WHEN OTHERS THEN IF utrerror.uterrcode = utrerror.assertion_failure THEN - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; ELSE - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 utrerror.report_define_error ( c_abbrev, 'UTP for ' @@ -324,25 +327,25 @@ prefix_out := rec.prefix; PROCEDURE rem (id_in IN ut_utp.id%TYPE) IS - &start81 + &start_ge_8_1 PRAGMA autonomous_transaction; - &end81 + &start_ge_8_1 BEGIN DELETE FROM ut_utp WHERE id = id_in; - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 EXCEPTION WHEN OTHERS THEN IF utrerror.uterrcode = utrerror.assertion_failure THEN - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 RAISE; ELSE - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 utrerror.report_define_error (c_abbrev, 'UTP ' || id_in); END IF; @@ -358,9 +361,9 @@ prefix_out := rec.prefix; prefix_in IN ut_utp.prefix%TYPE := NULL ) IS - &start81 + &start_ge_8_1 PRAGMA autonomous_transaction; - &end81 + &start_ge_8_1 l_name ut_utp.name%type := name_in; BEGIN if l_name not like '"%' then l_name := upper (l_name); end if; @@ -372,14 +375,14 @@ prefix_out := rec.prefix; utp_owner = utp_owner_in, prefix = prefix_in where id = id_in; - &start81 + &start_ge_8_1 COMMIT; - &end81 + &start_ge_8_1 EXCEPTION WHEN OTHERS THEN - &start81 ROLLBACK; &end81 + &start_ge_8_1 ROLLBACK; &start_ge_8_1 utrerror.report_define_error ( c_abbrev, 'UTP update for UTP ' diff --git a/source/ut_utp.pks b/source/ut_utp.pks index 8e3a750de..97f09e6a1 100644 --- a/source/ut_utp.pks +++ b/source/ut_utp.pks @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2003/07/01 19:36:47 chrisrimmer +Added Standard Headers + ************************************************************************/ c_name CONSTANT CHAR (18) := 'UNIT TEST PACKAGE'; From ab76168c69d5aa0da5f4e5d10ef413ffbe6a0989 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 23 Nov 2004 14:56:48 +0000 Subject: [PATCH 078/143] Moved dbms_pipe code into its own package. Also changed some preprocessor flags --- source/ut_assert.pkb | 22 +---- source/ut_assert2.pkb | 189 +++++++++++-------------------------- source/ut_config.pkb | 11 ++- source/ut_gen.pks | 7 +- source/ut_i_packages.sql | 6 +- source/ut_i_packages_b.sql | 6 +- source/ut_i_preprocess.sql | 20 ---- source/ut_i_uninstall.sql | 4 +- source/ut_package.pkb | 11 ++- source/ut_pipe.pkb | 97 +++++++++++++++++++ source/ut_pipe.pks | 53 +++++++++++ source/ut_plsql.pkb | 31 +++--- source/ut_plsql.pks | 7 +- source/ut_plsql2.pkb | 15 +-- source/ut_plsql_util.pkb | 11 ++- source/ut_suite.pkb | 5 +- source/ut_test.pkb | 5 +- source/ut_testcase.pkb | 5 +- 18 files changed, 283 insertions(+), 222 deletions(-) create mode 100644 source/ut_pipe.pkb create mode 100644 source/ut_pipe.pks diff --git a/source/ut_assert.pkb b/source/ut_assert.pkb index 0a6c1c1a3..6f0278984 100644 --- a/source/ut_assert.pkb +++ b/source/ut_assert.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.4 2004/11/16 09:46:48 chrisrimmer +Changed to new version detection system. + Revision 1.3 2004/07/14 17:01:57 chrisrimmer Added first version of pluggable reporter packages @@ -34,25 +37,6 @@ Added Standard Headers g_showresults BOOLEAN := FALSE; - -- DBMS_PIPE functionality based on code provided by John Beresniewicz, - -- Savant Corp, in ORACLE BUILT-IN PACKAGES - - -- For pipe equality checking - TYPE msg_rectype IS RECORD ( - item_type INTEGER, - mvc2 VARCHAR2 (4093), - mdt DATE, - mnum NUMBER, - mrid ROWID, - mraw RAW (4093)); - - /* - || msg_tbltype tables can hold an ordered list of - || message items, thus any message can be captured - */ - TYPE msg_tbltype IS TABLE OF msg_rectype - INDEX BY BINARY_INTEGER; - PROCEDURE this ( msg_in IN VARCHAR2, check_this_in IN BOOLEAN, diff --git a/source/ut_assert2.pkb b/source/ut_assert2.pkb index dafe94465..efeccfca4 100644 --- a/source/ut_assert2.pkb +++ b/source/ut_assert2.pkb @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.5 2004/11/16 09:46:48 chrisrimmer +Changed to new version detection system. + Revision 1.4 2004/07/14 17:01:57 chrisrimmer Added first version of pluggable reporter packages @@ -42,25 +45,6 @@ Added Standard Headers c_not_placeholder CONSTANT VARCHAR2 (10) := '#$NOT$#'; - -- DBMS_PIPE functionality based on code provided by John Beresniewicz, - -- Savant Corp, in ORACLE BUILT-IN PACKAGES - - -- For pipe equality checking - TYPE msg_rectype IS RECORD ( - item_type INTEGER, - mvc2 VARCHAR2 (4093), - mdt DATE, - mnum NUMBER, - mrid ROWID, - mraw RAW (4093)); - - /* - || msg_tbltype tables can hold an ordered list of - || message items, thus any message can be captured - */ - TYPE msg_tbltype IS TABLE OF msg_rectype - INDEX BY BINARY_INTEGER; - FUNCTION id (name_in IN ut_assertion.NAME%TYPE) RETURN ut_assertion.id%TYPE IS @@ -700,11 +684,11 @@ Added Standard Headers raise_exc_in IN BOOLEAN := FALSE ) IS - &start_lt_8 + &start_lt_8_1 fdbk PLS_INTEGER; cur PLS_INTEGER := DBMS_SQL.open_cursor; - &end_lt_8 + &end_lt_8_1 ival PLS_INTEGER; /* 2.0.8 suggested replacement below by Chris Rimmer to avoid duplicate column name issues @@ -752,7 +736,7 @@ UNION &start_ge_8_1 EXECUTE IMMEDIATE v_block USING OUT ival; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 DBMS_SQL.parse ( cur, v_block, @@ -771,7 +755,7 @@ UNION ival ); DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 this ( outcome_in, @@ -786,9 +770,9 @@ UNION EXCEPTION WHEN OTHERS THEN - &start_lt_8 + &start_lt_8_1 DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 this ( @@ -1003,11 +987,11 @@ UNION cv cv_t; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 cur PLS_INTEGER := DBMS_SQL.open_cursor; fdbk PLS_INTEGER; - &end_lt_8 + &end_lt_8_1 BEGIN IF utplsql2.tracing @@ -1026,7 +1010,7 @@ UNION FETCH cv INTO l_value; CLOSE cv; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 DBMS_SQL.parse ( cur, check_query_in, @@ -1036,7 +1020,7 @@ UNION fdbk := DBMS_SQL.execute_and_fetch (cur); DBMS_SQL.column_value (cur, 1, l_value); DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 l_success := (l_value = against_value_in) OR ( l_value IS NULL @@ -1095,11 +1079,11 @@ UNION cv cv_t; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 cur PLS_INTEGER := DBMS_SQL.open_cursor; fdbk PLS_INTEGER; - &end_lt_8 + &end_lt_8_1 BEGIN IF utplsql2.tracing @@ -1118,7 +1102,7 @@ UNION FETCH cv INTO l_value; CLOSE cv; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 DBMS_SQL.parse ( cur, check_query_in, @@ -1128,7 +1112,7 @@ UNION fdbk := DBMS_SQL.execute_and_fetch (cur); DBMS_SQL.column_value (cur, 1, l_value); DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 l_success := (l_value = against_value_in) OR ( l_value IS NULL @@ -1196,11 +1180,11 @@ UNION cv cv_t; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 cur PLS_INTEGER := DBMS_SQL.open_cursor; fdbk PLS_INTEGER; - &end_lt_8 + &end_lt_8_1 BEGIN IF utplsql2.tracing @@ -1219,7 +1203,7 @@ UNION FETCH cv INTO l_value; CLOSE cv; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 DBMS_SQL.parse ( cur, check_query_in, @@ -1229,7 +1213,7 @@ UNION fdbk := DBMS_SQL.execute_and_fetch (cur); DBMS_SQL.column_value (cur, 1, l_value); DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 l_success := (l_value = against_value_in) @@ -1479,76 +1463,9 @@ UNION cleanup (FALSE , msg_in => msg_in); END; - PROCEDURE receive_and_unpack ( - pipe_in IN VARCHAR2, - msg_tbl_out OUT msg_tbltype, - pipe_status_out IN OUT PLS_INTEGER - ) - IS - invalid_item_type EXCEPTION; - null_msg_tbl msg_tbltype; - next_item INTEGER; - item_count INTEGER := 0; - BEGIN - pipe_status_out := - DBMS_PIPE.receive_message ( - pipe_in, - TIMEOUT=> 0 - ); - - IF pipe_status_out != 0 - THEN - RAISE invalid_item_type; - END IF; - - LOOP - next_item := DBMS_PIPE.next_item_type; - EXIT WHEN next_item = 0; - item_count := item_count - + 1; - msg_tbl_out (item_count).item_type := - next_item; - - IF next_item = 9 - THEN - DBMS_PIPE.unpack_message ( - msg_tbl_out (item_count).mvc2 - ); - ELSIF next_item = 6 - THEN - DBMS_PIPE.unpack_message ( - msg_tbl_out (item_count).mnum - ); - ELSIF next_item = 11 - THEN - DBMS_PIPE.unpack_message_rowid ( - msg_tbl_out (item_count).mrid - ); - ELSIF next_item = 12 - THEN - DBMS_PIPE.unpack_message ( - msg_tbl_out (item_count).mdt - ); - ELSIF next_item = 23 - THEN - DBMS_PIPE.unpack_message_raw ( - msg_tbl_out (item_count).mraw - ); - ELSE - RAISE invalid_item_type; - END IF; - - next_item := DBMS_PIPE.next_item_type; - END LOOP; - EXCEPTION - WHEN invalid_item_type - THEN - msg_tbl_out := null_msg_tbl; - END receive_and_unpack; - PROCEDURE compare_pipe_tabs ( - tab1 msg_tbltype, - tab2 msg_tbltype, + tab1 utpipe.msg_tbltype, + tab2 utpipe.msg_tbltype, same_out IN OUT BOOLEAN ) IS @@ -1602,8 +1519,8 @@ UNION raise_exc_in IN BOOLEAN := FALSE ) IS - check_tab msg_tbltype; - against_tab msg_tbltype; + check_tab utpipe.msg_tbltype; + against_tab utpipe.msg_tbltype; check_status PLS_INTEGER; against_status PLS_INTEGER; same_message BOOLEAN := FALSE ; @@ -1613,12 +1530,12 @@ UNION BEGIN -- Compare contents of two pipes. LOOP - receive_and_unpack ( + utpipe.receive_and_unpack ( check_this_in, check_tab, check_status ); - receive_and_unpack ( + utpipe.receive_and_unpack ( against_this_in, against_tab, against_status @@ -1695,17 +1612,17 @@ UNION := 'begin :val := ' || str || '; end;'; - &start_lt_8 + &start_lt_8_1 fdbk PLS_INTEGER; cur PLS_INTEGER := DBMS_SQL.open_cursor; - &end_lt_8 + &end_lt_8_1 retval NUMBER; BEGIN &start_ge_8_1 EXECUTE IMMEDIATE sqlstr USING OUT retval; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 DBMS_SQL.parse ( cur, sqlstr, @@ -1714,14 +1631,14 @@ UNION fdbk := DBMS_SQL.EXECUTE (cur); DBMS_SQL.variable_value (cur, 'val', retval); DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 RETURN retval; EXCEPTION WHEN OTHERS THEN - &start_lt_8 + &start_lt_8_1 DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 RAISE; END; @@ -2098,11 +2015,11 @@ UNION bada PLS_INTEGER; badtext VARCHAR2 (32767); null_and_valid BOOLEAN := FALSE ; - &start_lt_8 + &start_lt_8_1 fdbk PLS_INTEGER; cur PLS_INTEGER := DBMS_SQL.open_cursor; - &end_lt_8 + &end_lt_8_1 BEGIN validatecoll ( @@ -2176,7 +2093,7 @@ UNION IN against_startrow_in, IN v_matchrow; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 DBMS_SQL.parse ( cur, dynblock, @@ -2224,7 +2141,7 @@ UNION badtext ); DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 END IF; this ( @@ -2249,9 +2166,9 @@ UNION EXCEPTION WHEN OTHERS THEN --p.l (sqlerrm); - &start_lt_8 + &start_lt_8_1 DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 this ( outcome_in, @@ -2307,11 +2224,11 @@ UNION valid_interim BOOLEAN; invalid_interim_msg VARCHAR2 (4000); null_and_valid BOOLEAN := FALSE ; - &start_lt_8 + &start_lt_8_1 fdbk PLS_INTEGER; cur PLS_INTEGER := DBMS_SQL.open_cursor; - &end_lt_8 + &end_lt_8_1 BEGIN validatecoll ( @@ -2364,7 +2281,7 @@ UNION IN against_startrow_in, IN v_matchrow; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 DBMS_SQL.parse ( cur, dynblock, @@ -2413,7 +2330,7 @@ UNION ); DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 <> this ( @@ -2437,9 +2354,9 @@ UNION EXCEPTION WHEN OTHERS THEN --p.l (sqlerrm); - &start_lt_8 + &start_lt_8_1 DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 this ( outcome_in, @@ -2574,17 +2491,17 @@ UNION || '; WHEN OTHERS THEN :indicator := SQLCODE; END;'; - &start_lt_8 + &start_lt_8_1 cur PLS_INTEGER := DBMS_SQL.open_cursor; ret_val PLS_INTEGER; - &end_lt_8 + &end_lt_8_1 BEGIN --Fire off the dynamic PL/SQL &start_ge_8_1 EXECUTE IMMEDIATE v_block USING OUT l_indicator; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 DBMS_SQL.parse ( cur, v_block, @@ -2598,7 +2515,7 @@ UNION l_indicator ); DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 this ( outcome_in, @@ -2657,17 +2574,17 @@ UNION || ';' || ' ELSE :indicator := SQLCODE; END IF; END;'; - &start_lt_8 + &start_lt_8_1 cur PLS_INTEGER := DBMS_SQL.open_cursor; ret_val PLS_INTEGER; - &end_lt_8 + &end_lt_8_1 BEGIN --Fire off the dynamic PL/SQL &start_ge_8_1 EXECUTE IMMEDIATE v_block USING OUT l_indicator; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 DBMS_SQL.parse ( cur, v_block, @@ -2681,7 +2598,7 @@ UNION l_indicator ); DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 this ( outcome_in, diff --git a/source/ut_config.pkb b/source/ut_config.pkb index 86609a7d4..bce80c178 100644 --- a/source/ut_config.pkb +++ b/source/ut_config.pkb @@ -22,6 +22,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.4 2004/11/16 09:46:48 chrisrimmer +Changed to new version detection system. + Revision 1.3 2004/07/14 17:01:57 chrisrimmer Added first version of pluggable reporter packages @@ -89,14 +92,14 @@ Added Standard Headers --Local procedure to do dynamic SQL PROCEDURE do_dml (statement_in IN VARCHAR2) IS - &start_lt_8 cursor_handle INTEGER; &end_lt_8 - &start_lt_8 rows INTEGER; &end_lt_8 + &start_lt_8_1 cursor_handle INTEGER; &end_lt_8_1 + &start_lt_8_1 rows INTEGER; &end_lt_8_1 BEGIN --In 8i, just do it &start_ge_8_1 EXECUTE IMMEDIATE statement_in; COMMIT; &start_ge_8_1 --Otherwise use DBMS_SQL - &start_lt_8 + &start_lt_8_1 --Open the cursor cursor_handle := DBMS_SQL.open_cursor; -- Parse the Statement @@ -110,7 +113,7 @@ Added Standard Headers THEN DBMS_SQL.close_cursor (cursor_handle); RAISE; - &end_lt_8 + &end_lt_8_1 END; BEGIN BEGIN diff --git a/source/ut_gen.pks b/source/ut_gen.pks index 4e4b0d0e6..6d6aad631 100644 --- a/source/ut_gen.pks +++ b/source/ut_gen.pks @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.3 2004/11/16 09:46:49 chrisrimmer +Changed to new version detection system. + Revision 1.2 2003/07/01 19:36:46 chrisrimmer Added Standard Headers @@ -38,12 +41,12 @@ Added Standard Headers c_asis CONSTANT CHAR (1) := '!'; &start_ge_8_1 SUBTYPE codeline_t IS VARCHAR2(200); &end_ge_8_1 - &start_lt_8 + &start_lt_8_1 v_codeline VARCHAR2 (200); SUBTYPE codeline_t IS v_codeline%TYPE; - &end_lt_8 + &end_lt_8_1 -- Each line in the grid represents a test case -- diff --git a/source/ut_i_packages.sql b/source/ut_i_packages.sql index 8ab13858c..961fed50f 100644 --- a/source/ut_i_packages.sql +++ b/source/ut_i_packages.sql @@ -28,10 +28,10 @@ @@ut_i_run ut_rerror.pks @@ut_i_run ut_receq.pks @@ut_i_run ut_output.pks - -@@ut_i_run ut_utoutput.pks - @@ut_i_run ut_filereporter.pks @@ut_i_run ut_htmlreporter.pks @@ut_i_run ut_outputreporter.pks @@ut_i_run ut_report.pks +@@ut_i_run ut_pipe.pks + +@@ut_i_run ut_utoutput.pks diff --git a/source/ut_i_packages_b.sql b/source/ut_i_packages_b.sql index 25b2b3389..9d565a884 100644 --- a/source/ut_i_packages_b.sql +++ b/source/ut_i_packages_b.sql @@ -28,10 +28,10 @@ @@ut_i_run ut_rerror.pkb @@ut_i_run ut_receq.pkb @@ut_i_run ut_output.pkb - -@@ut_i_run ut_utoutput.pkb - @@ut_i_run ut_filereporter.pkb @@ut_i_run ut_htmlreporter.pkb @@ut_i_run ut_outputreporter.pkb @@ut_i_run ut_report.pkb +@@ut_i_run ut_pipe.pkb + +@@ut_i_run ut_utoutput.pkb diff --git a/source/ut_i_preprocess.sql b/source/ut_i_preprocess.sql index 369ccc6e9..f58778994 100644 --- a/source/ut_i_preprocess.sql +++ b/source/ut_i_preprocess.sql @@ -60,24 +60,4 @@ COLUMN col NOPRINT NEW_VALUE end_lt_8_1 SELECT decode(greatest(8, &major_v+(&minor_v/10)), 8, '/* < v8.1 */', ' >= v8.1 */') col FROM dual; ---Flags for 8.x code -COLUMN col NOPRINT NEW_VALUE start_ge_8 - -SELECT decode(greatest(7, &major_v), 7, '/* < v8 ', '/* >= v8 */') col -FROM dual; - -COLUMN col NOPRINT NEW_VALUE end_ge_8 - -SELECT decode(greatest(7, &major_v), 7, ' < v8 */', '/* >= v8 */') col -FROM dual; - -COLUMN col NOPRINT NEW_VALUE start_lt_8 - -SELECT decode(greatest(7, &major_v), 7, '/* < v8 */', '/* >= v8 ') col -FROM dual; - -COLUMN col NOPRINT NEW_VALUE end_lt_8 - -SELECT decode(greatest(7, &major_v), 7, '/* < v8 */', ' >= v8 */') col -FROM dual; diff --git a/source/ut_i_uninstall.sql b/source/ut_i_uninstall.sql index ed49fa2ac..e8f464807 100644 --- a/source/ut_i_uninstall.sql +++ b/source/ut_i_uninstall.sql @@ -39,11 +39,11 @@ drop package UTTESTCASE; drop package UTTESTPREP; drop package UTUNITTEST; drop package UTUTP; - drop package UTFILEREPORTER; drop package UTHTMLREPORTER; drop package UTOUTPUTREPORTER; drop package UTREPORT; +drop package UTPIPE; drop package UT_UTOUTPUT; @@ -89,6 +89,7 @@ drop public synonym UTFILEREPORTER; drop public synonym UTHTMLREPORTER; drop public synonym UTOUTPUTREPORTER; drop public synonym UTREPORT; +drop public synonym UTPIPE; drop public synonym UT_ARGUMENT; drop public synonym UT_ASSERTION; drop public synonym UT_CONFIG; @@ -106,7 +107,6 @@ drop public synonym UT_TEST; drop public synonym UT_TESTCASE; drop public synonym UT_TESTPREP; drop public synonym UT_UNITTEST; -drop public synonym UT_UTOUTPUT; drop public synonym UT_UTP; drop public synonym UTPLSQL_RUNNUM_SEQ; drop public synonym UT_ASSERTION_SEQ; diff --git a/source/ut_package.pkb b/source/ut_package.pkb index 1b7200c27..e1362b7b5 100644 --- a/source/ut_package.pkb +++ b/source/ut_package.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.4 2004/11/16 09:46:49 chrisrimmer +Changed to new version detection system. + Revision 1.3 2004/07/14 17:01:57 chrisrimmer Added first version of pluggable reporter packages @@ -94,7 +97,7 @@ Added Standard Headers END IF; &start_ge_8_1 v_id := utplsql.seqval ('ut_package'); &start_ge_8_1 - &start_lt_8 SELECT ut_package_seq.NEXTVAL INTO v_id FROM dual; &end_lt_8 + &start_lt_8_1 SELECT ut_package_seq.NEXTVAL INTO v_id FROM dual; &end_lt_8_1 INSERT INTO ut_package (id, suite_id, name, @@ -106,7 +109,7 @@ Added Standard Headers IF id_from_name( UPPER (package_in),owner_in) IS NULL THEN &start_ge_8_1 v_id := utplsql.seqval ('ut_package'); &start_ge_8_1 - &start_lt_8 SELECT ut_package_seq.NEXTVAL INTO v_id FROM dual; &end_lt_8 + &start_lt_8_1 SELECT ut_package_seq.NEXTVAL INTO v_id FROM dual; &end_lt_8_1 INSERT INTO ut_package (id, suite_id, name, @@ -167,7 +170,7 @@ Added Standard Headers END; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 -- 7.3 DBMS_SQL Implementation DECLARE cur PLS_INTEGER := DBMS_SQL.open_cursor; @@ -210,7 +213,7 @@ Added Standard Headers DBMS_SQL.close_cursor (cur); END; - &end_lt_8 + &end_lt_8_1 END IF; &start_ge_8_1 COMMIT; &start_ge_8_1 EXCEPTION diff --git a/source/ut_pipe.pkb b/source/ut_pipe.pkb new file mode 100644 index 000000000..92fd8e62e --- /dev/null +++ b/source/ut_pipe.pkb @@ -0,0 +1,97 @@ +CREATE OR REPLACE PACKAGE BODY UTPIPE +IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2004 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ + +************************************************************************/ + + PROCEDURE receive_and_unpack ( + pipe_in IN VARCHAR2, + msg_tbl_out OUT msg_tbltype, + pipe_status_out IN OUT PLS_INTEGER + ) + IS + invalid_item_type EXCEPTION; + null_msg_tbl msg_tbltype; + next_item INTEGER; + item_count INTEGER := 0; + BEGIN + pipe_status_out := + DBMS_PIPE.receive_message ( + pipe_in, + TIMEOUT=> 0 + ); + + IF pipe_status_out != 0 + THEN + RAISE invalid_item_type; + END IF; + + LOOP + next_item := DBMS_PIPE.next_item_type; + EXIT WHEN next_item = 0; + item_count := item_count + + 1; + msg_tbl_out (item_count).item_type := + next_item; + + IF next_item = 9 + THEN + DBMS_PIPE.unpack_message ( + msg_tbl_out (item_count).mvc2 + ); + ELSIF next_item = 6 + THEN + DBMS_PIPE.unpack_message ( + msg_tbl_out (item_count).mnum + ); + ELSIF next_item = 11 + THEN + DBMS_PIPE.unpack_message_rowid ( + msg_tbl_out (item_count).mrid + ); + ELSIF next_item = 12 + THEN + DBMS_PIPE.unpack_message ( + msg_tbl_out (item_count).mdt + ); + ELSIF next_item = 23 + THEN + DBMS_PIPE.unpack_message_raw ( + msg_tbl_out (item_count).mraw + ); + ELSE + RAISE invalid_item_type; + END IF; + + next_item := DBMS_PIPE.next_item_type; + END LOOP; + EXCEPTION + WHEN invalid_item_type + THEN + msg_tbl_out := null_msg_tbl; + END receive_and_unpack; + +END UTPIPE; +/ \ No newline at end of file diff --git a/source/ut_pipe.pks b/source/ut_pipe.pks new file mode 100644 index 000000000..67f217aa9 --- /dev/null +++ b/source/ut_pipe.pks @@ -0,0 +1,53 @@ +CREATE OR REPLACE PACKAGE UTPIPE +IS + +/************************************************************************ +GNU General Public License for utPLSQL + +Copyright (C) 2000-2004 +Steven Feuerstein and the utPLSQL Project +(steven@stevenfeuerstein.com) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program (see license.txt); if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +************************************************************************ +$Log$ + +************************************************************************/ + + -- DBMS_PIPE functionality based on code provided by John Beresniewicz, + -- Savant Corp, in ORACLE BUILT-IN PACKAGES + + -- For pipe equality checking + TYPE msg_rectype IS RECORD ( + item_type INTEGER, + mvc2 VARCHAR2 (4093), + mdt DATE, + mnum NUMBER, + mrid ROWID, + mraw RAW (4093)); + + /* + || msg_tbltype tables can hold an ordered list of + || message items, thus any message can be captured + */ + TYPE msg_tbltype IS TABLE OF msg_rectype + INDEX BY BINARY_INTEGER; + + PROCEDURE receive_and_unpack(pipe_in IN VARCHAR2, + msg_tbl_out OUT msg_tbltype, + pipe_status_out IN OUT PLS_INTEGER); + +END UTPIPE; +/ \ No newline at end of file diff --git a/source/ut_plsql.pkb b/source/ut_plsql.pkb index 486a4ef03..b7147ef43 100644 --- a/source/ut_plsql.pkb +++ b/source/ut_plsql.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.5 2004/11/16 09:46:49 chrisrimmer +Changed to new version detection system. + Revision 1.4 2004/07/14 17:01:57 chrisrimmer Added first version of pluggable reporter packages @@ -117,16 +120,16 @@ Added Standard Headers DECLARE block VARCHAR2(100) := 'DECLARE obj ' || v_prog || '; BEGIN NULL; END;'; - &start_lt_8 + &start_lt_8_1 cur PLS_INTEGER := DBMS_SQL.open_cursor; fdbk PLS_INTEGER; - &end_lt_8 + &end_lt_8_1 BEGIN &start_ge_8_1 EXECUTE IMMEDIATE block; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 DBMS_SQL.parse ( cur, block, @@ -136,15 +139,15 @@ Added Standard Headers fdbk := DBMS_SQL.EXECUTE(cur); DBMS_SQL.close_cursor(cur); - &end_lt_8 + &end_lt_8_1 RETURN TRUE; EXCEPTION WHEN OTHERS THEN - &start_lt_8 + &start_lt_8_1 DBMS_SQL.close_cursor(cur); - &end_lt_8 + &end_lt_8_1 RETURN FALSE; END; /* End changes to check if v_prog is an object */ @@ -356,11 +359,11 @@ Added Standard Headers := progname (NAME_IN, testpkg.samepkg, testpkg.prefix); */ v_str VARCHAR2 (32767); - &start_lt_8 + &start_lt_8_1 fdbk PLS_INTEGER; cur PLS_INTEGER := DBMS_SQL.open_cursor; - &end_lt_8 + &end_lt_8_1 BEGIN IF tracing THEN @@ -392,18 +395,18 @@ Added Standard Headers &start_ge_8_1 EXECUTE IMMEDIATE v_str; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 DBMS_SQL.parse (cur, v_str, DBMS_SQL.native); fdbk := DBMS_SQL.EXECUTE (cur); DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 EXCEPTION WHEN OTHERS THEN - &start_lt_8 + &start_lt_8_1 DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 IF tracing THEN @@ -1221,7 +1224,7 @@ begin INTO retval; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 DECLARE fdbk PLS_INTEGER; cur PLS_INTEGER @@ -1243,7 +1246,7 @@ begin RAISE; END; - &end_lt_8 + &end_lt_8_1 RETURN retval; END; diff --git a/source/ut_plsql.pks b/source/ut_plsql.pks index fb9ea2658..b74f976eb 100644 --- a/source/ut_plsql.pks +++ b/source/ut_plsql.pks @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.4 2004/11/16 09:46:49 chrisrimmer +Changed to new version detection system. + Revision 1.2 2003/07/01 19:36:47 chrisrimmer Added Standard Headers @@ -37,9 +40,9 @@ Added Standard Headers c_teardown CONSTANT CHAR (8) := 'TEARDOWN'; c_enabled CONSTANT CHAR (7) := 'ENABLED'; c_disabled CONSTANT CHAR (8) := 'DISABLED'; - &start_lt_8 + &start_lt_8_1 dbmaxvc2 VARCHAR2 (2000); - &end_lt_8 + &end_lt_8_1 &start_ge_8_1 dbmaxvc2 VARCHAR2 (4000); diff --git a/source/ut_plsql2.pkb b/source/ut_plsql2.pkb index 6de93bc46..37fbe90d8 100644 --- a/source/ut_plsql2.pkb +++ b/source/ut_plsql2.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.4 2004/11/16 09:46:49 chrisrimmer +Changed to new version detection system. + Revision 1.3 2004/07/14 17:01:57 chrisrimmer Added first version of pluggable reporter packages @@ -149,10 +152,10 @@ Added Standard Headers IS v_name VARCHAR2 (100) := procedure_in; v_str VARCHAR2 (32767); - &start_lt_8 + &start_lt_8_1 fdbk PLS_INTEGER; cur PLS_INTEGER := DBMS_SQL.open_cursor; - &end_lt_8 + &end_lt_8_1 BEGIN IF tracing THEN @@ -177,18 +180,18 @@ Added Standard Headers &start_ge_8_1 EXECUTE IMMEDIATE v_str; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 DBMS_SQL.parse (cur, v_str, DBMS_SQL.native); fdbk := DBMS_SQL.EXECUTE (cur); DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 EXCEPTION WHEN OTHERS THEN - &start_lt_8 + &start_lt_8_1 DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 IF tracing THEN diff --git a/source/ut_plsql_util.pkb b/source/ut_plsql_util.pkb index 1ce255374..dd6d95186 100644 --- a/source/ut_plsql_util.pkb +++ b/source/ut_plsql_util.pkb @@ -22,6 +22,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.4 2004/11/16 09:46:49 chrisrimmer +Changed to new version detection system. + Revision 1.3 2003/11/21 16:28:44 chrisrimmer Fixed the commented out preprocessor flags, pointed out by Frank Puechl in bug 846639 @@ -967,19 +970,19 @@ AS PROCEDURE execute_ddl (stmt VARCHAR2) IS - &start_lt_8 + &start_lt_8_1 fdbk PLS_INTEGER; cur PLS_INTEGER := DBMS_SQL.open_cursor; - &end_lt_8 + &end_lt_8_1 BEGIN &start_ge_8_1 EXECUTE IMMEDIATE stmt; &start_ge_8_1 - &start_lt_8 + &start_lt_8_1 DBMS_SQL.parse (cur, stmt, DBMS_SQL.native); fdbk := DBMS_SQL.EXECUTE (cur); DBMS_SQL.close_cursor (cur); - &end_lt_8 + &end_lt_8_1 EXCEPTION WHEN OTHERS THEN diff --git a/source/ut_suite.pkb b/source/ut_suite.pkb index ef34a496c..2c888d3bc 100644 --- a/source/ut_suite.pkb +++ b/source/ut_suite.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.5 2004/11/16 09:46:49 chrisrimmer +Changed to new version detection system. + Revision 1.4 2004/07/14 17:01:57 chrisrimmer Added first version of pluggable reporter packages @@ -96,7 +99,7 @@ Added Standard Headers utrerror.assert (name_in IS NOT NULL, 'Suite names cannot be null.'); &start_ge_8_1 v_id := utplsql.seqval ('ut_suite'); &start_ge_8_1 - &start_lt_8 SELECT ut_suite_seq.NEXTVAL INTO v_id FROM dual; &end_lt_8 + &start_lt_8_1 SELECT ut_suite_seq.NEXTVAL INTO v_id FROM dual; &end_lt_8_1 INSERT INTO ut_suite (id, name, description, executions, failures,per_method_setup) diff --git a/source/ut_test.pkb b/source/ut_test.pkb index 19747a324..6fc9cb350 100644 --- a/source/ut_test.pkb +++ b/source/ut_test.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.4 2004/11/16 09:46:49 chrisrimmer +Changed to new version detection system. + Revision 1.3 2004/07/14 17:01:57 chrisrimmer Added first version of pluggable reporter packages @@ -75,7 +78,7 @@ Added Standard Headers v_id ut_test.id%TYPE; BEGIN &start_ge_8_1 v_id := utplsql.seqval ('ut_test'); &start_ge_8_1 - &start_lt_8 SELECT ut_test_seq.NEXTVAL INTO v_id FROM dual; &end_lt_8 + &start_lt_8_1 SELECT ut_test_seq.NEXTVAL INTO v_id FROM dual; &end_lt_8_1 INSERT INTO ut_test (id, package_id, name, description, diff --git a/source/ut_testcase.pkb b/source/ut_testcase.pkb index 642dfb50f..e8c214e79 100644 --- a/source/ut_testcase.pkb +++ b/source/ut_testcase.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.4 2004/11/16 09:46:49 chrisrimmer +Changed to new version detection system. + Revision 1.3 2004/07/14 17:01:57 chrisrimmer Added first version of pluggable reporter packages @@ -75,7 +78,7 @@ Added Standard Headers v_id ut_testcase.id%TYPE; BEGIN &start_ge_8_1 v_id := utplsql.seqval ('ut_testcase'); &start_ge_8_1 - &start_lt_8 SELECT ut_testcase_seq.NEXTVAL INTO v_id FROM dual; &end_lt_8 + &start_lt_8_1 SELECT ut_testcase_seq.NEXTVAL INTO v_id FROM dual; &end_lt_8_1 INSERT INTO ut_testcase (id, test_id, name, description, seq) From 965a1feed8b7f6832aba90788bc492c811731a6a Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 23 Nov 2004 15:02:18 +0000 Subject: [PATCH 079/143] Added missing preprocessor flags --- source/ut_pipe.pkb | 7 +++++-- source/ut_pipe.pks | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/source/ut_pipe.pkb b/source/ut_pipe.pkb index 92fd8e62e..c05b8eaad 100644 --- a/source/ut_pipe.pkb +++ b/source/ut_pipe.pkb @@ -1,4 +1,4 @@ -CREATE OR REPLACE PACKAGE BODY UTPIPE +CREATE OR REPLACE PACKAGE BODY UTPIPE &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.1 2004/11/23 14:56:47 chrisrimmer +Moved dbms_pipe code into its own package. Also changed some preprocessor flags + ************************************************************************/ @@ -94,4 +97,4 @@ $Log$ END receive_and_unpack; END UTPIPE; -/ \ No newline at end of file +/ diff --git a/source/ut_pipe.pks b/source/ut_pipe.pks index 67f217aa9..3c1cc340d 100644 --- a/source/ut_pipe.pks +++ b/source/ut_pipe.pks @@ -1,4 +1,4 @@ -CREATE OR REPLACE PACKAGE UTPIPE +CREATE OR REPLACE PACKAGE UTPIPE &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 IS /************************************************************************ @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.1 2004/11/23 14:56:48 chrisrimmer +Moved dbms_pipe code into its own package. Also changed some preprocessor flags + ************************************************************************/ @@ -50,4 +53,4 @@ $Log$ pipe_status_out IN OUT PLS_INTEGER); END UTPIPE; -/ \ No newline at end of file +/ From e9c9bc9fc4d275a052cf3e0279c61b25a346884b Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 23 Nov 2004 15:15:21 +0000 Subject: [PATCH 080/143] Added simple example file --- examples/simple_example.sql | 74 +++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 examples/simple_example.sql diff --git a/examples/simple_example.sql b/examples/simple_example.sql new file mode 100644 index 000000000..3015ab72e --- /dev/null +++ b/examples/simple_example.sql @@ -0,0 +1,74 @@ +create or replace package SIMPLE_EXAMPLE +as + procedure DOUBLE_IT(V IN number,W OUT number); + function TRIPLE_IT(Y IN number) return number; + +end SIMPLE_EXAMPLE; +/ + +create or replace package body SIMPLE_EXAMPLE +as + procedure DOUBLE_IT(V IN number,W OUT number) + IS + BEGIN + W := 2*V; + END DOUBLE_IT; + + function TRIPLE_IT(Y IN number) return number + IS + BEGIN + RETURN 3*Y; + END TRIPLE_IT; + +end SIMPLE_EXAMPLE; +/ + +create or replace package UT_SIMPLE_EXAMPLE +as + procedure UT_SETUP; + procedure UT_TEARDOWN; + + procedure UT_DOUBLE_IT; + procedure UT_TRIPLE_IT; + +end UT_SIMPLE_EXAMPLE; +/ + +create or replace package body UT_SIMPLE_EXAMPLE +as + procedure UT_SETUP + IS + BEGIN + NULL; + END UT_SETUP; + + procedure UT_TEARDOWN + IS + BEGIN + NULL; + END UT_TEARDOWN; + + procedure UT_DOUBLE_IT + IS + A NUMBER; + BEGIN + + SIMPLE_EXAMPLE.DOUBLE_IT(NULL, A); + utAssert.isnull('Null value', A); + + SIMPLE_EXAMPLE.DOUBLE_IT(1, A); + utAssert.eq('Typical value', A, 2); + + END UT_DOUBLE_IT; + + procedure UT_TRIPLE_IT + IS + BEGIN + + utAssert.isnull('Null value', SIMPLE_EXAMPLE.TRIPLE_IT(null)); + utAssert.eq('Typical value', SIMPLE_EXAMPLE.TRIPLE_IT(1), 3); + + END UT_TRIPLE_IT; + +end UT_SIMPLE_EXAMPLE; +/ \ No newline at end of file From 449abe642d0dafcfb19962173f0a2d4cbf45d5f3 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Sun, 28 Nov 2004 20:45:55 +0000 Subject: [PATCH 081/143] Tweaked documentation building scripts --- documentation/src/build_docs.pl | 2 +- documentation/src/clean_html.pl | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/documentation/src/build_docs.pl b/documentation/src/build_docs.pl index 4786a9f8e..03465e012 100755 --- a/documentation/src/build_docs.pl +++ b/documentation/src/build_docs.pl @@ -92,7 +92,7 @@ open OUTPUT, ">$OUTDIR/$map[$index]->[0]" or die "Cannot open $OUTDIR/$map[$index]->[0]"; if ($index != $#map){ - system("clean_html.pl $map[$index]->[0] > $map[$index]->[0].clean"); + system("./clean_html.pl $map[$index]->[0] > $map[$index]->[0].clean"); open INPUT, "$map[$index]->[0].clean" or die "Cannot open $map[$index]->[0].clean"; } diff --git a/documentation/src/clean_html.pl b/documentation/src/clean_html.pl index 9fdec3cba..2c636e7b8 100755 --- a/documentation/src/clean_html.pl +++ b/documentation/src/clean_html.pl @@ -12,7 +12,8 @@ #Make a tag filter object my $tf = HTML::TagFilter->new( - strip_comments => 0); + strip_comments => 0, + skip_xss_protection => 1); #Allow these tags $tf->allow_tags({ title => {none=>[]}, From 6638664ffb1115fc7f85c1406c6d1514bfdb18ca Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Sun, 28 Nov 2004 20:46:43 +0000 Subject: [PATCH 082/143] Began updating docs for version 2.2 --- documentation/src/fourstep.html | 34 ++++++++++++++++----------------- documentation/src/glossreq.html | 18 +++++++++-------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/documentation/src/fourstep.html b/documentation/src/fourstep.html index e0a8b4471..1f33e7ce8 100644 --- a/documentation/src/fourstep.html +++ b/documentation/src/fourstep.html @@ -31,7 +31,6 @@

    Step 1. Install (and Upgrade) utPLSQL.

    • Create a session.
    • Create tables, views, packages and sequences.
    • -
    • Execute the SYS.DBMS_PIPE package.

    The following is an example script submitted by Bill Pribyl, which creates a user "UTP" with sufficient privileges @@ -46,11 +45,10 @@

    Step 1. Install (and Upgrade) utPLSQL.

    drop public synonym to utp; alter user utp quota unlimited on users; + -connect sys as sysdba -grant execute on dbms_pipe to utp; - -

    Note If the schema in question does not have the ability to create and drop public synonyms, you +

    Note If the schema in question does not have the ability to create and drop public synonyms +or execute privilege on DBMS_PIPE, you may get error messages when installing. However, utPLSQL will still function correctly.

    Once you have connected to the schema, run the ut_i_do.sql @@ -63,8 +61,8 @@

    Step 1. Install (and Upgrade) utPLSQL.

    SQL> @ut_i_do install
     
    -

    This file will remove the existing installation of utPLSQL -and then create all tables and packages needed. Note that the installation script +

    This file will create all tables, packages and other objects needed. +Note that the installation script creates some files dynamically using the SPOOL command. For this reason, it is necessary that you have write permission in the directory.

    @@ -341,7 +339,7 @@

    Step 3. Build a test package.

    SQL> @ut_betwnstr.pks
     
    Package created.
     
    SQL> @ut_betwnstr.pkb
     
    Package body created.
    -

    Note: when you run your test, utPLSQL will automatically +

    Note: when you run your test, utPLSQL will by default attempt to recompile your test package to ensure that the latest changes are incorporated into the test. It is still worth doing an initial compile to make sure you built your test properly. You will also need to make sure that UTL_FILE is installed and configured so that your @@ -385,13 +383,19 @@

    Step 4. Run your test.

    Automatic Recompilation of Test Package

    -

    utPLSQL will, by default, recompile your test package code +

    utPLSQL will, by default, attempt to recompile your test package code (which must be put in two files <name>.pks for the package specification -and <name>.pkb for the package body). In order to do this, utPLSQL uses -the UTL_FILE package provided by Oracle to read the source code files and then -compile the code found in those files. Before using UTL_FILE you must configure it for use from within PL/SQL.

    +and <name>.pkb for the package body). This of course assumes that the files +are situated on the same machine as your database. If this is not the case, you can +turn off this functionality by calling utConfig.autocompile +as follows:

    + +
    utConfig.autocompile(false);
    -

    Once you have confirmed that UTL_FILE works in your database instance, you +

    If you do wish to use this functionality, utPLSQL needs +the UTL_FILE package provided by Oracle to read the source code files and then +compile the code found in those files. Before using UTL_FILE you must configure it for use from within PL/SQL. +Once you have confirmed that UTL_FILE works in your database instance, you must tell utPLSQL where the test package is located by calling utPLSQL.setdir. If you do not do this, then utPLSQL will not be able to recompile your test package before each run, and instead will display an error message.

    @@ -402,10 +406,6 @@

    Automatic Recompilation of Test Package

    SQL> exec utplsql.setdir ('e:\utplsql\testall')
    -

    You could also put this program call in your login.sql file -(see the login_sample.sql file) so that you don't have to type that code every -time you start up SQL*Plus (or connect to another session within SQL*Plus).

    -

    Where To Go From Here

    If you proceeded through all four steps, you should now have diff --git a/documentation/src/glossreq.html b/documentation/src/glossreq.html index 4c998a50c..e3af4d796 100644 --- a/documentation/src/glossreq.html +++ b/documentation/src/glossreq.html @@ -51,22 +51,20 @@

    Requirements

    -If you are using Oracle8i, utPLSQL takes advantage +If you are using Oracle8i or above, utPLSQL takes advantage of a number of Oracle8i features, including autonomous transactions, invoker -rights and native dynamic SQL. You can also, however, use utPLSQL on Oracle7 +rights and native dynamic SQL. utPLSQL will however still run on Oracle7 (7.3.4 and above) and Oracle8. Requirements for using utPLSQL include:
    • -The schema owning utPLSQL objects must have EXECUTE authority on the DBMS_PIPE -package, as well as the ability to create tables and packages. +The schema owning utPLSQL objects must have the ability to create tables and packages.

    • -If -you want utPLSQL to automatically recompile test packages for you, you +If you want utPLSQL to automatically recompile test packages for you, you will need to have UTL_FILE installed and configured to read from the directory or directories in which your package source files are located. @@ -74,11 +72,14 @@

    • Optional: -ability to create public synonyms. The installation script will attempt +The Ability to create public synonyms. The installation script will attempt to create public synonyms. If your schema does not hae the authority to do so, these commands will fail, but utPLSQL will still be available for use in the owning schema.

    • +
    • Optional: +Execute privilege on the DBMS_PIPE package. Without this, the UTPIPE package will not compile. +However, this is only required if you want to test data accessed via DBMS_PIPE.

    Requirements for Executing Test Code

    @@ -90,7 +91,7 @@

    If, however, you install utPLSQL in a shared schema and then access it from other schemas, you may need to grant additional privileges to the utPLSQL schema. utPLSQL uses dynamic PL/SQL to run the test code. It therefore requires directly granted EXECUTE privileges on those code elements (both the code to be tested and the test packages) -- or the AUTHID CURRENT_USER -capability of Oracle8i. +capability of Oracle8i and above.

    For Oracle8i and above

    @@ -104,5 +105,6 @@

    For Oracle7 and Oracle8

    + From 1bb09a8fe3a2be47ce42e668e557d2c76d96bdf3 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Sun, 28 Nov 2004 20:48:28 +0000 Subject: [PATCH 083/143] Removed superfluous version number constant --- source/ut_plsql2.pkb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/ut_plsql2.pkb b/source/ut_plsql2.pkb index 37fbe90d8..b894bd1e6 100644 --- a/source/ut_plsql2.pkb +++ b/source/ut_plsql2.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.5 2004/11/23 14:56:48 chrisrimmer +Moved dbms_pipe code into its own package. Also changed some preprocessor flags + Revision 1.4 2004/11/16 09:46:49 chrisrimmer Changed to new version detection system. @@ -36,7 +39,6 @@ Added Standard Headers ************************************************************************/ g_trc BOOLEAN := FALSE; - g_version VARCHAR2 (100) := '1.5.6'; g_current current_test_rt; -- Global state information From 7d919f814482cc5e7836914b6d298f950d197937 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Sun, 28 Nov 2004 20:48:55 +0000 Subject: [PATCH 084/143] Incremented version number --- source/ut_plsql.pkb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/ut_plsql.pkb b/source/ut_plsql.pkb index b7147ef43..00059c1cc 100644 --- a/source/ut_plsql.pkb +++ b/source/ut_plsql.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.6 2004/11/23 14:56:48 chrisrimmer +Moved dbms_pipe code into its own package. Also changed some preprocessor flags + Revision 1.5 2004/11/16 09:46:49 chrisrimmer Changed to new version detection system. @@ -39,7 +42,7 @@ Added Standard Headers ************************************************************************/ g_trc BOOLEAN := FALSE; - g_version VARCHAR2 (100) := '2.1.1'; + g_version VARCHAR2 (100) := '2.2'; tests test_tt; testpkg test_rt; From aed17df9a7cbce87dd320bd22bd7482f1d21d0d6 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 19 Jan 2005 16:10:59 +0000 Subject: [PATCH 085/143] Removed AUTHID clauses from package bodies --- source/ut_pipe.pkb | 5 ++++- source/ut_suiteutp.pkb | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/source/ut_pipe.pkb b/source/ut_pipe.pkb index c05b8eaad..ea79ce522 100644 --- a/source/ut_pipe.pkb +++ b/source/ut_pipe.pkb @@ -1,4 +1,4 @@ -CREATE OR REPLACE PACKAGE BODY UTPIPE &start_ge_8_1 AUTHID CURRENT_USER &end_ge_8_1 +CREATE OR REPLACE PACKAGE BODY UTPIPE IS /************************************************************************ @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2004/11/23 15:02:18 chrisrimmer +Added missing preprocessor flags + Revision 1.1 2004/11/23 14:56:47 chrisrimmer Moved dbms_pipe code into its own package. Also changed some preprocessor flags diff --git a/source/ut_suiteutp.pkb b/source/ut_suiteutp.pkb index 7e219032b..75fe1f102 100644 --- a/source/ut_suiteutp.pkb +++ b/source/ut_suiteutp.pkb @@ -1,5 +1,5 @@ /* Formatted on 2001/07/13 12:29 (RevealNet Formatter v4.4.1) */ -CREATE OR REPLACE PACKAGE BODY utsuiteutp -- &start_ge_8_1 AUTHID CURRENT_USER &start_ge_8_1 +CREATE OR REPLACE PACKAGE BODY utsuiteutp IS /************************************************************************ @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.4 2004/11/16 09:46:49 chrisrimmer +Changed to new version detection system. + Revision 1.3 2004/07/14 17:01:57 chrisrimmer Added first version of pluggable reporter packages From 8769906554410979f71b6ba460f40458b4582562 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Fri, 4 Feb 2005 10:44:33 +0000 Subject: [PATCH 086/143] Removed fileout line which pops up an error. --- source/ut_config.tab | 1 - 1 file changed, 1 deletion(-) diff --git a/source/ut_config.tab b/source/ut_config.tab index c09d79197..e235d1291 100644 --- a/source/ut_config.tab +++ b/source/ut_config.tab @@ -26,6 +26,5 @@ REM 2.1.1 ALTER TABLE UT_CONFIG ADD show_config_info VARCHAR2 (1) DEFAULT 'Y'; ALTER TABLE UT_CONFIG ADD editor VARCHAR2 (1000); -ALTER TABLE UT_CONFIG DROP COLUMN fileout; ALTER TABLE UT_CONFIG ADD reporter VARCHAR2(100); From 691abf2cd0aac3ed09dfe63dcc818e51937e912e Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Thu, 10 Feb 2005 22:42:00 +0000 Subject: [PATCH 087/143] Steven's bug fixes and the addition of null_ok parameter --- source/ut_gen.pkb | 811 ++++++++++++++++++++++++---------------------- source/ut_gen.pks | 180 +++++----- 2 files changed, 510 insertions(+), 481 deletions(-) diff --git a/source/ut_gen.pkb b/source/ut_gen.pkb index 47d06d9df..efd30bd4e 100644 --- a/source/ut_gen.pkb +++ b/source/ut_gen.pkb @@ -4,7 +4,7 @@ IS /************************************************************************ GNU General Public License for utPLSQL -Copyright (C) 2000-2003 +Copyright (C) 2000-2005 Steven Feuerstein and the utPLSQL Project (steven@stevenfeuerstein.com) @@ -23,6 +23,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.6 2004/11/16 09:46:49 chrisrimmer +Changed to new version detection system. + Revision 1.5 2004/07/14 17:01:57 chrisrimmer Added first version of pluggable reporter packages @@ -47,16 +50,15 @@ Added Standard Headers pkgarray code_tt; -- 1.5.6 Generic string parser - TYPE item_tt IS TABLE OF VARCHAR2 (2000) INDEX BY BINARY_INTEGER; PROCEDURE parse_string ( - string_in IN VARCHAR2, - items_out IN OUT item_tt, - delim_in IN VARCHAR2 := ',' + string_in IN VARCHAR2 + , items_out IN OUT item_tt + , delim_in IN VARCHAR2 := ',' ) - IS + IS v_item VARCHAR2 (32767); v_loc PLS_INTEGER; v_startloc PLS_INTEGER := 1; @@ -99,31 +101,30 @@ Added Standard Headers END parse_string; PROCEDURE get_nextline ( - file_in IN UTL_FILE.file_type, - line_out OUT VARCHAR2, - eof_out OUT BOOLEAN + file_in IN UTL_FILE.file_type + , line_out OUT VARCHAR2 + , eof_out OUT BOOLEAN ) IS BEGIN UTL_FILE.get_line (file_in, line_out); - eof_out := FALSE ; + eof_out := FALSE; EXCEPTION WHEN NO_DATA_FOUND THEN line_out := NULL; - eof_out := TRUE ; + eof_out := TRUE; END; -- 1.5.6: add this and rewrite isfunction - FUNCTION return_type ( - schema_in IN VARCHAR2, - package_in IN VARCHAR2, - program_in IN VARCHAR2, - overload_in IN PLS_INTEGER := NULL + schema_in IN VARCHAR2 + , package_in IN VARCHAR2 + , program_in IN VARCHAR2 + , overload_in IN PLS_INTEGER := NULL ) RETURN VARCHAR2 - IS + IS retval all_arguments.data_type%TYPE; BEGIN SELECT data_type @@ -161,32 +162,33 @@ Added Standard Headers END; FUNCTION isfunction ( - schema_in IN VARCHAR2, - package_in IN VARCHAR2, - program_in IN VARCHAR2, - overload_in IN PLS_INTEGER := NULL + schema_in IN VARCHAR2 + , package_in IN VARCHAR2 + , program_in IN VARCHAR2 + , overload_in IN PLS_INTEGER := NULL ) RETURN BOOLEAN IS BEGIN - RETURN (return_type (schema_in, package_in, program_in, overload_in) IS NOT NULL); + RETURN (return_type (schema_in, package_in, program_in, overload_in) IS NOT NULL + ); END; PROCEDURE testpkg ( - package_in IN VARCHAR2, - grid_in IN grid_tt, - program_in IN VARCHAR2 := '%', - samepackage_in IN BOOLEAN := FALSE , - prefix_in IN VARCHAR2 := NULL, - schema_in IN VARCHAR2 := NULL, - output_type_in IN PLS_INTEGER := c_screen, - dir_in IN VARCHAR2 := NULL, - delim_in IN VARCHAR2 := c_delim, - date_format_in IN VARCHAR2 := 'MM/DD/YYYY', - only_if_in_grid_in IN BOOLEAN := FALSE, - override_file_in IN VARCHAR2 := NULL + package_in IN VARCHAR2 + , grid_in IN grid_tt + , program_in IN VARCHAR2 := '%' + , samepackage_in IN BOOLEAN := FALSE + , prefix_in IN VARCHAR2 := NULL + , schema_in IN VARCHAR2 := NULL + , output_type_in IN PLS_INTEGER := c_screen + , dir_in IN VARCHAR2 := NULL + , delim_in IN VARCHAR2 := c_delim + , date_format_in IN VARCHAR2 := 'MM/DD/YYYY' + , only_if_in_grid_in IN BOOLEAN := FALSE + , override_file_in IN VARCHAR2 := NULL ) - IS + IS fid UTL_FILE.file_type; v_ispkg BOOLEAN := utplsql.ispackage (package_in, schema_in); v_dir VARCHAR2 (2000) := NVL (dir_in, utconfig.dir); @@ -245,10 +247,10 @@ Added Standard Headers &end_ge_9 CURSOR arg_cur ( - schema_in IN VARCHAR2, - package_in IN VARCHAR2, - program_in IN VARCHAR2, - overload_in IN PLS_INTEGER + schema_in IN VARCHAR2 + , package_in IN VARCHAR2 + , program_in IN VARCHAR2 + , overload_in IN PLS_INTEGER ) IS SELECT argument_name, data_type @@ -283,27 +285,30 @@ Added Standard Headers g_firstbodyrow := NULL; ELSIF output_type_in = c_file THEN - utassert.this ( - 'Compile error: you must specify a directory with utConfig.setdir!', - v_dir IS NOT NULL, - register_in => FALSE - ); + utassert.this + ('Compile error: you must specify a directory with utConfig.setdir!' + , v_dir IS NOT NULL + , register_in => FALSE + ); IF utplsql.tracing THEN utreport.pl (v_dir || '-' || package_in || '.' || ext); END IF; - fid := UTL_FILE.fopen ( - v_dir, - NVL (override_file_in, - NVL (prefix_in, utconfig.prefix (schema_in)) - || package_in - || '.' - || ext), - 'W' - &start_ge_8_1 , max_linesize => 32767 &start_ge_8_1 - ); + fid := + UTL_FILE.fopen (v_dir + , NVL (override_file_in + , NVL (prefix_in + , utconfig.prefix (schema_in) + ) + || package_in + || '.' + || ext + ) + , 'W' + , max_linesize => 32767 + ); END IF; END; @@ -340,11 +345,11 @@ Added Standard Headers END IF; END; - FUNCTION program_call ( -- 2.0.9.1 switch to whole record - rec IN prog_cur%ROWTYPE, - is_package IN BOOLEAN /* - package_in IN VARCHAR2, - program_in IN VARCHAR2 */ + FUNCTION program_call ( -- 2.0.9.1 switch to whole record + rec IN prog_cur%ROWTYPE + , is_package IN BOOLEAN /* + package_in IN VARCHAR2, + program_in IN VARCHAR2 */ ) RETURN VARCHAR2 IS @@ -357,8 +362,10 @@ Added Standard Headers END IF; END; - PROCEDURE iputline (string_in IN VARCHAR2, indentby_in IN PLS_INTEGER - := 3) + PROCEDURE iputline ( + string_in IN VARCHAR2 + , indentby_in IN PLS_INTEGER := 3 + ) IS BEGIN putline (LPAD (' ', indentby_in, ' ') || string_in); @@ -371,14 +378,14 @@ Added Standard Headers END; FUNCTION include_program ( - NAME_IN IN VARCHAR2, - overload_in IN PLS_INTEGER, - curr_name_in IN VARCHAR2, - curr_overload_in IN PLS_INTEGER + NAME_IN IN VARCHAR2 + , overload_in IN PLS_INTEGER + , curr_name_in IN VARCHAR2 + , curr_overload_in IN PLS_INTEGER ) RETURN BOOLEAN IS - BEGIN + BEGIN RETURN ( UPPER (NAME_IN) = curr_name_in AND ( overload_in = curr_overload_in OR (overload_in = 1 AND curr_overload_in IS NULL) @@ -390,7 +397,7 @@ Added Standard Headers FUNCTION include_program (rec IN prog_cur%ROWTYPE, grid_in IN grid_tt) RETURN BOOLEAN - IS + IS retval BOOLEAN := NOT only_if_in_grid_in; grid_index PLS_INTEGER := grid_in.FIRST; BEGIN @@ -400,14 +407,13 @@ Added Standard Headers LOOP EXIT WHEN grid_index IS NULL; - IF include_program ( - grid_in (grid_index).progname, - grid_in (grid_index).overload, - rec.object_name, - rec.overload - ) + IF include_program (grid_in (grid_index).progname + , grid_in (grid_index).overload + , rec.object_name + , rec.overload + ) THEN - retval := TRUE ; + retval := TRUE; EXIT; ELSE grid_index := grid_in.NEXT (grid_index); @@ -419,10 +425,10 @@ Added Standard Headers END; PROCEDURE generate_setup ( - prefix_in IN VARCHAR2, - schema_in IN VARCHAR2, - objpackage_in IN VARCHAR2, - objprogram_in IN VARCHAR2 + prefix_in IN VARCHAR2 + , schema_in IN VARCHAR2 + , objpackage_in IN VARCHAR2 + , objprogram_in IN VARCHAR2 ) IS BEGIN @@ -438,7 +444,9 @@ Added Standard Headers LOOP IF include_program (rec, grid_in) THEN - iputline (' utPLSQL.addtest (''' || rec.full_name || ''');'); + iputline (' utPLSQL.addtest (''' || rec.full_name + || ''');' + ); END IF; END LOOP; ELSE @@ -466,21 +474,35 @@ Added Standard Headers RETURN SUBSTR (string_in, 1, 1) = c_asis; END; + -- NOK0205: manage null ok argument inclusion + PROCEDURE add_null_ok (grid_in IN grid_rt) + IS + BEGIN + IF grid_in.null_ok = 'Y' + THEN + i6putline (' ,null_ok_in => TRUE'); + ELSIF grid_in.null_ok = 'N' + THEN + i6putline (' ,null_ok_in => FALSE'); + END IF; + END add_null_ok; + PROCEDURE generate_ut_procedure ( - prefix_in IN VARCHAR2, - rec IN prog_cur%ROWTYPE, + prefix_in IN VARCHAR2 + , rec IN prog_cur%ROWTYPE + , /*schema_in IN VARCHAR2, objpackage_in IN VARCHAR2, objprogram_in IN VARCHAR2,*/ grid_in IN grid_tt ) - IS + IS v_isfunction BOOLEAN; v_datatype VARCHAR2 (100); FUNCTION data_value (value_in IN VARCHAR2, type_in IN VARCHAR2) RETURN VARCHAR2 - IS + IS retval VARCHAR2 (2000) := value_in; BEGIN IF is_expression (value_in) @@ -500,39 +522,41 @@ Added Standard Headers retval := value_in; ELSIF type_in LIKE '%DATE%' THEN - retval := 'TO_DATE (''' - || value_in - || ''', ''' - || date_format_in - || ''')'; + retval := + 'TO_DATE (''' + || value_in + || ''', ''' + || date_format_in + || ''')'; END IF; RETURN retval; END; PROCEDURE generate_testcase ( - rec IN prog_cur%ROWTYPE, - isfunction_in IN BOOLEAN, - datatype_in IN VARCHAR2, - grid_in IN grid_rt + rec IN prog_cur%ROWTYPE + , isfunction_in IN BOOLEAN + , datatype_in IN VARCHAR2 + , grid_in IN grid_rt ) - IS + IS l_entries item_tt; PROCEDURE putarg ( - arg_in IN arg_cur%ROWTYPE, - ntharg_in IN PLS_INTEGER + arg_in IN arg_cur%ROWTYPE + , ntharg_in IN PLS_INTEGER ) IS BEGIN IF l_entries.COUNT > 0 THEN - i6putline ( - ' ' - || arg_in.argument_name - || ' => ' - || data_value (l_entries (ntharg_in), arg_in.data_type) - ); + i6putline ( ' ' + || arg_in.argument_name + || ' => ' + || data_value (l_entries (ntharg_in) + , arg_in.data_type + ) + ); ELSE i6putline (' ' || arg_in.argument_name || ' => '''''); END IF; @@ -556,23 +580,25 @@ Added Standard Headers IF isfunction_in THEN - i6putline ( - 'against_this := ' - || data_value (grid_in.return_value, datatype_in) - || ';' - ); + i6putline ( 'against_this := ' + || data_value (grid_in.return_value, datatype_in) + || ';' + ); END IF; i6putline (' '); i6putline ('-- Execute test code' || testname); i6putline (' '); - OPEN arg_cur ( - rec.owner, - rec.package_name, - rec.object_name, - rec.overload - ); - FETCH arg_cur INTO arg; + + OPEN arg_cur (rec.owner + , rec.package_name + , rec.object_name + , rec.overload + ); + + FETCH arg_cur + INTO arg; + noargs := arg_cur%NOTFOUND; IF isfunction_in @@ -582,9 +608,8 @@ Added Standard Headers IF noargs THEN - i6putline ( -- 2.0.9.1: use procedure, not explicit concat. - program_call (rec, v_ispkg) || ';' - ); + i6putline ( -- 2.0.9.1: use procedure, not explicit concat. + program_call (rec, v_ispkg) || ';'); ELSE i6putline (program_call (rec, v_ispkg) || ' ('); @@ -596,7 +621,9 @@ Added Standard Headers WHILE arg_cur%FOUND LOOP putarg (arg, arg_cur%ROWCOUNT); - FETCH arg_cur INTO arg; + + FETCH arg_cur + INTO arg; IF arg_cur%FOUND THEN @@ -608,15 +635,14 @@ Added Standard Headers END IF; CLOSE arg_cur; + i6putline (' '); i6putline ('-- Assert success' || testname); i6putline (' '); - --- Here I should access information in ut_assertion table to dynamically + -- Here I should access information in ut_assertion table to dynamically -- build the call to the utAssert procedure. For now, I will hard code -- for EQ and ISNULL to demonstrate the possibilities. - IF v_isfunction THEN IF grid_in.assertion_type = 'EQ' @@ -624,37 +650,39 @@ Added Standard Headers THEN i6putline ('-- Compare the two values.'); i6putline ('utAssert.eq ('); - i6putline ( - ' ''' - || NVL (grid_in.MESSAGE, 'Test of ' || rec.object_name) - || ''',' - ); + i6putline ( ' ''' + || NVL (grid_in.MESSAGE + , 'Test of ' || rec.object_name + ) + || ''',' + ); i6putline (' check_this,'); i6putline (' against_this'); + add_null_ok (grid_in); i6putline (' );'); ELSIF grid_in.assertion_type = 'ISNULL' THEN i6putline ('-- Check for NULL return value.'); i6putline ('utAssert.isNULL ('); - i6putline ( - ' ''' - || NVL ( - grid_in.MESSAGE, - 'NULL Test for ' || rec.object_name - ) - || ''',' - ); + i6putline ( ' ''' + || NVL (grid_in.MESSAGE + , 'NULL Test for ' || rec.object_name + ) + || ''',' + ); i6putline (' check_this'); i6putline (' );'); END IF; ELSE i6putline ('utAssert.this ('); - i6putline ( - ' ''' - || NVL (grid_in.MESSAGE, 'Test of ' || rec.object_name) - || ''',' - ); + i6putline ( ' ''' + || NVL (grid_in.MESSAGE + , 'Test of ' || rec.object_name + ) + || ''',' + ); i6putline (' '''''); + add_null_ok (grid_in); i6putline (' );'); END IF; @@ -663,31 +691,31 @@ Added Standard Headers END; PROCEDURE generate_testcase ( - rec IN prog_cur%ROWTYPE, - isfunction_in IN BOOLEAN, - datatype_in IN VARCHAR2 + rec IN prog_cur%ROWTYPE + , isfunction_in IN BOOLEAN + , datatype_in IN VARCHAR2 ) - IS + IS l_empty grid_rt; BEGIN generate_testcase (rec, isfunction_in, datatype_in, l_empty); END; BEGIN - v_isfunction := isfunction ( - rec.owner, - rec.package_name, - rec.object_name, - rec.overload - ); + v_isfunction := + isfunction (rec.owner + , rec.package_name + , rec.object_name + , rec.overload + ); IF v_isfunction THEN - v_datatype := return_type ( - rec.owner, - rec.package_name, - rec.object_name, - rec.overload - ); + v_datatype := + return_type (rec.owner + , rec.package_name + , rec.object_name + , rec.overload + ); END IF; iputline ('PROCEDURE ' || prefix_in || rec.full_name); @@ -708,36 +736,36 @@ Added Standard Headers ELSE FOR indx IN grid_in.FIRST .. grid_in.LAST LOOP - generate_testcase ( - rec, - v_isfunction, - v_datatype, - grid_in (indx) - ); + generate_testcase (rec + , v_isfunction + , v_datatype + , grid_in (indx) + ); END LOOP; END IF; iputline ('END ' || v_progprefix || rec.full_name || ';'); putline (''); END; - BEGIN /* MAIN TESTPKG */ - utassert.this ( - 'Invalid target to generate a package: ' || output_type_in, - output_type_in IN (c_string, c_screen, c_file, c_array), - register_in => FALSE - ); - v_pkg := utplsql.pkgname ( - package_in, - samepackage_in, - NVL (prefix_in, utconfig.prefix (schema_in)), - v_ispkg - ); - v_progprefix := utplsql.progname ( - NULL, - samepackage_in, - NVL (prefix_in, utconfig.prefix (schema_in)), - v_ispkg - ); + + BEGIN /* MAIN TESTPKG */ + utassert.this ('Invalid target to generate a package: ' + || output_type_in + , output_type_in IN (c_string, c_screen, c_file, c_array) + , register_in => FALSE + ); + v_pkg := + utplsql.pkgname (package_in + , samepackage_in + , NVL (prefix_in, utconfig.prefix (schema_in)) + , v_ispkg + ); + v_progprefix := + utplsql.progname (NULL + , samepackage_in + , NVL (prefix_in, utconfig.prefix (schema_in)) + , v_ispkg + ); IF v_ispkg THEN @@ -751,7 +779,6 @@ Added Standard Headers setup ('pks'); -- Spit out the package spec - IF samepackage_in THEN putline ('-- START: place in specification of source package'); @@ -782,7 +809,6 @@ Added Standard Headers END IF; -- Spit out the package body into a separate file - IF output_type_in = c_file THEN cleanup; @@ -818,28 +844,25 @@ Added Standard Headers FOR indx IN grid_in.FIRST .. grid_in.LAST LOOP -- should switch to passing in records. - IF include_program ( - grid_in (indx).progname, - grid_in (indx).overload, - rec.object_name, - rec.overload - ) + IF include_program (grid_in (indx).progname + , grid_in (indx).overload + , rec.object_name + , rec.overload + ) THEN - l_grid (indx) := grid_in (indx); + -- NOK0205g - assign to sequential rows, not same indx value + l_grid (l_grid.COUNT + 1) := grid_in (indx); END IF; END LOOP; END IF; - IF l_grid.COUNT > 0 OR NOT NVL (only_if_in_grid_in, FALSE ) + IF l_grid.COUNT > 0 OR NOT NVL (only_if_in_grid_in, FALSE) -- IF l_grid.COUNT > 0 THEN - generate_ut_procedure ( - v_progprefix, - rec, /*schema_in, - rec.package_name, - rec.object_name,*/ - l_grid - ); + generate_ut_procedure (v_progprefix, rec, /*schema_in, + rec.package_name, + rec.object_name,*/ + l_grid); END IF; END LOOP; @@ -855,9 +878,9 @@ Added Standard Headers END testpkg; PROCEDURE clean_up_file_io ( - prog_in IN VARCHAR2, - file_in IN OUT UTL_FILE.file_type, - err_in IN VARCHAR2 := NULL + prog_in IN VARCHAR2 + , file_in IN OUT UTL_FILE.file_type + , err_in IN VARCHAR2 := NULL ) IS BEGIN @@ -870,31 +893,30 @@ Added Standard Headers END; PROCEDURE testpkg ( - package_in IN VARCHAR2, - program_in IN VARCHAR2 := '%', - samepackage_in IN BOOLEAN := FALSE , - prefix_in IN VARCHAR2 := NULL, - schema_in IN VARCHAR2 := NULL, - output_type_in IN PLS_INTEGER := c_screen, - dir_in IN VARCHAR2 := NULL, - override_file_in IN VARCHAR2 := NULL + package_in IN VARCHAR2 + , program_in IN VARCHAR2 := '%' + , samepackage_in IN BOOLEAN := FALSE + , prefix_in IN VARCHAR2 := NULL + , schema_in IN VARCHAR2 := NULL + , output_type_in IN PLS_INTEGER := c_screen + , dir_in IN VARCHAR2 := NULL + , override_file_in IN VARCHAR2 := NULL ) - IS + IS l_grid grid_tt; BEGIN -- pass an empty grid to the engine. - testpkg ( - package_in, - l_grid, - program_in, - samepackage_in, - prefix_in, - schema_in, - output_type_in, - dir_in, - only_if_in_grid_in => FALSE, - override_file_in => override_file_in - ); + testpkg (package_in + , l_grid + , program_in + , samepackage_in + , prefix_in + , schema_in + , output_type_in + , dir_in + , only_if_in_grid_in => FALSE + , override_file_in => override_file_in + ); END; FUNCTION valid_entry (string_in IN VARCHAR2) @@ -905,22 +927,22 @@ Added Standard Headers END; PROCEDURE testpkg_from_file ( - package_in IN VARCHAR2, - gridfile_loc_in IN VARCHAR2, - gridfile_in IN VARCHAR2, - program_in IN VARCHAR2 := '%', - samepackage_in IN BOOLEAN := FALSE , - prefix_in IN VARCHAR2 := NULL, - schema_in IN VARCHAR2 := NULL, - output_type_in IN PLS_INTEGER := c_screen, - dir_in IN VARCHAR2 := NULL, - field_delim_in IN VARCHAR2 := '|', - arg_delim_in IN VARCHAR2 := c_delim, - date_format_in IN VARCHAR2 := 'MM/DD/YYYY', - only_if_in_grid_in IN BOOLEAN := FALSE, - override_file_in IN VARCHAR2 := NULL + package_in IN VARCHAR2 + , gridfile_loc_in IN VARCHAR2 + , gridfile_in IN VARCHAR2 + , program_in IN VARCHAR2 := '%' + , samepackage_in IN BOOLEAN := FALSE + , prefix_in IN VARCHAR2 := NULL + , schema_in IN VARCHAR2 := NULL + , output_type_in IN PLS_INTEGER := c_screen + , dir_in IN VARCHAR2 := NULL + , field_delim_in IN VARCHAR2 := '|' + , arg_delim_in IN VARCHAR2 := c_delim + , date_format_in IN VARCHAR2 := 'MM/DD/YYYY' + , only_if_in_grid_in IN BOOLEAN := FALSE + , override_file_in IN VARCHAR2 := NULL ) - IS + IS c_progname VARCHAR2 (30) := 'testpkg_from_file'; fid UTL_FILE.file_type; l_line VARCHAR2 (1000); @@ -951,20 +973,19 @@ Added Standard Headers END LOOP; clean_up_file_io (c_progname, fid); - testpkg ( - package_in, - l_grid, - program_in, - samepackage_in, - prefix_in, - schema_in, - output_type_in, - dir_in, - arg_delim_in, - date_format_in, - only_if_in_grid_in, - override_file_in => override_file_in - ); + testpkg (package_in + , l_grid + , program_in + , samepackage_in + , prefix_in + , schema_in + , output_type_in + , dir_in + , arg_delim_in + , date_format_in + , only_if_in_grid_in + , override_file_in => override_file_in + ); EXCEPTION WHEN UTL_FILE.invalid_path THEN @@ -993,22 +1014,22 @@ Added Standard Headers END testpkg_from_file; PROCEDURE testpkg_from_string ( - package_in IN VARCHAR2, - grid_in IN VARCHAR2, - program_in IN VARCHAR2 := '%', - samepackage_in IN BOOLEAN := FALSE , - prefix_in IN VARCHAR2 := NULL, - schema_in IN VARCHAR2 := NULL, - output_type_in IN PLS_INTEGER := c_screen, - dir_in IN VARCHAR2 := NULL, - line_delim_in IN VARCHAR := CHR (10), - field_delim_in IN VARCHAR2 := '|', - arg_delim_in IN VARCHAR2 := c_delim, - date_format_in IN VARCHAR2 := 'MM/DD/YYYY', - only_if_in_grid_in IN BOOLEAN := FALSE, - override_file_in IN VARCHAR2 := NULL + package_in IN VARCHAR2 + , grid_in IN VARCHAR2 + , program_in IN VARCHAR2 := '%' + , samepackage_in IN BOOLEAN := FALSE + , prefix_in IN VARCHAR2 := NULL + , schema_in IN VARCHAR2 := NULL + , output_type_in IN PLS_INTEGER := c_screen + , dir_in IN VARCHAR2 := NULL + , line_delim_in IN VARCHAR := CHR (10) + , field_delim_in IN VARCHAR2 := '|' + , arg_delim_in IN VARCHAR2 := c_delim + , date_format_in IN VARCHAR2 := 'MM/DD/YYYY' + , only_if_in_grid_in IN BOOLEAN := FALSE + , override_file_in IN VARCHAR2 := NULL ) - IS + IS c_progname VARCHAR2 (30) := 'testpkg_from_string'; l_line VARCHAR2 (1000); l_lines item_tt; @@ -1033,99 +1054,101 @@ Added Standard Headers l_grid (l_indx).arglist := l_entries (5); l_grid (l_indx).return_value := l_entries (6); l_grid (l_indx).assertion_type := UPPER (l_entries (7)); + -- NOK0205: grab value for last entry as well. + l_grid (l_indx).null_ok := UPPER (l_entries (8)); END IF; END LOOP; - testpkg ( - package_in, - l_grid, - program_in, - samepackage_in, - prefix_in, - schema_in, - output_type_in, - dir_in, - arg_delim_in, - date_format_in, - only_if_in_grid_in, - override_file_in => override_file_in - ); + testpkg (package_in + , l_grid + , program_in + , samepackage_in + , prefix_in + , schema_in + , output_type_in + , dir_in + , arg_delim_in + , date_format_in + , only_if_in_grid_in + , override_file_in => override_file_in + ); END IF; END; PROCEDURE testpkg_from_string_od ( - package_in IN VARCHAR2, - grid_in IN VARCHAR2, - dir_in IN VARCHAR2 := NULL, - override_file_in IN VARCHAR2 := NULL + package_in IN VARCHAR2 + , grid_in IN VARCHAR2 + , dir_in IN VARCHAR2 := NULL + , override_file_in IN VARCHAR2 := NULL ) IS BEGIN - testpkg_from_string ( - package_in, - grid_in, - output_type_in => c_file, - dir_in => dir_in, - only_if_in_grid_in => TRUE, - override_file_in => override_file_in - ); + testpkg_from_string (package_in + , grid_in + , output_type_in => c_file + , dir_in => dir_in + , only_if_in_grid_in => TRUE + , override_file_in => override_file_in + ); END; PROCEDURE clear_grid ( - owner_in IN ut_grid.owner%TYPE - ,package_in IN ut_grid.PACKAGE%TYPE) + owner_in IN ut_grid.owner%TYPE + , package_in IN ut_grid.PACKAGE%TYPE + ) IS BEGIN - delete from ut_grid WHERE ut_grid.owner = UPPER (owner_in) - AND ut_grid.PACKAGE = UPPER (package_in); - + DELETE FROM ut_grid + WHERE ut_grid.owner = UPPER (owner_in) + AND ut_grid.PACKAGE = UPPER (package_in); END; - + PROCEDURE add_to_grid ( owner_in IN ut_grid.owner%TYPE - ,package_in IN ut_grid.PACKAGE%TYPE - ,progname_in IN ut_grid.progname%TYPE - ,overload_in IN ut_grid.overload%TYPE - ,tcname_in IN ut_grid.tcname%TYPE - ,message_in IN ut_grid.MESSAGE%TYPE - ,arglist_in IN ut_grid.arglist%TYPE - ,return_value_in IN ut_grid.return_value%TYPE - ,assertion_type_in IN ut_grid.assertion_type%TYPE + , package_in IN ut_grid.PACKAGE%TYPE + , progname_in IN ut_grid.progname%TYPE + , overload_in IN ut_grid.overload%TYPE + , tcname_in IN ut_grid.tcname%TYPE + , message_in IN ut_grid.MESSAGE%TYPE + , arglist_in IN ut_grid.arglist%TYPE + , return_value_in IN ut_grid.return_value%TYPE + , assertion_type_in IN ut_grid.assertion_type%TYPE ) IS BEGIN INSERT INTO ut_grid - (owner, PACKAGE, progname, overload, tcname, MESSAGE - ,arglist, return_value, assertion_type + (owner, PACKAGE, progname, overload + , tcname, MESSAGE, arglist, return_value + , assertion_type ) - VALUES (owner_in, package_in, progname_in, overload_in, tcname_in, message_in - ,arglist_in, return_value_in, assertion_type_in + VALUES (owner_in, package_in, progname_in, overload_in + , tcname_in, message_in, arglist_in, return_value_in + , assertion_type_in ); END add_to_grid; - + -- 2.0.10.1 From Patrick Barel /* START Patch72 607131 */ PROCEDURE testpkg_from_table ( - package_in IN VARCHAR2, - program_in IN VARCHAR2 := '%', - samepackage_in IN BOOLEAN := FALSE , - prefix_in IN VARCHAR2 := NULL, - schema_in IN VARCHAR2 := NULL, - output_type_in IN PLS_INTEGER := c_screen, - dir_in IN VARCHAR2 := NULL, - date_format_in IN VARCHAR2 := 'MM/DD/YYYY', - override_file_in IN VARCHAR2 := NULL + package_in IN VARCHAR2 + , program_in IN VARCHAR2 := '%' + , samepackage_in IN BOOLEAN := FALSE + , prefix_in IN VARCHAR2 := NULL + , schema_in IN VARCHAR2 := NULL + , output_type_in IN PLS_INTEGER := c_screen + , dir_in IN VARCHAR2 := NULL + , date_format_in IN VARCHAR2 := 'MM/DD/YYYY' + , override_file_in IN VARCHAR2 := NULL ) - IS + IS CURSOR c_ut_grid (p_package VARCHAR2, p_owner VARCHAR2) IS - SELECT ut_grid.owner, - ut_grid.progname, ut_grid.overload, ut_grid.tcname, - ut_grid.MESSAGE, ut_grid.arglist, ut_grid.return_value, - ut_grid.assertion_type + SELECT ut_grid.owner, ut_grid.progname, ut_grid.overload + , ut_grid.tcname, ut_grid.MESSAGE, ut_grid.arglist + , ut_grid.return_value, ut_grid.assertion_type FROM ut_grid - WHERE NVL(ut_grid.owner, USER) = UPPER (p_owner) - AND ut_grid.PACKAGE = UPPER (p_package) + WHERE ut_grid.owner = UPPER (p_owner) + AND ut_grid.PACKAGE = UPPER (p_package) ORDER BY ut_grid.progname; lv_grid utgen.grid_tt; @@ -1135,10 +1158,14 @@ Added Standard Headers IF c_ut_grid%ISOPEN THEN CLOSE c_ut_grid; - END IF; -- c_ut_grid%IsOpen + END IF; -- c_ut_grid%IsOpen + + OPEN c_ut_grid (p_package => package_in + , p_owner => NVL (schema_in, USER) + ); - OPEN c_ut_grid (p_package => package_in, p_owner => NVL (schema_in, USER)); - FETCH c_ut_grid INTO rc_ut_grid; + FETCH c_ut_grid + INTO rc_ut_grid; WHILE c_ut_grid%FOUND LOOP @@ -1150,13 +1177,15 @@ Added Standard Headers lv_grid (lv_index).arglist := rc_ut_grid.arglist; lv_grid (lv_index).return_value := rc_ut_grid.return_value; lv_grid (lv_index).assertion_type := rc_ut_grid.assertion_type; - FETCH c_ut_grid INTO rc_ut_grid; + + FETCH c_ut_grid + INTO rc_ut_grid; END LOOP; IF c_ut_grid%ISOPEN THEN CLOSE c_ut_grid; - END IF; -- c_ut_grid%IsOpen + END IF; -- c_ut_grid%IsOpen IF lv_index > -1 THEN @@ -1167,23 +1196,23 @@ Added Standard Headers ); */ -- We have access to all parameters (either sent in or default). Why not use them? - utgen.testpkg ( - package_in => package_in /* SEF fix 10/9/2 lv_package*/ - , grid_in => lv_grid - , program_in => program_in - , samepackage_in => samepackage_in - , prefix_in => prefix_in - , schema_in => schema_in - , output_type_in => output_type_in - , dir_in => dir_in - , date_format_in => date_format_in - , override_file_in => override_file_in - ); - - END IF; -- lv_index > -1 + utgen.testpkg + (package_in => package_in + /* SEF fix 10/9/2 lv_package*/ + , grid_in => lv_grid + , program_in => program_in + , samepackage_in => samepackage_in + , prefix_in => prefix_in + , schema_in => schema_in + , output_type_in => output_type_in + , dir_in => dir_in + , date_format_in => date_format_in + , override_file_in => override_file_in + ); + END IF; -- lv_index > -1 END; -/* END Patch72 607131 */ +/* END Patch72 607131 */ FUNCTION pkgstring RETURN VARCHAR2 IS @@ -1194,7 +1223,7 @@ Added Standard Headers /* Returns data in order retrieved (ie, Nth row). */ FUNCTION nthrow (nth IN PLS_INTEGER, direction IN SIGNTYPE := 1) RETURN codeline_t - IS + IS v_nth PLS_INTEGER := 1; v_row PLS_INTEGER; retval codeline_t; @@ -1309,10 +1338,10 @@ Added Standard Headers END; PROCEDURE showrows ( - startrow IN PLS_INTEGER := NULL, - endrow IN PLS_INTEGER := NULL + startrow IN PLS_INTEGER := NULL + , endrow IN PLS_INTEGER := NULL ) - IS + IS v_start PLS_INTEGER := NVL (startrow, 1); v_end PLS_INTEGER := NVL (endrow, countrows); BEGIN @@ -1324,7 +1353,7 @@ Added Standard Headers END; -- TO COMPLETE: apply same output type flexibility - -- from testpkg to receq_compare. + -- from testpkg to receq_compare. PROCEDURE putline (str IN VARCHAR2) IS BEGIN @@ -1333,13 +1362,13 @@ Added Standard Headers -- 2.0.8 Implementation provided by Dan Spencer! PROCEDURE receq_package ( - table_in IN VARCHAR2, - pkg_in IN VARCHAR2 := NULL, - owner_in IN VARCHAR2 := NULL + table_in IN VARCHAR2 + , pkg_in IN VARCHAR2 := NULL + , owner_in IN VARCHAR2 := NULL ) - IS + IS v_pkg VARCHAR2 (30) - := NVL (pkg_in, SUBSTR ('receq_' || table_in, 1, 30)); + := NVL (pkg_in, SUBSTR ('receq_' || table_in, 1, 30)); v_owner VARCHAR2 (30) := UPPER (NVL (owner_in, USER)); v_table VARCHAR2 (30) := UPPER (table_in); BEGIN @@ -1349,13 +1378,12 @@ Added Standard Headers FROM all_tables WHERE owner = v_owner AND table_name = v_table) LOOP - putline ( - 'FUNCTION eq(a ' - || tabs_rec.table_name - || '%ROWTYPE , b ' - || tabs_rec.table_name - || '%ROWTYPE ) RETURN BOOLEAN; ' - ); + putline ( 'FUNCTION eq(a ' + || tabs_rec.table_name + || '%ROWTYPE , b ' + || tabs_rec.table_name + || '%ROWTYPE ) RETURN BOOLEAN; ' + ); END LOOP; putline (' END ' || v_pkg || ';'); @@ -1367,22 +1395,21 @@ Added Standard Headers FROM all_tables WHERE owner = v_owner AND table_name = v_table) LOOP - putline ( - 'FUNCTION eq( a ' - || tabs_rec.table_name - || '%ROWTYPE , ' - || 'b ' - || tabs_rec.table_name - || '%ROWTYPE ) ' - || 'RETURN BOOLEAN ' - ); + putline ( 'FUNCTION eq( a ' + || tabs_rec.table_name + || '%ROWTYPE , ' + || 'b ' + || tabs_rec.table_name + || '%ROWTYPE ) ' + || 'RETURN BOOLEAN ' + ); putline ('IS BEGIN '); putline (' RETURN ('); FOR user_tab_columns_rec IN (SELECT * FROM user_tab_columns WHERE table_name = - tabs_rec.table_name + tabs_rec.table_name ORDER BY column_id) LOOP IF user_tab_columns_rec.column_id > 1 @@ -1392,29 +1419,27 @@ Added Standard Headers IF user_tab_columns_rec.data_type = 'CLOB' THEN - putline ( - '( ( a.' - || user_tab_columns_rec.column_name - || ' IS NULL AND b.' - || user_tab_columns_rec.column_name - || ' IS NULL ) OR DBMS_LOB.COMPARE( a.' - || user_tab_columns_rec.column_name - || ' , b.' - || user_tab_columns_rec.column_name - || ') = 0 )' - ); + putline ( '( ( a.' + || user_tab_columns_rec.column_name + || ' IS NULL AND b.' + || user_tab_columns_rec.column_name + || ' IS NULL ) OR DBMS_LOB.COMPARE( a.' + || user_tab_columns_rec.column_name + || ' , b.' + || user_tab_columns_rec.column_name + || ') = 0 )' + ); ELSE - putline ( - '( ( a.' - || user_tab_columns_rec.column_name - || ' IS NULL AND b.' - || user_tab_columns_rec.column_name - || ' IS NULL ) OR a.' - || user_tab_columns_rec.column_name - || ' = b.' - || user_tab_columns_rec.column_name - || ')' - ); + putline ( '( ( a.' + || user_tab_columns_rec.column_name + || ' IS NULL AND b.' + || user_tab_columns_rec.column_name + || ' IS NULL ) OR a.' + || user_tab_columns_rec.column_name + || ' = b.' + || user_tab_columns_rec.column_name + || ')' + ); END IF; END LOOP; diff --git a/source/ut_gen.pks b/source/ut_gen.pks index 6d6aad631..9fd4a2fde 100644 --- a/source/ut_gen.pks +++ b/source/ut_gen.pks @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.4 2004/11/23 14:56:47 chrisrimmer +Moved dbms_pipe code into its own package. Also changed some preprocessor flags + Revision 1.3 2004/11/16 09:46:49 chrisrimmer Changed to new version detection system. @@ -39,96 +42,96 @@ Added Standard Headers c_delim CONSTANT CHAR (1) := ';'; c_comment CONSTANT CHAR (1) := '#'; c_asis CONSTANT CHAR (1) := '!'; + &start_ge_8_1 SUBTYPE codeline_t IS VARCHAR2(200); &end_ge_8_1 &start_lt_8_1 v_codeline VARCHAR2 (200); - SUBTYPE codeline_t IS v_codeline%TYPE; - &end_lt_8_1 -- Each line in the grid represents a test case -- TYPE grid_rt IS RECORD ( - progname VARCHAR2 (100), - overload PLS_INTEGER, - tcname VARCHAR2 (100), - MESSAGE VARCHAR2 (2000), - arglist VARCHAR2 (2000), - return_value VARCHAR2 (2000), - assertion_type VARCHAR2 (100) + progname VARCHAR2 (100) + , overload PLS_INTEGER + , tcname VARCHAR2 (100) + , MESSAGE VARCHAR2 (2000) + , arglist VARCHAR2 (2000) + , return_value VARCHAR2 (2000) + , assertion_type VARCHAR2 (100) + , null_ok VARCHAR2 (1) -- NOK0205: Y or N ); TYPE grid_tt IS TABLE OF grid_rt INDEX BY BINARY_INTEGER; PROCEDURE testpkg ( - package_in IN VARCHAR2, - program_in IN VARCHAR2 := '%', - samepackage_in IN BOOLEAN := FALSE , - prefix_in IN VARCHAR2 := NULL, - schema_in IN VARCHAR2 := NULL, - output_type_in IN PLS_INTEGER := c_screen, - dir_in IN VARCHAR2 := NULL, - override_file_in IN VARCHAR2 := NULL + package_in IN VARCHAR2 + , program_in IN VARCHAR2 := '%' + , samepackage_in IN BOOLEAN := FALSE + , prefix_in IN VARCHAR2 := NULL + , schema_in IN VARCHAR2 := NULL + , output_type_in IN PLS_INTEGER := c_screen + , dir_in IN VARCHAR2 := NULL + , override_file_in IN VARCHAR2 := NULL ); PROCEDURE testpkg ( - package_in IN VARCHAR2, - grid_in IN grid_tt, - program_in IN VARCHAR2 := '%', - samepackage_in IN BOOLEAN := FALSE , - prefix_in IN VARCHAR2 := NULL, - schema_in IN VARCHAR2 := NULL, - output_type_in IN PLS_INTEGER := c_screen, - dir_in IN VARCHAR2 := NULL, - delim_in IN VARCHAR2 := c_delim, - date_format_in IN VARCHAR2 := 'MM/DD/YYYY', - only_if_in_grid_in IN BOOLEAN := FALSE, - override_file_in IN VARCHAR2 := NULL + package_in IN VARCHAR2 + , grid_in IN grid_tt + , program_in IN VARCHAR2 := '%' + , samepackage_in IN BOOLEAN := FALSE + , prefix_in IN VARCHAR2 := NULL + , schema_in IN VARCHAR2 := NULL + , output_type_in IN PLS_INTEGER := c_screen + , dir_in IN VARCHAR2 := NULL + , delim_in IN VARCHAR2 := c_delim + , date_format_in IN VARCHAR2 := 'MM/DD/YYYY' + , only_if_in_grid_in IN BOOLEAN := FALSE + , override_file_in IN VARCHAR2 := NULL ); PROCEDURE testpkg_from_file ( - package_in IN VARCHAR2, - gridfile_loc_in IN VARCHAR2, - gridfile_in IN VARCHAR2, - program_in IN VARCHAR2 := '%', - samepackage_in IN BOOLEAN := FALSE , - prefix_in IN VARCHAR2 := NULL, - schema_in IN VARCHAR2 := NULL, - output_type_in IN PLS_INTEGER := c_screen, - dir_in IN VARCHAR2 := NULL, - field_delim_in IN VARCHAR2 := '|', - arg_delim_in IN VARCHAR2 := c_delim, - date_format_in IN VARCHAR2 := 'MM/DD/YYYY', - only_if_in_grid_in IN BOOLEAN := FALSE, - override_file_in IN VARCHAR2 := NULL + package_in IN VARCHAR2 + , gridfile_loc_in IN VARCHAR2 + , gridfile_in IN VARCHAR2 + , program_in IN VARCHAR2 := '%' + , samepackage_in IN BOOLEAN := FALSE + , prefix_in IN VARCHAR2 := NULL + , schema_in IN VARCHAR2 := NULL + , output_type_in IN PLS_INTEGER := c_screen + , dir_in IN VARCHAR2 := NULL + , field_delim_in IN VARCHAR2 := '|' + , arg_delim_in IN VARCHAR2 := c_delim + , date_format_in IN VARCHAR2 := 'MM/DD/YYYY' + , only_if_in_grid_in IN BOOLEAN := FALSE + , override_file_in IN VARCHAR2 := NULL ); PROCEDURE testpkg_from_string ( - package_in IN VARCHAR2, - grid_in IN VARCHAR2, - program_in IN VARCHAR2 := '%', - samepackage_in IN BOOLEAN := FALSE , - prefix_in IN VARCHAR2 := NULL, - schema_in IN VARCHAR2 := NULL, - output_type_in IN PLS_INTEGER := c_screen, - dir_in IN VARCHAR2 := NULL, - line_delim_in IN VARCHAR := CHR (10), - field_delim_in IN VARCHAR2 := '|', - arg_delim_in IN VARCHAR2 := c_delim, - date_format_in IN VARCHAR2 := 'MM/DD/YYYY', - only_if_in_grid_in IN BOOLEAN := FALSE, - override_file_in IN VARCHAR2 := NULL + package_in IN VARCHAR2 + , grid_in IN VARCHAR2 + , program_in IN VARCHAR2 := '%' + , samepackage_in IN BOOLEAN := FALSE + , prefix_in IN VARCHAR2 := NULL + , schema_in IN VARCHAR2 := NULL + , output_type_in IN PLS_INTEGER := c_screen + , dir_in IN VARCHAR2 := NULL + , line_delim_in IN VARCHAR := CHR (10) + , field_delim_in IN VARCHAR2 := '|' + , arg_delim_in IN VARCHAR2 := c_delim + , date_format_in IN VARCHAR2 := 'MM/DD/YYYY' + , only_if_in_grid_in IN BOOLEAN := FALSE + , override_file_in IN VARCHAR2 := NULL ); PROCEDURE testpkg_from_string_od ( - package_in IN VARCHAR2, - grid_in IN VARCHAR2, - dir_in IN VARCHAR2 := NULL, - override_file_in IN VARCHAR2 := NULL + package_in IN VARCHAR2 + , grid_in IN VARCHAR2 + , dir_in IN VARCHAR2 := NULL + , override_file_in IN VARCHAR2 := NULL ); -- Retrieve single string with generated package. @@ -168,46 +171,47 @@ Added Standard Headers PROCEDURE prevrow; PROCEDURE showrows ( - startrow IN PLS_INTEGER := NULL, - endrow IN PLS_INTEGER := NULL + startrow IN PLS_INTEGER := NULL + , endrow IN PLS_INTEGER := NULL ); FUNCTION isfunction ( - schema_in IN VARCHAR2, - package_in IN VARCHAR2, - program_in IN VARCHAR2, - overload_in IN PLS_INTEGER := NULL + schema_in IN VARCHAR2 + , package_in IN VARCHAR2 + , program_in IN VARCHAR2 + , overload_in IN PLS_INTEGER := NULL ) RETURN BOOLEAN; -- 2.0.10.1 From Patrick Barel PROCEDURE add_to_grid ( owner_in IN ut_grid.owner%TYPE - ,package_in IN ut_grid.PACKAGE%TYPE - ,progname_in IN ut_grid.progname%TYPE - ,overload_in IN ut_grid.overload%TYPE - ,tcname_in IN ut_grid.tcname%TYPE - ,message_in IN ut_grid.MESSAGE%TYPE - ,arglist_in IN ut_grid.arglist%TYPE - ,return_value_in IN ut_grid.return_value%TYPE - ,assertion_type_in IN ut_grid.assertion_type%TYPE + , package_in IN ut_grid.PACKAGE%TYPE + , progname_in IN ut_grid.progname%TYPE + , overload_in IN ut_grid.overload%TYPE + , tcname_in IN ut_grid.tcname%TYPE + , message_in IN ut_grid.MESSAGE%TYPE + , arglist_in IN ut_grid.arglist%TYPE + , return_value_in IN ut_grid.return_value%TYPE + , assertion_type_in IN ut_grid.assertion_type%TYPE ); - + PROCEDURE clear_grid ( - owner_in IN ut_grid.owner%TYPE - ,package_in IN ut_grid.PACKAGE%TYPE); - + owner_in IN ut_grid.owner%TYPE + , package_in IN ut_grid.PACKAGE%TYPE + ); + /* START Patch72 607131 */ PROCEDURE testpkg_from_table ( - package_in IN VARCHAR2, - program_in IN VARCHAR2 := '%', - samepackage_in IN BOOLEAN := FALSE , - prefix_in IN VARCHAR2 := NULL, - schema_in IN VARCHAR2 := NULL, - output_type_in IN PLS_INTEGER := c_screen, - dir_in IN VARCHAR2 := NULL, - date_format_in IN VARCHAR2 := 'MM/DD/YYYY', - override_file_in IN VARCHAR2 := NULL + package_in IN VARCHAR2 + , program_in IN VARCHAR2 := '%' + , samepackage_in IN BOOLEAN := FALSE + , prefix_in IN VARCHAR2 := NULL + , schema_in IN VARCHAR2 := NULL + , output_type_in IN PLS_INTEGER := c_screen + , dir_in IN VARCHAR2 := NULL + , date_format_in IN VARCHAR2 := 'MM/DD/YYYY' + , override_file_in IN VARCHAR2 := NULL ); /* END Patch72 607131 */ From 583505e817dc33f0b43d9176b0eb64849e54cda1 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Mon, 9 May 2005 15:33:16 +0000 Subject: [PATCH 088/143] Added notes about which schemas to use --- documentation/src/fourstep.html | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/documentation/src/fourstep.html b/documentation/src/fourstep.html index 1f33e7ce8..bf9afaba4 100644 --- a/documentation/src/fourstep.html +++ b/documentation/src/fourstep.html @@ -13,7 +13,9 @@

    Step 3. Build a test package.

    Step 4. Run your test.

    -

    Where To Go From Here

    +

    A note on which schemas to use

    + +

    Where to go from here

    Step 1. Install (and Upgrade) utPLSQL.

    @@ -33,7 +35,9 @@

    Step 1. Install (and Upgrade) utPLSQL.

  • Create tables, views, packages and sequences.
  • -

    The following is an example script submitted by Bill Pribyl, which creates a user "UTP" with sufficient privileges +

    If you like, you can install utPLSQL into the SYSTEM schema, which will avoid the need to create +a new user. However, you may prefer to keep everything in a separate place. +The following is an example script submitted by Bill Pribyl, which creates a user "UTP" with sufficient privileges to install utPLSQL. Obviously it is only an example and will need to be changed for your environment:

    connect system/manager
    @@ -406,7 +410,18 @@ 

    Automatic Recompilation of Test Package

    SQL> exec utplsql.setdir ('e:\utplsql\testall')
    -

    Where To Go From Here

    +

    A note on which schemas to use

    + +

    In step 1, above, we described which user should own the objects which make up the utPLSQL framework. +However, there has often been confusion about which schema should contain the test packages and which schema to connect as +when running the tests. There are many ways to do it, but the simplest is as follows: +

      +
    • It doesn't matter which schema owns utPLSQL itself, so long as other users have access to it.
    • +
    • The test packages should go in the same schema as the code that is being tested.
    • +
    • You should connect as the user who owns the test packages (and hence the tested code) when running the tests
    • +

    + +

    Where to go from here

    If you proceeded through all four steps, you should now have used utPLSQL successfully to test a very simple function (betwnstr) or your own From 176ffaa97bce046777a34fa861ba34d1405f3fa1 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Tue, 10 May 2005 14:23:26 +0000 Subject: [PATCH 089/143] Added documentation of output reporters --- documentation/src/defsuite.html | 2 +- documentation/src/fileout.html | 23 +--- documentation/src/map.txt | 5 +- documentation/src/release.html | 15 +++ documentation/src/reporter.html | 146 ++++++++++++++++++++++++++ documentation/src/userguide.html | 11 +- documentation/src/utconfig.html | 49 ++++++--- documentation/src/utplsql.html | 173 ++++++++++++++++--------------- documentation/src/utresult.html | 14 +-- 9 files changed, 306 insertions(+), 132 deletions(-) create mode 100644 documentation/src/reporter.html diff --git a/documentation/src/defsuite.html b/documentation/src/defsuite.html index 0b5b71374..be6a8d695 100644 --- a/documentation/src/defsuite.html +++ b/documentation/src/defsuite.html @@ -3,7 +3,7 @@

    -Define Test Suites

    +Defining Test Suites

    If you define test suites and register packages within those suites, then utPLSQL will run an unlimited number of diff --git a/documentation/src/fileout.html b/documentation/src/fileout.html index 348ac26f0..293496f59 100644 --- a/documentation/src/fileout.html +++ b/documentation/src/fileout.html @@ -3,14 +3,14 @@

    -Configuring File Output +Configuring the File Reporter

    Outline

    By default, the results of a test run are written to the screen -(via DBMS_OUTPUT). The subprograms described in this section were created +(via the default Output Reporter). The subprograms described in this section were created by Rainer Medert to allow these results to be written to file instead. They form part of the utConfig package. Don't forget that you will first need to enable file output from the database @@ -20,22 +20,8 @@

    Turning file output on

    -

    To turn on file output, use the follow procedure:

    - -
    PROCEDURE setfile (
    -  fileout_in IN BOOLEAN := FALSE, 
    -  username_in IN VARCHAR2 := NULL
    -);
    - -

    the boolean flag specifies whether file output should be turned on or off, -while the username specifies which tester to set the flag for. As usual, -this defaults to the user returned by utConfig.tester.

    - -

    To see if file output is being used, use the following:

    - -
    FUNCTION getfile (username_in IN VARCHAR2 := NULL) RETURN BOOLEAN;
    - -

    this will return the file output flag for the given user.

    +

    To turn on file output, you will need to switch to using the File Reporter, or a custom reporter +that uses it. See this page for details.

    Setting the directory to be used @@ -127,7 +113,6 @@

    It is possible to set all the file output parameters at once using the following procedure:

    PROCEDURE setfileinfo ( 
    -  fileout_in IN BOOLEAN := FALSE,
       dir_in IN VARCHAR2 := NULL,
       userprefix_in IN VARCHAR2 := NULL, 
       incname_in IN BOOLEAN := FALSE,     
    diff --git a/documentation/src/map.txt b/documentation/src/map.txt
    index fe73c9ca4..71794aedb 100644
    --- a/documentation/src/map.txt
    +++ b/documentation/src/map.txt
    @@ -24,11 +24,12 @@ suite.html,Create and Run a Test Suite
     userguide.html,User Guide*
     utplsql.html,utPLSQL Package
     utconfig.html,utConfig Package
    -fileout.html,Configuring File Output
     utresult.html,utResult Package
     utassert.html,utAssert Package
     utgen.html,utGen Package
     utoutput.html,utOutput Package
     utreceq.html,utRecEq Package
    -defsuite.html,Define Test Suites
    +defsuite.html,Defining Test Suites
    +reporter.html,Custom Reporter Packages
    +fileout.html,Configuring the File Reporter
     release.html,Release Notes*
    diff --git a/documentation/src/release.html b/documentation/src/release.html
    index a8886bab1..1c7c57d13 100644
    --- a/documentation/src/release.html
    +++ b/documentation/src/release.html
    @@ -22,6 +22,21 @@ 

    utPLSQL version 2.x

    Change History

    +

    utPLSQL version 2.2

    +
      +
    • + This version introduces the concept of Output Reporters. The existing code to output to DBMS_OUPUT or to file has been refactored to + fit into this framework. +
    • +
    • +The installation procedure has been changed so that the database version is picked up more robustly. Version 2.2 works with 10g, +which previous versions did not. It should also work with future versions (so long as the version is to be found in the same place +in the data dictionary). +
    • +
    • +There are also a variety of small fixes in this release. +
    • +

    utPLSQL version 2.1.1

    • diff --git a/documentation/src/reporter.html b/documentation/src/reporter.html new file mode 100644 index 000000000..3f52fc886 --- /dev/null +++ b/documentation/src/reporter.html @@ -0,0 +1,146 @@ + + + + +

      Custom Reporter Packages

      +

      Generally, the default output provided by utPLSQL is sufficient. This +just writes to the screen using DBMS_OUTPUT. If you are running it +interactively while doing some development, you just need to know if the tests +are passing and details of the failing tests. +However, there are cases where you'd like the results to be reported in a +different format, especially when the tests are being run in batch mode. To +support this, utPLSQL has the concept of Reporter Packages. utPLSQL is +distributed with the following reporter packages as standard:

      + + + +The naming convention is that reporter packages are called +UT<NAME>REPORTER. To set which reporter is used, you will +need to call utConfig.Setreporter, passing the name of the reporter. +To use the HTML reporter for example, you should issue the following command: +
      BEGIN
      +   utConfig.setreporter('HTML');
      +END; 
      + +For more details of how to develop your own custom +reporter package, see below. + +

      Output Reporter

      + +

      Contained in the UTOUTPUTREPORTER package, this simply encapsulates the +standard behaviour, whereby the output is written out to DBMS_OUTPUT. When a +problem occurs with another reporter, utPLSQL will automatically fall back on +this mechanism to report problems. This means it is wise to have DBMS_OUTPUT +enabled even if you are using another output method.

      + +

      File Reporter

      + +

      This reporter, contained in the UTFILEREPORTER package, writes test results +out to a file. For details on how to configure this process, see the details +which can be found here. This functionality was +available before version 2.2 of utPLSQL, but has now been moved into its own +package.

      + +

      HTML Reporter

      + +

      The package UTHTMLREPORTER is really just an example package to be used as +a basis for your own custom reporters. It builds on the filereporter described above to +send results to a file. The difference is that the results are presented in a (rather crude) +HTML table.

      + +

      Writing your own Reporter

      + +

      To define your own reporter package you need it conform to a particular API. The various +procedures are then registered as 'callbacks' for utPLSQL to use. +An example package spec is given below. +

      +CREATE OR REPLACE PACKAGE utMyRssReporter
      +IS
      +
      +   PROCEDURE open;
      +   PROCEDURE pl (str IN VARCHAR2);
      +   
      +   PROCEDURE before_results(run_id IN utr_outcome.run_id%TYPE);
      +   PROCEDURE show_failure;
      +   PROCEDURE show_result;
      +   PROCEDURE after_results(run_id IN utr_outcome.run_id%TYPE);
      +   
      +   PROCEDURE before_errors(run_id IN utr_error.run_id%TYPE);
      +   PROCEDURE show_error;
      +   PROCEDURE after_errors(run_id IN utr_error.run_id%TYPE);   
      +   
      +   PROCEDURE close;
      +
      +END utMyRssReporter;
      +/
      +
      +

      +The implementation of these procedures should be as follows: +

      open

      +

      This is called at the very start of the process and is the ideal place to do initialization, such as opening any files that you will be writing to.

      + +

      pl

      +

      This is a general routine to simply write out the given string for purposes of logging etc. +If you don't want this to show up in your output, you can simply call utoutputreporter.pl to send this to DBMS_OUTPUT instead.

      + +

      before_results

      +

      As the name suggests, this is called before the results are output. Note that the tests have already completed at this point, +so it is possible to call utresult.success (run_id) to determine if the run was a success or not and display a large banner.

      + +

      show_failure

      +

      This is called when a failure is reported and we are only showing failures (i.e. utconfig.showfailuresonly has been set). +To get details of the failure, you will need to examine the package level record utreport.outcome.

      + +

      show_result

      +

      This is called whenever a result is reported and we are showing all results. To get details, you will need to examine utreport.outcome. See below for details.

      + +

      after_results

      +

      This is called after all the results have been sent for output.

      + +

      before_errors

      +

      This is called before any errors are sent for output.

      + +

      show_error

      +

      This is called for each error to output. To get details, you will need to examine the package level record utreport.error. See below for details.

      + +

      after_errors

      +

      This is called after any errors have been sent for output.

      + +

      Outcome and Error records

      +

      In order to keep the API as simple as possible, many of the procedures defined above take no parameters. In particular, details of the outcome or error which +triggered the callback are not passed through to your procedure. These are stored as package level records in the utReport package as shown below. + +

      outcome utr_outcome%ROWTYPE;
      +error utr_error%ROWTYPE;
      + +The important fields in the outcome record are: +
        +
      • status - This is a string which is either "SUCCESS" or "FAILURE" depending on the outcome of this test.
      • +
      • description - The text describing the success or failure.
      • +
      + +The important fields in the error record are: +
        +
      • errlevel - The Error Level
      • +
      • errcode - The Error Code
      • +
      • errtext - The Description of the error that occurred
      • +
      +

      + +

      Using Your Custom Reporter

      +To use your custom reporter, you simply call utConfig.Setreporter with the name of your reporter. So if +you have defined your reporter in the utMyRssReporter package, you need to call: + +
      BEGIN
      +   utConfig.setreporter('MyRss');
      +END; 
      + +Then you just run your tests as usual and hopefully your reporter will format the results as you expect. + + + + diff --git a/documentation/src/userguide.html b/documentation/src/userguide.html index c75f20d16..4f2e85a16 100644 --- a/documentation/src/userguide.html +++ b/documentation/src/userguide.html @@ -9,9 +9,8 @@

      • A set of tables to hold information about unit tests and test suites.
      • - -A set of packages that allow you to run tests, -build test packages and access information about tests you have run. +
      • A set of packages that allow you to run tests, +build test packages and access information about tests you have run.
      This document tells you how to use those utPLSQL packages:

      @@ -40,6 +39,12 @@

      Define Test Suites

      +

      +Using and defining Custom Reporter Packages + +

      +Configuring the File Reporter + diff --git a/documentation/src/utconfig.html b/documentation/src/utconfig.html index d319102b7..65f4a4435 100644 --- a/documentation/src/utconfig.html +++ b/documentation/src/utconfig.html @@ -92,24 +92,24 @@

      - utConfig.showfailuresonly + utConfig.showingfailuresonly Return whether successful test results are shown or not - utConfig.setfile - Sets file output TRUE or FALSE + utConfig.setreporter + Sets the default Output Reporter to use - utConfig.getfile - Return whether file output is being used + utConfig.getreporter + Gets the name of the default Output Reporter to use utConfig.setfiledir - Set the directory for the file output + Set the directory for file output @@ -119,47 +119,47 @@

      utConfig.setuserprefix - Set the user prefix for the output file name + Set the user prefix for output file names utConfig.userprefix - Return the user prefix for the output file name + Return the user prefix for output file names utConfig.setincludeprogname - Set whether to include the name of the program being tested in the output file name + Set whether to include the name of the program being tested in output file names utConfig.includeprogname - Return whether to include the name of the program being tested in the output file name + Return whether to include the name of the program being tested in output file names utConfig.setdateformat - Set the date format for the date portion of the output file name + Set the date format for the date portion of output file names utConfig.dateformat - Return the date format used to construct output file name + Return the date format used to construct output file names utConfig.setfileextension - Set the file extension for the output file name + Set the file extension for output file names utConfig.fileextension - Return the file extension used for the output file name + Return the file extension used for output file names utConfig.setfileinfo - Set all of the above file output related items + Set all of the above file output related items @@ -470,6 +470,25 @@

      FUNCTION showingfailuresonly (username_in IN VARCHAR2 := NULL)
             RETURN BOOLEAN;

      + + +

      + Set and Get the default output reporter +

      +

      +By default, all results are sent to the screen via DBMS_OUTPUT. However, it is possible to use other output reporters as described in more detail +on this page. The following procedure allows you to set which output reporter should be used by default: +

      PROCEDURE setreporter (
      +      reporter_in   IN   VARCHAR2
      +     ,username_in   IN   VARCHAR2 := NULL
      +   );
      +
      +as usual, the current setting can be obtain by the following function: +
      FUNCTION getreporter (username_in IN VARCHAR2 := NULL)
      +      RETURN VARCHAR2;
      +
      +

      + diff --git a/documentation/src/utplsql.html b/documentation/src/utplsql.html index b6b2cc131..15601ee7c 100644 --- a/documentation/src/utplsql.html +++ b/documentation/src/utplsql.html @@ -26,14 +26,7 @@

      utPLSQL Package

      Run a test suite

      - - -

      utPLSQL.addtest

      - - -

      Register a unit test in a test package

      - - +

      utPLSQL.version

      @@ -51,6 +44,14 @@

      utPLSQL Package

      Control utPLSQL's tracing mechanism

      + + + +

      utPLSQL.addtest

      + + +

      Register a unit test in a test package

      + @@ -419,6 +420,85 @@

      Recording and Accessing Test Statistics

      All of this is done for you automatically. You can then write queries and reports against the ut_package and ut_suite tables.

      + +

      Return utPLSQL version

      + +

      Run the utPLSQL.version function to return the version of +utPLSQL you have installed:

      + +
      FUNCTION utPLSQL.version RETURN VARCHAR2
      + +

      utPLSQL Trace

      + +

      These routines are very simple and take no arguments:

      + +
      +PROCEDURE trc;
      +
      +PROCEDURE notrc;
      +
      +FUNCTION tracing RETURN BOOLEAN;
      +
      + +

      The procedures trc and notrc are used to turn tracing on and off +respectively. The function tracing returns TRUE if tracing is currently turned +on and FALSE otherwise. This facility is useful when writing code in utPLSQL +(the framework itself, not your test code). An example of the output generated +is:

      + +
      +Initialized utPLSQL session...
      +Setpkg to Lottery
      +Package and program = ut_Lottery
      +Same package? N
      +Is package? Y
      +Prefix = ut_
      +Recompiling ut_Lottery in
      +Runprog of ut_SETUP
      +Package and program = ut_Lottery.ut_SETUP
      +Same package? N
      +Is package? Y
      +Prefix = ut_
      +Addtest
      +Package and program = Lottery.UT_DRAW
      +Same package? N
      +Override? Y
      +Prefix = ut_
      +Runprog of UT_DRAW
      +Package and program = ut_Lottery.UT_DRAW
      +Same package? N
      +Is package? Y
      +Prefix = ut_
      +.
      +>  FFFFFFF   AA     III  L      U     U RRRRR   EEEEEEE
      +>  F        A  A     I   L      U     U R    R  E
      +>  F       A    A    I   L      U     U R     R E
      +>  F      A      A   I   L      U     U R     R E
      +>  FFFF   A      A   I   L      U     U RRRRRR  EEEE
      +>  F      AAAAAAAA   I   L      U     U R   R   E
      +>  F      A      A   I   L      U     U R    R  E
      +>  F      A      A   I   L       U   U  R     R E
      +>  F      A      A  III  LLLLLLL  UUU   R     R EEEEEEE
      +.
      +FAILURE: "Lottery"
      +.
      +> Individual Test Case Results:
      +>
      +FAILURE - EQ "Test of DRAW" Expected "01 02 05 27 43 49" and got "02 04 27 28 31 33"
      +>
      +>
      +> Errors recorded in utPLSQL Error Log:
      +>
      +> NONE FOUND
      +Runprog of ut_TEARDOWN
      +Package and program = ut_Lottery.ut_TEARDOWN
      +Same package? N
      +Is package? Y
      +Prefix = ut_
      +
      +PL/SQL procedure successfully completed.
      +
      +

      Register a Unit Test

      As of version 1.4.1, you @@ -506,83 +586,6 @@

      Register a Unit Test

      Once you have placed your addtest programs into your test package's setup procedure, you are ready to build your own unit tests.

      -

      Return utPLSQL version

      - -

      Run the utPLSQL.version function to return the version of -utPLSQL you have installed:

      - -
      FUNCTION utPLSQL.version RETURN VARCHAR2
      - -

      utPLSQL Trace

      - -

      These routines are very simple and take no arguments:

      - -
      -PROCEDURE trc;
      -
      -PROCEDURE notrc;
      -
      -FUNCTION tracing RETURN BOOLEAN;
      -
      - -

      The procedures trc and notrc are used to turn tracing on and off -respectively. The function tracing returns TRUE if tracing is currently turned -on and FALSE otherwise. This facility is useful when writing code in utPLSQL -(the framework itself, not your test code). An example of the output generated -is:

      - -
      -Initialized utPLSQL session...
      -Setpkg to Lottery
      -Package and program = ut_Lottery
      -Same package? N
      -Is package? Y
      -Prefix = ut_
      -Recompiling ut_Lottery in
      -Runprog of ut_SETUP
      -Package and program = ut_Lottery.ut_SETUP
      -Same package? N
      -Is package? Y
      -Prefix = ut_
      -Addtest
      -Package and program = Lottery.UT_DRAW
      -Same package? N
      -Override? Y
      -Prefix = ut_
      -Runprog of UT_DRAW
      -Package and program = ut_Lottery.UT_DRAW
      -Same package? N
      -Is package? Y
      -Prefix = ut_
      -.
      ->  FFFFFFF   AA     III  L      U     U RRRRR   EEEEEEE
      ->  F        A  A     I   L      U     U R    R  E
      ->  F       A    A    I   L      U     U R     R E
      ->  F      A      A   I   L      U     U R     R E
      ->  FFFF   A      A   I   L      U     U RRRRRR  EEEE
      ->  F      AAAAAAAA   I   L      U     U R   R   E
      ->  F      A      A   I   L      U     U R    R  E
      ->  F      A      A   I   L       U   U  R     R E
      ->  F      A      A  III  LLLLLLL  UUU   R     R EEEEEEE
      -.
      -FAILURE: "Lottery"
      -.
      -> Individual Test Case Results:
      ->
      -FAILURE - EQ "Test of DRAW" Expected "01 02 05 27 43 49" and got "02 04 27 28 31 33"
      ->
      ->
      -> Errors recorded in utPLSQL Error Log:
      ->
      -> NONE FOUND
      -Runprog of ut_TEARDOWN
      -Package and program = ut_Lottery.ut_TEARDOWN
      -Same package? N
      -Is package? Y
      -Prefix = ut_
      -
      -PL/SQL procedure successfully completed.
      -
      diff --git a/documentation/src/utresult.html b/documentation/src/utresult.html index ca2b4b8fe..542964caf 100644 --- a/documentation/src/utresult.html +++ b/documentation/src/utresult.html @@ -51,13 +51,13 @@

      you employ the utPLSQL.test and utPLSQL.testsuite to run your tests, then the results will be displayed by calling the utResult.show procedure. -So, generally, you do not have to do anything to -see or evaluate the results of a test (or suite of tests). The information -will be displayed on your screen using DBMS_OUTPUT. You might, however, -want to access this information in another environment (say, Oracle Forms -or Java, etc.). You might also want to build -your own assertion logic or test engine. In either of these cases, -you will want to use the programs in the utResult package. +So, generally, you do not have to do anything to see or evaluate the results of +a test (or suite of tests). The information will be displayed on your screen +using DBMS_OUTPUT, or elsewhere if you use a custom output reporter. You might, +however, want to access this information in another environment (say, Oracle +Forms or Java, etc.). You might also want to build your own assertion logic or +test engine. In either of these cases, you will want to use the programs in the +utResult package.

      Initialize

      From a341ad3d4ec35aaeddbf736af578f68dbbe7663f Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 11 May 2005 08:58:02 +0000 Subject: [PATCH 090/143] Added further details on reporter packages --- documentation/src/reporter.html | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/documentation/src/reporter.html b/documentation/src/reporter.html index 3f52fc886..6210e8292 100644 --- a/documentation/src/reporter.html +++ b/documentation/src/reporter.html @@ -79,7 +79,8 @@

      Writing your own Reporter

      /

    -The implementation of these procedures should be as follows: +Your reporter package can define other functions and procedures, for example to allow configuration, but all the procedures shown above should be defined. +The usage of these procedures is as follows:

    open

    This is called at the very start of the process and is the ideal place to do initialization, such as opening any files that you will be writing to.

    @@ -139,7 +140,23 @@

    Using Your Custom Reporter

    utConfig.setreporter('MyRss'); END; -Then you just run your tests as usual and hopefully your reporter will format the results as you expect. +Then you just run your tests as usual and hopefully your reporter will format the results as you expect. + +

    Sending output to the current reporter

    +If you wish to send output to the current reporter, for example, for logging purposes, you should call utReport.pl. +This is part of the utReport package, which acts as a facade and passes any calls through to the current reporter package. +So if you have set up a custom reporter package 'utMyRssReporter' as shown above and called utConfig.setreporter('MyRss'), +any calls such as the following: + +
    BEGIN
    +  utReport.pl('Logging Message');
    +END;
    + +will be equivalent to + +
    BEGIN
    +  utMyRssReporter.pl('Logging Message');
    +END;
    From 39c087468c78ac4828e74f578c718d057ab7dfd9 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 11 May 2005 21:33:38 +0000 Subject: [PATCH 091/143] Added testing of reporter infrastructure --- source/ut_i_packages.sql | 1 + source/ut_i_packages_b.sql | 1 + source/ut_i_synonyms.sql | 1 + source/ut_i_uninstall.sql | 1 + source/ut_report.pkb | 6 +- source/ut_utreport.pkb | 148 +++++++++++++++++++++++++++++++++++++ source/ut_utreport.pks | 10 +++ 7 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 source/ut_utreport.pkb create mode 100644 source/ut_utreport.pks diff --git a/source/ut_i_packages.sql b/source/ut_i_packages.sql index 961fed50f..697ff74ed 100644 --- a/source/ut_i_packages.sql +++ b/source/ut_i_packages.sql @@ -35,3 +35,4 @@ @@ut_i_run ut_pipe.pks @@ut_i_run ut_utoutput.pks +@@ut_i_run ut_utreport.pks diff --git a/source/ut_i_packages_b.sql b/source/ut_i_packages_b.sql index 9d565a884..86fb36d8e 100644 --- a/source/ut_i_packages_b.sql +++ b/source/ut_i_packages_b.sql @@ -35,3 +35,4 @@ @@ut_i_run ut_pipe.pkb @@ut_i_run ut_utoutput.pkb +@@ut_i_run ut_utreport.pkb diff --git a/source/ut_i_synonyms.sql b/source/ut_i_synonyms.sql index 33c202e12..b6fb906c5 100644 --- a/source/ut_i_synonyms.sql +++ b/source/ut_i_synonyms.sql @@ -26,6 +26,7 @@ select decode(&fine,0,'','create public synonym '||object_name||' for '||object_ from all_objects where owner='&ut_owner' and object_name like 'UT%' +and object_name not in ('UT_UTOUTPUT', 'UT_UTREPORT') and object_type IN ('PACKAGE', 'TABLE', 'VIEW', 'SEQUENCE'); select decode(&fine,0,'','PROMPT &finished') from dual; diff --git a/source/ut_i_uninstall.sql b/source/ut_i_uninstall.sql index e8f464807..78b54a687 100644 --- a/source/ut_i_uninstall.sql +++ b/source/ut_i_uninstall.sql @@ -46,6 +46,7 @@ drop package UTREPORT; drop package UTPIPE; drop package UT_UTOUTPUT; +drop package UT_UTREPORT; SET TERMOUT ON diff --git a/source/ut_report.pkb b/source/ut_report.pkb index ba6601353..02270f1fd 100644 --- a/source/ut_report.pkb +++ b/source/ut_report.pkb @@ -24,6 +24,9 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2004/11/16 09:46:49 chrisrimmer +Changed to new version detection system. + Revision 1.1 2004/07/14 17:01:57 chrisrimmer Added first version of pluggable reporter packages @@ -118,7 +121,8 @@ Added first version of pluggable reporter packages PROCEDURE use(reporter IN VARCHAR2) IS BEGIN - g_reporter := reporter; + g_reporter := NVL(reporter, DEFAULT_REPORTER); + g_actual := g_reporter; END; FUNCTION using RETURN VARCHAR2 diff --git a/source/ut_utreport.pkb b/source/ut_utreport.pkb new file mode 100644 index 000000000..53b1d8e76 --- /dev/null +++ b/source/ut_utreport.pkb @@ -0,0 +1,148 @@ +CREATE OR REPLACE PACKAGE BODY UT_UTREPORT +AS + + reporter_before VARCHAR2(1000); + + PROCEDURE ut_setup + IS + BEGIN + + reporter_before := utConfig.getreporter; + + EXECUTE IMMEDIATE 'CREATE OR REPLACE PACKAGE utTestReporter +AS + char_log VARCHAR2(1000); + + PROCEDURE open; + PROCEDURE pl (str IN VARCHAR2); + PROCEDURE before_results(run_id IN utr_outcome.run_id%TYPE); + PROCEDURE show_failure; + PROCEDURE show_result; + PROCEDURE after_results(run_id IN utr_outcome.run_id%TYPE); + PROCEDURE before_errors(run_id IN utr_error.run_id%TYPE); + PROCEDURE show_error; + PROCEDURE after_errors(run_id IN utr_error.run_id%TYPE); + PROCEDURE close; +END;'; + + EXECUTE IMMEDIATE 'CREATE OR REPLACE PACKAGE BODY utTestReporter +AS + PROCEDURE open IS BEGIN char_log := char_log || '' open''; END; + PROCEDURE pl (str IN VARCHAR2) IS BEGIN char_log := char_log || '' pl(''|| str || '')''; END; + PROCEDURE before_results(run_id IN utr_outcome.run_id%TYPE) + IS BEGIN char_log := char_log || '' before_results''; END; + PROCEDURE show_failure + IS BEGIN char_log := char_log || '' show_failure''; END; + PROCEDURE show_result + IS BEGIN char_log := char_log || '' show_result''; END; + PROCEDURE after_results(run_id IN utr_outcome.run_id%TYPE) + IS BEGIN char_log := char_log || '' after_results''; END; + PROCEDURE before_errors(run_id IN utr_error.run_id%TYPE) + IS BEGIN char_log := char_log || '' before_errors''; END; + PROCEDURE show_error + IS BEGIN char_log := char_log || '' show_error''; END; + PROCEDURE after_errors(run_id IN utr_error.run_id%TYPE) + IS BEGIN char_log := char_log || '' after_errors''; END; + PROCEDURE close + IS BEGIN char_log := char_log || '' close''; END; +END;'; + + END; + + PROCEDURE ut_teardown + IS + BEGIN + BEGIN + EXECUTE IMMEDIATE 'DROP PACKAGE utTestReporter'; + EXCEPTION + WHEN OTHERS THEN + NULL; + END; + + utConfig.setreporter(reporter_before); + + END; + + FUNCTION get_log RETURN VARCHAR2 IS + char_log VARCHAR2(1000); + BEGIN + EXECUTE IMMEDIATE 'BEGIN :1 := utTestReporter.char_log; END;' USING OUT char_log; + RETURN char_log; + END; + + PROCEDURE clear_log IS + BEGIN + EXECUTE IMMEDIATE 'BEGIN utTestReporter.char_log := NULL; END;'; + END; + + ----------------------------------------------------------- + --This checks that calls to utreport get passed through to + --our custom reporter package. + ----------------------------------------------------------- + PROCEDURE ut_check_report_facade + IS + + run_id utr_outcome.run_id%TYPE; + rec_result utr_outcome%ROWTYPE; + rec_error utr_error%ROWTYPE; + + BEGIN + + utreport.outcome.status := NULL; + utreport.error.description := NULL; + + utConfig.setreporter('Test'); + + clear_log; + utReport.open; + utAssert.eq('open', get_log, ' open'); + + clear_log; + utReport.pl('Blah'); + utAssert.eq('pl', get_log, ' pl(Blah)'); + + clear_log; + utReport.before_results(run_id); + utAssert.eq('before_results', get_log, ' before_results'); + + clear_log; + rec_result.STATUS := 'FAILURE'; + utReport.show_failure(rec_result); + utAssert.eq('show_failure', get_log, ' show_failure'); + utAssert.eq('show_failure: outcome set', utreport.outcome.status, 'FAILURE'); + + clear_log; + rec_result.STATUS := 'RESULT'; + utReport.show_result(rec_result); + utAssert.eq('show_result', get_log, ' show_result'); + utAssert.eq('show_failure: outcome set', utreport.outcome.status, 'RESULT'); + + clear_log; + utReport.after_results(run_id); + utAssert.eq('after_results', get_log, ' after_results'); + + clear_log; + utReport.before_errors(run_id); + utAssert.eq('before_errors', get_log, ' before_errors'); + + clear_log; + rec_error.DESCRIPTION := 'BOOM!'; + utReport.show_error(rec_error); + utAssert.eq('show_error', get_log, ' show_error'); + utAssert.eq('show_error: error set', utreport.error.description, 'BOOM!'); + + clear_log; + utReport.after_errors(run_id); + utAssert.eq('after_errors', get_log, ' after_errors'); + + utConfig.setreporter(reporter_before); + + EXCEPTION + WHEN OTHERS THEN + utConfig.setreporter(reporter_before); + RAISE; + + END; + +END; +/ diff --git a/source/ut_utreport.pks b/source/ut_utreport.pks new file mode 100644 index 000000000..25ff468c6 --- /dev/null +++ b/source/ut_utreport.pks @@ -0,0 +1,10 @@ +CREATE OR REPLACE PACKAGE UT_UTREPORT +AS + + PROCEDURE ut_setup; + PROCEDURE ut_teardown; + + PROCEDURE ut_check_report_facade; + +END; +/ \ No newline at end of file From 2aa7e07a76758807b2f85dc93c7c53cc8c436188 Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 11 May 2005 22:23:17 +0000 Subject: [PATCH 092/143] Updated dates on file --- documentation/readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/readme.txt b/documentation/readme.txt index f383fe3fc..82da7cb21 100644 --- a/documentation/readme.txt +++ b/documentation/readme.txt @@ -2,7 +2,7 @@ Welcome to utPLSQL, the unit testing framework for PL/SQL ==================================================================== -Copyright (c) 2000-2003, Steven Feuerstein and the utPLSQL Project +Copyright (c) 2000-2005, Steven Feuerstein and the utPLSQL Project You have downloaded utPLSQL. From 925370c14d5379384527f12c42e452117c548bed Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 25 May 2005 12:56:59 +0000 Subject: [PATCH 093/143] Fixed file rerporter so it actually works. Doh! --- source/ut_filereporter.pkb | 55 +++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/source/ut_filereporter.pkb b/source/ut_filereporter.pkb index 3fe330bdb..c810dc65e 100644 --- a/source/ut_filereporter.pkb +++ b/source/ut_filereporter.pkb @@ -23,13 +23,16 @@ along with this program (see license.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ************************************************************************ $Log$ +Revision 1.2 2004/11/16 09:46:48 chrisrimmer +Changed to new version detection system. + Revision 1.1 2004/07/14 17:01:57 chrisrimmer Added first version of pluggable reporter packages ************************************************************************/ - g_fid UTL_FILE.FILE_TYPE; + g_fid UTL_FILE.FILE_TYPE := NULL; PROCEDURE record_error (str IN VARCHAR2) IS @@ -47,7 +50,7 @@ Added first version of pluggable reporter packages END IF; g_fid := UTL_FILE.FOPEN (dir, filename, filemode); - + EXCEPTION WHEN UTL_FILE.INVALID_PATH THEN record_error ('invalid_path'); @@ -145,10 +148,52 @@ Added first version of pluggable reporter packages END; + PROCEDURE before_results(run_id IN utr_outcome.run_id%TYPE) + IS + BEGIN + utOutputReporter.before_results(run_id); + END; + + PROCEDURE show_failure + IS + BEGIN + utOutputReporter.show_failure; + END; + + PROCEDURE show_result + IS + BEGIN + utOutputReporter.show_result; + END; + + PROCEDURE after_results(run_id IN utr_outcome.run_id%TYPE) + IS + BEGIN + utOutputReporter.after_results(run_id); + END; + + PROCEDURE before_errors(run_id IN utr_error.run_id%TYPE) + IS + BEGIN + utOutputReporter.before_errors(run_id); + END; + + PROCEDURE show_error + IS + BEGIN + utOutputReporter.show_error; + END; + + PROCEDURE after_errors(run_id IN utr_error.run_id%TYPE) + IS + BEGIN + utOutputReporter.after_errors(run_id); + END; + PROCEDURE CLOSE(bool_abort BOOLEAN := FALSE) IS BEGIN - IF NOT bool_abort THEN + IF NOT bool_abort AND g_fid.ID IS NOT NULL THEN pl('-- '||TO_CHAR(SYSDATE,Utconfig.dateformat)); END IF; @@ -159,6 +204,10 @@ Added first version of pluggable reporter packages IS BEGIN + IF g_fid.ID IS NULL THEN + utfilereporter.open; + END IF; + -- write input to file UTL_FILE.PUT_LINE (g_fid, str); From d648fb7e914cff2de63f571f6f5f443546a55fec Mon Sep 17 00:00:00 2001 From: chrisrimmer Date: Wed, 25 May 2005 13:22:07 +0000 Subject: [PATCH 094/143] Added extra documentation on writing your own reporter --- documentation/src/reporter.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/documentation/src/reporter.html b/documentation/src/reporter.html index 6210e8292..ce19a1a9d 100644 --- a/documentation/src/reporter.html +++ b/documentation/src/reporter.html @@ -80,7 +80,10 @@

    Writing your own Reporter

    Your reporter package can define other functions and procedures, for example to allow configuration, but all the procedures shown above should be defined. -The usage of these procedures is as follows: +The usage of these procedures follows. Note If you want to keep the +format of the output the same as for the Output Reporter, but wish to send +it elsewhere, you can define open, close and pl, but simply call the equivalent +procedure in utOutputReporter for the others. For an example of this, see the File Reporter.

    open

    This is called at the very start of the process and is the ideal place to do initialization, such as opening any files that you will be writing to.

    From 38f98bd6d470aaed3f70492ef3e634ce2f0e2e68 Mon Sep 17 00:00:00 2001 From: Patrick Barel Date: Thu, 2 Jun 2005 12:06:43 +0000 Subject: [PATCH 095/143] Minor change to get the script working on PBA's machine --- documentation/src/build_docs.pl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/documentation/src/build_docs.pl b/documentation/src/build_docs.pl index 03465e012..c3a9164ab 100755 --- a/documentation/src/build_docs.pl +++ b/documentation/src/build_docs.pl @@ -92,7 +92,10 @@ open OUTPUT, ">$OUTDIR/$map[$index]->[0]" or die "Cannot open $OUTDIR/$map[$index]->[0]"; if ($index != $#map){ - system("./clean_html.pl $map[$index]->[0] > $map[$index]->[0].clean"); +# PBA 20050602: The following line didn't seem to work on my configuration +# removed the ./ and now it does work. +# system("./clean_html.pl $map[$index]->[0] > $map[$index]->[0].clean"); + system("clean_html.pl $map[$index]->[0] > $map[$index]->[0].clean"); open INPUT, "$map[$index]->[0].clean" or die "Cannot open $map[$index]->[0].clean"; } @@ -103,7 +106,7 @@ print OUTPUT "$map[$index]->[1]\n"; print OUTPUT "\n"; print OUTPUT "\n"; - print OUTPUT "\n"; + print OUTPUT "\n"; print OUTPUT "[1]\"/>\n"; print OUTPUT "\n"; print OUTPUT "\n"; From c25e5e2c3540ae1c20fa82b781b8b42484111b73 Mon Sep 17 00:00:00 2001 From: Patrick Barel Date: Tue, 21 Jun 2005 17:26:04 +0000 Subject: [PATCH 096/143] Updated the release notes to reflect the relocation of the pl procedure --- documentation/src/release.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/src/release.html b/documentation/src/release.html index 1c7c57d13..db70a7de4 100644 --- a/documentation/src/release.html +++ b/documentation/src/release.html @@ -26,7 +26,7 @@

    utPLSQL version 2.2

    -Given that, let's take a look at the implementation of the test program: -
    PROCEDURE ut_setpath
    +
    +PROCEDURE ut_setpath
     IS
     BEGIN
        /* Populate base collection */
    @@ -148,16 +181,22 @@ 

    'fileio.dirs', 'fileio.ut_dirs' ); -END;

    -This program consists of three steps: -
    -
  • -Populate the test collection with direct assignments. Call the setPath -program to populate the actual collection (fileIO.dirs). Call the assertion -program to compare the two. Notice that I pass the names of the -collections to the assertion program. utAssert uses dynamic SQL to build -a PL/SQL block "on the fly" that compares values from the collections.
  • -
    +END; +
    + +

    This program consists of three steps:

    + +
    +
      +
    • + Populate the test collection with direct assignments. Call the setPath + program to populate the actual collection (fileIO.dirs). Call the assertion + program to compare the two. Notice that I pass the names of the + collections to the assertion program. utAssert uses dynamic SQL to build + a PL/SQL block "on the fly" that compares values from the collections. +
    • +
    +
    diff --git a/documentation/src/started.html b/documentation/src/started.html index dade88f1c..b431d4540 100644 --- a/documentation/src/started.html +++ b/documentation/src/started.html @@ -1,63 +1,62 @@ - - + + + + + + + -

    -Getting Started

    +

    Getting Started

    -

    This document gives you all the information you need to get started -with utPLSQL: how to install the product, build a test package and run -your test. If you are new to unit testing, you should take a few moments -to review the Glossary to familiarize yourself with the terminology. -

    And it is always worthwhile reviewing requirements before installing -the software! -

    -What is utPLSQL and what do I need?

    +

    + This document gives you all the information you need to get started + with utPLSQL: how to install the product, build a test package and run + your test. If you are new to unit testing, you should take a few moments + to review the Glossary to familiarize yourself with the terminology. +

    + +

    + And it is always worthwhile reviewing requirements before installing + the software! +

    -
    -

    -Glossary

    +

    What is utPLSQL and what do I need?

    -

    -Requirements

    -
    +
    +

    Glossary

    -

    -The Four Step Program to Using utPLSQL

    +

    Requirements

    +
    -
    -

    -Step 1. Install utPLSQL.

    +

    The Four Step Program to Using utPLSQL

    -

    -Step 2. Choose a program to test and identify -the test cases.

    +
    +

    Step 1. Install utPLSQL.

    -

    -Step 3. Build a test package.

    +

    Step 2. Choose a program to test and identify the test cases.

    -

    -Step 4. Run your test.

    +

    Step 3. Build a test package.

    -

    -Where -To Go From Here

    -
    +

    Step 4. Run your test.

    -

    -Administrative Topics

    +

    + + Where To Go From Here +

    +
    -
    -

    -Configuring UTL_FILE

    +

    Administrative Topics

    -

    -Join the Project Team

    +
    +

    Configuring UTL_FILE

    -

    -Reporting Bugs and Enhancement Requests

    +

    Join the Project Team

    -
    +

    Reporting Bugs and Enhancement Requests

    + +
    diff --git a/documentation/src/suite.html b/documentation/src/suite.html index d4f652072..035aed229 100644 --- a/documentation/src/suite.html +++ b/documentation/src/suite.html @@ -1,17 +1,28 @@ - - + + + + + + + -

    -Create and Run a Test Suite

    +

    Create and Run a Test Suite

    -

    Usually our applications are composed of multiple packages. To test -our application, we must test all of the packages. utPLSQL makes it easier -for you to do that by offering test suites. -

    Here is an example of a script that defines a (partial) test suite for -PL/Vision, a code library available from RevealNet -as part of its Active PL/SQL Knowledge Base: -

    /*file plvision.tst */
    +   

    + Usually our applications are composed of multiple packages. To test + our application, we must test all of the packages. utPLSQL makes it easier + for you to do that by offering test suites. +

    +

    + Here is an example of a script that defines a (partial) test suite for + PL/Vision, a code library available from RevealNet + as part of its Active PL/SQL Knowledge Base: +

    + +
    +/*file plvision.tst */
     BEGIN
        -- Define a test suite for PL/Vision
        utsuite.add ('PLVision');
    @@ -22,17 +33,25 @@ 

    utpackage.add ( 'PLVision', 'PLVdate', dir_in => 'e:\openoracle\utplsql\examples'); END; -/

    -This is a very simple test suite definition. I rely on all defaults, but -I specify a location for my test package code. By doing this, utPLSQL will -be able to find my test packages even if the default/current utPLSQL directory -is set to another location. -

    If I want to, I can also specify the order in which packages are tested -by passing a value for the seq_in argument. I can request that the test -code be looked for in the same package as the source code, and so on. Here -is a rewriting of the above sutie creation script that demonstrates these -options: -

    BEGIN
    +/
    +
    + +

    + This is a very simple test suite definition. I rely on all defaults, but + I specify a location for my test package code. By doing this, utPLSQL will + be able to find my test packages even if the default/current utPLSQL directory + is set to another location. +

    +

    + If I want to, I can also specify the order in which packages are tested + by passing a value for the seq_in argument. I can request that the test + code be looked for in the same package as the source code, and so on. Here + is a rewriting of the above sutie creation script that demonstrates these + options: +

    + +
    +BEGIN
        utsuite.add ('PLVision');
     
        utpackage.add ('PLVision',
    diff --git a/documentation/src/template.html b/documentation/src/template.html
    index d417e748e..b07d2978b 100644
    --- a/documentation/src/template.html
    +++ b/documentation/src/template.html
    @@ -1,30 +1,34 @@
    -
    -
    +
    +
    +
    +   
    +   
    +
    +
     
     
    -

    -Heading -

    +

    Heading

    -

    -Subheading 1 -

    -Some body text here... +

    Subheading 1

    +

    + Some body text here... +

     BEGIN
       Some.Example(Code);
     END;
     
    -

    -Subheading 2 -

    -Some more body text here... -
      -
    • Point 1
    • -
    • Point 2
    • -
    • Point 3
    • -
    +

    Subheading 2

    +

    + Some more body text here... +

    +
      +
    • Point 1
    • +
    • Point 2
    • +
    • Point 3
    • +
    diff --git a/documentation/src/testapi.html b/documentation/src/testapi.html index ebea4a8d7..ef2e08c32 100644 --- a/documentation/src/testapi.html +++ b/documentation/src/testapi.html @@ -1,49 +1,67 @@ - - + + + + + + + -

    -Test an Entire Package API

    +

    Test an Entire Package API

    -

    Most packages consist of lots more than a single program, and you will -generally want to test each and every of the programs listed in the package -specification. When you generate a test package with utGen, -it will produce a template unit test procedure for each program in the -package specification. You will then need to modify each of these programs. -

    One example of this more complex package structure is the table encapsulation -package. This kind of package establishes a layer of code and therefore -control between application requirements and underlying data structures. -While the building of such a layer is uncommon in the world of PL/SQL developers, -it is strongly recommended practice. A variety of tools, in fact, offer -automated table encapsulation package generation, including Oracle -Designer, RevealNet's PL/Generator -and a variety of IDE (integrated development environment) tools. -

    Suppose, then, that I used PL/Generator to generate a table encapsulation -package for the employee table. It would look like the code found in te_employee.pks -and te_employee.pkb(1) (being rather -lengthy, we will not reproduce it in the documentation. If you take a look, -you will see that their are dozens of programs in the API, which means -that you would have lots of work to do in building your unit test cases. -In addition, many of the programs will be performing DML operations (updating, -deleting, inserting). How you can easily and dependably test those programs? -

    When you are dealing with lots of programs that have a uniform structure -and behavior (which should be the case if you are building table -API packages), then you should look for ways to generate, rather -than write manually, your test package. utGen cannot do this generation -work for you, since the logic in your encapsulation package is specific -to your environment. -

    You can, instead, build your own custom generator or use an existing -generator that is sufficiently flexible to meet your needs. The original -creator of utPLSQL, Steven Feuerstein, -has also been working on generator utilities for a number of years. One -of these utilities, currently "code named" GenX, came in very handy for -creating a test package for his PL/Generator-generated encapsulation packages. -

    Using CGML (Code Generation Markup Language), Steven created a template -(See te_utpkg.gdr in the Examples directory of the utPLSQL distribution) -that reads information from the data dictionary and defines the setup, -teardown and at least a good starting point for the unit test procedures. -Here is the template logic for the setup procedure: -

       PROCEDURE {utprefix}setup
    +   

    + Most packages consist of lots more than a single program, and you will + generally want to test each and every of the programs listed in the package + specification. When you generate a test package with utGen, + it will produce a template unit test procedure for each program in the + package specification. You will then need to modify each of these programs. +

    +

    + One example of this more complex package structure is the table encapsulation + package. This kind of package establishes a layer of code and therefore + control between application requirements and underlying data structures. + While the building of such a layer is uncommon in the world of PL/SQL developers, + it is strongly recommended practice. A variety of tools, in fact, offer + automated table encapsulation package generation, including Oracle + Designer, RevealNet's PL/Generator + and a variety of IDE (integrated development environment) tools. +

    +

    + Suppose, then, that I used PL/Generator to generate a table encapsulation + package for the employee table. It would look like the code found in te_employee.pks + and te_employee.pkb(1) (being rather + lengthy, we will not reproduce it in the documentation. If you take a look, + you will see that their are dozens of programs in the API, which means + that you would have lots of work to do in building your unit test cases. + In addition, many of the programs will be performing DML operations (updating, + deleting, inserting). How you can easily and dependably test those programs? +

    +

    + When you are dealing with lots of programs that have a uniform structure + and behavior (which should be the case if you are building table + API packages), then you should look for ways to generate, rather + than write manually, your test package. utGen cannot do this generation + work for you, since the logic in your encapsulation package is specific + to your environment. +

    +

    + You can, instead, build your own custom generator or use an existing + generator that is sufficiently flexible to meet your needs. The original + creator of utPLSQL, Steven Feuerstein, + has also been working on generator utilities for a number of years. One + of these utilities, currently "code named" GenX, came in very handy for + creating a test package for his PL/Generator-generated encapsulation packages. +

    +

    + Using CGML (Code Generation Markup Language), Steven created a template + (See te_utpkg.gdr in the Examples directory of the utPLSQL distribution) + that reads information from the data dictionary and defines the setup, + teardown and at least a good starting point for the unit test procedures. + Here is the template logic for the setup procedure: +

    +
    +   PROCEDURE {utprefix}setup
        IS
        BEGIN
           -- Clean start
    @@ -66,15 +84,23 @@ 

    [ENDIF] [ENDFOREACH] - END;

    -You are not, of course, expected to understand all the logic and syntax -in this fragment. If you are interested in pursuing these sorts of genreation -opportunities and would like to check out GenX, drop a note to Steven -Feuerstein. -

    Here is a portion of the generated logic (found in ut_te_employee.pks -and ut_te_employee.pkb"(1)), the -program that tests the delete operation in the encapsulation package: -

       PROCEDURE ut_del1
    +   END;
    +
    + +

    + You are not, of course, expected to understand all the logic and syntax + in this fragment. If you are interested in pursuing these sorts of genreation + opportunities and would like to check out GenX, drop a note to Steven + Feuerstein. +

    +

    + Here is a portion of the generated logic (found in ut_te_employee.pks + and ut_te_employee.pkb"(1)), the + program that tests the delete operation in the encapsulation package: +

    + +
    +   PROCEDURE ut_del1
        IS
           fdbk PLS_INTEGER;
        BEGIN
    @@ -114,42 +140,57 @@ 

    'DEL1 exception ' || SQLERRM, SQLCODE = 0 ); - END;

    -In this procedure, I test for two scenarios: a delete that removes zero -rows and a delete that removes a specific set of rows. In both cases, I -perform the explicit (non-encapsulated) DML logic against a copy -of the actual table (this copy is created in the setup -procedure; that is the reason I use dynamic SQL to refer to this table --- it doesn't exist when the package is compiled!). Then I do the (hopefully) -same operation by using the API program. Finally, I call the appropriate -utAssert assertion program to compare the results -- and at the end of -the procedure issue a ROLLBACK so that my "source" table (employee, in -this case), i set back to the original data state. Notice that I also put -an assertion program in the exception section to trap any errors and flag -it as a failed test. -

    That should give you a good feel for the kind of code you might write -to test a table encapsulation package. The next two sections show you how -I used the setup and teardown procedures to manage the data structures -I use in my tests. -

    -Set Up Data Structures

    -As I contemplated how best to test these large packages, I revisited some -of my testing principles and found one to be of particular importance: + END; +
    + +

    + In this procedure, I test for two scenarios: a delete that removes zero + rows and a delete that removes a specific set of rows. In both cases, I + perform the explicit (non-encapsulated) DML logic against a copy + of the actual table (this copy is created in the setup + procedure; that is the reason I use dynamic SQL to refer to this table + -- it doesn't exist when the package is compiled!). Then I do the (hopefully) + same operation by using the API program. Finally, I call the appropriate + utAssert assertion program to compare the results -- and at the end of + the procedure issue a ROLLBACK so that my "source" table (employee, in + this case), i set back to the original data state. Notice that I also put + an assertion program in the exception section to trap any errors and flag + it as a failed test. +

    +

    + That should give you a good feel for the kind of code you might write + to test a table encapsulation package. The next two sections show you how + I used the setup and teardown procedures to manage the data structures + I use in my tests. +

    -

    Build isolated tests. +

    Set Up Data Structures

    + +

    + As I contemplated how best to test these large packages, I revisited some + of my testing principles and found one to be of particular importance: +

    -

    This principle is important because it allows you to run one, all or -a subset of your tests without having to worry about the impact or dependencies -on the other tests. And test isolation is particularly important -when testing DML operations. The way to validate a successful DML operation -is by analyzing the contents of the "source" table against a "test" table. -If all the tests modify the same test table, ti will be very difficult -if not impossible to verify success or notice failure. -

    So I decided that the best way to run my unit tests for DML operations -was to create a separate test table for each unit test. As a consequence, -my setup procedure for the te_employee package looks like this: -(See ut_te_employee.pkb in the Examples directory of the utPLSQL distribution) -

       PROCEDURE ut_setup
    +   

    Build isolated tests.

    + +

    + This principle is important because it allows you to run one, all or + a subset of your tests without having to worry about the impact or dependencies + on the other tests. And test isolation is particularly important + when testing DML operations. The way to validate a successful DML operation + is by analyzing the contents of the "source" table against a "test" table. + If all the tests modify the same test table, ti will be very difficult + if not impossible to verify success or notice failure. +

    +

    + So I decided that the best way to run my unit tests for DML operations + was to create a separate test table for each unit test. As a consequence, + my setup procedure for the te_employee package looks like this: + (See ut_te_employee.pkb in the Examples directory of the utPLSQL distribution) +

    + +
    +   PROCEDURE ut_setup
        IS
        BEGIN
           ut_teardown;
    @@ -171,18 +212,29 @@ 

    SELECT * FROM employee'; EXECUTE IMMEDIATE 'CREATE TABLE ut_UPD$SALARY1 AS SELECT * FROM employee'; - END;

    -I first remove all my data structures using the teardown procedure to make -sure I have a clean start. Then I use dynamic SQL (the Oracle8i version) -to create all my tables. I must rely on dynamic SQL because PL/SQL does -not yet support native DDL statements, such as CREATE TABLE. -

    Then I am set to test. -

    -Tear Down Data Structures

    -Well, if I am going to create a whole bunch of data structures to run my -tests, I had better get rid of those structures when I am done. Here is -the teardown program I generated for the te_employee package: -
       PROCEDURE ut_teardown
    +   END;
    +
    + +

    + I first remove all my data structures using the teardown procedure to make + sure I have a clean start. Then I use dynamic SQL (the Oracle8i version) + to create all my tables. I must rely on dynamic SQL because PL/SQL does + not yet support native DDL statements, such as CREATE TABLE. +

    +

    + Then I am set to test. +

    + +

    Tear Down Data Structures

    + +

    + Well, if I am going to create a whole bunch of data structures to run my + tests, I had better get rid of those structures when I am done. Here is + the teardown program I generated for the te_employee package: +

    + +
    +   PROCEDURE ut_teardown
        IS
        BEGIN
           BEGIN
    @@ -257,13 +309,21 @@ 

    NULL; END; - END;

    -Again, I use dynamic SQL, but enclose each DROP TABLE statement inside -its own exception section so that if for any reason the DROP fails, I continue -on in an attempt to get as much done as possible. -
    -

    Footnotes

    -1. These files are in the Examples directory of the utPLSQL distribution. + END; +
    + +

    + Again, I use dynamic SQL, but enclose each DROP TABLE statement inside + its own exception section so that if for any reason the DROP fails, I continue + on in an attempt to get as much done as possible. +

    + +
    + +

    Footnotes

    +

    + 1. These files are in the Examples directory of the utPLSQL distribution. +

    diff --git a/documentation/src/testfunc.html b/documentation/src/testfunc.html index d5d9d63fa..8a6fc6176 100644 --- a/documentation/src/testfunc.html +++ b/documentation/src/testfunc.html @@ -1,39 +1,48 @@ - - + + + + + + + -

    -Test a Function

    +

    Test a Function

    -

    As with the procedure, there are a couple of scenarios to consider: -

      -
    • -The function returns a scalar value (number, -date, string, Boolean). In this case, you can embed your call to the function -directly inside a call to a uAssert assertion program, making your test -procedure very concise and easy to write.
    • +

      + As with the procedure, there are a couple of scenarios to consider: +

      +
        +
      • + The function returns a scalar value (number, + date, string, Boolean). In this case, you can embed your call to the function + directly inside a call to a uAssert assertion program, making your test + procedure very concise and easy to write. +
      • +
      • + The function returns a non-scalar value, + such as an object or a collection. In this case, you will need to call + the function and then evaluate the contents of the returned structure. +
      • +
      • + A third situation to consider is that your function returns a value, but + it also takes a number of other actions, the success of which is not reflected + in the returned value. Fully testing such a function (one with "side effects") + can be very difficult, since you must test for a variety of conditions. +
      • +
      -
    • -The function returns a non-scalar value, -such as an object or a collection. In this case, you will need to call -the function and then evaluate the contents of the returned structure.
    • - - - -
    • -A third situation to consider is that your function returns a value, but -it also takes a number of other actions, the success of which is not reflected -in the returned value. Fully testing such a function (one with "side effects") -can be very difficult, since you must test for a variety of conditions.
    • - -
    +

    Testing a Scalar Function

    + +

    + First, a test of a function returning a scalar value. Consider the following + packaged function: +

    -

    -Testing a Scalar Function

    -First, a test of a function returning a scalar value. Consider the following -packaged function: -
    /*file str.pks and str.pkb */
    +
    +/*file str.pks and str.pkb */
     CREATE OR REPLACE PACKAGE str
     IS
        FUNCTION betwn (
    @@ -43,12 +52,21 @@ 

    ) RETURN VARCHAR2; END str; -/

    -The str.betwn function returns the sub-string of a string_in that is found -between the start and end locations specified by start_in and end_in. -

    So...time to test! I generate a test package -and then modify the unit test procedure to check for various conditions: -

    /*file ut_str.pkb */
    +/
    +
    + +

    + The str.betwn function returns the sub-string of a string_in that is found + between the start and end locations specified by start_in and end_in. +

    + +

    + So...time to test! I generate a test package + and then modify the unit test procedure to check for various conditions: +

    + +
    +/*file ut_str.pkb */
     CREATE OR REPLACE PACKAGE BODY ut_str
     IS
        PROCEDURE ut_setup
    @@ -85,9 +103,13 @@ 

    END ut_betwn; END ut_str; -/

    -As you can see, my calls to str.betwn are embedded right within calls to -utAssert.eq and utAssert.isNULL, making my test code compact. +/ +
    + +

    + As you can see, my calls to str.betwn are embedded right within calls to + utAssert.eq and utAssert.isNULL, making my test code compact. +

    diff --git a/documentation/src/testproc.html b/documentation/src/testproc.html index 9fb608cf6..a00b1f523 100644 --- a/documentation/src/testproc.html +++ b/documentation/src/testproc.html @@ -1,32 +1,42 @@ - - + + + + + + + -

    -Test a Procedure

    - -

    There are a couple of scenarios to consider: -

      -
    • -The procedure runs some code and then passes back results through the parameter -list. In this case, I can write a unit test that analyzes the OUT and IN -OUT argument values.
    • - -The procedure runs some code, which changes -other elements of the application (such as a database table or a file). -The parameter list does not contain arguments that can be analyzed for -successful execution. So to assert success, I will need to analyze/compare -the data structures that have been modified. -
    - -

    -Test Success Through Parameters

    - -We'll start with a really simple example. I -have built a procedure that accepts two dates and returns the number of -seconds between them. Here it is: - -
    /*file calc_secs_between.sp */
    +   

    Test a Procedure

    + +

    There are a couple of scenarios to consider:

    + +
      +
    • + The procedure runs some code and then passes back results through the parameter + list. In this case, I can write a unit test that analyzes the OUT and IN + OUT argument values. +
    • +
    • + The procedure runs some code, which changes + other elements of the application (such as a database table or a file). + The parameter list does not contain arguments that can be analyzed for + successful execution. So to assert success, I will need to analyze/compare + the data structures that have been modified. +
    • +
    + +

    Test Success Through Parameters

    + +

    + We'll start with a really simple example. I + have built a procedure that accepts two dates and returns the number of + seconds between them. Here it is: +

    + +
    +/*file calc_secs_between.sp */
     CREATE OR REPLACE PROCEDURE calc_secs_between (
        date1 IN DATE,
        date2 IN DATE,
    @@ -38,12 +48,16 @@ 

    -- 60 seconds in a minute... secs := (date2 - date1) * 24 * 60 * 60; END; -/

    +/ +
    -After compiling my code cleanly, I generate -my test package: +

    + After compiling my code cleanly, I generate + my test package: +

    -
    SQL> SET SERVEROUTPUT ON FORMAT WRAPPED
    +
    +SQL> SET SERVEROUTPUT ON FORMAT WRAPPED
     SQL> exec utGen.testpkg ('calc_secs_between ')
     CREATE OR REPLACE PACKAGE ut_calc_secs_between
     IS
    @@ -86,20 +100,28 @@ 

    END ut_CALC_SECS_BETWEEN; END ut_calc_secs_between; -/

    - -I generated the output to the screen, but it -is actually easier to deposit the code directly into two separate files -for package spec and body, ut_calc_secs_between.pks and ut_calc_secs_between.pkb, -which I do as follows: - -
    SQL> exec utGen.testpkg ('calc_secs_between ', output_type_in => utGen.c_file)
    - -By conforming to this standard, utPLSQL can -automatically compile this code before each test. I now edit the ut_calc_secs_between -procedure to test for various cases: - -
    PROCEDURE ut_CALC_SECS_BETWEEN 
    +/
    +
    + +

    + I generated the output to the screen, but it + is actually easier to deposit the code directly into two separate files + for package spec and body, ut_calc_secs_between.pks and ut_calc_secs_between.pkb, + which I do as follows: +

    + +
    +SQL> exec utGen.testpkg ('calc_secs_between ', output_type_in => utGen.c_file)
    +
    + +

    + By conforming to this standard, utPLSQL can + automatically compile this code before each test. I now edit the ut_calc_secs_between + procedure to test for various cases: +

    + +
    +PROCEDURE ut_CALC_SECS_BETWEEN 
     IS
        secs PLS_INTEGER;
     BEGIN
    @@ -131,11 +153,13 @@ 

    24 * 60 * 60 ); -END ut_CALC_SECS_BETWEEN;

    +END ut_CALC_SECS_BETWEEN; +
    -and now I can run my test: +

    and now I can run my test:

    -
    SQL> exec utplsql.test ('calc_secs_between')
    +
    +SQL> exec utplsql.test ('calc_secs_between')
     .
     >    SSSS   U     U   CCC     CCC   EEEEEEE   SSSS     SSSS
     >   S    S  U     U  C   C   C   C  E        S    S   S    S
    @@ -147,19 +171,24 @@ 

    > S S U U C C C C E S S S S > SSSS UUU CCC CCC EEEEEEE SSSS SSSS . - SUCCESS: "calc_secs_between"

    + SUCCESS: "calc_secs_between" +
    -Certainly, there are a variety of other conditions -to test, but this should give you a good idea of how to go about it! +

    + Certainly, there are a variety of other conditions + to test, but this should give you a good idea of how to go about it! +

    -

    -Test Success by Analyzing Impact

    +

    Test Success by Analyzing Impact

    -Now let's consider a more complicated situation. -I have a procedure that truncates all the rows in the specified table. -To do this I just use dynamic SQL, as you can see in: +

    + Now let's consider a more complicated situation. + I have a procedure that truncates all the rows in the specified table. + To do this I just use dynamic SQL, as you can see in: +

    -
    /*file truncit.sp */
    +
    +/*file truncit.sp */
     CREATE OR REPLACE PROCEDURE truncit (
        tab IN VARCHAR2,
        sch IN VARCHAR2 := NULL
    @@ -168,15 +197,19 @@ 

    BEGIN EXECUTE IMMEDIATE 'truncate table ' || NVL (sch, USER) || '.' || tab; END; -/

    - -After I run this test, I cannot simply check -the value returned by the procedure. Instead, I must check to see how many -rows are left in the table. Fortunately, I have another dynamic SQL utility -to help me out here, one that returns the count of rows in any table: -(Note that you could also use utAssert.eqqueryvalue here.) - -
    /*file tabcount.sf */
    +/
    +
    + +

    + After I run this test, I cannot simply check + the value returned by the procedure. Instead, I must check to see how many + rows are left in the table. Fortunately, I have another dynamic SQL utility + to help me out here, one that returns the count of rows in any table: + (Note that you could also use utAssert.eqqueryvalue here.) +

    + +
    +/*file tabcount.sf */
     CREATE OR REPLACE FUNCTION tabcount (
        sch IN VARCHAR2,
        tab IN VARCHAR2)
    @@ -193,20 +226,28 @@ 

    THEN RETURN NULL; END; -/

    - -So I will generate a package -to test truncit and then modify the package body: - -
    SQL> SET SERVEROUTPUT ON FORMAT WRAPPED
    -SQL> exec utGen.testpkg ('truncit', output_type_in => utGen.c_file)
    - -To run my test, I need to truncate a table. -That is an irreversible action, so I will create a "temporary" table in -the setup procedure and drop it in the teardown procedure. Then I will -run my code and use tabCount to validate the results: - -
    /*file ut_truncit.pkb */
    +/
    +
    + +

    + So I will generate a package + to test truncit and then modify the package body: +

    + +
    +SQL> SET SERVEROUTPUT ON FORMAT WRAPPED
    +SQL> exec utGen.testpkg ('truncit', output_type_in => utGen.c_file)
    +
    + +

    + To run my test, I need to truncate a table. + That is an irreversible action, so I will create a "temporary" table in + the setup procedure and drop it in the teardown procedure. Then I will + run my code and use tabCount to validate the results: +

    + +
    +/*file ut_truncit.pkb */
     CREATE OR REPLACE PACKAGE BODY ut_truncit
     IS
        PROCEDURE ut_setup
    @@ -240,14 +281,17 @@ 

    END ut_TRUNCIT; END ut_truncit; -/

    - -Not quite as straightforward as checking values -returned in OUT or IN OUT arguments, but not too awful, right? Of course, -things can get considerably more complicated as your code (and the results -you must test for) grows more complex. Regardless, you will find it easier -to build and run your tests through utPLSQL than through more ad hoc and -considerably less organized approaches. +/ +
    + +

    + Not quite as straightforward as checking values + returned in OUT or IN OUT arguments, but not too awful, right? Of course, + things can get considerably more complicated as your code (and the results + you must test for) grows more complex. Regardless, you will find it easier + to build and run your tests through utPLSQL than through more ad hoc and + considerably less organized approaches. +

    diff --git a/documentation/src/testrun.html b/documentation/src/testrun.html index 7cca678bc..f51722ff6 100644 --- a/documentation/src/testrun.html +++ b/documentation/src/testrun.html @@ -1,378 +1,328 @@ - - + + + + + + + -

    -A "Test Run" with utPLSQL

    - -

    I will put utPLSQL to work in a small-scale development -effort, to show you how it all hangs together. I've got a "hangnail" in -my PL/SQL development work, called SUBSTR. This function bothers me and -I want to take care of it. What's the problem? SUBSTR is great when you -know the starting location of a string and number of characters you want. In -many situations, though, I have the start and end locations and I need -to figure out the number of characters I then want. Is it: -

    mystring := SUBSTR (full_string, 5, 17); -- start and end? Nah...
    - -
    mystring := SUBSTR (full_string, 5, 12); -- end – start?
    - -
    mystring := SUBSTR (full_string, 5, 13); -- end – start + 1?
    - -
    mystring := SUBSTR (full_string, 5, 11); -- end – start 1 1?
    - -Why should I have to remember stuff like this? I -never do, and so I take out a scrap of paper, write down 'abcdefgh', put -a mark over the "c" and another over the "g", count on my fingers and then -remember that of course the formula is "end – start + 1". - -All right, so I did that a dozen times, I am sick -of it and determined to stop wasting my time in the future. I will write -a function called "str.betwn" (the betwn function defined in the str package) -that does the work and the remembering for me. - -Instead of immediately coding the function, however, -I will first write my unit tests with utPLSQL! Since my source package -is named "str", I will create a test package named "ut_str". I am a lazy -fellow, so I will take the lazy way out and generate the starting point -for my package: - -
    SQL> exec utgen.testpkg ('str', output_type_in => utplsql.c_file)
    - -Note: for the above call to work, I must have already -set my default directory for utPLSQL, which I do via a SQL*Plus login script -that looks like this: - -
    exec utplsql.setdir ('e:\utplsql\test')
    - -
    SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED
    - -Otherwise, I would need to specify the directory -in my call to genpkg, as in: - -
    SQL> exec utgen.testpkg ('str', output_type_in => utplsql.c_file, dir_in => 'e:\utplsql\test')
    - -I then will find this package spec in the ut_str.pks -file: - -
    CREATE OR REPLACE PACKAGE ut_str
    - -
    IS
    - -
       PROCEDURE ut_setup;
    - -
       PROCEDURE ut_teardown;
    - -
      
    - -
       -- For each program to test...
    - -
       PROCEDURE ut_betwn;
    - -
    END ut_str;
    - -
    /
    - -And I don't really have to modify the specification -at all. The body will, on the other hand, require some work, since I haven't -yet figured out a way to automatically generate the test code itself. Here -is the purely generated test package body found -in the ut_str.pkb file: - -
    CREATE OR REPLACE PACKAGE BODY ut_str
    - -
    IS
    - -
       PROCEDURE ut_setup
    - -
       IS
    - -
       BEGIN
    - -
          NULL;
    - -
       END;
    - -
      
    - -
       PROCEDURE ut_teardown
    - -
       IS
    - -
       BEGIN
    - -
          NULL;
    - -
       END;
    - -
      
    - -
       -- For each program to test...
    - -
       PROCEDURE ut_betwn
    - -
       IS
    - -
       BEGIN
    - -
          utAssert.this (
    - -
             'Test of betwn',
    - -
             <boolean expression>,
    - -
             );
    - -
       END;
    - -
      
    - -
    END ut_str;
    - -
    /
    - -The setup and teardown procedures are fine (I don't -have any special setup and therefore teardown requirements), but the ut_betwn -needs lots of work. It doesn't really test anything yet. - -Before I start writing my test code, however, I -will just sit back and think about what I want to test. Here are some inputs -that I can think of: - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -String - -Start - -End - -Expected Result -
    -"this is a string" - -3 (positive number) - -7 (bigger positive number) - -"is is" -
    -"this is a string" - --3 (invalid negative number) - -7 (bigger positive number) - -"ing" (consistent with SUBSTR behavior) -
    -"this is a string" - -3 (positive number) - -1 (smaller positive number) - -NULL -
    - - -

    We could easily come up with a whole lot more test -cases – and if this was real life and not product documentation, I would -not move forward until I had identified all interesting tests. So let's -suppose I have done that and now I am ready to do some coding. Since I -am testing a function, I will want to compare the result of the function -call to my expected results. I will therefore change my assertion from -the generic "assert this" procedure to the utAssert.eq program, and put -the call to the function right into the assertion routine. Here, then, -is my first crack at transforming my ut_betwn procedure: -

    PROCEDURE ut_betwn IS
    - -
    BEGIN
    - -
       utAssert.eq (
    - -
          'Test of betwn',
    - -
          str.betwn ('this is a string', 3, 7),
    - -
          'is is'
    - -
          );
    - -
    END;
    - -Following the Extreme Programming philosophy ("code -a little, test a lot"), I will test this test case before I add all the -other test cases. I do this with a very simple call: - -
    SQL> exec utplsql.test ('str')
    -
    ->    SSSS   U     U   CCC     CCC   EEEEEEE   SSSS     SSSS
    ->   S    S  U     U  C   C   C   C  E        S    S   S    S
    ->  S        U     U C     C C     C E       S        S
    ->   S       U     U C       C       E        S        S
    ->    SSSS   U     U C       C       EEEE      SSSS     SSSS
    ->        S  U     U C       C       E             S        S
    ->         S U     U C     C C     C E              S        S
    ->   S    S   U   U   C   C   C   C  E        S    S   S    S
    ->    SSSS     UUU     CCC     CCC   EEEEEEE   SSSS     SSSS
    -
    ->SUCCESS: "str"
    - -Now, you could say: "Great it worked!" Or you could -say: "I have no idea if it worked. Maybe it always says success." -I go for the latter, so let's deliberately cause a failure: - -
    PROCEDURE ut_betwn IS
    - -
    BEGIN
    - -
       utAssert.eq (
    - -
          'Test of betwn',
    - -
          str.betwn ('this is a string', 3, 7),
    - -
          'this is a pipe'
    - -
          );
    - -
    END;
    - -Saving the file (but not bothering to recompile, -since utPLSQL will do it for me automagically), -I then run my test again: - -
    SQL> exec utplsql.test ('str', recompile_in=>false)
    -
    ->  FFFFFFF   AA     III  L      U     U RRRRR   EEEEEEE
    ->  F        A  A     I   L      U     U R    R  E
    ->  F       A    A    I   L      U     U R     R E
    ->  F      A      A   I   L      U     U R     R E
    ->  FFFF   A      A   I   L      U     U RRRRRR  EEEE
    ->  F      AAAAAAAA   I   L      U     U R   R   E
    ->  F      A      A   I   L      U     U R    R  E
    ->  F      A      A   I   L       U   U  R     R E
    ->  F      A      A  III  LLLLLLL  UUU   R     R EEEEEEE
    +   

    A "Test Run" with utPLSQL

    + +

    + I will put utPLSQL to work in a small-scale development + effort, to show you how it all hangs together. I've got a "hangnail" in + my PL/SQL development work, called SUBSTR. This function bothers me and + I want to take care of it. What's the problem? SUBSTR is great when you + know the starting location of a string and number of characters you want. In + many situations, though, I have the start and end locations and I need + to figure out the number of characters I then want. Is it: +

    + +
    +mystring := SUBSTR (full_string, 5, 17); -- start and end? Nah...
    +
    +mystring := SUBSTR (full_string, 5, 12); -- end - start?
    +
    +mystring := SUBSTR (full_string, 5, 13); -- end - start + 1?
    +
    +mystring := SUBSTR (full_string, 5, 11); -- end - start 1 1?
    +
    + +

    + Why should I have to remember stuff like this? I + never do, and so I take out a scrap of paper, write down 'abcdefgh', put + a mark over the "c" and another over the "g", count on my fingers and then + remember that of course the formula is "end - start + 1". +

    + +

    + All right, so I did that a dozen times, I am sick + of it and determined to stop wasting my time in the future. I will write + a function called "str.betwn" (the betwn function defined in the str package) + that does the work and the remembering for me. +

    + +

    + Instead of immediately coding the function, however, + I will first write my unit tests with utPLSQL! Since my source package + is named "str", I will create a test package named "ut_str". I am a lazy + fellow, so I will take the lazy way out and generate the starting point + for my package: +

    + +
    +SQL> exec utgen.testpkg ('str', output_type_in => utplsql.c_file)
    +
    + +

    + Note: for the above call to work, I must have already + set my default directory for utPLSQL, which I do via a SQL*Plus login script + that looks like this: +

    + +
    +exec utplsql.setdir ('e:\utplsql\test')
    +
    +SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED
    +
    + +

    + Otherwise, I would need to specify the directory + in my call to genpkg, as in: +

    + +
    +SQL> exec utgen.testpkg ('str', output_type_in => utplsql.c_file, dir_in => 'e:\utplsql\test')
    +
    + +

    I then will find this package spec in the ut_str.pks file:

    + +
    +CREATE OR REPLACE PACKAGE ut_str
    +IS
    +   PROCEDURE ut_setup;
    +   PROCEDURE ut_teardown;
    +   
    +   -- For each program to test...
    +   PROCEDURE ut_betwn;
    +END ut_str;
    +/
    +
    + +

    + And I don't really have to modify the specification + at all. The body will, on the other hand, require some work, since I haven't + yet figured out a way to automatically generate the test code itself. Here + is the purely generated test package body found + in the ut_str.pkb file: +

    + +
    +CREATE OR REPLACE PACKAGE BODY ut_str
    +IS
    +   PROCEDURE ut_setup
    +   IS
    +   BEGIN
    +      NULL;
    +   END;
    +   
    +   PROCEDURE ut_teardown
    +   IS
    +   BEGIN
    +      NULL;
    +   END;
    +   
    +   -- For each program to test...
    +   PROCEDURE ut_betwn
    +   IS
    +   BEGIN
    +      utAssert.this (
    +         'Test of betwn',
    +         <boolean expression>,
    +      );
    +   END;
    +   
    +END ut_str;
    +/
    +
    + +

    + The setup and teardown procedures are fine (I don't + have any special setup and therefore teardown requirements), but the ut_betwn + needs lots of work. It doesn't really test anything yet. +

    + +

    + Before I start writing my test code, however, I + will just sit back and think about what I want to test. Here are some inputs + that I can think of: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    StringStartEndExpected Result
    "this is a string"3 (positive number)7 (bigger positive number)"is is"
    "this is a string"-3 (invalid negative number)7 (bigger positive number)"ing" (consistent with SUBSTR behavior)
    "this is a string"3 (positive number)1 (smaller positive number)NULL
    + + +

    + We could easily come up with a whole lot more test + cases - and if this was real life and not product documentation, I would + not move forward until I had identified all interesting tests. So let's + suppose I have done that and now I am ready to do some coding. Since I + am testing a function, I will want to compare the result of the function + call to my expected results. I will therefore change my assertion from + the generic "assert this" procedure to the utAssert.eq program, and put + the call to the function right into the assertion routine. Here, then, + is my first crack at transforming my ut_betwn procedure: +

    + +
    +PROCEDURE ut_betwn IS
    +BEGIN
    +   utAssert.eq (
    +      'Test of betwn',
    +      str.betwn ('this is a string', 3, 7),
    +      'is is'
    +   );
    +END;
    +
    + +

    + Following the Extreme Programming philosophy ("code + a little, test a lot"), I will test this test case before I add all the + other test cases. I do this with a very simple call: +

    + +
    +SQL> exec utplsql.test ('str')
    +
    +>    SSSS   U     U   CCC     CCC   EEEEEEE   SSSS     SSSS
    +>   S    S  U     U  C   C   C   C  E        S    S   S    S
    +>  S        U     U C     C C     C E       S        S
    +>   S       U     U C       C       E        S        S
    +>    SSSS   U     U C       C       EEEE      SSSS     SSSS
    +>        S  U     U C       C       E             S        S
    +>         S U     U C     C C     C E              S        S
    +>   S    S   U   U   C   C   C   C  E        S    S   S    S
    +>    SSSS     UUU     CCC     CCC   EEEEEEE   SSSS     SSSS
    +
    +>SUCCESS: "str"
    +
    + +

    + Now, you could say: "Great it worked!" Or you could + say: "I have no idea if it worked. Maybe it always says success." + I go for the latter, so let's deliberately cause a failure: +

    + +
    +PROCEDURE ut_betwn IS
    +BEGIN
    +   utAssert.eq (
    +      'Test of betwn',
    +      str.betwn ('this is a string', 3, 7),
    +      'this is a pipe'
    +   );
    +END;
    +
    + +

    + Saving the file (but not bothering to recompile, + since utPLSQL will do it for me automagically), + I then run my test again: +

    + +
    +SQL> exec utplsql.test ('str', recompile_in=>false)
    +
    +>  FFFFFFF   AA     III  L      U     U RRRRR   EEEEEEE
    +>  F        A  A     I   L      U     U R    R  E
    +>  F       A    A    I   L      U     U R     R E
    +>  F      A      A   I   L      U     U R     R E
    +>  FFFF   A      A   I   L      U     U RRRRRR  EEEE
    +>  F      AAAAAAAA   I   L      U     U R   R   E
    +>  F      A      A   I   L      U     U R    R  E
    +>  F      A      A   I   L       U   U  R     R E
    +>  F      A      A  III  LLLLLLL  UUU   R     R EEEEEEE
     
     FAILURE: "str"
     
    -BETWN: Typical Valid Usage; expected "is is", got "this is a pipe"
    - -Now I have a higher degree of confidence that I -am getting this right. Excellent! Now I will add the other test cases: - -
    PROCEDURE ut_betwn IS
    - -
    BEGIN
    - -
       utAssert.eq (
    - -
          'Typical Valid Usage',
    - -
          str.betwn ('this is a string', 3, 7),
    - -
          'is is'
    - -
          );
    - -
         
    - -
       utAssert.eq (
    - -
          'Test Negative Start',
    - -
          str.betwn ('this is a string', -3, 7),
    - -
          'ing'
    - -
          );
    +BETWN: Typical Valid Usage; expected "is is", got "this is a pipe" +
    + +

    + Now I have a higher degree of confidence that I + am getting this right. Excellent! Now I will add the other test cases: +

    + +
    +PROCEDURE ut_betwn IS
    +BEGIN
    +   utAssert.eq (
    +      'Typical Valid Usage',
    +      str.betwn ('this is a string', 3, 7),
    +      'is is'
    +   );
    +   
    +   utAssert.eq (
    +      'Test Negative Start',
    +      str.betwn ('this is a string', -3, 7),
    +      'ing'
    +   );
    +   
    +   utAssert.isNULL (
    +      'Start bigger than end',
    +      str.betwn ('this is a string', 3, 1)
    +   );
    +END;
    +
    + +

    + I will deliberately cause each of these tests to + fail, to give you a sense of the quality of feedback: +

    + +
    +>  FFFFFFF   AA     III  L      U     U RRRRR   EEEEEEE
    +>  F        A  A     I   L      U     U R    R  E
    +>  F       A    A    I   L      U     U R     R E
    +>  F      A      A   I   L      U     U R     R E
    +>  FFFF   A      A   I   L      U     U RRRRRR  EEEE
    +>  F      AAAAAAAA   I   L      U     U R   R   E
    +>  F      A      A   I   L      U     U R    R  E
    +>  F      A      A   I   L       U   U  R     R E
    +>  F      A      A  III  LLLLLLL  UUU   R     R EEEEEEE
     
    -
         
    - -
       utAssert.isNULL (
    - -
          'Start bigger than end',
    - -
          str.betwn ('this is a string', 3, 1)
    - -
          );
    - -
    END;
    - -I will deliberately cause each of these tests to -fail, to give you a sense of the quality of feedback: - -
    >  FFFFFFF   AA     III  L      U     U RRRRR   EEEEEEE
    ->  F        A  A     I   L      U     U R    R  E
    ->  F       A    A    I   L      U     U R     R E
    ->  F      A      A   I   L      U     U R     R E
    ->  FFFF   A      A   I   L      U     U RRRRRR  EEEE
    ->  F      AAAAAAAA   I   L      U     U R   R   E
    ->  F      A      A   I   L      U     U R    R  E
    ->  F      A      A   I   L       U   U  R     R E
    ->  F      A      A  III  LLLLLLL  UUU   R     R EEEEEEE
    -
    -FAILURE: "str"
    - -
    betwn: Typical Valid Usage; expected "is is", got "this is a pipe"
    - -
    betwn: Test Negative Start; expected "ing", got "BRRRING"
    - -
    betwn: IS NOT NULL: Start bigger than end
    - -Faced with these results, I can zoom in on the code -within str.betwn that is causing these incorrect results. I resist the -temptation to fix the code for all my tests all at once. Instead, I make -one change at a time, then run my test again. I do that over and over again -until the failure for the single test case goes away. Then I move to the -next one. Eventually, I get a green light and am highly confident of my -program – if, of course, I really did come up with an exhaustive list of -tests. - -As I think of another test case, I add a call to -utAssert to run that test. - -As a bug is reported to me, I add a call to utAssert -to reproduce that bug. Then I repair my code. +FAILURE: "str" +betwn: Typical Valid Usage; expected "is is", got "this is a pipe" +betwn: Test Negative Start; expected "ing", got "BRRRING" +betwn: IS NOT NULL: Start bigger than end +
    + +

    + Faced with these results, I can zoom in on the code + within str.betwn that is causing these incorrect results. I resist the + temptation to fix the code for all my tests all at once. Instead, I make + one change at a time, then run my test again. I do that over and over again + until the failure for the single test case goes away. Then I move to the + next one. Eventually, I get a green light and am highly confident of my + program - if, of course, I really did come up with an exhaustive list of + tests. +

    + +

    + As I think of another test case, I add a call to + utAssert to run that test. +

    + +

    + As a bug is reported to me, I add a call to utAssert + to reproduce that bug. Then I repair my code. +

    diff --git a/documentation/src/userguide.html b/documentation/src/userguide.html index 4f2e85a16..ca07a47c4 100644 --- a/documentation/src/userguide.html +++ b/documentation/src/userguide.html @@ -1,49 +1,52 @@ - - + + + + + + + -

    -User Guide

    +

    User Guide

    -

    The utPLSQL unit testing framework consists of several different elements: -

      -
    • -A set of tables to hold information about unit tests and test suites.
    • -
    • A set of packages that allow you to run tests, -build test packages and access information about tests you have run.
    • -
    -This document tells you how to use those utPLSQL packages: -

    -utPLSQL - Register and run test packages

    +

    + The utPLSQL unit testing framework consists of several different elements: +

    +
      +
    • + A set of tables to hold information about unit tests and test suites. +
    • +
    • + A set of packages that allow you to run tests, + build test packages and access information about tests you have run. +
    • +
    -

    -utConfig - Set how tests are run

    +

    This document tells you how to use those utPLSQL packages:

    + +

    utPLSQL - Register and run test packages

    -

    -utResult - Analyze and display results -of unit tests

    +

    utConfig - Set how tests are run

    -

    -utAssert - Assert that code works -properly

    +

    + utResult - Analyze and display results + of unit tests +

    -

    -utGen - Generate test packages

    +

    utAssert - Assert that code works properly

    -

    - utOutput - Handling DBMS_OUTPUT for testing

    +

    utGen - Generate test packages

    -

    - utRecEq - Generate functions to compare record types

    +

    utOutput - Handling DBMS_OUTPUT for testing

    -

    -Define Test Suites

    +

    utRecEq - Generate functions to compare record types

    -

    -Using and defining Custom Reporter Packages +

    Define Test Suites

    -

    -Configuring the File Reporter +

    Using and defining Custom Reporter Packages

    + +

    Configuring the File Reporter

    diff --git a/documentation/src/utassert.html b/documentation/src/utassert.html index 384f082b9..4ed5acf94 100644 --- a/documentation/src/utassert.html +++ b/documentation/src/utassert.html @@ -1,557 +1,1003 @@ - - + + + + + + + -

    utAssert Package

    +

    utAssert Package

    -

    This package contains the following procedures and functions:
    +

    This package contains the following procedures and functions:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    utAssert.thisGeneric "Assert This" Procedure
    utAssert.isnull
    - utAssert.isnotnull
    Check for NULL and NOT NULL values
    utAssert.eqCheck Equality of Scalar Values
    utAssert.eqtableCheck Equality of Database Tables
    utAssert.eqtabcountCheck Equality of Table Counts
    utAssert.eqqueryCheck Equality of Queries
    utAssert.eqqueryvalueCheck Equality of Query against single value
    utAssert.eqfileCheck Equality of Files
    utAssert.eqpipeCheck Equality of Database Pipes
    utAssert.eqcoll
    - utAssert.eqcollapi
    Check Equality of Collections
    utAssert.throwsCheck a procedure or function throws an exception
    utAssert.previous_passed
    -utAssert.previous_failed

    -
    Check if the previous assertion -passed or failed
    -
    utAssert.eqoutputCheck Equality of DBMS_OUTPUT Collections
    utAssert.objexists
    - utAssert.objnotexists
    Check for existence of database objects
    utAssert.eq_refc_queryCheck Equality of RefCursor and Query
    utAssert.eq_refc_tableCheck Equality of RefCursor and Database Table
    - The utAssert package provides a set of assertion routines ("assert that -the following condition is true") that you will use to register the outcome -of a test case. You must call a utAssert assertion program after (or containing) -a test case so that the results of that test can be recorded and then reported. -See Build Test Packages for many examples and -more details on this process. Here is a very simple example, though, to give -you an idea of the code you would write:
       PROCEDURE ut_BETWNSTR IS
    BEGIN
    utAssert.eq (
    'Typical valid usage',
    BETWNSTR(
    STRING_IN => 'abcdefg'
    ,
    START_IN => 3
    ,
    END_IN => 5
    ),
    'cde'
    );
    END;
    - utAssert offers a wide (and ever expanding) set of assertion programs that -allow you to efficiently (a) test the outcome of your unit test and (b) report -the results of that test to utPLSQL. You should review -Common Assertion Parameters and Behavior before using any specific assertion -program. It is also possible to build your own assertion -routine. Note: all utAssert assertions are defined in the ut_assertion -table, as well as actually coded in the utAssert package.

    -

    Common Assertion Parameters and Behavior

    - Each type of assertion routine accepts different kinds of data, but there -are lots of similarities between the assertions, as well. Here is an explanation -of the common assertion parameters: - - - - - - - - - - - - - - - - - - - - - - +
    msg_in A message to be displayed if the assertion -fails. This is the first argument and is mandatory, because the tests need -to be self documenting.
    check_this_in The value to be checked.. If a Boolean expression, -this will usually include the invocation of the method being tested, resulting -in a single line of code for the entire test case.
    against_this_in For assert_eq, the assertion routine will -check the check_this_in value against the against_this_in value. This parameter -should be the certifiably correct value.
    null_ok_in TRUE if a NULL value should be interpreted -as a successful test, FALSE if NULL indicates failure.
    raise_exc_in TRUE if it is OK for the assertion routine -to allow an exception to be propagated out unhandled.
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    utAssert.thisGeneric "Assert This" Procedure
    + utAssert.isnull + utAssert.isnotnull + Check for NULL and NOT NULL values
    utAssert.eqCheck Equality of Scalar Values
    utAssert.eqtableCheck Equality of Database Tables
    utAssert.eqtabcountCheck Equality of Table Counts
    utAssert.eqqueryCheck Equality of Queries
    utAssert.eqqueryvalueCheck Equality of Query against single value
    utAssert.eqfileCheck Equality of Files
    utAssert.eqpipeCheck Equality of Database Pipes
    + utAssert.eqcoll + utAssert.eqcollapi + Check Equality of Collections
    utAssert.throwsCheck a procedure or function throws an exception
    + utAssert.previous_passed + utAssert.previous_failed + + Check if the previous assertion + passed or failed +
    utAssert.eqoutputCheck Equality of DBMS_OUTPUT Collections
    + utAssert.objexists + utAssert.objnotexists + Check for existence of database objects
    utAssert.eq_refc_queryCheck Equality of RefCursor and Query
    utAssert.eq_refc_tableCheck Equality of RefCursor and Database Table
    +

    + The utAssert package provides a set of assertion routines ("assert that + the following condition is true") that you will use to register the outcome + of a test case. You must call a utAssert assertion program after (or containing) + a test case so that the results of that test can be recorded and then reported. + See Build Test Packages for many examples and + more details on this process. Here is a very simple example, though, to give + you an idea of the code you would write: +

    + +
    +PROCEDURE ut_BETWNSTR IS
    +BEGIN
    +   utAssert.eq (
    +      'Typical valid usage',
    +      BETWNSTR(
    +         STRING_IN => 'abcdefg',
    +         START_IN => 3,
    +         END_IN => 5
    +      ),
    +      'cde'
    +   );
    +END;
    +
    +

    + utAssert offers a wide (and ever expanding) set of assertion programs that + allow you to efficiently (a) test the outcome of your unit test and (b) report + the results of that test to utPLSQL. You should review + Common Assertion Parameters and Behavior before using any specific assertion + program. It is also possible to build your own assertion + routine. Note: all utAssert assertions are defined in the ut_assertion + table, as well as actually coded in the utAssert package. +

    + +

    Common Assertion Parameters and Behavior

    + +

    + Each type of assertion routine accepts different kinds of data, but there + are lots of similarities between the assertions, as well. Here is an explanation + of the common assertion parameters: +

    + + + + + + + + + + + + + + + + + + + + + + +
    msg_in + A message to be displayed if the assertion + fails. This is the first argument and is mandatory, because the tests need + to be self documenting. +
    check_this_in + The value to be checked.. If a Boolean expression, + this will usually include the invocation of the method being tested, resulting + in a single line of code for the entire test case. +
    against_this_in + For assert_eq, the assertion routine will + check the check_this_in value against the against_this_in value. This parameter + should be the certifiably correct value. +
    null_ok_in + TRUE if a NULL value should be interpreted + as a successful test, FALSE if NULL indicates failure. +
    raise_exc_in + TRUE if it is OK for the assertion routine + to allow an exception to be propagated out unhandled. +
    + +

    Generic "Assert This" Assertion Procedure

    + +

    + This most generic assertion program simply says "assert this" and passes + a Boolean expression. It is used by all the other assertion routines, which + construct a Boolean expression from their specific values and logic. +

    - - +
    +   PROCEDURE utAssert.this (
    +      msg_in        IN VARCHAR2,
    +      check_this_in IN BOOLEAN,
    +      null_ok_in    IN BOOLEAN := FALSE,
    +      raise_exc_in  IN BOOLEAN := FALSE
    +   );
    +
    + +

    + Use utAssert.this when you have a Boolean expression that you want to check, + as in: +

    + +
    +BEGIN
    +   ...
    +   utAssert.this (
    +      'Boolean function result',
    +      is_valid_account (my_account)
    +   );
    +
    + +

    + You can also use this assertion to register a failure, most usually in + an exception section, as in: +

    + +
    +EXCEPTION
    +   WHEN OTHERS
    +   THEN
    +      utAssert.this (
    +         SQLERRM,
    +         FALSE
    +      );
    +
    + +

    + Generally, you should avoid utAssert.this and instead use a specialized + assertion routine, documented below. Most of the assertions give you the + ability check for equality (of scalars, such as strings, or more complex + data structures like tables, pipes and files): does the data generated by + my code match the expected value(s)? +

    + +

    Check for NULL and NOT NULL Values

    -

    Generic "Assert This" Assertion Procedure

    - This most generic assertion program simply says "assert this" and passes -a Boolean expression. It is used by all the other assertion routines, which -construct a Boolean expression from their specific values and logic. -
       PROCEDURE utAssert.this (
    -
          msg_in IN VARCHAR2,
    -
          check_this_in IN BOOLEAN,
    -
          null_ok_in IN BOOLEAN := FALSE,
    -
          raise_exc_in IN BOOLEAN := FALSE
    -
       );
    - Use utAssert.this when you have a Boolean expression that you want to check, -as in:.
    BEGIN
    -
       ...
    -
       utAssert.this (
    -
          'Boolean function result',
    -
          is_valid_account (my_account)
    -
          );
    - You can also use this assertion to register a failure, most usually in -an exception section, as in:
    EXCEPTION
    -
       WHEN OTHERS
    -
       THEN
    utAssert.this (
    -
             SQLERRM,
    -
             FALSE);
    - Generally, you should avoid utAssert.this and instead use a specialized -assertion routine, documented below. Most of the assertions give you the -ability check for equality (of scalars, such as strings, or more complex -data structures like tables, pipes and files): does the data generated by -my code match the expected value(s)? -

    Check for NULL and NOT NULL Values

    - You can check to see if a value is NULL or is NOT NULL with the following -assertions:
    PROCEDURE utAssert.isnotnull (
    msg_in IN VARCHAR2,
    check_this_in IN VARCHAR2,
    null_ok_in IN BOOLEAN := FALSE,
    raise_exc_in IN BOOLEAN := FALSE
    );

    PROCEDURE utAssert.isnull (
    msg_in IN VARCHAR2,
    check_this_in IN VARCHAR2,
    null_ok_in IN BOOLEAN := FALSE,
    raise_exc_in IN BOOLEAN := FALSE
    );

    PROCEDURE utAssert.isnotnull (
    msg_in IN VARCHAR2,
    check_this_in IN BOOLEAN,
    null_ok_in IN BOOLEAN := FALSE,
    raise_exc_in IN BOOLEAN := FALSE
    );

    PROCEDURE utAssert.isnull (
    msg_in IN VARCHAR2,
    check_this_in IN BOOLEAN,

    null_ok_in IN BOOLEAN := FALSE,
    raise_exc_in IN BOOLEAN := FALSE
    );
    - Use these assertions when you simply want to check if a scalar expression -(string, date, number and Boolean are supported) is NULL or NOT NULL, as -in:
    -
    -
    BEGIN
    -
       ...
    -
       utAssert.isNULL (
    -
          'Should be nothing left',
    -
          TRANSLATE (digits_in_string, 'A1234567890', 'A')
    -
          );
    +

    + You can check to see if a value is NULL or is NOT NULL with the following + assertions: +

    + +
    +PROCEDURE utAssert.isnotnull (
    +   msg_in        IN VARCHAR2,
    +   check_this_in IN VARCHAR2,
    +   null_ok_in    IN BOOLEAN := FALSE,
    +   raise_exc_in  IN BOOLEAN := FALSE
    +);
    +
    +PROCEDURE utAssert.isnull (
    +   msg_in        IN VARCHAR2,
    +   check_this_in IN VARCHAR2,
    +   null_ok_in    IN BOOLEAN := FALSE,
    +   raise_exc_in  IN BOOLEAN := FALSE
    +);
    +
    +PROCEDURE utAssert.isnotnull (
    +   msg_in        IN VARCHAR2,
    +   check_this_in IN BOOLEAN,
    +   null_ok_in    IN BOOLEAN := FALSE,
    +   raise_exc_in  IN BOOLEAN := FALSE
    +);
    +
    +PROCEDURE utAssert.isnull (
    +   msg_in        IN VARCHAR2,
    +   check_this_in IN BOOLEAN,
    +   null_ok_in    IN BOOLEAN := FALSE,
    +   raise_exc_in  IN BOOLEAN := FALSE
    +);
    +
    + +

    + Use these assertions when you simply want to check if a scalar expression + (string, date, number and Boolean are supported) is NULL or NOT NULL, as + in: +

    + +
    +BEGIN
    +   ...
    +   utAssert.isNULL (
    +      'Should be nothing left',
    +      TRANSLATE (digits_in_string, 'A1234567890', 'A')
    +   );
    +
    -

    Check Equality of Scalar Values

    - If you need to compare two dates or two strings or two numbers or two Booleans, -use the utAssert.eq assertion program. -

    Here is the header for the scalar equality check assertion:

    PROCEDURE utAssert.eq (
    -
       msg_in IN VARCHAR2,
    -
       check_this_in IN VARCHAR2|BOOLEAN|DATE|NUMBER,
    -
       against_this_in IN VARCHAR2|BOOLEAN|DATE|NUMBER,
    -
       null_ok_in IN BOOLEAN := FALSE,
    -
       raise_exc_in IN BOOLEAN := FALSE
    -
    );
    - If the two values are equal, your code gets a green light. Otherwise, utAssert -writes the test results to the utResult package, resulting in a red light -for the test. If NULL values are considered value for this test, pass TRUE -for null_ok_in. If you want the assertion to raise an exception on failure -and stop the test from proceeding, pass TRUE for raise_exc_in. Here is an -example of using the utAssert.eq program:
       PROCEDURE ut_emp_dept_lookuprowcount
    IS
    -
          l_rowcount1 PLS_INTEGER;
    l_rowcount2 PLS_INTEGER;
    BEGIN
    -- Run baseline code.
    SELECT COUNT (*)
    INTO l_rowcount1
    FROM employee
    WHERE department_id = 30;
    -
     
    -
          -- Compare to program call:
    l_rowcount2 :=
    te_employee.emp_dept_lookuprowcount (30);
    -
     
    -
          -- Test results
    utassert.eq (
    'Successful EMP_DEPT_LOOKUPROWCOUNT',
    l_rowcount2,
    l_rowcount1
    );
    END;
    -

    -

    Check Equality of DatabaseTables

    - If your test performs DML operations (update, insert or delete), you will -need to check your results in a database table. You could do this by querying -the results into local variables and then calling utAssert.eq to check those -values against your expected data. That can be a very laborious process, -so utAssert offers the eqtable and equerry assertion routines to streamline -the process. Both these procedures use the MINUS SQL operator to essentially -"subtract" the contents of one table (query) from the other. If anything -is left, then the two tables (queries) are not the same and the test is given -a red light. As you can probably see, the structure of the two tables (queries) -must be identical for this assertion to work properly. The utAssert.eqtable -allows you to compare the contents of your data table (changed by your code) -against another table, which you can preset with the data you expect to see -after the test. Here is the header for eqtable:
    PROCEDURE utAssert.eqtable (
    -
       msg_in IN VARCHAR2,
    -
       check_this_in IN VARCHAR2,
    -
       against_this_in IN VARCHAR2,
    -
       check_where_in IN VARCHAR2 := NULL,
    -
       against_where_in IN VARCHAR2 := NULL,
    -
       raise_exc_in IN BOOLEAN := FALSE
    -
    );
    - where check_this_in and against_this_in are the names of tables or views. -You can supply an optional WHERE clause to restrict the rows you wish to -compare. Here is an example that calls eqTable twice, to test two different -conditions.
    PROCEDURE ut_del1
    IS
    fdbk PLS_INTEGER;
    BEGIN
    /* Delete that finds now rows. */

    EXECUTE IMMEDIATE '
    DELETE FROM ut_DEL1
    WHERE employee_id = -1
    ';
    te_employee.del (-1, rowcount_out => fdbk);
    -
       -- Test results
    utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1');
    /* Successful delete */

    EXECUTE IMMEDIATE '
    DELETE FROM ut_DEL1
    WHERE employee_id between 7800 and 7899
    ';

    FOR rec IN (SELECT *
    FROM employee
    WHERE employee_id BETWEEN 7800 AND 7899)
    LOOP
    te_employee.del (
    rec.employee_id,
    rowcount_out => fdbk
    );
    END LOOP;

    -- Test results
    utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1');
    ROLLBACK;
    EXCEPTION
    WHEN OTHERS
    THEN
    utassert.this (
    'DEL1 exception ' || SQLERRM,
    SQLCODE = 0
    );
    END;
    +

    Check Equality of Scalar Values

    +

    + If you need to compare two dates or two strings or two numbers or two Booleans, + use the utAssert.eq assertion program. +

    + +

    Here is the header for the scalar equality check assertion:

    + +
    +PROCEDURE utAssert.eq (
    +   msg_in          IN VARCHAR2,
    +   check_this_in   IN VARCHAR2|BOOLEAN|DATE|NUMBER,
    +   against_this_in IN VARCHAR2|BOOLEAN|DATE|NUMBER,
    +   null_ok_in      IN BOOLEAN := FALSE,
    +   raise_exc_in    IN BOOLEAN := FALSE
    +);
    +
    + +

    + If the two values are equal, your code gets a green light. Otherwise, utAssert + writes the test results to the utResult package, resulting in a red light + for the test. If NULL values are considered value for this test, pass TRUE + for null_ok_in. If you want the assertion to raise an exception on failure + and stop the test from proceeding, pass TRUE for raise_exc_in. Here is an + example of using the utAssert.eq program: +

    + +
       
    +   PROCEDURE ut_emp_dept_lookuprowcount
    +   IS
    +      l_rowcount1 PLS_INTEGER;
    +      l_rowcount2 PLS_INTEGER;
    +      BEGIN
    +         -- Run baseline code.
    +         SELECT COUNT (*)
    +         INTO l_rowcount1
    +         FROM employee
    +         WHERE department_id = 30;
    +         
    +         -- Compare to program call:
    +         l_rowcount2 := te_employee.emp_dept_lookuprowcount (30);
    +         
    +         -- Test results
    +         utassert.eq (
    +            'Successful EMP_DEPT_LOOKUPROWCOUNT',
    +            l_rowcount2,
    +            l_rowcount1
    +         );
    +      END;
    +
    + +

    Check Equality of DatabaseTables

    -

    Check Equality of Table Counts

    - If your tests simply produce the right number of rows in a table but not -a fixed set of values, you will not be able to use -utAssert.eqtable above. However, utAssert.eqtabcount allows you to simply -test that the numbers of rows are equal. The declaration of the procedure -is as follows:
    PROCEDURE utAssert.eqtabcount (
    -
       msg_in IN VARCHAR2,
    -
       check_this_in IN VARCHAR2,
    -
       against_this_in IN VARCHAR2,
    -
       check_where_in IN VARCHAR2 := NULL,
    -
       against_where_in IN VARCHAR2 := NULL,
    -
       raise_exc_in IN BOOLEAN := FALSE
    -
    );
    - where check_this_in and against_this_in are the names of tables or views. -As in utAssert.eqtable, you can supply an optional WHERE clause to restrict -the rows you wish to compare. The following test will compare the number -of rows in the CD_COLLECTION and UT_TEST_5_1 tables where the given condition -holds:
    utassert.eqtabcount('Test 5.1: Insert new rows',
    -
                        'CD_COLLECTION',
    -
                        'UT_TEST_5_1',
    -
                        'ARTIST = ''The Fall''',
    -
                        'ARTIST = ''The Fall''');
    - -

    Asserting Query Equality

    - The utAssert.eqquery allows you to compare the data returned by two queries -(strings that are contained in the check_this_in and against_this_in parameters). -In this case, you specify the full SELECT statements for each query as the -parameters. By using equery, you may be able to avoid constructing a separate -table with preset data.
    PROCEDURE utAssert.eqquery (
    -
       msg_in IN VARCHAR2,
    -
       check_this_in IN VARCHAR2,
    -
       against_this_in IN VARCHAR2,
    -
       raise_exc_in IN BOOLEAN := FALSE
    -
    );
    - If you want the assertion to raise an exception on failure and stop the -test from proceeding, pass TRUE for raise_exc_in. Here is an example of -using eqQuery:
    PROCEDURE ut_upd1
    IS
    BEGIN
    /* Update 3 columns by ID */

    EXECUTE IMMEDIATE '
    UPDATE ut_UPD1 SET
    FIRST_NAME = ''SILLY'',
    HIRE_DATE = trunc (SYSDATE+100),
    COMMISSION = 5000
    WHERE
    EMPLOYEE_ID = 7600
    ';
    te_employee.upd (
    7600,
    first_name_in => 'SILLY',
    commission_in => 5000,
    hire_date_in => TRUNC (SYSDATE + 100),
    rowcount_out => fdbk
    );
    -- Test results (audit fields are different so do a query)
    utassert.eqquery (
    'Update three columns',
    'select first_name, commission, hire_date from EMPLOYEE',
    'select first_name, commission, hire_date from ut_upd1'
    );
    ROLLBACK;
    END;
    +

    + If your test performs DML operations (update, insert or delete), you will + need to check your results in a database table. You could do this by querying + the results into local variables and then calling utAssert.eq to check those + values against your expected data. That can be a very laborious process, + so utAssert offers the eqtable and equerry assertion routines to streamline + the process. Both these procedures use the MINUS SQL operator to essentially + "subtract" the contents of one table (query) from the other. If anything + is left, then the two tables (queries) are not the same and the test is given + a red light. As you can probably see, the structure of the two tables (queries) + must be identical for this assertion to work properly. The utAssert.eqtable + allows you to compare the contents of your data table (changed by your code) + against another table, which you can preset with the data you expect to see + after the test. Here is the header for eqtable: +

    + +
    +PROCEDURE utAssert.eqtable (
    +   msg_in           IN VARCHAR2,
    +   check_this_in    IN VARCHAR2,
    +   against_this_in  IN VARCHAR2,
    +   check_where_in   IN VARCHAR2 := NULL,
    +   against_where_in IN VARCHAR2 := NULL,
    +   raise_exc_in     IN BOOLEAN := FALSE
    +);
    +
    + +

    + where check_this_in and against_this_in are the names of tables or views. + You can supply an optional WHERE clause to restrict the rows you wish to + compare. Here is an example that calls eqTable twice, to test two different + conditions. +

    + +
    +PROCEDURE ut_del1
    +IS
    +   fdbk PLS_INTEGER;
    +BEGIN
    +   /* Delete that finds now rows. */
    +
    +   EXECUTE IMMEDIATE '
    +   DELETE FROM ut_DEL1
    +   WHERE employee_id = -1
    +   ';
    +   te_employee.del (-1, rowcount_out => fdbk);
    +
    +   -- Test results
    +   utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1');
    +
    +   /* Successful delete */
    +
    +   EXECUTE IMMEDIATE '
    +   DELETE FROM ut_DEL1
    +   WHERE employee_id between 7800 and 7899
    +   ';
    +      
    +   FOR rec IN (SELECT *
    +                 FROM employee
    +                WHERE employee_id BETWEEN 7800 AND 7899)
    +   LOOP
    +      te_employee.del (
    +         rec.employee_id,
    +         rowcount_out => fdbk
    +      );
    +   END LOOP;
    +   
    +   -- Test results
    +   utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1');
    +   ROLLBACK;
    +EXCEPTION
    +   WHEN OTHERS
    +   THEN
    +      utassert.this (
    +         'DEL1 exception ' || SQLERRM,
    +         SQLCODE = 0
    +      );
    +END;
    +
    -

    Check Query Equality against a Single Value

    - Often we will wish to test the result of a query against a single value rather -than another query as in utAssert.eqquery above. -It is possible to get around this problem by using a trivial query of the -form:
    SELECT fixed_value
    FROM DUAL;
    - Unfortunately, if the query returns multiple values or the wrong value we -will only be told that the test has failed with no details. This is where -utAssert.eqqueryvalue comes to the rescue. The procedure is declared as -follows:
    PROCEDURE utAssert.eqqueryvalue (
    -
          msg_in IN VARCHAR2,
    -
          check_query_in IN VARCHAR2,
    -
          against_value_in IN VARCHAR2|NUMBER|DATE,
    -
          raise_exc_in IN BOOLEAN := FALSE
    -
    );
    - Where check_query_in is the query in question and against_value_in is the -value to check it against. If the query returns more than one value, the -resulting error message will tell you this. Similarly, if the query returns -the wrong value, the message will state the expected and obtained values. - The following call compares the maximum value found in a table against a -given number value:
    utAssert.eqqueryvalue('Maximum value test',
    -
                          'SELECT MAX(MEMORY)
    -
                           FROM COMPUTERS
    -
                           WHERE OS IN (''Linux'', ''Unix'')',
    -
                           256);
    - Obviously this should only return a single value, but if it returns something -other than 256, we'll know about it. -

    Check Equality of Files

    - Many programs generate output to operating system files; alternatively, -you might write data to a file simply to test results. Use the eqfile assertion -for either of these scenarios. This procedure uses PL/SQL's UTL_FILE package -to compare the contents of two different files. Note: If you have not used -UTL_FILE in the past, you must configure - it before it can be used -- by utPLSQL or by your own code. UTL_FILE must -be allowed accss to either or both of the directories you specify (this involves -setting the utl_file_dir database parameter).
    PROCEDURE utAssert.eqfile (
    -
       msg_in IN VARCHAR2,
    -
       check_this_in IN VARCHAR2,
    -
       check_this_dir_in IN VARCHAR2,
    -
       against_this_in IN VARCHAR2,
    -
       against_this_dir_in IN VARCHAR2 := NULL,
    -
       raise_exc_in IN BOOLEAN := FALSE
    -
    );
    - If you want the assertion to raise an exception on failure and stop the -test from proceeding, pass TRUE for raise_exc_in. You must specify the directory -containing the "check this" file; if you do not specify a directory for the -"against this" file, the "check this" directory will be used. Here is an -example of using eqFile (see ut_DEPARTMENT2file.pkg in the Examples directory -for the full implementation):
    PROCEDURE ut_DEPARTMENT2FILE IS
    BEGIN
    DEPARTMENT2FILE (
    LOC => 'c:\temp',
    FILE => 'department.dat',
    DELIM => '***'
    );

    utAssert.eqfile (
    'Test of DEPARTMENT2FILE',
    'department.dat',
    'c:\temp',
    'department.tst',
    'c:\temp'
    );
    END ut_DEPARTMENT2FILE;
    +

    Check Equality of Table Counts

    + +

    + If your tests simply produce the right number of rows in a table but not + a fixed set of values, you will not be able to use + utAssert.eqtable above. However, utAssert.eqtabcount allows you to simply + test that the numbers of rows are equal. The declaration of the procedure + is as follows: +

    + +
    +PROCEDURE utAssert.eqtabcount (
    +   msg_in           IN VARCHAR2,
    +   check_this_in    IN VARCHAR2,
    +   against_this_in  IN VARCHAR2,
    +   check_where_in   IN VARCHAR2 := NULL,
    +   against_where_in IN VARCHAR2 := NULL,
    +   raise_exc_in     IN BOOLEAN := FALSE
    +);
    +
    + +

    + where check_this_in and against_this_in are the names of tables or views. + As in utAssert.eqtable, you can supply an optional WHERE clause to restrict + the rows you wish to compare. The following test will compare the number + of rows in the CD_COLLECTION and UT_TEST_5_1 tables where the given condition + holds: +

    + +
    +utassert.eqtabcount('Test 5.1: Insert new rows',
    +                    'CD_COLLECTION',
    +                    'UT_TEST_5_1',
    +                    'ARTIST = ''The Fall''',
    +                    'ARTIST = ''The Fall''');
    +
    + +

    Asserting Query Equality

    -

    Check Equality of Database Pipes

    - Database pipes offer a handy mechanism for passing data between different -sessions connected to the RDBMS. It is important to know that pipes are being -filled properly; use the eqpipe to check this condition. With the eqpipe -procedure, you compare the contents of two different pipes.
    PROCEDURE utAssert.eqpipe (
    -
       msg_in IN VARCHAR2,
    -
       check_this_in IN VARCHAR2,
    -
       against_this_in IN VARCHAR2,
    -
       raise_exc_in IN BOOLEAN := FALSE
    -
    );
    - If you want the assertion to raise an exception on failure and stop the -test from proceeding, pass TRUE for raise_exc_in. To check the contents -of a pipe based on the execution of code, you will need to populate a pipe -against which to test equality. The employee_pipe.pkg file in the Examples -directory contains a demonstration of the kind of code you might write to -do this. This package contains all of the unit test code within the same -package. Here is my unit test program, which relies on the utAssert.eqpipe -program:
    PROCEDURE ut_fillpipe IS
    stat PLS_INTEGER;
    BEGIN
    emptypipe ('emps');
    emptypipe ('emps2');

    fillpipe ('emps');

    /* Direct filling of pipe. */

    FOR rec IN (SELECT *
    FROM employee)
    LOOP
    DBMS_PIPE.RESET_BUFFER;
    DBMS_PIPE.PACK_MESSAGE (rec.EMPLOYEE_ID);
    DBMS_PIPE.PACK_MESSAGE (rec.LAST_NAME);
    DBMS_PIPE.PACK_MESSAGE (rec.FIRST_NAME);
    DBMS_PIPE.PACK_MESSAGE (rec.MIDDLE_INITIAL);
    DBMS_PIPE.PACK_MESSAGE (rec.JOB_ID);
    DBMS_PIPE.PACK_MESSAGE (rec.MANAGER_ID);
    DBMS_PIPE.PACK_MESSAGE (rec.HIRE_DATE);
    DBMS_PIPE.PACK_MESSAGE (rec.SALARY);
    DBMS_PIPE.PACK_MESSAGE (rec.COMMISSION);
    DBMS_PIPE.PACK_MESSAGE (rec.DEPARTMENT_ID);
    DBMS_PIPE.PACK_MESSAGE (rec.CHANGED_BY);
    DBMS_PIPE.PACK_MESSAGE (rec.CHANGED_ON);

    stat := DBMS_PIPE.SEND_MESSAGE ('emps2', 0);
    END LOOP;

    /* Compare the two */
    utassert.eqpipe (
    'Two employee pipes', 'emps', 'emps2');

    END ut_fillpipe;
    - Since I have stored my unit test logic with my source code package, I would -run my test as follows:
    SQL> exec utplsql.test ('employee_pipe', samepackage_in=>TRUE)
    FAILURE: "employee_pipe"
    fillpipe: Pipes equal? Compared "emps" against "emps2"
    +

    + The utAssert.eqquery allows you to compare the data returned by two queries + (strings that are contained in the check_this_in and against_this_in parameters). + In this case, you specify the full SELECT statements for each query as the + parameters. By using equery, you may be able to avoid constructing a separate + table with preset data. +

    + +
    +PROCEDURE utAssert.eqquery (
    +   msg_in          IN VARCHAR2,
    +   check_this_in   IN VARCHAR2,
    +   against_this_in IN VARCHAR2,
    +   raise_exc_in    IN BOOLEAN := FALSE
    +);
    +
    + +

    + If you want the assertion to raise an exception on failure and stop the + test from proceeding, pass TRUE for raise_exc_in. Here is an example of + using eqQuery: +

    + +
    +PROCEDURE ut_upd1
    +IS
    +BEGIN
    +   /* Update 3 columns by ID */
    +   EXECUTE IMMEDIATE '
    +   UPDATE ut_UPD1 SET
    +      FIRST_NAME = ''SILLY'',
    +      HIRE_DATE = trunc (SYSDATE+100),
    +      COMMISSION = 5000
    +    WHERE
    +       EMPLOYEE_ID = 7600
    +   ';
    +   te_employee.upd (
    +      7600,
    +      first_name_in => 'SILLY',
    +      commission_in => 5000,
    +      hire_date_in => TRUNC (SYSDATE + 100),
    +      rowcount_out => fdbk
    +   );
    +   -- Test results (audit fields are different so do a query)
    +   utassert.eqquery (
    +      'Update three columns',
    +      'select first_name, commission, hire_date from EMPLOYEE',
    +      'select first_name, commission, hire_date from ut_upd1'
    +   );
    +   ROLLBACK;
    +END;
    +
    -

    Check Equality of Collections

    - Collections are as close as you come to arrays in PL/SQL. They are very -useful for managing lists of information, but can be difficult to debug and -maintain. With the eqcoll and eqcollAPI procedures, you can compare the -contents of two different arrays. Use the eqColl procedure when you want -to compare two collections that are defined in the specification of a package. -Use the eqCollAPI procedure when you want to compare two collections that -are defined in the body of a package, with programs defined in the specification -(an API) to access and manipulate the collections. The collection equality -check headers are:
       /* Direct access to collections */
    -
       PROCEDURE utAssert.eqcoll (
    -
          msg_in IN VARCHAR2,
    -
          check_this_in IN VARCHAR2, /* pkg1.coll */
    -
          against_this_in IN VARCHAR2, /* pkg2.coll */
    -
          eqfunc_in IN VARCHAR2 := NULL,
    -
          check_startrow_in IN PLS_INTEGER := NULL,
    -
          check_endrow_in IN PLS_INTEGER := NULL,
    -
          against_startrow_in IN PLS_INTEGER := NULL,
    -
          against_endrow_in IN PLS_INTEGER := NULL,
    -
          match_rownum_in IN BOOLEAN := FALSE,
    -
          null_ok_in IN BOOLEAN := TRUE,
    -
          raise_exc_in IN BOOLEAN := FALSE
    -
       );
    -
      
    -
       /* API based access to collections */
    -
       PROCEDURE utAssert.eqcollapi (
    -
          msg_in IN VARCHAR2,
    -
          check_this_pkg_in IN VARCHAR2,
    -
          against_this_pkg_in IN VARCHAR2,
    -
          eqfunc_in IN VARCHAR2 := NULL,
    -
          countfunc_in IN VARCHAR2 := 'COUNT',
    -
          firstrowfunc_in IN VARCHAR2 := 'FIRST',
    -
          lastrowfunc_in IN VARCHAR2 := 'LAST',
    -
          nextrowfunc_in IN VARCHAR2 := 'NEXT',
    -
          getvalfunc_in IN VARCHAR2 := 'NTHVAL',
    -
          check_startrow_in IN PLS_INTEGER := NULL,
    -
          check_endrow_in IN PLS_INTEGER := NULL,
    -
          against_startrow_in IN PLS_INTEGER := NULL,
    -
          against_endrow_in IN PLS_INTEGER := NULL,
    -
          match_rownum_in IN BOOLEAN := FALSE,
    -
          null_ok_in IN BOOLEAN := TRUE,
    -
          raise_exc_in IN BOOLEAN := FALSE
    -
       );
    - where the eqcoll-specific parameters are as follows: - - - - - - - - - - - - - - - - - - - - -
    ParameterDescription
    msg_in The message to be displayed if the test failes -
    check_this_in The name of the collection to be checked. -Format: package.collection. In other words, the collection must be defined -in a package specification. Use eqCollAPI (and check_this_pkg_in) if you -want to hide the declaration of your collection in your package body (recommended). -
    against_this_in The name of the collection to be checked -against. Format: package.collection. In other words, the collection must -be defined in a package specification. Use eqCollAPI (and check_this_pkg_in) -if you want to hide the declaration of your collection in your package body -(recommended).
    +

    Check Query Equality against a Single Value

    +

    + Often we will wish to test the result of a query against a single value rather + than another query as in utAssert.eqquery above. + It is possible to get around this problem by using a trivial query of the + form: +

    + +
    +SELECT fixed_value
    +FROM DUAL;
    +
    + +

    + Unfortunately, if the query returns multiple values or the wrong value we + will only be told that the test has failed with no details. This is where + utAssert.eqqueryvalue comes to the rescue. The procedure is declared as + follows: +

    + +
    +PROCEDURE utAssert.eqqueryvalue (
    +   msg_in           IN VARCHAR2,
    +   check_query_in   IN VARCHAR2,
    +   against_value_in IN VARCHAR2|NUMBER|DATE,
    +   raise_exc_in     IN BOOLEAN := FALSE
    +);
    +
    + +

    + Where check_query_in is the query in question and against_value_in is the + value to check it against. If the query returns more than one value, the + resulting error message will tell you this. Similarly, if the query returns + the wrong value, the message will state the expected and obtained values. + The following call compares the maximum value found in a table against a + given number value: +

    -

    and the eqcollAPI-specific parameters are as follows:
    +

    +utAssert.eqqueryvalue('Maximum value test',
    +                      'SELECT MAX(MEMORY)
    +                       FROM COMPUTERS
    +                       WHERE OS IN (''Linux'', ''Unix'')',
    +                       256);
    +
    + +

    + Obviously this should only return a single value, but if it returns something + other than 256, we'll know about it. +

    + +

    Check Equality of Files

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ParameterDescription
    msg_in The message to be displayed if the test failes -
    check_this_pkg_in The name of the package that contains the -collection to be checked.
    against_this_pkg_in The name of the package that contains the -collection to be checked against.
    countfunc_in The name of the function in the package that -returns the number of rows defined in the collection.
    firstrowfunc_in The name of the function in the package that -returns the first definedrow in the collection.
    lastrowfunc_in The name of the function in the package that -returns the last definedrow in the collection.
    nextrowfunc_in The name of the function in the package that -returns the next definedrow in the collection from the specified row.
    getvalfunc_in The name of the function in the package that -returns the contents of the specified row.
    +

    + Many programs generate output to operating system files; alternatively, + you might write data to a file simply to test results. Use the eqfile assertion + for either of these scenarios. This procedure uses PL/SQL's UTL_FILE package + to compare the contents of two different files. Note: If you have not used + UTL_FILE in the past, you must configure + it before it can be used -- by utPLSQL or by your own code. UTL_FILE must + be allowed accss to either or both of the directories you specify (this involves + setting the utl_file_dir database parameter).

    -

    The parameters common to both eqColl and eqCollAPI are as follows
    + +

    +PROCEDURE utAssert.eqfile (
    +   msg_in IN VARCHAR2,
    +   check_this_in IN VARCHAR2,
    +   check_this_dir_in IN VARCHAR2,
    +   against_this_in IN VARCHAR2,
    +   against_this_dir_in IN VARCHAR2 := NULL,
    +   raise_exc_in IN BOOLEAN := FALSE
    +);
    +
    + +

    + If you want the assertion to raise an exception on failure and stop the + test from proceeding, pass TRUE for raise_exc_in. You must specify the directory + containing the "check this" file; if you do not specify a directory for the + "against this" file, the "check this" directory will be used. Here is an + example of using eqFile (see ut_DEPARTMENT2file.pkg in the Examples directory + for the full implementation): +

    + +
    +PROCEDURE ut_DEPARTMENT2FILE IS
    +BEGIN
    +   DEPARTMENT2FILE (
    +      LOC => 'c:\temp',
    +      FILE => 'department.dat',
    +      DELIM => '***'
    +    );
    +
    +   utAssert.eqfile (
    +      'Test of DEPARTMENT2FILE',
    +      'department.dat',
    +      'c:\temp',
    +      'department.tst',
    +      'c:\temp'
    +      );      
    +END ut_DEPARTMENT2FILE;
    +
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ParameterDescription
    eqfunc_in The function used to determine if the contents -of each row of the two collections are the same. If you pass NULL for this -argument, then a standard equality check will be used. This is fine for scalar -values, but will not work, for example, with tables of records.
    check_startrow_in The starting row in the check collection -for comparison. If NULL, then first row is used.
    check_endrow_in The ending row in the check collection for -comparison. If NULL, then last row is used.
    against_startrow_in The starting row in the against collection -for comparison. If NULL, then first row is used.
    against_endrow_in The ending row in the against collection -for comparison. If NULL, then last row is used.
    match_rownum_in Pass TRUE if you want to make sure that the -same row numbers are used in each collection. If FALSE, then the row numbers -can be different, but the contents of each corresponding row must be the same. -
    null_ok_in Pass TRUE if the assertion routine should -consider two NULL collections to be equal.
    raise_exc_in If you want the assertion to raise an exception -on failure and stop the test from proceeding, pass TRUE for raise_exc_in. -
    -

    -

    Here is an example of a script that uses utAssert.eqColl (taken from filepath1.pkg -in the Examples directory):

    PROCEDURE ut_setpath
    IS
    BEGIN
    /* Populate base collection */
    ut_dirs.DELETE;
    ut_dirs.EXTEND(2);
    ut_dirs(1) := 'c:\temp';
    ut_dirs(2) := 'e:\demo';

    /* Call setpath to do the work */
    setpath ('c:\temp;e:\demo');

    utAssert.eqColl (
    'Valid double entry',
    'fileio.dirs',
    'fileio.ut_dirs'
    );
    END;
    -

    -

    Checking a Procedure or Function throws an exception

    - Sometimes we design a procedure or function to throw an exception under certain -circumstances. This is something we'd like to be able to test for. Obviously -this is not particularly easy due to the way exceptions propagate through -the call stack. If we simply call the procedure in our test code, the exception -will have no chance of being caught within the utAssert package! Therefore, -we need to pass the tested call in to the package as a string. The procedure -utAssert.throws allows us to do this:
    PROCEDURE throws (
    -
          msg_in VARCHAR2,
    -
          check_call_in IN VARCHAR2,
    -
          against_exc_in IN VARCHAR2|NUMBER
    -
       );
    - Where check_call_in is the call to be made, complete with parameters and -terminating semicolon. The argument against_exc_in is the exception we expect -to be thrown. This can be specified either as a named exception, or a SQLCODE -value. -

    The following example shows both usages:

    /* Test the Except Function */
    PROCEDURE ut_except
    IS
    BEGIN

    /* Call the procedure with a negative number */
    /* We expect a NO_DATA_FOUND exception */
    utAssert.throws('Negative Number',
    'Except(-1);',
    'NO_DATA_FOUND'
    );

    /* Call the procedure with zero and a string */
    /* over 2 in length - We expect a SQLCODE of -1 */
    utAssert.throws('Zero and String',
    'Except(0, ''Hello'');',
    -1
    );
    END;
    - Note how we have to quote the string parameters to the call and terminate -the string with a semicolon.
    -

    -

    Check if the Previous Assertion Passed or Failed

    -Sometimes, a procedure may have a large number of effects that need to be -tested.  For example, it might insert and update data in a series of -tables.  To test all of these changes, it will be necessary to make -a series of calls to utAssert.  This can have the effect that if the -procedure is not behaving as expected, then the user is presented with a -screenful of errors.  To avoid this and just present them with a single -error, the functions previous_passed and previous_failed can be used.  -These return a BOOLEAN argument giving the success or failure of the previously -called assertion. 
    -
    -The following example gives a demonstration:
    -
    /* Test the BookTrips Procedure */
    +   

    Check Equality of Database Pipes

    +

    + Database pipes offer a handy mechanism for passing data between different + sessions connected to the RDBMS. It is important to know that pipes are being + filled properly; use the eqpipe to check this condition. With the eqpipe + procedure, you compare the contents of two different pipes. +

    + +
    +PROCEDURE utAssert.eqpipe (
    +   msg_in          IN VARCHAR2,
    +   check_this_in   IN VARCHAR2,
    +   against_this_in IN VARCHAR2,
    +   raise_exc_in    IN BOOLEAN := FALSE
    +);
    +
    + +

    + If you want the assertion to raise an exception on failure and stop the + test from proceeding, pass TRUE for raise_exc_in. To check the contents + of a pipe based on the execution of code, you will need to populate a pipe + against which to test equality. The employee_pipe.pkg file in the Examples + directory contains a demonstration of the kind of code you might write to + do this. This package contains all of the unit test code within the same + package. Here is my unit test program, which relies on the utAssert.eqpipe + program: +

    + +
    +PROCEDURE ut_fillpipe IS
    +   stat PLS_INTEGER;
    +BEGIN
    +   emptypipe ('emps');
    +   emptypipe ('emps2');
    +   
    +   fillpipe ('emps');
    +   
    +   /* Direct filling of pipe. */
    +   
    +   FOR rec IN (SELECT *
    +                 FROM employee)
    +   LOOP
    +      DBMS_PIPE.RESET_BUFFER;
    +      DBMS_PIPE.PACK_MESSAGE (rec.EMPLOYEE_ID);
    +      DBMS_PIPE.PACK_MESSAGE (rec.LAST_NAME);
    +      DBMS_PIPE.PACK_MESSAGE (rec.FIRST_NAME);
    +      DBMS_PIPE.PACK_MESSAGE (rec.MIDDLE_INITIAL);
    +      DBMS_PIPE.PACK_MESSAGE (rec.JOB_ID);
    +      DBMS_PIPE.PACK_MESSAGE (rec.MANAGER_ID);
    +      DBMS_PIPE.PACK_MESSAGE (rec.HIRE_DATE);
    +      DBMS_PIPE.PACK_MESSAGE (rec.SALARY);
    +      DBMS_PIPE.PACK_MESSAGE (rec.COMMISSION);
    +      DBMS_PIPE.PACK_MESSAGE (rec.DEPARTMENT_ID);
    +      DBMS_PIPE.PACK_MESSAGE (rec.CHANGED_BY);
    +      DBMS_PIPE.PACK_MESSAGE (rec.CHANGED_ON);
    +
    +      stat := DBMS_PIPE.SEND_MESSAGE ('emps2', 0);
    +   END LOOP;
    +   
    +   /* Compare the two */
    +   utassert.eqpipe (
    +      'Two employee pipes', 'emps', 'emps2');
    +      
    +END ut_fillpipe;
    +
    + +

    + Since I have stored my unit test logic with my source code package, I would + run my test as follows: +

    + +
    +SQL> exec utplsql.test ('employee_pipe', samepackage_in=>TRUE)
    +FAILURE: "employee_pipe"
    +fillpipe: Pipes equal? Compared "emps" against "emps2"
    +
    + +

    Check Equality of Collections

    + +

    + Collections are as close as you come to arrays in PL/SQL. They are very + useful for managing lists of information, but can be difficult to debug and + maintain. With the eqcoll and eqcollAPI procedures, you can compare the + contents of two different arrays. Use the eqColl procedure when you want + to compare two collections that are defined in the specification of a package. + Use the eqCollAPI procedure when you want to compare two collections that + are defined in the body of a package, with programs defined in the specification + (an API) to access and manipulate the collections. The collection equality + check headers are: +

    + +
    +   /* Direct access to collections */
    +   PROCEDURE utAssert.eqcoll (
    +      msg_in IN VARCHAR2,
    +      check_this_in IN VARCHAR2, /* pkg1.coll */
    +      against_this_in IN VARCHAR2, /* pkg2.coll */
    +      eqfunc_in IN VARCHAR2 := NULL,
    +      check_startrow_in IN PLS_INTEGER := NULL,
    +      check_endrow_in IN PLS_INTEGER := NULL,
    +      against_startrow_in IN PLS_INTEGER := NULL,
    +      against_endrow_in IN PLS_INTEGER := NULL,
    +      match_rownum_in IN BOOLEAN := FALSE,
    +      null_ok_in IN BOOLEAN := TRUE,
    +      raise_exc_in IN BOOLEAN := FALSE
    +   );
    +  
    +   /* API based access to collections */
    +   PROCEDURE utAssert.eqcollapi (
    +      msg_in IN VARCHAR2,
    +      check_this_pkg_in IN VARCHAR2,
    +      against_this_pkg_in IN VARCHAR2,
    +      eqfunc_in IN VARCHAR2 := NULL,
    +      countfunc_in IN VARCHAR2 := 'COUNT',
    +      firstrowfunc_in IN VARCHAR2 := 'FIRST',
    +      lastrowfunc_in IN VARCHAR2 := 'LAST',
    +      nextrowfunc_in IN VARCHAR2 := 'NEXT',
    +      getvalfunc_in IN VARCHAR2 := 'NTHVAL',
    +      check_startrow_in IN PLS_INTEGER := NULL,
    +      check_endrow_in IN PLS_INTEGER := NULL,
    +      against_startrow_in IN PLS_INTEGER := NULL,
    +      against_endrow_in IN PLS_INTEGER := NULL,
    +      match_rownum_in IN BOOLEAN := FALSE,
    +      null_ok_in IN BOOLEAN := TRUE,
    +      raise_exc_in IN BOOLEAN := FALSE
    +   );
    +
    + +

    where the eqcoll-specific parameters are as follows:

    + + + + + + + + + + + + + + + + + + +
    ParameterDescription
    msg_in The message to be displayed if the test failes
    check_this_in + The name of the collection to be checked. + Format: package.collection. In other words, the collection must be defined + in a package specification. Use eqCollAPI (and check_this_pkg_in) if you + want to hide the declaration of your collection in your package body (recommended). +
    against_this_in + The name of the collection to be checked + against. Format: package.collection. In other words, the collection must + be defined in a package specification. Use eqCollAPI (and check_this_pkg_in) + if you want to hide the declaration of your collection in your package body + (recommended). +
    + +

    and the eqcollAPI-specific parameters are as follows:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ParameterDescription
    msg_in The message to be displayed if the test failes
    check_this_pkg_in + The name of the package that contains the + collection to be checked. +
    against_this_pkg_in + The name of the package that contains the + collection to be checked against. +
    countfunc_in + The name of the function in the package that + returns the number of rows defined in the collection. +
    firstrowfunc_in + The name of the function in the package that + returns the first defined row in the collection. +
    lastrowfunc_in + The name of the function in the package that + returns the last defined row in the collection. +
    nextrowfunc_in + The name of the function in the package that + returns the next defined row in the collection from the specified row. +
    getvalfunc_in + The name of the function in the package that + returns the contents of the specified row. +
    + +

    The parameters common to both eqColl and eqCollAPI are as follows

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ParameterDescription
    eqfunc_in + The function used to determine if the contents + of each row of the two collections are the same. If you pass NULL for this + argument, then a standard equality check will be used. This is fine for scalar + values, but will not work, for example, with tables of records. +
    check_startrow_in + The starting row in the check collection + for comparison. If NULL, then first row is used. +
    check_endrow_in + The ending row in the check collection for + comparison. If NULL, then last row is used. +
    against_startrow_in + The starting row in the against collection + for comparison. If NULL, then first row is used. +
    against_endrow_in + The ending row in the against collection + for comparison. If NULL, then last row is used. +
    match_rownum_in + Pass TRUE if you want to make sure that the + same row numbers are used in each collection. If FALSE, then the row numbers + can be different, but the contents of each corresponding row must be the same. +
    null_ok_in + Pass TRUE if the assertion routine should + consider two NULL collections to be equal. +
    raise_exc_in + If you want the assertion to raise an exception + on failure and stop the test from proceeding, pass TRUE for raise_exc_in. +
    + +

    + Here is an example of a script that uses utAssert.eqColl (taken from filepath1.pkg + in the Examples directory): +

    + +
    +PROCEDURE ut_setpath
    +IS
    +BEGIN
    +   /* Populate base collection */
    +   ut_dirs.DELETE;
    +   ut_dirs.EXTEND(2);
    +   ut_dirs(1) := 'c:\temp';
    +   ut_dirs(2) := 'e:\demo';
    +   
    +   /* Call setpath to do the work */
    +   setpath ('c:\temp;e:\demo');
    +   
    +   utAssert.eqColl (
    +      'Valid double entry',
    +      'fileio.dirs',
    +      'fileio.ut_dirs'
    +      );
    +END;
    +
    + +

    Checking a Procedure or Function throws an exception

    + +

    + Sometimes we design a procedure or function to throw an exception under certain + circumstances. This is something we'd like to be able to test for. Obviously + this is not particularly easy due to the way exceptions propagate through + the call stack. If we simply call the procedure in our test code, the exception + will have no chance of being caught within the utAssert package! Therefore, + we need to pass the tested call in to the package as a string. The procedure + utAssert.throws allows us to do this: +

    + +
    +PROCEDURE throws (
    +      msg_in VARCHAR2,
    +      check_call_in IN VARCHAR2,
    +      against_exc_in IN VARCHAR2|NUMBER
    +   );
    +
    +

    + Where check_call_in is the call to be made, complete with parameters and + terminating semicolon. The argument against_exc_in is the exception we expect + to be thrown. This can be specified either as a named exception, or a SQLCODE + value. +

    +

    The following example shows both usages:

    + +
    +/* Test the Except Function */
    +PROCEDURE ut_except
    +IS
    +BEGIN
    +
    +   /* Call the procedure with a negative number */
    +   /* We expect a NO_DATA_FOUND exception       */
    +   utAssert.throws('Negative Number',
    +      'Except(-1);',
    +      'NO_DATA_FOUND'
    +   );
    +   
    +   /* Call the procedure with zero and a string    */
    +   /* over 2 in length - We expect a SQLCODE of -1 */  
    +   utAssert.throws('Zero and String',
    +      'Except(0, ''Hello'');',
    +      -1
    +     );
    +END;
    +
    + +

    + Note how we have to quote the string parameters to the call and terminate + the string with a semicolon. +

    + +

    Check if the Previous Assertion Passed or Failed

    + +

    + Sometimes, a procedure may have a large number of effects that need to be + tested. For example, it might insert and update data in a series of + tables. To test all of these changes, it will be necessary to make + a series of calls to utAssert. This can have the effect that if the + procedure is not behaving as expected, then the user is presented with a + screenful of errors. To avoid this and just present them with a single + error, the functions previous_passed and previous_failed can be used. + These return a BOOLEAN argument giving the success or failure of the previously + called assertion. +

    + +

    The following example gives a demonstration:

    + +
    +/* Test the BookTrips Procedure */
     PROCEDURE ut_bookTrips
     IS 
     BEGIN
    @@ -587,15 +1033,18 @@ 

    Check if the Previous Assertion Passed or Failed

    END IF; -END;
    +END; +
    -

    Comparing output from DBMS_OUTPUT

    +

    Comparing output from DBMS_OUTPUT

    -

    To complement the utOutput package, these -assertions allow you to easily compare collections of the type -DBMS_OUTPUT.CHARARR. Unlike the eqcoll and - eqcollapi assertions, this allows the comparison of locally defined -collections. The procedures are declared as follows:

    +

    + To complement the utOutput package, these + assertions allow you to easily compare collections of the type + DBMS_OUTPUT.CHARARR. Unlike the eqcoll and + eqcollapi assertions, this allows the comparison of locally defined + collections. The procedures are declared as follows: +

     PROCEDURE eqoutput (
    @@ -620,9 +1069,11 @@ 

    Comparing output from DBMS_OUTPUT

    );
    -

    The first version simply compares two collections, whereas the second compares a collection against a delimited string. The delimiter -can be specified by the line_delimiter_in parameter. If NULL is passed in (which is the default) then the lines are delimited by carriage returns. -Thus to test a collection mybuff which should look like:

    +

    + The first version simply compares two collections, whereas the second compares a collection against a delimited string. The delimiter + can be specified by the line_delimiter_in parameter. If NULL is passed in (which is the default) then the lines are delimited by carriage returns. + Thus to test a collection mybuff which should look like: +

        mybuff(0) := 'Zidane';
    @@ -630,14 +1081,14 @@ 

    Comparing output from DBMS_OUTPUT

    mybuff(2) := 'Kahn';
    -

    we could pass in parameters:

    +

    we could pass in parameters:

        check_this_in => 'Zidane|Ronaldo|Kahn';
        line_delimiter_in => '|';
     
    -

    or:

    +

    or:

        check_this_in => 
    @@ -647,22 +1098,27 @@ 

    Comparing output from DBMS_OUTPUT

    line_delimiter_in => NULL;
    -

    There are also the following flags to modify the way that the line-by-line comparisons are carried out:

    - -
      -
    • ignore_case_in - this specifies that case should be ignored when comparing lines.
    • -
    • ignore_whitespace_in - this specifies that whitespace differences should be ignored when comparing lines.
    • -
    +

    There are also the following flags to modify the way that the line-by-line comparisons are carried out:

    -

    Finally, note that only the text itself is compared. These assertions do -not care about how the records within the collections are numbered.

    +
      +
    • ignore_case_in - this specifies that case should be ignored when comparing lines.
    • +
    • ignore_whitespace_in - this specifies that whitespace differences should be ignored when comparing lines.
    • +
    -

    Check for Existence of Database Objects

    +

    + Finally, note that only the text itself is compared. These assertions do + not care about how the records within the collections are numbered. +

    -

    The following assertions (created by Raji) check that a named database -object exists or does not exist: +

    Check for Existence of Database Objects

    -
    PROCEDURE objExists (
    +   

    + The following assertions (created by Raji) check that a named database + object exists or does not exist: +

    + +
    +PROCEDURE objExists (
        msg_in            IN   VARCHAR2,
        check_this_in     IN   VARCHAR2,
        null_ok_in        IN   BOOLEAN := FALSE,
    @@ -674,21 +1130,35 @@ 

    Check for Existence of Database Objects

    check_this_in IN VARCHAR2, null_ok_in IN BOOLEAN := FALSE, raise_exc_in IN BOOLEAN := FALSE -);
    - -In both cases, the check_this_in parameter gives the name of the object to -check for. So passing 'MYTHING' will check if the MYTHING object exists. This -is assumed to be in the current schema. To check for objects in a schema other -than the current one, simply add the name of the schema, separated by a dot. -So passing 'ANOTHER.THATTHING' will check for the existence of the THATTHING -object in the ANOTHER schema.

    +); +
    -

    Check Equality of RefCursor and Query

    - If you have a procedure or function that returns a REF CURSOR type you often would like to compare the data of the REF CURSOR against a query (if your REF CURSOR returns a complete table you can use utAssert.eq_refc_table below). In this case, you specify the REF CURSOR of the procedure or function and the full SELECT statement as parameters. By using eq_refc_query, you may be able to avoid the huge workload of constructing separate tables with preset data. +

    + In both cases, the check_this_in parameter gives the name of the object to + check for. So passing 'MYTHING' will check if the MYTHING object exists. This + is assumed to be in the current schema. To check for objects in a schema other + than the current one, simply add the name of the schema, separated by a dot. + So passing 'ANOTHER.THATTHING' will check for the existence of the THATTHING + object in the ANOTHER schema. +

    -

    Before calling the comparison you have to specifiy the parameters of the procedure or function you are going to use. -This is done with the procedures utPLSQL_Util.reg_In_Param, utPLSQL_Util.reg_InOut_Param or utPLSQL_Util.reg_Out_Param. -The details of the parameters are built up in a variable of type utplsql_util.utplsql_params, which is then passed into eq_refc_query. +

    Check Equality of RefCursor and Query

    + +

    + If you have a procedure or function that returns a REF CURSOR type you + often would like to compare the data of the REF CURSOR against a query (if + your REF CURSOR returns a complete table you can use + utAssert.eq_refc_table below). In this case, + you specify the REF CURSOR of the procedure or function and the full + SELECT statement as parameters. By using eq_refc_query, you may be able to + avoid the huge workload of constructing separate tables with preset data. +

    + +

    + Before calling the comparison you have to specifiy the parameters of the procedure or function you are going to use. + This is done with the procedures utPLSQL_Util.reg_In_Param, utPLSQL_Util.reg_InOut_Param or utPLSQL_Util.reg_Out_Param. + The details of the parameters are built up in a variable of type utplsql_util.utplsql_params, which is then passed into eq_refc_query. +

     PROCEDURE utPLSQL_Util.reg_In_Param (
    @@ -707,7 +1177,10 @@ 

    Check Equality of RefCursor and Query

    params IN OUT utplsql_util.utplsql_params );
    -

    Having specified all the parameters for the procedure or function returning the REF CURSOR, the comparison can be started. +

    + Having specified all the parameters for the procedure or function + returning the REF CURSOR, the comparison can be started. +

     PROCEDURE utAssert.eq_refc_query (
    @@ -718,80 +1191,74 @@ 

    Check Equality of RefCursor and Query

    qry IN VARCHAR2 );
    - where the reg_In_Param, reg_InOut_Param and reg_Out_Param-specific parameters are as follows: - - - - - - - - - - - - - - - - - - - -
    ParameterDescription
    par_pos Defines the parameter position beginning with 1, or 0 specifying the return value -
    par_type Specifies the data type of the return value and must be one out of 'NUMBER', 'VARCHAR', 'CHAR' or 'REFCURSOR' -
    params The local variable to keep the values that is used as a parameter for eq_refc_query -
    - -

    and the eq_refc_query-specific parameters are as follows: - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ParameterDescription
    p_msg_nm The message to be displayed if the test fails -
    proc_name Specifies the procedure or function that delivers the REF CURSOR -
    params The parameter setting for the procedure or function -
    cursor_position Position of the REF CURSOR parameter to be checked, beginning with 1, or 0 to specify the return value of a function -
    qry The SELECT statement to be checked against -
    - -

    Finally, note that only the record itself is compared. These assertions do not care about how the records within the cursor are numbered.

    - - -

    Check Equality of RefCursor and Database Table

    - - If you have a procedure or function that returns a REF CURSOR type that represents a complete table or view you - often would like to compare the data of this REF CURSOR against the table or view - (if your REF CURSOR doesn't return a complete table or view you can use utAssert.eq_refc_query above). - In this case, you specify the REF CURSOR of the procedure or function and the table or view name as parameters. - By using eq_refc_table, you may be able to avoid the huge workload of constructing separate tables with preset data. - -

    Before calling the comparison you have to specifiy the parameters of the procedure or function you are going to use. -This is done with the procedures utPLSQL_Util.reg_In_Param, utPLSQL_Util.reg_InOut_Param or utPLSQL_Util.reg_Out_Param. -The details of the parameters are built up in a variable of type utplsql_util.utplsql_params, which is then passed into eq_refc_query. +

    where the reg_In_Param, reg_InOut_Param and reg_Out_Param-specific parameters are as follows:

    + + + + + + + + + + + + + + + + + + +
    ParameterDescription
    par_pos Defines the parameter position beginning with 1, or 0 specifying the return value
    par_type Specifies the data type of the return value and must be one out of 'NUMBER', 'VARCHAR', 'CHAR' or 'REFCURSOR'
    params The local variable to keep the values that is used as a parameter for eq_refc_query
    + +

    and the eq_refc_query-specific parameters are as follows:

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ParameterDescription
    p_msg_nm The message to be displayed if the test fails
    proc_name Specifies the procedure or function that delivers the REF CURSOR
    params The parameter setting for the procedure or function
    cursor_position Position of the REF CURSOR parameter to be checked, beginning with 1, or 0 to specify the return value of a function
    qry The SELECT statement to be checked against
    + +

    Finally, note that only the record itself is compared. These assertions do not care about how the records within the cursor are numbered.

    + + +

    Check Equality of RefCursor and Database Table

    + +

    + If you have a procedure or function that returns a REF CURSOR type that represents a complete table or view you + often would like to compare the data of this REF CURSOR against the table or view + (if your REF CURSOR doesn't return a complete table or view you can use utAssert.eq_refc_query above). + In this case, you specify the REF CURSOR of the procedure or function and the table or view name as parameters. + By using eq_refc_table, you may be able to avoid the huge workload of constructing separate tables with preset data. +

    + +

    + Before calling the comparison you have to specifiy the parameters of the procedure or function you are going to use. + This is done with the procedures utPLSQL_Util.reg_In_Param, utPLSQL_Util.reg_InOut_Param or utPLSQL_Util.reg_Out_Param. + The details of the parameters are built up in a variable of type utplsql_util.utplsql_params, which is then passed into eq_refc_query. +

     PROCEDURE utPLSQL_Util.reg_In_Param (
    @@ -810,7 +1277,7 @@ 

    Check Equality of RefCursor and Database Table< params IN OUT utplsql_util.utplsql_params );

    -

    Having specified all the parameters for the procedure or function returning the REF CURSOR, the comparison can be started. +

    Having specified all the parameters for the procedure or function returning the REF CURSOR, the comparison can be started.

     PROCEDURE utAssert.eq_refc_table (
    @@ -821,82 +1288,111 @@ 

    Check Equality of RefCursor and Database Table< table_name IN VARCHAR2 );

    - where the reg_In_Param, reg_InOut_Param and reg_Out_Param-specific parameters are as follows: - - - - - - - - - - - - - - - - - - - -
    ParameterDescription
    par_pos Defines the parameter position beginning with 1, or 0 specifying the return value -
    par_type Specifies the data type of the return value and must be one out of 'NUMBER', 'VARCHAR', 'CHAR' or 'REFCURSOR' -
    params The local variable to keep the values that is used as a parameter for eq_refc_query -
    - -

    and the eq_refc_query-specific parameters are as follows: - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ParameterDescription
    p_msg_nm The message to be displayed if the test fails -
    proc_name Specifies the procedure or function that delivers the REF CURSOR -
    params The parameter setting for the procedure or function -
    cursor_position Position of the REF CURSOR parameter to be checked, beginning with 1, or 0 to specify the return value of a function -
    table_name The name of the table name or view to be checked against -
    - -

    Finally, note that only the record itself is compared. These assertions do not care about how the records within the cursor are numbered.

    - -

    Building Your Own Assertion

    - You may want to build assertion routines that fit your specific needs. -If PL/SQL supported inheritance, you could extend the utAssert assertion -routines and then customize them through polymorphism. Lacking this feature, -however, you will write your own procedures that follow the same steps as -the pre-build assertions. In order to integrate the results of your assertion -test into the utResult package, you will want to mimic the utAssert.this procedure. -Here is its current implementation (Release 1.3.2); check the body of the -utAssert package for any changes.
    PROCEDURE this (
    msg_in IN VARCHAR2,
    check_this_in IN BOOLEAN,
    null_ok_in IN BOOLEAN := FALSE,
    raise_exc_in IN BOOLEAN := FALSE,
    register_in IN BOOLEAN := TRUE
    )
    IS
    BEGIN
    IF NOT check_this_in
    OR ( check_this_in IS NULL
    AND NOT null_ok_in)
    THEN
    IF register_in
    THEN
    -
             -- Registers the results in the utResult databank.
    utresult.report (msg_in);
    ELSE
    utreport.pl (msg_in); -- used to be utplsql.pl (msg_in) (PBA 20050621)
    END IF;

    IF showing_results AND register_in
    THEN
    -
             -- Show the results of the test more recently run.
    utresult.showlast;
    END IF;

    IF raise_exc_in
    THEN
    RAISE test_failure;
    END IF;
    END IF;
    END;
    - The most important statement to include in your assertion routine is the - call to utResult.report, which will log the results of the test. +

    where the reg_In_Param, reg_InOut_Param and reg_Out_Param-specific parameters are as follows:

    + + + + + + + + + + + + + + + + + + +
    ParameterDescription
    par_pos Defines the parameter position beginning with 1, or 0 specifying the return value
    par_type Specifies the data type of the return value and must be one out of 'NUMBER', 'VARCHAR', 'CHAR' or 'REFCURSOR'
    params The local variable to keep the values that is used as a parameter for eq_refc_query
    + +

    and the eq_refc_query-specific parameters are as follows:

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ParameterDescription
    p_msg_nm The message to be displayed if the test fails
    proc_name Specifies the procedure or function that delivers the REF CURSOR
    params The parameter setting for the procedure or function
    cursor_position Position of the REF CURSOR parameter to be checked, beginning with 1, or 0 to specify the return value of a function
    table_name The name of the table name or view to be checked against
    + +

    Finally, note that only the record itself is compared. These assertions do not care about how the records within the cursor are numbered.

    + +

    Building Your Own Assertion

    + +

    + You may want to build assertion routines that fit your specific needs. + If PL/SQL supported inheritance, you could extend the utAssert assertion + routines and then customize them through polymorphism. Lacking this feature, + however, you will write your own procedures that follow the same steps as + the pre-build assertions. In order to integrate the results of your assertion + test into the utResult package, you will want to mimic the utAssert.this procedure. + Here is its current implementation (Release 1.3.2); check the body of the + utAssert package for any changes. +

    + +
    +PROCEDURE this (
    +   msg_in        IN VARCHAR2,
    +   check_this_in IN BOOLEAN,
    +   null_ok_in    IN BOOLEAN := FALSE,
    +   raise_exc_in  IN BOOLEAN := FALSE,
    +   register_in   IN BOOLEAN := TRUE
    +   )
    +IS
    +BEGIN
    +   IF    NOT check_this_in
    +      OR (    check_this_in IS NULL
    +          AND NOT null_ok_in)
    +   THEN
    +      IF register_in
    +      THEN
    +         -- Registers the results in the utResult databank.
    +         utresult.report (msg_in);
    +      ELSE
    +         utreport.pl (msg_in); -- used to be utplsql.pl (msg_in) (PBA 20050621)
    +      END IF;
    +      
    +      IF showing_results AND register_in
    +      THEN
    +         -- Show the results of the test more recently run.
    +         utresult.showlast;
    +      END IF;
    +
    +      IF raise_exc_in
    +      THEN
    +         RAISE test_failure;
    +      END IF;
    +   END IF;
    +END;
    +
    +

    + The most important statement to include in your assertion routine is the + call to utResult.report, which will log the results of the test. +

    diff --git a/documentation/src/utconfig.html b/documentation/src/utconfig.html index 65f4a4435..2bf5bf9ac 100644 --- a/documentation/src/utconfig.html +++ b/documentation/src/utconfig.html @@ -1,493 +1,603 @@ - - + + + + + + + -

    -utConfig Package

    - -

    This package contains the following functions and procedures: -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +

    utConfig Package

    + +

    This package contains the following functions and procedures:

    + +
    utConfig.testerReturn whose configuration is used
    utConfig.settesterSet whose configuration is used
    utConfig.showconfigView a schema's configuration
    utConfig.setdirSet the directory containing the test package code
    utConfig.dirReturn the directory containing the test package code
    utConfig.setprefixSet the default unit test prefix for your code
    utConfig.prefixReturn the default unit test prefix for your code
    utConfig.registertestSet the registration mode (manual or automatic)
    utConfig.registeringReturn the registration mode
    utConfig.autocompileSet autocompile feature
    utConfig.autocompiling
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    utConfig.testerReturn whose configuration is used
    utConfig.settesterSet whose configuration is used
    utConfig.showconfigView a schema's configuration
    utConfig.setdirSet the directory containing the test package code
    utConfig.dirReturn the directory containing the test package code
    utConfig.setprefixSet the default unit test prefix for your code
    utConfig.prefixReturn the default unit test prefix for your code
    utConfig.registertestSet the registration mode (manual or automatic)
    utConfig.registeringReturn the registration mode
    utConfig.autocompileSet autocompile feature
    utConfig.autocompilingReturn the autocompile flag
    utConfig.setdelimiterSet the V2 delimiter
    utConfig.delimiterReturn the V2 delimiter
    utConfig.showfailuresonlyTurn off the display of successful tests
    utConfig.showingfailuresonlyReturn whether successful test results are shown or not
    utConfig.setreporterSets the default Output Reporter to use
    utConfig.getreporterGets the name of the default Output Reporter to use
    utConfig.setfiledirSet the directory for file output
    utConfig.filedirReturn which directory is used for file output
    utConfig.setuserprefixSet the user prefix for output file names
    utConfig.userprefixReturn the user prefix for output file names
    utConfig.setincludeprognameSet whether to include the name of the program being tested in output file names
    utConfig.includeprognameReturn whether to include the name of the program being tested in output file names
    utConfig.setdateformatSet the date format for the date portion of output file names
    utConfig.dateformatReturn the date format used to construct output file names
    utConfig.setfileextensionSet the file extension for output file names
    utConfig.fileextensionReturn the file extension used for output file names
    utConfig.setfileinfoSet all of the above file output related items
    utConfig.fileinfoReturn all of the above file output related items
    + +

    + To make it as easy as possible for you to run your tests, utPLSQL stores + various pieces of configuration data in the ut_config table. This data + is stored by schema name and is automatically loaded into utPLSQL the first + time you use this utility in your session. This configuration information + is also automatically updated whenever you call utPLSQL.test -- or any + of the utPLSQL programs specifically designed to change the configuration + settings. +

    + +

    + You can at any time view the utPLSQL configuration for the currently-connected + schema or for another schema (there is not at this point any schema-level + security; all utPLSQL users can view the configurations of all other users). +

    + +

    The data that is currently maintained for a utPLSQL user are:

    + +

    + Test package directory - the location of the test package code + you want to run. You must specify a directory in order to allow utPLSQL + to automatically compile your test packages before each test run. +

    + +

    + Unit test prefix - the prefix used for test package names and + the program names within the package. If you do not specify a prefix, the + default of "ut_" is automatically applied. +

    + +

    + Unit test registration mode - This setting determines whether + utPLSQL will automatically identify the unit tests to be run (strongly + recommended) or if you have chosen to manually register your unit tests + in the test package setup procedure. +

    + +

    + Auto-compilation of test packages - By default, utPLSQL will + recompile your test package before execution. You can turn off this feature + and manually recompile only when you desire (a fine idea if your test package + has gotten very large!). +

    + +

    Return whose configuration is being used

    + +

    + By default, the configuration stored for the currently-connected user will + be used. However, it is possible to use configurations stored against + other usernames. To show whose configuration is currently being used + the following function is used: +

    + +
    +FUNCTION utConfig.tester RETURN VARCHAR2;
    +
    - Return the autocompile flag - +

    Set whose configuration is being used

    - -utConfig.setdelimiter +

    + This returns the configuration that will be used whenever a username is + not specified. To set this, the following procedure is used: +

    + +
    +PROCEDURE utConfig.settester (username_in IN VARCHAR2 := USER);
    +
    -Set the V2 delimiter - +

    View a schema's configuration

    - - utConfig.delimiter +

    + Call the utconfig.showconfig procedure to view the configuration for a specified + schema. The header is: +

    + +
    +PROCEDURE utConfig.showconfig (username_in IN VARCHAR2 := NULL);
    +
    - Return the V2 delimiter - - - - utConfig.showfailuresonly - Turn off the display of successful tests - - - - utConfig.showingfailuresonly - Return whether successful test results are shown or not - - - - utConfig.setreporter - Sets the default Output Reporter to use - - - - utConfig.getreporter - Gets the name of the default Output Reporter to use - - - - - utConfig.setfiledir - Set the directory for file output - - - - utConfig.filedir - Return which directory is used for file output - - - - utConfig.setuserprefix - Set the user prefix for output file names - - - - utConfig.userprefix - Return the user prefix for output file names - - - - utConfig.setincludeprogname - Set whether to include the name of the program being tested in output file names - - - - utConfig.includeprogname - Return whether to include the name of the program being tested in output file names - - - - utConfig.setdateformat - Set the date format for the date portion of output file names - - - - utConfig.dateformat - Return the date format used to construct output file names - - - - utConfig.setfileextension - Set the file extension for output file names - - - - utConfig.fileextension - Return the file extension used for output file names - - - - utConfig.setfileinfo - Set all of the above file output related items - - - - utConfig.fileinfo - Return all of the above file output related items - - - - -

    To make it as easy as possible for you to run your tests, utPLSQL stores -various pieces of configuration data in the ut_config table. This data -is stored by schema name and is automatically loaded into utPLSQL the first -time you use this utility in your session. This configuration information -is also automatically updated whenever you call utPLSQL.test -- or any -of the utPLSQL programs specifically designed to change the configuration -settings. -

    You can at any time view the utPLSQL configuration for the currently-connected -schema or for another schema (there is not at this point any schema-level -security; all utPLSQL users can view the configurations of all other users). -

    The data that is currently maintained for a utPLSQL user are: -

    Test package directory - the location of the test package code -you want to run. You must specify a directory in order to allow utPLSQL -to automatically compile your test packages before each test run. -

    Unit test prefix - the prefix used for test package names and -the program names within the package. If you do not specify a prefix, the -default of "ut_" is automatically applied. -

    Unit test registration mode - This setting determines whether -utPLSQL will automatically identify the unit tests to be run (strongly -recommended) or if you have chosen to manually register your unit tests -in the test package setup procedure. -

    Auto-compilation of test packages - By default, utPLSQL will -recompile your test package before execution. You can turn off this feature -and manually recompile only when you desire (a fine idea if your test package -has gotten very large!). -

    -Return whose configuration is being used

    -By default, the configuration stored for the currently-connected user will -be used. However, it is possible to use configurations stored against -other usernames. To show whose configuration is currently being used -the following function is used: -
    FUNCTION utConfig.tester RETURN VARCHAR2;
    - -

    -Set whose configuration is being used

    -This returns the configuration that will be used whenever a username is -not specified. To set this, the following procedure is used: -
    PROCEDURE utConfig.settester (username_in IN VARCHAR2 := USER);
    - -

    -View a schema's configuration

    -Call the utconfig.showconfig procedure to view the configuration for a specified -schema. The header is: -
    PROCEDURE utConfig.showconfig (username_in IN VARCHAR2 := NULL);
    -If you do not specify a schema, then the currently -used configuration is returned. Here is an example of output from this -procedure: -
    SQL> exec utconfig.showconfig
    +   

    + If you do not specify a schema, then the currently + used configuration is returned. Here is an example of output from this + procedure: +

    + +
    +SQL> exec utconfig.showconfig
     =============================================================
     utPLSQL Configuration for SCOTT
        Directory: /apps/utplsql/code
        Autcompile? Y
        Manual test registration? N
        Prefix = test_
    -=============================================================
    -And here is an example of calling showConfig for a different schema: -
    SQL> exec utconfig.showconfig ('COMP')
    +=============================================================
    +
    + +

    And here is an example of calling showConfig for a different schema:

    + +
    +SQL> exec utconfig.showconfig ('COMP')
     =============================================================
     utPLSQL Configuration for COMP
        Directory: M:\shared_apps\utplsql\comp
        Autcompile? N
        Manual test registration? N
        Prefix = ut_
    -=============================================================
    -You might want to put a call to showConfig in your SQL*Plus login file -so that you are reminded on startup as to what the current settings are. -Here is such a script (to be found in Examples\login_sample.sql): -
    exec utconfig.setdir ('e:\openoracle\utplsql\utinstall\examples')
    -SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED
    -exec utconfig.showconfig
    - -

    -Set the directory containing the test package code

    -If you want utPLSQL to compile your test package, you must tell it the -directory in which your code is found. You can do this either when you -define -your test suite and packages within the suite, or you can call the -utConfig.setdir procedure to set the directory for your current session. -

    Note: as of v1.5.1, the value you pass in any of these programs is saved -in the configuration table and will be used in the future -- until you -change it by passing a different value. -

    The header for this procedure is: -

    PROCEDURE utConfig.setdir (dir_in IN VARCHAR2, username_in IN VARCHAR2 := NULL);
    -where dir_in is the directory and username_in is the name of the schema -to which this directory applies (NULL means the currently -used configuration is set), as in: -
    SQL> exec utconfig.setdir ('e:\demo\utplsql');
    -or, with the specification of a non-current schema: -
    SQL> exec utconfig.setdir ('e:\demo\utplsql', 'ANALYSIS');
    -Note that this directory must be accessible through UTL_FILE. -

    You might consider putting the the call to utConfig.setdir into your -login.sql so that it is run automatically, each time your start up SQL*Plus --- if you are always working from the same directory. -

    -Return the directory containing the test package code

    -You can obtain the current directory with a call to utConfig.dir: -
    FUNCTION utConfig.dir (username_in IN VARCHAR2 := NULL)
    -      RETURN VARCHAR2;
    - -

    -Set the default unit test prefix for your code.

    -The unit test prefix is very important in utPLSQL; the utility uses the -prefix to associate source code to be tested with the test package. The -prefix also allows utPLSQL to automatically identify the programs within -a test package that are to be executed as unit tests. -

    The default prefix in utPLSQL is "ut_", but you can override this when -you call utPLSQL.test or by calling the utConfig.setprefix procedure: -

    PROCEDURE utConfig.setPrefix (
    -   prefix_in IN VARCHAR2, username_in IN VARCHAR2 := NULL)
    -where prefix_in is the prefix and username_in is the name of the schema -to which this prefix applies (NULL means the currently -used configuration is set), as in: -
    SQL> exec utconfig.setPrefix ('tst#');
    -or, with the specification of a non-current schema: -
    SQL> exec utconfig.setPrefix ('t_', 'ANALYSIS');
    - -

    -Return the default unit test prefix for your code.

    -You can obtain the current prefix with a call to utConfig.prefix: -
    FUNCTION utConfig.prefix (username_in IN VARCHAR2 := NULL)
    -      RETURN VARCHAR2;
    -uPLSQL currently does not support the use of a suffix, or combination of -suffix and prefix, to identify test packages and unit test procedures. -

    -Set the registration mode (manual or automatic).

    -As of utPLSQL v1.5.1, you no longer have to register your unit test procedures -in the setup procedure of your test package. Instead, utPLSQL will scan -the data dictionary (via theALL_ARGUMENTS view) for the names of all the -unit test procedures you have defined, and then run them. utPLSQL identifies -these programs by looking for all programs whose names start with the specified -prefix. -

    If you so choose, you can request that utPLSQL turn off automatic detection -of unit test procedures and only run those programs listed in the setup -procedure. To do this, you call the utConfig.registerTest procedure: -

    PROCEDURE utConfig.registerTest (
    -      onoff_in IN BOOLEAN,
    -      username_in IN VARCHAR2 := NULL
    -   );
    -as in: -
    SQL> exec utConfig.registerTest (TRUE)
    -Note: if you are using automatic unit test detection, any calls to utPLSQL.addtest -in the setup procedure will be ignored. - -

    You can return the current registration mode using the following function: -

    FUNCTION registeringtest (username_in IN VARCHAR2 := NULL)
    -   RETURN BOOLEAN;
    -This returns TRUE if the registration mode has been set to manual and FALSE otherwise. -

    - -

    -Set autocompile feature

    - -The default settings for utPLSQL is to re-compile -your base package before each unit test. This guarantees that any recent -changes will be tested. It also saves you the step of doing an explicit -compile. - -In order to perform automatic compilation: - -
      -Your schema will need to -have either CREATE PROCEDURE or CREATE ANY PROCEDURE privileges granted -directly; -you cannot grant these privileges through roles. - -You will need to set or -pass the location of the source code. You can do this by calling utConfig.setdir -or by including the directory location in your call to utPLSQL.test -or utPLSQL.testsuite (the dir_in -parameter). - -The package specification -must be contained in a file named <package>.pks; the body must be stored -in <package>.pkb. - -You must have configured -the -UTL_FILE built-in package for use -on your database instance. -
    - -In general (and the default), you should allow your -test package to be recompiled with each execution. You might want to avoid -recompilation if: - -
      -You have made a copy of the package body with some -temporary changes and already compiled that. If you recompile automatically, -you will wipe out those changes. - -You have not set up UTL_FILE -and you don't want to deal with it. +============================================================= +
    -You are running the tests -on a server to which you have no access other than via a database connection. - +

    + You might want to put a call to showConfig in your SQL*Plus login file + so that you are reminded on startup as to what the current settings are. + Here is such a script (to be found in Examples\login_sample.sql): +

    + +
    +exec utconfig.setdir ('e:\openoracle\utplsql\utinstall\examples')
    +SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED
    +exec utconfig.showconfig
    +
    -

    -Turning off Auto-compile

    +

    Set the directory containing the test package code

    + +

    + If you want utPLSQL to compile your test package, you must tell it the + directory in which your code is found. You can do this either when you + define your test suite and packages within the suite, or you can call the + utConfig.setdir procedure to set the directory for your current session. +

    + +

    + Note: as of v1.5.1, the value you pass in any of these programs is saved + in the configuration table and will be used in the future -- until you + change it by passing a different value. +

    + +

    The header for this procedure is:

    + +
    +PROCEDURE utConfig.setdir (dir_in IN VARCHAR2, username_in IN VARCHAR2 := NULL);
    +
    -If you are working with products like SQL*Navigator, -you may be always editing from code stored in the database. In this case, -you will never want to have utPLSQL recompile your code for you – it will -already be compiled and you do not need to hassle with UTL_FILE. +

    + where dir_in is the directory and username_in is the name of the schema + to which this directory applies (NULL means the currently + used configuration is set), as in: +

    + +
    +SQL> exec utconfig.setdir ('e:\demo\utplsql');
    +
    -You can avoid auto-recompilation in two ways: +

    or, with the specification of a non-current schema:

    + +
    +SQL> exec utconfig.setdir ('e:\demo\utplsql', 'ANALYSIS');
    +
    -1. Pass a value of FALSE for the recompile_in argument -to utPLSQL.test or utPLSQL.testsuite. Here is an example: +

    Note that this directory must be accessible through UTL_FILE.

    + +

    + You might consider putting the the call to utConfig.setdir into your + login.sql so that it is run automatically, each time your start up SQL*Plus + -- if you are always working from the same directory. +

    + +

    Return the directory containing the test package code

    + +

    You can obtain the current directory with a call to utConfig.dir:

    + +
    +FUNCTION utConfig.dir (username_in IN VARCHAR2 := NULL)
    +      RETURN VARCHAR2;
    +
    -
    BEGIN
    +

    Set the default unit test prefix for your code.

    + +

    + The unit test prefix is very important in utPLSQL; the utility uses the + prefix to associate source code to be tested with the test package. The + prefix also allows utPLSQL to automatically identify the programs within + a test package that are to be executed as unit tests. +

    + +

    + The default prefix in utPLSQL is "ut_", but you can override this when + you call utPLSQL.test or by calling the utConfig.setprefix procedure: +

    + +
    +PROCEDURE utConfig.setPrefix (
    +   prefix_in IN VARCHAR2, username_in IN VARCHAR2 := NULL)
    +
    -
       -- Define a test suite for PL/Vision
    +

    + where prefix_in is the prefix and username_in is the name of the schema + to which this prefix applies (NULL means the currently + used configuration is set), as in: +

    + +
    +SQL> exec utconfig.setPrefix ('tst#');
    +
    -
       utsuite.add ('PLVision');
    +

    or, with the specification of a non-current schema:

    -
      
    +
    +SQL> exec utconfig.setPrefix ('t_', 'ANALYSIS');
    +
    -
       -- Add two packages for testing
    +

    Return the default unit test prefix for your code.

    -
       utsuite.addpkg (
    +

    You can obtain the current prefix with a call to utConfig.prefix:

    -
          'PLVision', 'PLVstr', dir_in => 'e:\utplsql');
    +
    +FUNCTION utConfig.prefix (username_in IN VARCHAR2 := NULL)
    +      RETURN VARCHAR2;
    +
    -
       utsuite.addpkg (
    +

    + uPLSQL currently does not support the use of a suffix, or combination of + suffix and prefix, to identify test packages and unit test procedures. +

    + +

    Set the registration mode (manual or automatic).

    + +

    + As of utPLSQL v1.5.1, you no longer have to register your unit test procedures + in the setup procedure of your test package. Instead, utPLSQL will scan + the data dictionary (via theALL_ARGUMENTS view) for the names of all the + unit test procedures you have defined, and then run them. utPLSQL identifies + these programs by looking for all programs whose names start with the specified + prefix. +

    + +

    + If you so choose, you can request that utPLSQL turn off automatic detection + of unit test procedures and only run those programs listed in the setup + procedure. To do this, you call the utConfig.registerTest procedure: +

    + +
    +PROCEDURE utConfig.registerTest (
    +      onoff_in IN BOOLEAN,
    +      username_in IN VARCHAR2 := NULL
    +   );
    +
    -
          'PLVision', 'PLVdate', dir_in => 'e:\utplsql');
    +

    as in:

    -
      
    +
    +SQL> exec utConfig.registerTest (TRUE)
    +
    -
       -- Run the test suite
    +

    + Note: if you are using automatic unit test detection, any calls to utPLSQL.addtest + in the setup procedure will be ignored. +

    + +

    You can return the current registration mode using the following function:

    -
       utplsql.testsuite (
    +
    +FUNCTION registeringtest (username_in IN VARCHAR2 := NULL)
    +   RETURN BOOLEAN;
    +
    -
          'PLVision', recompile_in => FALSE);
    +

    This returns TRUE if the registration mode has been set to manual and FALSE otherwise.

    + +

    Set autocompile feature

    + +

    + The default settings for utPLSQL is to re-compile + your base package before each unit test. This guarantees that any recent + changes will be tested. It also saves you the step of doing an explicit + compile. +

    + +

    In order to perform automatic compilation:

    + +
      +
    • + Your schema will need to + have either CREATE PROCEDURE or CREATE ANY PROCEDURE privileges granted + directly; + you cannot grant these privileges through roles. +
    • + +
    • + You will need to set or + pass the location of the source code. You can do this by calling utConfig.setdir + or by including the directory location in your call to utPLSQL.test + or utPLSQL.testsuite (the dir_in + parameter). +
    • + +
    • + The package specification + must be contained in a file named <package>.pks; the body must be stored + in <package>.pkb. +
    • + +
    • + You must have configured + the + UTL_FILE built-in package for use + on your database instance. +
    • +
    + +

    + In general (and the default), you should allow your + test package to be recompiled with each execution. You might want to avoid + recompilation if: +

    + +
      +
    • + You have made a copy of the package body with some + temporary changes and already compiled that. If you recompile automatically, + you will wipe out those changes. +
    • +
    • + You have not set up UTL_FILE + and you don't want to deal with it. +
    • +
    • + You are running the tests + on a server to which you have no access other than via a database connection. +
    • +
    + +

    Turning off Auto-compile

    + +

    + If you are working with products like SQL*Navigator, + you may be always editing from code stored in the database. In this case, + you will never want to have utPLSQL recompile your code for you - it will + already be compiled and you do not need to hassle with UTL_FILE. +

    + +

    You can avoid auto-recompilation in two ways:

    + +

    + 1. Pass a value of FALSE for the recompile_in argument + to utPLSQL.test or utPLSQL.testsuite. Here is an example: +

    + +
    +BEGIN
    +   -- Define a test suite for PL/Vision
    +   utsuite.add ('PLVision');
    +  
    +   -- Add two packages for testing
    +   utsuite.addpkg (
    +      'PLVision', 'PLVstr', dir_in => 'e:\utplsql');
    +   utsuite.addpkg (
    +      'PLVision', 'PLVdate', dir_in => 'e:\utplsql');
    +  
    +   -- Run the test suite
    +   utplsql.testsuite (
    +      'PLVision', recompile_in => FALSE);
    +END;
    +/
    + +

    + If you know that you will never want to recompilation, + however, you can set the default behavior at the schema level by calling + the autocompile procedure +

    + +
    +   PROCEDURE utConfig.autocompile (
    +      onoff_in IN BOOLEAN,
    +      username_in IN VARCHAR2 := NULL
    +   );
    +
    -
    END;
    +

    + So I can make the following + call to turn off autocompilation for the SCOTT schema: +

    -
    /
    +
    +SQL> exec utconfig.autocompile (FALSE, 'SCOTT')
    +
    -If you know that you will never want to recompilation, -however, you can set the default behavior at the schema level by calling -the autocompile procedure +

    + This program updates the ut_config table with your information and then + commits the setting. +

    -
       PROCEDURE utConfig.autocompile (
    +

    + You can determine the current + setting for auto-compilation at any time by calling the following function: +

    -
          onoff_in IN BOOLEAN,
    +
    +   FUNCTION utConfig.autocompiling (username_in IN VARCHAR2 := NULL)
    +      RETURN BOOLEAN;
    +
    -
          username_in IN VARCHAR2 := NULL
    +

    + Note: When you set the schema-level recompilation + value to FALSE, that will override anything you pass in a call to utPLSQL.test + or utPLSQL.testsuite. +

    -
       );
    +

    V2 Delimiter

    -
     
    +

    You can set the delimiter to be used in V2 procedure names using the following procedure:

    + +
    +PROCEDURE setdelimiter (
    +  delimiter_in IN VARCHAR2, 
    +  username_in IN VARCHAR2 := NULL
    +); 
    +
    -So I can make the following -call to turn off autocompilation for the SCOTT schema: +

    while the current delimiter can be obtained by the function:

    + +
    +FUNCTION delimiter (username_in IN VARCHAR2 := NULL)
    +  RETURN VARCHAR2;
    +
    -
    -
    -
    SQL> exec utconfig.autocompile (FALSE, 'SCOTT') 
    -This program updates the ut_config table with your information and then -commits the setting. +

    Turn off the display of successful test results

    + +

    + By default, the results of all the tests are shown. This includes both successful and unsuccessful + results. The following procedure allows you to limit the tests shown to only those that have failed: +

    + +
    +PROCEDURE showfailuresonly (
    +     onoff_in      IN   BOOLEAN,
    +     username_in   IN   VARCHAR2 := NULL
    +   );
    +
    -

    You can determine the current -setting for auto-compilation at any time by calling the following function: -

    
    +   

    the current setting can be obtained by the function:

    -
       FUNCTION utConfig.autocompiling (username_in IN VARCHAR2 := NULL)
    +
    +FUNCTION showingfailuresonly (username_in IN VARCHAR2 := NULL)
    +      RETURN BOOLEAN;
    +
    -
          RETURN BOOLEAN;
    +

    Set and Get the default output reporter

    -Note: When you set the schema-level recompilation -value to FALSE, that will override anything you pass in a call to utPLSQL.test -or utPLSQL.testsuite. +

    + By default, all results are sent to the screen via DBMS_OUTPUT. However, it is possible to use other output reporters as described in more detail + on this page. The following procedure allows you to set which output reporter should be used by default: +

    -

    - V2 Delimiter

    -

    You can set the delimiter to be used in V2 procedure names using the following procedure: -

    PROCEDURE setdelimiter (
    -  delimiter_in IN VARCHAR2, 
    -  username_in IN VARCHAR2 := NULL
    -); 
    -while the current delimiter can be obtained by the function: -
    FUNCTION delimiter (username_in IN VARCHAR2 := NULL)
    -  RETURN VARCHAR2;
    -

    - -

    - Turn off the display of successful test results -

    -

    -By default, the results of all the tests are shown. This includes both successful and unsuccessful -results. The following procedure allows you to limit the tests shown to only those that have failed: -

    PROCEDURE showfailuresonly (
    -     onoff_in      IN   BOOLEAN,
    -     username_in   IN   VARCHAR2 := NULL
    -   );
    -the current setting can be obtained by the function: -
    FUNCTION showingfailuresonly (username_in IN VARCHAR2 := NULL)
    -      RETURN BOOLEAN;
    -

    - - -

    - Set and Get the default output reporter -

    -

    -By default, all results are sent to the screen via DBMS_OUTPUT. However, it is possible to use other output reporters as described in more detail -on this page. The following procedure allows you to set which output reporter should be used by default: -

    PROCEDURE setreporter (
    +
    +PROCEDURE setreporter (
           reporter_in   IN   VARCHAR2
          ,username_in   IN   VARCHAR2 := NULL
        );
     
    -as usual, the current setting can be obtain by the following function: -
    FUNCTION getreporter (username_in IN VARCHAR2 := NULL)
    +
    +   

    as usual, the current setting can be obtain by the following function:

    + +
    +FUNCTION getreporter (username_in IN VARCHAR2 := NULL)
           RETURN VARCHAR2;
     
    -

    + diff --git a/documentation/src/utgen.html b/documentation/src/utgen.html index 3d757492b..0ce2eebc8 100644 --- a/documentation/src/utgen.html +++ b/documentation/src/utgen.html @@ -1,553 +1,569 @@ - - + + + + + + + -

    -utGen Package

    +

    utGen Package

    + +

    This package contains the following procedures and functions:

    + + + + + + + + + + + + + + + + + + +
    utGen.testpkg (basic version)Generate skeleton test packages
    + utGen.testpkg (grid version)
    + utGen.testpkg_from_file
    + utGen.testpkg_from_string +
    Generate skeleton test packages with test cases
    utGen.pkgstringGet skeleton as a string
    + utGen.countRows +
    utGen.firstRow +
    utGen.firstBodyRow +
    utGen.atFirstRow +
    utGen.lastRow +
    utGen.atLastRow +
    utGen.setRow +
    utGen.getRow +
    utGen.nextRow +
    utGen.prevRow +
    utGen.showRows +
    utGen.nthRow +
    Get rows from generated skeleton test package as array
    + +

    Generate Skeleton Test Packages

    + +

    + The utGen contains a procedure that allows you to generate a starting point + for a unit test package. This package can be sent to the screen, + a file, a delimited string or + an array (best for interfacing with a front end). + You can generate a stand-alone test package or code "fragments" to be placed + inside an existing source package. +

    + +

    + We strongly recommend that you use utGen.testpkg + as a starting point for all of your utPLSQL unit test construction. By + taking this approach, you will most easily (and transparently) conform + to the most up to date guidelines for utPLSQL test packages. +

    + +

    + Note: While utGen.testpkg goes as far as + possible to generate sensible unit test code, you will need to edit this + code before you can compile and use it. +

    + +

    Here is the header of the testpkg procedure:

    -

    This package contains the following procedures and functions: -
    - - - - - - - - - - - - - - - - - - - - - - - - - -
    utGen.testpkg (basic version)Generate skeleton test packages
    - utGen.testpkg (grid version)
    - utGen.testpkg_from_file
    - utGen.testpkg_from_string -
    Generate skeleton test packages with test cases
    utGen.pkgstringGet skeleton as a string
    utGen.countRows -
    utGen.firstRow -
    utGen.firstBodyRow -
    utGen.atFirstRow -
    utGen.lastRow -
    utGen.atLastRow -
    utGen.setRow -
    utGen.getRow -
    utGen.nextRow -
    utGen.prevRow -
    utGen.showRows -
    utGen.nthRow
    Get rows from generated skeleton test package as array
    - - -

    -Generate Skeleton Test Packages

    -The utGen contains a procedure that allows you to generate a starting point -for a unit test package. This package can be sent to the screen, -a file, a delimited string or -an array (best for interfacing with a front end). -You can generate a stand-alone test package or code "fragments" to be placed -inside an existing source package. - -We strongly recommend that you use utGen.testpkg -as a starting point for all of your utPLSQL unit test construction. By -taking this approach, you will most easily (and transparently) conform -to the most up to date guidelines for utPLSQL test packages. - -Note: While utGen.testpkg goes as far as -possible to generate sensible unit test code, you will need to edit this -code before you can compile and use it. - -Here is the header of the testpkg procedure: - -
       PROCEDURE utGen.testpkg (
    - -
          package_in IN VARCHAR2,
    - -
          program_in IN VARCHAR2 := '%',
    - -
          samepackage_in IN BOOLEAN := FALSE,
    - -
          prefix_in IN VARCHAR2 := NULL,
    - -
          schema_in IN VARCHAR2 := NULL,
    - -
          output_type_in IN PLS_INTEGER := c_screen,
    - -
          dir_in IN VARCHAR2 := NULL,
    - -
          delim_in IN VARCHAR2 := c_delim
    - -
       );
    - -And here is a description of the parameters: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Parameter NameUsage
    -package_in - -The name of the package or stand-alone program for -which a test package is to be generated. -
    -program_in - -The filter to be applied to the list of programs -for which unit test procedures will be generated. So if you only wanted -to generate unit tests for programs that start with "UPD", you would pass -'UPD%' for this argument. -
    -samepackage_in - -TRUE if you plan to insert the generated code into -the source package, FALSE if you want a stand-alone test package. -
    -prefix_in - -The prefix to be used for the test package and/or -unit test procedures. See section " Organizing Your Test Code" for details. -
    -schema_in - -The schema that owns the package or program specified -by package_in. The default is the currently connected schema. -
    -output_type_in - -The type of output that will receive the generated -code. Valid options are defined as packaged constants: - -
      -
    • utGen.c_file
    • - -
    • utGen.c_screen
    • - -
    • utGen.c_string
    • - -
    • utGen.c_array
    • -
    - -The following sections explain the way you would -work with these constants and the resulting generated code. -
    -dir_in - -The location of the file containing the generated -code. Used only if you specify utGen.c_file for the output type. -
    -delim_in - -The delimiter used to separate lines of generated -code. Used only if you specify utGen.c_string for the output type. -
    - - -

    Before you use utGen.testpkg, you should make a few -decisions about your generated code: -

      -
    • -Do you want the generated test code to be a stand-alone package or to be -inserted into an existing package? The default is stand-alone. Pass TRUE -for samepackage_in if you want to generate code that can be easily cut -and pasted into your source package. Note that utGen.testpkg does not -actually modify your source package.
    • - -Do you want to generate a unit test program -for every procedure and function in your package? If so, then go with the -default for program_in. If, on the other hand, your package has one hundred -programs and you only want to test, say, only those programs that perform -updates, you might want to pass a non-trivial filter, such as "UPD%". - -Where do you want to send your output? You -can display to the screen, which can then be grabbed and put into a file -(or in SQL*Plus spool it directly to a file). You can send the code to -a file. You can deposit the code in a delimited string and then parse it -within your own environment. Finally -- and of most relevance if you are -building a GUI interface to utPLSQL -- you can generate to an internal -array and then retrieve individual rows of the arrays through the utGen -API. -
    - -Here are some examples of using utGen.testpkg: - -
      -
    1. -Generate to the screen a stand-alone test package for the STR package:
    2. -
    - -
    -
    -
    SQL> exec utGen.testpkg ('str')
    -
    -
    - -
      -
    1. -Generate to the screen unit test code to be embedded inside the STR package:
    2. -
    - -
    -
    -
    SQL> exec utGen.testpkg ('str', samepackage_in => TRUE)
    -
    -
    - -
      -
    1. -Generate to the screen unit test code for all programs whose names contain -"STR" to be embedded inside the STR package,.
    2. -
    - -
    -
    -
    SQL> exec utGen.testpkg ('str', '%STR%', samepackage_in => TRUE)
    -
    -
    - -Now let's explore how to direct the generated code -to different types of output. - -

    -Generating to Screen

    - -The default behavior of utGen.testpkg is to generate -code to your screen (via DBMS_OUTPUT.PUT_LINE). So unless you specify some -other value for output_type_in, the code will be displayed on your screen -or within a window of your PL/SQL IDE (such as TOAD or SQL*Programmer and -so on). You can then transfer that content to a file, or move it to another -window for immediate editing and compilation. - -Here is an example of using utGen.testpkg, while -also spooling to a file: - -
    SQL> set serveroutput on size 1000000
    - -
    SQL> spool str.pkg
    - -
    SQL> exec utgen.testpkg ('str')
    - -...out comes the code... - -
    SQL> spool off
    - -If DBMS_OUTPUT is not enabled in your session, then -utGen.testpkg will not generate any output. - -

    -Generating to File

    - -If you are working with utGen in a command line -style (ie, you are not using a utGen-enabled GUI), then you will probably -find it most useful to generate testing code directly to file. You do this -by specifying utGen.c_file for the output type. You must also specify the -directory in which you want the files (one for the package specification -and another for the body)created. - -Here's a generation request that creates two files -named ut_str.pks and ut_str.pkb in the /newcode directory: - -
    SQL> exec utgen.testpkg ('str', output_type_in => utGen.c_file, dir_in => '/newcode')
    - -Notes on generating to file: - - -
      -
    1. -You do not have to specify a directory if you have previously (in your -current session) called utConfig.setdir to set the default directory for -all file-related utPLSQL operations. The following two lines of code are, -in other words, equivalent to the single line shown above:
    2. -
    - - -
    -
    -
    SQL> exec utconfig.setdir ('/newcode')
    - -
    SQL> exec utgen.testpkg ('str', output_type_in => utGen.c_file);
    -
    -
    - -
      -
    1. -You set up the UTL_FILE package (add at least one utl_file_dir entry in -your database parameter initialization file) and make sure your directory -is accessible through UTL_FILE, before this operation can succeed.
    2. -
    - -

    -Generating to String

    - -If you are accessing utPLSQL functionality through -a GUI, you might find it more useful to direct output to a string (or array, -see next section). You probably don't want to hassle with UTL_FILE (server-based -file IO) and grabbing information from DBMS_OUTPUT.PUT_LINE is just a general -hassle. - -If you generate to a string, you can then retrieve -that string value into a local variable and then parse it for display and -manipulation. Here is an example of redirection to string: - -
    BEGIN
    - -
       utgen.testpkg ('str', output_type_in => utGen.c_string);
    - -
    END;
    - -The generated code is composed of multiple lines -of information, so they need to be separated by a delimiter. The default -delimiter is the vertical bar, '|'. You can override that and provide your -own delimiter. In the following example, I have decided to use the carriage -return character as my delimiter: - -
    BEGIN
    - -
       utgen.testpkg (
    - -
          'str',
    - -
          output_type_in => utGen.c_string,
    - -
          delim_in => CHR(10));
    - -
    END;
    - -Great, so the code has been put in a string. How -do you get all that generated code? Call the utGen.pkgstring function: - -
    FUNCTION utGen.pkgString RETURN VARCHAR2;
    - -

    -Generating to Array

    - -If you are accessing utPLSQL functionality through -a GUI, you might find it more useful to direct output to an array. You -probably don't want to hassle with UTL_FILE (server-based file IO) and -grabbing information from DBMS_OUTPUT.PUT_LINE is just a general hassle. - -If you generate to an array, you can then retrieve -the individual lines of code in the array through an API provided by utGen -(the array itself is "hidden"). Here is an example of redirection to the -utGen array: - -
    BEGIN
    - -
       utgen.testpkg ('str', output_type_in => utGen.c_array);
    - -
    END;
    - -Great, so the code has been put in an array. How -do you get all that generated code? Take advantage of the utGen -API to retrieve individual rows in the array, which offers these features: - -Get the number of rows currently in the array: - -
       FUNCTION utGen.countRows RETURN PLS_INTEGER;
    - -Get the absolute index of the first row in the array: - -
       FUNCTION utGen.firstRow RETURN PLS_INTEGER;
    - -Get the absolute index of the last row in the array: - -
       FUNCTION utGen.lastRow RETURN PLS_INTEGER;
    - -The API offers a set of programs to iterate through -the array, by maintaining a "current row" inside the package. You can: - -Find out if you are positioned at the first row -in the set: - -
       FUNCTION utGen.atFirstRow RETURN BOOLEAN;
    - -Find out if you are positioned at the last row in -the set: - -
       FUNCTION utGen.atLastRow RETURN BOOLEAN;
    - -Find the first relative row containing the start -of the package body definition. This is handy when you want to put the -code for the specification and body in separate windows and/or files: - -
       FUNCTION utGen.firstBodyRow RETURN PLS_INTEGER;
    - -Retrieve the text in the Nth row of the array. This -gives you "random access" to the contents of the array. You can even specify -a negative direction to get the Nth row from the end of the array. - -
       FUNCTION utGen.nthRow (nth IN PLS_INTEGER, direction utGen.IN SIGNTYPE := 1) RETURN codeline_t;
    - -Set the pointer in the array to the specified row -number. This allows you then move either forward or backward from that -row in the array (using nextRow and prevRow, respectively): +
    +   PROCEDURE utGen.testpkg (
    +      package_in IN VARCHAR2,
    +      program_in IN VARCHAR2 := '%',
    +      samepackage_in IN BOOLEAN := FALSE,
    +      prefix_in IN VARCHAR2 := NULL,
    +      schema_in IN VARCHAR2 := NULL,
    +      output_type_in IN PLS_INTEGER := c_screen,
    +      dir_in IN VARCHAR2 := NULL,
    +      delim_in IN VARCHAR2 := c_delim
    +   );
    +
    -
       PROCEDURE utGen.setRow (nth IN PLS_INTEGER);
    +

    And here is a description of the parameters:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Parameter NameUsage
    package_in + The name of the package or stand-alone program for + which a test package is to be generated. +
    program_in + The filter to be applied to the list of programs + for which unit test procedures will be generated. So if you only wanted + to generate unit tests for programs that start with "UPD", you would pass + 'UPD%' for this argument. +
    samepackage_in + TRUE if you plan to insert the generated code into + the source package, FALSE if you want a stand-alone test package. +
    prefix_in + The prefix to be used for the test package and/or + unit test procedures. See section " Organizing Your Test Code" for details. +
    schema_in + The schema that owns the package or program specified + by package_in. The default is the currently connected schema. +
    output_type_in + The type of output that will receive the generated + code. Valid options are defined as packaged constants: +
      +
    • utGen.c_file
    • +
    • utGen.c_screen
    • +
    • utGen.c_string
    • +
    • utGen.c_array
    • +
    + The following sections explain the way you would + work with these constants and the resulting generated code. +
    dir_in + The location of the file containing the generated + code. Used only if you specify utGen.c_file for the output type. +
    delim_in + The delimiter used to separate lines of generated + code. Used only if you specify utGen.c_string for the output type. +
    + +

    + Before you use utGen.testpkg, you should make a few + decisions about your generated code: +

    + +
      +
    • + Do you want the generated test code to be a stand-alone package or to be + inserted into an existing package? The default is stand-alone. Pass TRUE + for samepackage_in if you want to generate code that can be easily cut + and pasted into your source package. Note that utGen.testpkg does not + actually modify your source package. +
    • + +
    • + Do you want to generate a unit test program + for every procedure and function in your package? If so, then go with the + default for program_in. If, on the other hand, your package has one hundred + programs and you only want to test, say, only those programs that perform + updates, you might want to pass a non-trivial filter, such as "UPD%". +
    • + +
    • + Where do you want to send your output? You + can display to the screen, which can then be grabbed and put into a file + (or in SQL*Plus spool it directly to a file). You can send the code to + a file. You can deposit the code in a delimited string and then parse it + within your own environment. Finally -- and of most relevance if you are + building a GUI interface to utPLSQL -- you can generate to an internal + array and then retrieve individual rows of the arrays through the utGen + API. +
    • +
    + +

    Here are some examples of using utGen.testpkg:

    + +
      +
    1. + Generate to the screen a stand-alone test package for the STR package: +
    2. +
    + +
    +
    +
    +SQL> exec utGen.testpkg ('str')
    +
    +
    +
    -Retrieve the line of code stored in the current -row in the array (set via setRow, nextRow or prevRow): +
      +
    1. + Generate to the screen unit test code to be embedded inside the STR package: +
    2. +
    -
       FUNCTION utGen.getRow RETURN codeline_t;
    +
    +
    +
    +SQL> exec utGen.testpkg ('str', samepackage_in => TRUE)
    +
    +
    +
    + +
      +
    1. + Generate to the screen unit test code for all programs whose names contain + "STR" to be embedded inside the STR package,. +
    2. +
    + +
    +
    +
    +SQL> exec utGen.testpkg ('str', '%STR%', samepackage_in => TRUE)
    +
    +
    +
    + +

    + Now let's explore how to direct the generated code + to different types of output. +

    + +

    Generating to Screen

    + +

    + The default behavior of utGen.testpkg is to generate + code to your screen (via DBMS_OUTPUT.PUT_LINE). So unless you specify some + other value for output_type_in, the code will be displayed on your screen + or within a window of your PL/SQL IDE (such as TOAD or SQL*Programmer and + so on). You can then transfer that content to a file, or move it to another + window for immediate editing and compilation. +

    +

    + Here is an example of using utGen.testpkg, while + also spooling to a file: +

    -Go to the next row in the array: +
    +SQL> set serveroutput on size 1000000
    +SQL> spool str.pkg
    +SQL> exec utgen.testpkg ('str')
    +
    -
       PROCEDURE utGen.nextRow;
    +

    ...out comes the code...

    -Go to the previous row in the array: +
    +SQL> spool off
    +
    -
       PROCEDURE utGen.prevRow;
    +

    + If DBMS_OUTPUT is not enabled in your session, then + utGen.testpkg will not generate any output. +

    -Show the contents of the array using DBMS_OUTPUT.PUT_LINE: +

    Generating to File

    -
       PROCEDURE utGen.showRows (
    +

    + If you are working with utGen in a command line + style (ie, you are not using a utGen-enabled GUI), then you will probably + find it most useful to generate testing code directly to file. You do this + by specifying utGen.c_file for the output type. You must also specify the + directory in which you want the files (one for the package specification + and another for the body)created. +

    -
          startRow IN PLS_INTEGER := NULL,
    +

    + Here's a generation request that creates two files + named ut_str.pks and ut_str.pkb in the /newcode directory: +

    -
          endRow IN PLS_INTEGER := NULL);
    +
    +SQL> exec utgen.testpkg ('str', output_type_in => utGen.c_file, dir_in => '/newcode')
    +
    -Here is the code I would write in PL/SQL using this -API to display the contents of the array (actually, it is the implementation -of showRows): +

    Notes on generating to file:

    -
       PROCEDURE showrows (
    +
      +
    1. + You do not have to specify a directory if you have previously (in your + current session) called utConfig.setdir to set the default directory for + all file-related utPLSQL operations. The following two lines of code are, + in other words, equivalent to the single line shown above: +
    2. +
    -
          startrow IN PLS_INTEGER := NULL,
    -
          endrow IN PLS_INTEGER := NULL
    +
    +
    +
    +SQL> exec utconfig.setdir ('/newcode')
    +SQL> exec utgen.testpkg ('str', output_type_in => utGen.c_file);
    +
    +
    +
    + +
      +
    1. + You set up the UTL_FILE package (add at least one utl_file_dir entry in + your database parameter initialization file) and make sure your directory + is accessible through UTL_FILE, before this operation can succeed. +
    2. +
    + +

    Generating to String

    + +

    + If you are accessing utPLSQL functionality through + a GUI, you might find it more useful to direct output to a string (or array, + see next section). You probably don't want to hassle with UTL_FILE (server-based + file IO) and grabbing information from DBMS_OUTPUT.PUT_LINE is just a general + hassle. +

    + +

    + If you generate to a string, you can then retrieve + that string value into a local variable and then parse it for display and + manipulation. Here is an example of redirection to string: +

    -
       )
    +
    +BEGIN
    +   utgen.testpkg ('str', output_type_in => utGen.c_string);
    +END;
    +
    -
       IS
    +

    + The generated code is composed of multiple lines + of information, so they need to be separated by a delimiter. The default + delimiter is the vertical bar, '|'. You can override that and provide your + own delimiter. In the following example, I have decided to use the carriage + return character as my delimiter: +

    -
          v_start PLS_INTEGER
    +
    +BEGIN
    +   utgen.testpkg (
    +      'str',
    +      output_type_in => utGen.c_string,
    +      delim_in => CHR(10));
    +END;
    +
    -
                        := NVL (startrow, 1);
    +

    + Great, so the code has been put in a string. How + do you get all that generated code? Call the utGen.pkgstring function: +

    -
          v_end PLS_INTEGER
    +
    +FUNCTION utGen.pkgString RETURN VARCHAR2;
    +
    -
             := NVL (endrow, utGen.countRows);
    +

    Generating to Array

    + +

    + If you are accessing utPLSQL functionality through + a GUI, you might find it more useful to direct output to an array. You + probably don't want to hassle with UTL_FILE (server-based file IO) and + grabbing information from DBMS_OUTPUT.PUT_LINE is just a general hassle. +

    + +

    + If you generate to an array, you can then retrieve + the individual lines of code in the array through an API provided by utGen + (the array itself is "hidden"). Here is an example of redirection to the + utGen array: +

    + +
    +BEGIN
    +   utgen.testpkg ('str', output_type_in => utGen.c_array);
    +END;
    +
    -
       BEGIN
    +

    + Great, so the code has been put in an array. How + do you get all that generated code? Take advantage of the utGen + API to retrieve individual rows in the array, which offers these features: +

    -
          FOR indx IN 1 .. utGen.countRows
    +

    Get the number of rows currently in the array:

    -
          LOOP
    +
    +   FUNCTION utGen.countRows RETURN PLS_INTEGER;
    +
    -
             DBMS_OUTPUT.put_line (utGen.getRow (indx));
    +

    Get the absolute index of the first row in the array:

    -
          END LOOP;
    +
    +   FUNCTION utGen.firstRow RETURN PLS_INTEGER;
    +
    -
       END;
    +

    Get the absolute index of the last row in the array:

    -Here is the code I would write to separate out the -contents of the specification from the body: +
    +   FUNCTION utGen.lastRow RETURN PLS_INTEGER;
    +
    -
       PROCEDURE showrows (
    +

    + The API offers a set of programs to iterate through + the array, by maintaining a "current row" inside the package. You can: +

    + +

    + Find out if you are positioned at the first row + in the set: +

    -
          startrow IN PLS_INTEGER := NULL,
    +
    +   FUNCTION utGen.atFirstRow RETURN BOOLEAN;
    +
    -
          endrow IN PLS_INTEGER := NULL
    +

    + Find out if you are positioned at the last row in + the set: +

    -
       )
    +
    +   FUNCTION utGen.atLastRow RETURN BOOLEAN;
    +
    -
       IS
    +

    + Find the first relative row containing the start + of the package body definition. This is handy when you want to put the + code for the specification and body in separate windows and/or files: +

    + +
    +   FUNCTION utGen.firstBodyRow RETURN PLS_INTEGER;
    +
    -
          v_start PLS_INTEGER
    +

    + Retrieve the text in the Nth row of the array. This + gives you "random access" to the contents of the array. You can even specify + a negative direction to get the Nth row from the end of the array. +

    + +
    +   FUNCTION utGen.nthRow (nth IN PLS_INTEGER, direction utGen.IN SIGNTYPE := 1) RETURN codeline_t;
    +
    -
                        := NVL (startrow, 1);
    +

    + Set the pointer in the array to the specified row + number. This allows you then move either forward or backward from that + row in the array (using nextRow and prevRow, respectively): +

    -
          v_end PLS_INTEGER
    +
    +   PROCEDURE utGen.setRow (nth IN PLS_INTEGER);
    +
    -
             := NVL (endrow, utGen.countRows);
    +

    + Retrieve the line of code stored in the current + row in the array (set via setRow, nextRow or prevRow): +

    -
       BEGIN
    +
    +   FUNCTION utGen.getRow RETURN codeline_t;
    +
    -
          FOR indx IN 1 .. utGen.countRows
    +

    Go to the next row in the array:

    -
          LOOP
    +
    +   PROCEDURE utGen.nextRow;
    +
    -
             IF indx = utGen.firstBodyRow
    +

    Go to the previous row in the array:

    -
             THEN
    +
    +   PROCEDURE utGen.prevRow;
    +
    -
                -- switch to Body window or file
    +

    Show the contents of the array using DBMS_OUTPUT.PUT_LINE:

    -
             END IF;
    +
    +   PROCEDURE utGen.showRows (
    +      startRow IN PLS_INTEGER := NULL,
    +      endRow IN PLS_INTEGER := NULL);
    +
    -
             write_to_target (utGen.getRow (indx));
    +

    + Here is the code I would write in PL/SQL using this + API to display the contents of the array (actually, it is the implementation + of showRows): +

    + +
    +   PROCEDURE showrows (
    +      startrow IN PLS_INTEGER := NULL,
    +      endrow IN PLS_INTEGER := NULL
    +   )
    +   IS
    +      v_start PLS_INTEGER
    +                    := NVL (startrow, 1);
    +      v_end PLS_INTEGER
    +         := NVL (endrow, utGen.countRows);
    +   BEGIN
    +      FOR indx IN 1 .. utGen.countRows
    +      LOOP
    +         DBMS_OUTPUT.put_line (utGen.getRow (indx));
    +      END LOOP;
    +   END;
    +
    -
          END LOOP;
    +

    + Here is the code I would write to separate out the + contents of the specification from the body: +

    -
       END;
    +
    +   PROCEDURE showrows (
    +      startrow IN PLS_INTEGER := NULL,
    +      endrow IN PLS_INTEGER := NULL
    +   )
    +   IS
    +      v_start PLS_INTEGER
    +                    := NVL (startrow, 1);
    +      v_end PLS_INTEGER
    +         := NVL (endrow, utGen.countRows);
    +   BEGIN
    +      FOR indx IN 1 .. utGen.countRows
    +      LOOP
    +         IF indx = utGen.firstBodyRow
    +         THEN
    +            -- switch to Body window or file
    +         END IF;
    +         write_to_target (utGen.getRow (indx));
    +      END LOOP;
    +   END;
    +
    -

    - Generating Test Packages with Test Cases

    +

    Generating Test Packages with Test Cases

    -

    The procedures to generate test packages with test cases are similar to testpkg above, but with a number of extra parameters:

    +

    + The procedures to generate test packages with test cases are similar to + testpkg above, but with a number of extra parameters: +

    -
     PROCEDURE testpkg (
    +
    + PROCEDURE testpkg (
           package_in           IN   VARCHAR2,
           grid_in              IN   grid_tt,
           program_in           IN   VARCHAR2 := '%',
    @@ -591,16 +607,20 @@ 

    arg_delim_in IN VARCHAR2 := c_delim, date_format_in IN VARCHAR2 := 'MM/DD/YYYY', only_if_in_grid_in IN BOOLEAN := FALSE - );

    + ); +
    -

    In each case, the idea is the same. We have to provide not only the -arguments supplied to the basic version of testpkg, but also details of each of -the test cases in a grid. In the first case, this is as a PL/SQL table, in the -second this is as a file and in the final case, this is as a string.

    +

    + In each case, the idea is the same. We have to provide not only the + arguments supplied to the basic version of testpkg, but also details of each of + the test cases in a grid. In the first case, this is as a PL/SQL table, in the + second this is as a file and in the final case, this is as a string. +

    -

    The PL/SQL table passed to testpkg is defined as follows:

    +

    The PL/SQL table passed to testpkg is defined as follows:

    -
     TYPE grid_rt IS RECORD (
    +
     
    +TYPE grid_rt IS RECORD (
           progname                      VARCHAR2 (100),
           overload                      PLS_INTEGER,
           tcname                        VARCHAR2 (100),
    @@ -610,48 +630,53 @@ 

    assertion_type VARCHAR2 (100)); TYPE grid_tt IS TABLE OF grid_rt - INDEX BY BINARY_INTEGER;

    - -

    Where the definitions of the fields are as follows:

    - -
      - -
    1. progname - This is the name of the subprogram to be tested.
    2. - -
    3. overload - This is the version of the subprogram where - overladed versions exist. (You may have to look in the data dictionary to - work this out).
    4. - -
    5. tcname - The name of the test case.
    6. - -
    7. message - The message to be used in the assertion - code.
    8. - -
    9. arglist - The list of arguments to be passed to the - subprogram.
    10. - -
    11. return_value - The return value to be checked against.
    12. - -
    13. assertion_type - The type of assertion to be used. - Currently this is ignored unless it contains 'EQ' or 'ISNULL'
    14. - -
    - -

    In testpkg_from_file and testpkg_from_string, exactly the same fields need -to be passed (and in the same order). These fields are separated by the -character given by the field_delim_in parameter which defaults to '|', the pipe -symbol. In the case of testpkg_from_string, we can also specify the line -delimiter in the line_delim_in parameter, which defaults to an ASCII linefeed -character.

    - -

    In all cases, the arguments specified in the arglist field are separated -by yet another delimiter, which is passed in the arg_delim_in parameter (or just delim_in in the case of testpkg). This defaults to a semicolon.

    - -

    The remaining arguments passed to these routines are date_format_in and only_if_in_grid_in. The former gives the date format used in dates passed through the arglist and return_values fields. The latter specifies if tests should only be generated for subprograms listed in the grid or not.

    - -

    An Example

    + INDEX BY BINARY_INTEGER; +
    -

    All of this is probably best explained with an example. Suppose I have a package defined as:

    +

    Where the definitions of the fields are as follows:

    + +
      +
    1. progname - This is the name of the subprogram to be tested.
    2. +
    3. + overload - This is the version of the subprogram where + overladed versions exist. (You may have to look in the data dictionary to + work this out). +
    4. +
    5. tcname - The name of the test case.
    6. +
    7. message - The message to be used in the assertion code.
    8. +
    9. arglist - The list of arguments to be passed to the subprogram.
    10. +
    11. return_value - The return value to be checked against.
    12. +
    13. + assertion_type - The type of assertion to be used. + Currently this is ignored unless it contains 'EQ' or 'ISNULL' +
    14. +
    + +

    + In testpkg_from_file and testpkg_from_string, exactly the same fields need + to be passed (and in the same order). These fields are separated by the + character given by the field_delim_in parameter which defaults to '|', the pipe + symbol. In the case of testpkg_from_string, we can also specify the line + delimiter in the line_delim_in parameter, which defaults to an ASCII linefeed + character. +

    + +

    + In all cases, the arguments specified in the arglist field are separated + by yet another delimiter, which is passed in the arg_delim_in parameter ( + or just delim_in in the case of testpkg). This defaults to a semicolon. +

    + +

    + The remaining arguments passed to these routines are date_format_in and + only_if_in_grid_in. The former gives the date format used in dates passed + through the arglist and return_values fields. The latter specifies if + tests should only be generated for subprograms listed in the grid or not. +

    + +

    An Example

    + +

    All of this is probably best explained with an example. Suppose I have a package defined as:

     CREATE OR REPLACE PACKAGE lottery AS
    @@ -659,23 +684,22 @@ 

    An Example

    END;
    -

    This returns a string describing a lottery draw, given a seed and a date. I -want to test the following conditions: (It doesn't make much sense, but hey, -it's only an example) - -

      - -
    • Passing both parameters as NULL, we should get back '01 02 03 04 05 - 06'.
    • - -
    • Passing in 7 for the seed and 1 January 2001 for the date, we should get back '23 24 27 37 39 48'.
    • - -
    • Passing in 0 for the seed and today's date, we should get back NULL
    • - -
    So to generate the skeleton I require I could run the following through -SQL*Plus:

    +

    + This returns a string describing a lottery draw, given a seed and a date. I + want to test the following conditions: (It doesn't make much sense, but hey, + it's only an example) +

    + +
      +
    • Passing both parameters as NULL, we should get back '01 02 03 04 05 06'.
    • +
    • Passing in 7 for the seed and 1 January 2001 for the date, we should get back '23 24 27 37 39 48'.
    • +
    • Passing in 0 for the seed and today's date, we should get back NULL
    • +
    + +

    So to generate the skeleton I require I could run the following through SQL*Plus:

    -
    set serveroutput on size 1000000
    +
    +set serveroutput on size 1000000
     declare
       a_grid utgen.grid_tt;
     begin
    @@ -705,9 +729,10 @@ 

    An Example

    end; /
    -

    or the equivalent:

    +

    or the equivalent:

    -
    set serveroutput on size 1000000
    +
    +set serveroutput on size 1000000
     begin
       utgen.testpkg_from_string (
           package_in => 'LOTTERY',
    @@ -718,11 +743,13 @@ 

    An Example

    date_format_in => 'YYYY-MM-DD' ); end; -/
    +/ +
    -

    which generate the following for the body of ut_draw (tidied up a little for compactness):

    +

    which generate the following for the body of ut_draw (tidied up a little for compactness):

    -
    PROCEDURE ut_DRAW
    +
    +PROCEDURE ut_DRAW
     IS
        -- Verify and complete data types.
        against_this VARCHAR2(2000);
    @@ -767,14 +794,19 @@ 

    An Example

    -- End of test for "Test Case 3" -END ut_DRAW;
    - -

    Note that the different data types are handled automatically. So '2001-01-01' is converted to -a date using TO_DATE and the specified date format. However, we wanted to enter SYSDATE for our -argument in one of these cases. How do we stop this being converted into a date? The answer -is that we need to prefix the value with a '!' (an exclamation mark). This causes utGen to -pass this along 'as is' without attempting any conversion. Note that this cannot currently -be overridden, so if your data starts with an exclamation mark, you'll have to work around -this problem.

    +END ut_DRAW; +
    - +

    + Note that the different data types are handled automatically. So '2001-01-01' is converted to + a date using TO_DATE and the specified date format. However, we wanted to enter SYSDATE for our + argument in one of these cases. How do we stop this being converted into a date? The answer + is that we need to prefix the value with a '!' (an exclamation mark). This causes utGen to + pass this along 'as is' without attempting any conversion. Note that this cannot currently + be overridden, so if your data starts with an exclamation mark, you'll have to work around + this problem. +

    + + + + diff --git a/documentation/src/utoutput.html b/documentation/src/utoutput.html index 330e8ba90..0d422fbee 100644 --- a/documentation/src/utoutput.html +++ b/documentation/src/utoutput.html @@ -1,61 +1,70 @@ - - + + + + + + + -

    -utOutput Package

    - -

    This package contains the following procedures and functions: -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    utOutput.saveTurn on the 'save' flag
    utOutput.nosaveTurn off the 'save' flag
    utOutput.savingReturn the 'save' flag
    utOutput.extractPull text from the DBMS_OUTPUT buffer
    utOutput.replaceReplace saved output in the DBMS_OUTPUT buffer
    utOutput.nextLinePull the next line from the DBMS_OUTPUT buffer
    utOutput.countCount the lines in the DBMS_OUTPUT buffer
    - -

    Outline of Usage

    - -

    The problem with attempting to test output in PL/SQL is that there is a single -DBMS_OUTPUT buffer. When your test is run, there may already be output in the -buffer from other tests, or from the tested code. So what state should you -leave it in once you have finished? Perhaps you want all the output created by -your tested code to end up in the buffer as if it had been run normally (i.e. -not from within utPLSQL), or maybe you want only the text that was in the -buffer before you started to be left.

    - -

    This package attempts to allow to do any of these. There is a flag in the -package to determine whether text pulled from the output buffer should be -saved. This is set with 'save' and 'nosave' and returned by -'saving'. Data is pulled from the buffer using 'extract', -while the procedure 'replace' puts any saved data back into the output -buffer.

    - -

    The intent is that it is used like this:

    +

    utOutput Package

    + +

    This package contains the following procedures and functions:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    utOutput.saveTurn on the 'save' flag
    utOutput.nosaveTurn off the 'save' flag
    utOutput.savingReturn the 'save' flag
    utOutput.extractPull text from the DBMS_OUTPUT buffer
    utOutput.replaceReplace saved output in the DBMS_OUTPUT buffer
    utOutput.nextLinePull the next line from the DBMS_OUTPUT buffer
    utOutput.countCount the lines in the DBMS_OUTPUT buffer
    + +

    Outline of Usage

    + +

    + The problem with attempting to test output in PL/SQL is that there is a single + DBMS_OUTPUT buffer. When your test is run, there may already be output in the + buffer from other tests, or from the tested code. So what state should you + leave it in once you have finished? Perhaps you want all the output created by + your tested code to end up in the buffer as if it had been run normally (i.e. + not from within utPLSQL), or maybe you want only the text that was in the + buffer before you started to be left. +

    + +

    + This package attempts to allow to do any of these. There is a flag in the + package to determine whether text pulled from the output buffer should be + saved. This is set with 'save' and 'nosave' and returned by + 'saving'. Data is pulled from the buffer using 'extract', + while the procedure 'replace' puts any saved data back into the output + buffer. +

    + +

    The intent is that it is used like this:

     PROCEDURE ut_my_test IS
    @@ -73,18 +82,24 @@ 

    Outline of Usage

    END;
    -

    So to start with, we save any text already in the buffer. We then carry out -our testing. If we want the output generated by the testing to end up back in -the output buffer, we turn on saving. Finally, we put the saved text back.

    +

    + So to start with, we save any text already in the buffer. We then carry out + our testing. If we want the output generated by the testing to end up back in + the output buffer, we turn on saving. Finally, we put the saved text back. +

    -

    Warning

    -

    In the current version of utPLSQL (2.0.9.1) use of this package is virtually impossible with -utPLSQL tracing turned on. The reason for this is that this facility writes output using -DBMS_OUTPUT every time an assertion is called.

    +

    Warning

    + +

    + In the current version of utPLSQL (2.0.9.1) use of this package is virtually impossible with + utPLSQL tracing turned on. The reason for this is that this facility writes output using + DBMS_OUTPUT every time an assertion is called. +

    -

    Saving Output

    +

    Saving Output

    + +

    The three routines for handling the save flag are:

    -

    The three routines for handling the save flag are:

     PROCEDURE save;
     
    @@ -93,12 +108,14 @@ 

    Warning

    FUNCTION saving RETURN BOOLEAN;
    -

    Quite simply, 'save' turns the flag on, 'nosave' turns it off and 'saving' -returns its current value.

    +

    + Quite simply, 'save' turns the flag on, 'nosave' turns it off and 'saving' + returns its current value. +

    -

    Extracting Output

    +

    Extracting Output

    -

    There are 4 versions of the extract routine to get text from the output buffer:

    +

    There are 4 versions of the extract routine to get text from the output buffer:

     FUNCTION extract (
    @@ -124,27 +141,36 @@ 

    Warning

    );
    -

    The function versions return the number of lines extracted from the -DBMS_OUTPUT buffer. The other parameters are used as follows: -

      -
    • buffer_out - This is a buffer in which to put the extracted text.
    • -
    • max_lines_in - This is the maximum number of lines to be extracted. If NULL is passed in (the default) then all the lines are extracted.
    • -
    • save_in - This specifies if the extracted output should be saved. It overrides the global save flag.
    • -
    -

    +

    + The function versions return the number of lines extracted from the + DBMS_OUTPUT buffer. The other parameters are used as follows: +

    + +
      +
    • buffer_out - This is a buffer in which to put the extracted text.
    • +
    • max_lines_in - This is the maximum number of lines to be extracted. If NULL is passed in (the default) then all the lines are extracted.
    • +
    • save_in - This specifies if the extracted output should be saved. It overrides the global save flag.
    • +
    -

    Replacing Output

    +

    Replacing Output

    + +

    The replace procedure takes no parameters:

    -

    The replace procedure takes no parameters:

     PROCEDURE replace;   
     
    -

    It simply puts the saved text back into the DBMS_OUTPUT buffer. Note that the buffer is emptied at this point.

    -

    Checking Output Line-by-Line

    +

    + It simply puts the saved text back into the DBMS_OUTPUT buffer. Note that + the buffer is emptied at this point. +

    + +

    Checking Output Line-by-Line

    -

    The nextLine function makes it easy to check output line-by-line as it -simply extracts and returns the next line of output:

    +

    + The nextLine function makes it easy to check output line-by-line as it + simply extracts and returns the next line of output: +

     FUNCTION nextLine(
    @@ -153,18 +179,22 @@ 

    Warning

    ) RETURN VARCHAR2;
    -

    The raise_exc_in flag determines if the function should throw the exception utOutput.EMPTY_OUTPUT_BUFFER when asked for the next line from an empty buffer. If no exception is thrown, NULL is returned. As with extract, the save_in flag simply overrides the global save flag setting. -

    +

    + The raise_exc_in flag determines if the function should throw the + exception utOutput.EMPTY_OUTPUT_BUFFER when asked for the next line from + an empty buffer. If no exception is thrown, NULL is returned. As with + extract, the save_in flag simply overrides the global save flag setting. +

    -

    Size of Output

    +

    Size of Output

    -

    This function simply counts the number of lines present in the output buffer:

    +

    This function simply counts the number of lines present in the output buffer:

     FUNCTION count RETURN INTEGER;   
     
    -

    Note that the output itself is left untouched.

    +

    Note that the output itself is left untouched.

    diff --git a/documentation/utplsql.css b/documentation/src/utplsql.css similarity index 100% rename from documentation/utplsql.css rename to documentation/src/utplsql.css diff --git a/documentation/src/utplsql.html b/documentation/src/utplsql.html index 15601ee7c..061e45788 100644 --- a/documentation/src/utplsql.html +++ b/documentation/src/utplsql.html @@ -1,74 +1,83 @@ - - + + + + + + + -

    utPLSQL Package

    - -

    The utPLSQL package offers the following capabilities:
    -

    - - - - - - - - - - - - - - - - - - - - - - - -
    -

    utPLSQL.test
    - utPLSQL.run

    -
    -

    Run a test

    -
    -

    utPLSQL.testsuite
    - utPLSQL.runsuite

    -
    -

    Run a test suite

    -
    -

    utPLSQL.version

    -
    -

    Get the version of utPLSQL

    -
    -

    utPLSQL.trc
    - utPLSQL.notrc
    - utPLSQL.tracing

    -
    -

    Control utPLSQL's tracing mechanism

    -
    -

    utPLSQL.addtest

    -
    -

    Register a unit test in a test package

    -
    - -

    Run a Test or Test Suite

    - -

    With utPLSQL, you can run all the unit tests contained in a -single test package, or run the tests for a series of test packages defined in -a test suite.

    - -

    The utPLSQL package offers two procedures, test and testsuite, to make it -easy for you to run "red light, green light" tests. Before you can -use these programs, however, you must build -your own test package.

    - -

    To run a test for a single package, use the utPLSQL.test procedure:

    - -
    PROCEDURE utPLSQL.test (
    +   

    utPLSQL Package

    + +

    The utPLSQL package offers the following capabilities:

    + + + + + + + + + + + + + + + + + + + + + + +
    + utPLSQL.test
    + utPLSQL.run +
    + Run a test +
    + utPLSQL.testsuite
    + utPLSQL.runsuite +
    + Run a test suite +
    + utPLSQL.version + + Get the version of utPLSQL +
    + utPLSQL.trc
    + utPLSQL.notrc
    + utPLSQL.tracing +
    + Control utPLSQL's tracing mechanism +
    + utPLSQL.addtest + + Register a unit test in a test package +
    + +

    Run a Test or Test Suite

    + +

    + With utPLSQL, you can run all the unit tests contained in a + single test package, or run the tests for a series of test packages defined in + a test suite. +

    + +

    + The utPLSQL package offers two procedures, test and testsuite, to make it + easy for you to run "red light, green light" tests. Before you can + use these programs, however, you must build + your own test package. +

    + +

    To run a test for a single package, use the utPLSQL.test procedure:

    + +
    +PROCEDURE utPLSQL.test (
        package_in IN VARCHAR2,
        samepackage_in IN BOOLEAN := FALSE,
        prefix_in IN VARCHAR2 := NULL,
    @@ -80,180 +89,198 @@ 

    Run a Test or Test Suite

    from_suite_in IN BOOLEAN := FALSE, subprogram_in IN VARCHAR2 := '%', per_method_setup_in IN BOOLEAN := FALSE -);
    - -

    where the parameters are defined as follows:
    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +); + + +

    where the parameters are defined as follows:

    + +
    -

    package_in

    -
    -

    The name of the package or stand-alone program to be - tested.

    -
    -

    samepackage_in

    -
    -

    Pass TRUE if your unit test programs are defined in the same - package as the source code to be tested. The default is that you have created - a separate package.

    -
    -

    prefix_in

    -
    -

    The prefix to be appended to package_in to come up with - the name of the test package. If you do not provide a value, the last prefix - you specified (or the default) will be used.

    -
    -

    recompile_in

    -
    -

    Pass FALSE if you do not want utPLSQL to automatically recompile your test package - before running the test.

    -
    -

    dir_in

    -
    -

    The directory containing the test package source code. If - you do not provide a value in your call to utPLSQL.test (the default) and if - you have not turned off automatic recompilation, utPLSQL will look for the - test package source code in the directory specified by a call to utConfig.setdir. If you do not provide a - value, the last directory you specified (if any) will be used.

    -
    -

    suite_in

    -
    -

    The name of the suite that contains the specified test - package. This is an optional value and is used to update statistics - for the test.

    -
    -

    owner_in

    -
    -

    The name of the schema that was specified when the test - suite was defined and the packaged added to the suite. This is an - optional value and is used to update statistics for - the test.

    -
    -

    reset_results_in

    -
    -

    Pass FALSE to tell utPLSQL to not reset the results - information, in which case you will still be able to view results by calling utResult.show . Otherwise, utPLSQL clears the result - data after each test.

    -
    -

    from_suite_in

    -
    -

    Pass TRUE to tell utPLSQL that this test is being run from - within a test suite (for internal use only).

    -
    -

    subprogram_in

    -
    -

    Pass a string to restrict which of the test procedures - will be executed for this run. Default of % means all tests will be run.

    -
    -

    per_method_setup_in

    -
    -

    Pass TRUE to run the setup and teardown procedure before - and after each unit test procedure is executed. Default of FALSE means that - these programs will be run once, at the start and end of the package test - execution as a whole.

    -
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + -
    + package_in + + The name of the package or stand-alone program to be tested. +
    + samepackage_in + + Pass TRUE if your unit test programs are defined in the same + package as the source code to be tested. The default is that you have created + a separate package. +
    + prefix_in + + The prefix to be appended to package_in to come up with + the name of the test package. If you do not provide a value, the last prefix + you specified (or the default) will be used. +
    + recompile_in + + Pass FALSE if you do not want utPLSQL to automatically recompile your test package + before running the test. +
    + dir_in + + The directory containing the test package source code. If + you do not provide a value in your call to utPLSQL.test (the default) and if + you have not turned off automatic recompilation, utPLSQL will look for the + test package source code in the directory specified by a call to utConfig.setdir. If you do not provide a + value, the last directory you specified (if any) will be used. +
    + suite_in + + The name of the suite that contains the specified test + package. This is an optional value and is used to update statistics + for the test. +
    + owner_in + + The name of the schema that was specified when the test + suite was defined and the packaged added to the suite. This is an + optional value and is used to update statistics for + the test. +
    + reset_results_in + + Pass FALSE to tell utPLSQL to not reset the results + information, in which case you will still be able to view results by calling utResult.show . Otherwise, utPLSQL clears the result + data after each test. +
    + from_suite_in + + Pass TRUE to tell utPLSQL that this test is being run from + within a test suite (for internal use only). +
    + subprogram_in + + Pass a string to restrict which of the test procedures + will be executed for this run. Default of % means all tests will be run. +
    + per_method_setup_in + + Pass TRUE to run the setup and teardown procedure before + and after each unit test procedure is executed. Default of FALSE means that + these programs will be run once, at the start and end of the package test + execution as a whole. +
    -

    override_package_in

    -
    -

    Override the automatic determination of package names thus removing the - one to one relationship between test package and package to test. - Default is NULL. Instead of using this parameter consider the procedure run.

    -
    + override_package_in + + Override the automatic determination of package names thus removing the + one to one relationship between test package and package to test. + Default is NULL. Instead of using this parameter consider the procedure run. +
    + -

    Here are some examples of using the utPLSQL.test procedure:

    +

    Here are some examples of using the utPLSQL.test procedure:

    -

    1. Run the unit test for the betwnstr function (by executing the ut_betwnstr -test package, since the default prefix is used). Do not recompile the test -package.

    +

    + 1. Run the unit test for the betwnstr function (by executing the ut_betwnstr + test package, since the default prefix is used). Do not recompile the test + package. +

    -
    SQL> exec utPLSQL.test ('betwnstr', recompile_in => FALSE)
    +
    +SQL> exec utPLSQL.test ('betwnstr', recompile_in => FALSE)
    +
    -

    2. Run all of the unit tests for the te_employee package, -stored in a test package called "test_te_employee" in the /tmp -directory. Recompile the test package before execution.

    +

    + 2. Run all of the unit tests for the te_employee package, + stored in a test package called "test_te_employee" in the /tmp + directory. Recompile the test package before execution. +

    -
    SQL> exec utPLSQL.test ('te_employee', prefix_in => 'test_', dir_in => '/tmp')
    +
    +SQL> exec utPLSQL.test ('te_employee', prefix_in => 'test_', dir_in => '/tmp')
    +
    -

    3. Run all the unit tests for the corporate_polluters -package, located in the same package as the source code.

    +

    + 3. Run all the unit tests for the corporate_polluters + package, located in the same package as the source code. +

    -
    SQL> exec utPLSQL.test ('te_employee', samepackage_in => TRUE)
    +
    +SQL> exec utPLSQL.test ('te_employee', samepackage_in => TRUE)
    +
    -

    Since utPLSQL follows the red light-green light approach on -reporting results, each time you run utPLSQL.test, it will display the results. -If successful, you will see output like this:

    +

    + Since utPLSQL follows the red light-green light approach on + reporting results, each time you run utPLSQL.test, it will display the results. + If successful, you will see output like this: +

    -
    SUCCESS: "betwnstr"
    +
    +SUCCESS: "betwnstr"
    +
    -

    If the test fails at some point, you will see output like -this:

    +

    If the test fails at some point, you will see output like this:

    -
    FAILURE: "betwnstr"
    +
    +FAILURE: "betwnstr"
     BETWNSTR: IS NULL: NULL start
    -BETWNSTR: End larger than string length; expected "cdeg", got "cdefg"
    +BETWNSTR: End larger than string length; expected "cdeg", got "cdefg" +
    -

    Running a Test the other way

    - -

    The normal usage of the test procedure as described above assumes that for -each package you want to test, say mypackage, has a package for -testing this package having the same name but with an additional prefix: -ut_mypackage. Instead of using this approach, you can use the procedure -run. This procedure runs a test package directly without any further -conditions on the name or other packages. The only condition that still applies -is the naming conventions necessary to make it a valid test package. -

    -
    +   

    Running a Test the other way

    + +

    + The normal usage of the test procedure as described above assumes that for + each package you want to test, say mypackage, has a package for + testing this package having the same name but with an additional prefix: + ut_mypackage. Instead of using this approach, you can use the procedure + run. This procedure runs a test package directly without any further + conditions on the name or other packages. The only condition that still applies + is the naming conventions necessary to make it a valid test package. +

    + +
     PROCEDURE run (
         testpackage_in      IN VARCHAR2,
         prefix_in           IN VARCHAR2 := NULL,
    @@ -265,172 +292,192 @@ 

    Running a Test the other way

    per_method_setup_id IN BOOLEAN := FALSE);
    -

    where the parameters are defined as follows:
    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -

    test_package_in

    -
    -

    The name of the test package to run.

    -
    -

    prefix_in

    -
    -

    The prefix to be appended to package_in to come up with - the name of the test package. If you do not provide a value, NULL is used as - a default. i.e. the package name is used as provided in the first parameter

    -
    -

    suite_in

    -
    -

    The name of the suite that contains the specified test - package. This is an optional value and is used to update statistics - for the test.

    -
    -

    owner_in

    -
    -

    The name of the schema that was specified when the test - suite was defined and the packaged added to the suite. This is an - optional value and is used to update statistics for - the test.

    -
    -

    reset_results_in

    -
    -

    Pass FALSE to tell utPLSQL to not reset the results - information, in which case you will still be able to view results by calling utResult.show . Otherwise, utPLSQL clears the result - data after each test.

    -
    -

    from_suite_in

    -
    -

    Pass TRUE to tell utPLSQL that this test is being run from - within a test suite (for internal use only).

    -
    -

    subprogram_in

    -
    -

    Pass a string to restrict which of the test procedures - will be executed for this run. Default of '%' means all tests will be run.

    -
    -

    per_method_setup_in

    -
    -

    Pass TRUE to run the setup and teardown procedure before - and after each unit test procedure is executed. Default of FALSE means that - these programs will be run once, at the start and end of the package test - execution as a whole.

    -
    +

    where the parameters are defined as follows:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + test_package_in + + The name of the test package to run. +
    + prefix_in + + The prefix to be appended to package_in to come up with + the name of the test package. If you do not provide a value, NULL is used as + a default. i.e. the package name is used as provided in the first parameter +
    + suite_in + + The name of the suite that contains the specified test + package. This is an optional value and is used to update statistics + for the test. +
    + owner_in + + The name of the schema that was specified when the test + suite was defined and the packaged added to the suite. This is an + optional value and is used to update statistics for + the test. +
    + reset_results_in + + Pass FALSE to tell utPLSQL to not reset the results + information, in which case you will still be able to view results by calling utResult.show . Otherwise, utPLSQL clears the result + data after each test. +
    + from_suite_in + + Pass TRUE to tell utPLSQL that this test is being run from + within a test suite (for internal use only). +
    + subprogram_in + + Pass a string to restrict which of the test procedures + will be executed for this run. Default of '%' means all tests will be run. +
    + per_method_setup_in + + Pass TRUE to run the setup and teardown procedure before + and after each unit test procedure is executed. Default of FALSE means that + these programs will be run once, at the start and end of the package test + execution as a whole. +
    -

    Running a Test Suite

    +

    Running a Test Suite

    -

    In addition to running a test for a single test package, you -can set up a test suite that consists of one or more test packages. You can -then run an entire suite of tests with a call to utPLSQL.testsuite:

    +

    + In addition to running a test for a single test package, you + can set up a test suite that consists of one or more test packages. You can + then run an entire suite of tests with a call to utPLSQL.testsuite: +

    -
    PROCEDURE utPLSQL.testsuite (
    +
    +PROCEDURE utPLSQL.testsuite (
        suite_in IN VARCHAR2,
        recompile_in IN BOOLEAN := TRUE,
        reset_results_in IN BOOLEAN := TRUE
        per_method_setup_in in BOOLEAN := FALSE
    -   );
    + ); +
    -

    where suite_in is the name of the suite and recompiled_in -determines the auto compilation behavior. -

    +

    + where suite_in is the name of the suite and recompiled_in + determines the auto compilation behavior. +

    -

    Here is an example of the call I would make to run all my tests for the -PL/Vision library:

    +

    + Here is an example of the call I would make to run all my tests for the + PL/Vision library: +

    -
    SQL> exec utplsql.testsuite ('plvision');
    +
    +SQL> exec utplsql.testsuite ('plvision');
    +
    -

    The parameter list for utPLSQL.testSuite is much shorter -than utPLSQL.test; rather than pass information like directory, owner name and -same-package through a parameter list, you define these characteristics in the -suite itself (stored in a series of utPLSQL tables).

    +

    + The parameter list for utPLSQL.testSuite is much shorter + than utPLSQL.test; rather than pass information like directory, owner name and + same-package through a parameter list, you define these characteristics in the + suite itself (stored in a series of utPLSQL tables). +

    -

    Before you can test an entire suite, you must define -the suite.

    +

    + Before you can test an entire suite, you must define + the suite. +

    -

    Running a Test Suite the other way

    +

    Running a Test Suite the other way

    -

    Similiar to the run procedure for single packages, there is the -runsuite procedure to run testsuites. When you use this procedure -there is no relationship assumed between the names of test packages specified in the -test suite and the procedures to be tested. -

    +

    + Similiar to the run procedure for single packages, there is the + runsuite procedure to run testsuites. When you use this procedure + there is no relationship assumed between the names of test packages specified in the + test suite and the procedures to be tested. +

    -
    PROCEDURE utPLSQL.runsuite (
    +
    +PROCEDURE utPLSQL.runsuite (
        suite_in IN VARCHAR2,
        reset_results_in IN BOOLEAN := TRUE
        per_method_setup_in in BOOLEAN := FALSE
    -   );
    + ); +
    -

    -The usage of the parameters is just as in testsuite. -

    +

    + The usage of the parameters is just as in testsuite. +

    -

    Recording and Accessing Test Statistics

    +

    Recording and Accessing Test Statistics

    -

    If you have defined test suites, and packages within those -test suites, utPLSQL will update those definitions with the follow statistics -after each test is run:

    +

    + If you have defined test suites, and packages within those + test suites, utPLSQL will update those definitions with the follow statistics + after each test is run: +

    -
      -
    • Status of last run: success - or failure?
    • -
    • Start and end times of last - run
    • -
    • Total number of failures
    • -
    • Total number of executions of - the test
    • -
    +
      +
    • Status of last run: success or failure?
    • +
    • Start and end times of last run
    • +
    • Total number of failures
    • +
    • Total number of executions of the test
    • +
    -

    All of this is done for you automatically. You can then write queries and reports against the -ut_package and ut_suite tables.

    +

    + All of this is done for you automatically. You can then write queries and reports against the + ut_package and ut_suite tables. +

    -

    Return utPLSQL version

    +

    Return utPLSQL version

    -

    Run the utPLSQL.version function to return the version of -utPLSQL you have installed:

    +

    + Run the utPLSQL.version function to return the version of + utPLSQL you have installed: +

    -
    FUNCTION utPLSQL.version RETURN VARCHAR2
    +
    +FUNCTION utPLSQL.version RETURN VARCHAR2
    +
    -

    utPLSQL Trace

    +

    utPLSQL Trace

    -

    These routines are very simple and take no arguments:

    +

    These routines are very simple and take no arguments:

     PROCEDURE trc;
    @@ -440,11 +487,13 @@ 

    utPLSQL Trace

    FUNCTION tracing RETURN BOOLEAN;
    -

    The procedures trc and notrc are used to turn tracing on and off -respectively. The function tracing returns TRUE if tracing is currently turned -on and FALSE otherwise. This facility is useful when writing code in utPLSQL -(the framework itself, not your test code). An example of the output generated -is:

    +

    + The procedures trc and notrc are used to turn tracing on and off + respectively. The function tracing returns TRUE if tracing is currently turned + on and FALSE otherwise. This facility is useful when writing code in utPLSQL + (the framework itself, not your test code). An example of the output generated + is: +

     Initialized utPLSQL session...
    @@ -499,38 +548,53 @@ 

    utPLSQL Trace

    PL/SQL procedure successfully completed.
    -

    Register a Unit Test

    +

    Register a Unit Test

    -

    As of version 1.4.1, you -no longer have to explicitly register a unit test! The default -behavior of utPLSQL is now to extract from the data dictionary (via the -ALL_ARGUMENTS data dictionary view) the names of all the unit test procedures -you have defined, and then run them. utPLSQL identifies these programs by -looking for all programs whose names start with the specified prefix.

    +

    + As of version 1.4.1, you + no longer have to explicitly register a unit test! The default + behavior of utPLSQL is now to extract from the data dictionary (via the + ALL_ARGUMENTS data dictionary view) the names of all the unit test procedures + you have defined, and then run them. utPLSQL identifies these programs by + looking for all programs whose names start with the specified prefix. +

    -

    If you decide that you want to explicitly register your unit -tests, then you will need to turn on manual registration:

    +

    + If you decide that you want to explicitly register your unit + tests, then you will need to turn on manual registration: +

    -
    SQL> exec utConfig.registertest (TRUE)
    +
    +SQL> exec utConfig.registertest (TRUE)
    +
    -

    This setting is immediately saved in the database for your -schema. To turn off manual registration:

    +

    + This setting is immediately saved in the database for your + schema. To turn off manual registration: +

    -
    SQL> exec utConfig.registertest (FALSE)
    +
    +SQL> exec utConfig.registertest (FALSE)
    +
    -

    So read no further unless you have turned on manual -registration! You might do this, for example, if you have already built a -number of test packages in a version of utPLSQL prior to 1.4.1 and do not want -to make any changes to your test package code.

    +

    + So read no further unless you have turned on manual + registration! You might do this, for example, if you have already built a + number of test packages in a version of utPLSQL prior to 1.4.1 and do not want + to make any changes to your test package code. +

    -

    All aspects of manual registration of unit tests for a -program or package actually occur within the Unit Test Package itself, in the setup procedure. No persistent unit test information -is stored between runs of the unit test, unless you define that unit test -within a test suite.

    +

    + All aspects of manual registration of unit tests for a + program or package actually occur within the Unit Test Package itself, in the setup procedure. No persistent unit test information + is stored between runs of the unit test, unless you define that unit test + within a test suite. +

    -

    Use the utPLSQL.addtest procedure to register a unit test.

    +

    Use the utPLSQL.addtest procedure to register a unit test.

    -
       PROCEDURE utPLSQL.addtest (
    +
    +   PROCEDURE utPLSQL.addtest (
           NAME_IN IN VARCHAR2,
           utprefix_in IN VARCHAR2,
           iterations_in IN PLS_INTEGER := 1
    @@ -541,32 +605,44 @@ 

    Register a Unit Test

    NAME_IN IN VARCHAR2, utprefix_in IN VARCHAR2, iterations_in IN PLS_INTEGER := 1 - );
    - -

    where

    - -

    name_in is the name of the program you are -testing. Note that this is the name of the unit test procedure itself, -including the unit test prefix..

    - -

    utprefix_in is the prefix to be applied to -name_in to construct the unit tst procedure. This is currently NOT IN USE; only -the package prefix specified in your call to utPLSQL.test and utPLSQL.testsuite -is used.

    - -

    iterations_in is the number of times you wish to -run the test (currently NOT IN USE).

    - -

    package_in is the name of the package containing -the unit test procedure. If you provide a package name when you call -utPLSQL.addtest, you will override the package name set when you called -utPLSQL.test -- but only for that one test. We recommend that you not change -the package name.

    + ); +
    -

    Here is a setup procedure that sets up a series of tests for -a query-only encapsulation of the employee table:

    +

    where

    + +

    + name_in is the name of the program you are + testing. Note that this is the name of the unit test procedure itself, + including the unit test prefix.. +

    + +

    + utprefix_in is the prefix to be applied to + name_in to construct the unit tst procedure. This is currently NOT IN USE; only + the package prefix specified in your call to utPLSQL.test and utPLSQL.testsuite + is used. +

    + +

    + iterations_in is the number of times you wish to + run the test (currently NOT IN USE). +

    + +

    + package_in is the name of the package containing + the unit test procedure. If you provide a package name when you call + utPLSQL.addtest, you will override the package name set when you called + utPLSQL.test -- but only for that one test. We recommend that you not change + the package name. +

    + +

    + Here is a setup procedure that sets up a series of tests for + a query-only encapsulation of the employee table: +

    -
    CREATE OR REPLACE PACKAGE BODY ut_te_employee
    +
    +CREATE OR REPLACE PACKAGE BODY ut_te_employee
     IS
        PROCEDURE ut_setup
        IS
    @@ -581,10 +657,13 @@ 

    Register a Unit Test

    utplsql.addtest ('UT_PKYROWCOUNT'); utplsql.addtest ('UT_ROWCOUNT'); utplsql.addtest ('UT_SALARY$VAL'); - END;
    + END; +
    -

    Once you have placed your addtest programs into your test -package's setup procedure, you are ready to build your own unit tests.

    +

    + Once you have placed your addtest programs into your test + package's setup procedure, you are ready to build your own unit tests. +

    diff --git a/documentation/utplsql.jpg b/documentation/src/utplsql.jpg similarity index 100% rename from documentation/utplsql.jpg rename to documentation/src/utplsql.jpg diff --git a/documentation/src/utreceq.html b/documentation/src/utreceq.html index 0a01c0a21..46836d968 100644 --- a/documentation/src/utreceq.html +++ b/documentation/src/utreceq.html @@ -1,90 +1,115 @@ - - + + + + + + + -

    - utRecEq Package -

    - -

    This package contains the following procedures and functions: -
    - - - - - - - - - - - - - - -
    utRecEq.addAdd a record type comparison function
    utRecEq.compileCompile a package's record type comparison functions
    utRecEq.remRemove record type comparison functions
    - -

    Generate functions to compare record types

    - -

    This package (created by Dan Spencer) allows the creation of functions to -allow the comparison of record types based on tables or views (%ROWTYPE -records in other words). They are generated by the add procedure: - -

    PROCEDURE add(
    +   

    utRecEq Package

    + +

    This package contains the following procedures and functions:

    + + + + + + + + + + + + + + +
    utRecEq.addAdd a record type comparison function
    utRecEq.compileCompile a package's record type comparison functions
    utRecEq.remRemove record type comparison functions
    + +

    Generate functions to compare record types

    + +

    + This package (created by Dan Spencer) allows the creation of functions to + allow the comparison of record types based on tables or views (%ROWTYPE + records in other words). They are generated by the add procedure: +

    + +
    +PROCEDURE add(
        pkg_name_in IN ut_package.name%TYPE,
        record_in  IN ut_receq.name%TYPE,
        rec_owner_in  IN ut_receq.created_by%TYPE := USER
    -);
    - -The pkg_name_in parameter contains the name of a tested package you wish to -associate with this record type. Note that this package name should already -exist in the ut_package table. The record_in parameter contains the name of -the view or table whose record type is to be compared. The final (optional) -parameter contains the name of the schema in which the table or view exists. -It defaults to the current user.

    - -

    The generated function will be named EQ_{Record_Schema_}Record_Name. The -schema is only inserted when the record type is not within the current one. The -function will return TRUE if the two records are identical on a field-by-field -comparison and FALSE otherwise. Note that NULL fields are considered -equal.

    - -

    The details of the EQ_* functions and their association with tested packages held in two tables: -

      - -
    • UT_RECEQ - This table holds a list of the EQ_* functions including the - target table/view and the schema in which it is found.
    • - -
    • UT_RECEQ_PKG - This table cross-references the tested packages against the functions listed in UT_RECEQ.
    • - -

    - -

    Compile a package's record comparison functions

    - -

    This routine recompiles all the EQ_* functions associated with a given package: - -

    PROCEDURE compile(pkg_name_in IN ut_package.name%TYPE);
    - -when autocompiling is turned on, this is called by -utplsql.test or utplsql.testsuite before the test packages themselves are recompiled.

    - -

    Remove record comparison functions

    - -

    To remove record comparison functions, use the following: - -

    PROCEDURE rem(
    +);
    +
    + +

    + The pkg_name_in parameter contains the name of a tested package you wish to + associate with this record type. Note that this package name should already + exist in the ut_package table. The record_in parameter contains the name of + the view or table whose record type is to be compared. The final (optional) + parameter contains the name of the schema in which the table or view exists. + It defaults to the current user. +

    + +

    + The generated function will be named EQ_{Record_Schema_}Record_Name. The + schema is only inserted when the record type is not within the current one. The + function will return TRUE if the two records are identical on a field-by-field + comparison and FALSE otherwise. Note that NULL fields are considered + equal. +

    + +

    + The details of the EQ_* functions and their association with tested packages held in two tables: +

    + +
      +
    • + UT_RECEQ - This table holds a list of the EQ_* functions including the + target table/view and the schema in which it is found. +
    • +
    • + UT_RECEQ_PKG - This table cross-references the tested packages against the functions listed in UT_RECEQ. +
    • +
    + +

    Compile a package's record comparison functions

    + +

    This routine recompiles all the EQ_* functions associated with a given package:

    + +
    +PROCEDURE compile(pkg_name_in IN ut_package.name%TYPE);
    +
    + +

    + when autocompiling is turned on, this is called by + utplsql.test or utplsql.testsuite before the test packages themselves are recompiled. +

    + +

    Remove record comparison functions

    + +

    To remove record comparison functions, use the following:

    + +
    +PROCEDURE rem(
        name_in  IN ut_receq.name%TYPE,
        rec_owner_in   IN ut_receq.created_by%TYPE := USER
        for_package_in IN BOOLEAN := FALSE
    -);
    - -If for_package_in is FALSE, then name_in is taken to refer to a record type to -remove, with rec_owner_in specifying the schema the record type is in. All package associations for this record type are removed and the EQ_* function is dropped.

    - -

    On the other hand, if for_package_in is TRUE, then name_in is taken to refer -to a package. In this case, all the package's associations are removed. If no -other package is associated with a given record, then the EQ_* function is -dropped. (Note that the rec_owner_in parameter is ignored here).

    +); +
    + +

    + If for_package_in is FALSE, then name_in is taken to refer to a record type to + remove, with rec_owner_in specifying the schema the record type is in. All package associations for this record type are removed and the EQ_* function is dropped. +

    + +

    + On the other hand, if for_package_in is TRUE, then name_in is taken to refer + to a package. In this case, all the package's associations are removed. If no + other package is associated with a given record, then the EQ_* function is + dropped. (Note that the rec_owner_in parameter is ignored here). +

    diff --git a/documentation/src/utresult.html b/documentation/src/utresult.html index 542964caf..e99f66b40 100644 --- a/documentation/src/utresult.html +++ b/documentation/src/utresult.html @@ -1,94 +1,133 @@ - - + + + + + + + -

    -utResult Package

    - -

    This package contains the following procedures and functions: -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    utResult.initInitialize the results data
    utResult.show -
    utResult.showone -
    utResult.showlast
    Show results
    utResult.success -
    utResult.failure
    Show the success or failure of the last test
    utResult.firstresult -
    utResult.nextresult -
    utResult.nthresult -
    utResult.resultcount
    Iterate through the results array
    utResult.include_successes
    - utResult.ignore_successes
    Control the display of passed tests
    - -The utResult package offers an API to the information -sent by the various utAssert assertion routines after a test is run. If -you employ the utPLSQL.test and utPLSQL.testsuite to run your tests, then -the results will be displayed by calling the utResult.show procedure. - -So, generally, you do not have to do anything to see or evaluate the results of -a test (or suite of tests). The information will be displayed on your screen -using DBMS_OUTPUT, or elsewhere if you use a custom output reporter. You might, -however, want to access this information in another environment (say, Oracle -Forms or Java, etc.). You might also want to build your own assertion logic or -test engine. In either of these cases, you will want to use the programs in the -utResult package. - -

    -Initialize

    -Initialize the utResult data, setting it all back to NULL: -
    PROCEDURE utResult.init;
    - -

    -Show Results

    -Show the results of your test with one of the following three procedures. -
    PROCEDURE utResult.show (reset_in IN BOOLEAN := FALSE);
    +   

    utResult Package

    + +

    This package contains the following procedures and functions:

    + + + + + + + + + + + + + + + + + + + + + + +
    + utResult.init + + Initialize the results data +
    + utResult.show +
    utResult.showone +
    utResult.showlast +
    + Show results +
    + utResult.success +
    utResult.failure +
    + Show the success or failure of the last test +
    + utResult.firstresult +
    utResult.nextresult +
    utResult.nthresult +
    utResult.resultcount +
    + Iterate through the results array +
    + utResult.include_successes
    + utResult.ignore_successes +
    + Control the display of passed tests +
    + +

    + The utResult package offers an API to the information + sent by the various utAssert assertion routines after a test is run. If + you employ the utPLSQL.test and utPLSQL.testsuite to run your tests, then + the results will be displayed by calling the utResult.show procedure. +

    +

    + So, generally, you do not have to do anything to see or evaluate the results of + a test (or suite of tests). The information will be displayed on your screen + using DBMS_OUTPUT, or elsewhere if you use a custom output reporter. You might, + however, want to access this information in another environment (say, Oracle + Forms or Java, etc.). You might also want to build your own assertion logic or + test engine. In either of these cases, you will want to use the programs in the + utResult package. +

    + +

    Initialize

    + +

    Initialize the utResult data, setting it all back to NULL:

    + +
    +PROCEDURE utResult.init;
    +
    + +

    Show Results

    + +

    Show the results of your test with one of the following three procedures.

    + +
    +PROCEDURE utResult.show (reset_in IN BOOLEAN := FALSE);
     PROCEDURE utResult.showone (indx_in in pls_integer);
    -PROCEDURE utResult.showlast;
    -Use the show procedure to display the full set of results stored -in the utResult array. If you pass TRUE for its single argument, the results -informatino will be initialized. -

    Use the showone procedure to show the Nth result. -

    Use the showlast procedure to show the results of the last test -run. -

    -Retrieve Test Status

    -The success and failure functions return the status of the most recently -executed test. -
    FUNCTION utResult.success RETURN BOOLEAN;
    -FUNCTION utResult.failure RETURN BOOLEAN;
    - -

    -Scan Results Array

    -The utPLSQL.show procedure iterates through the contents of the utResult -array and displays the information found there. You can write the same -kind of logic by calling a combination of the following programs: -
    PROCEDURE utResult.firstresult;
    +PROCEDURE utResult.showlast;
    +
    + +

    + Use the show procedure to display the full set of results stored + in the utResult array. If you pass TRUE for its single argument, the results + informatino will be initialized. +

    + +

    Use the showone procedure to show the Nth result.

    + +

    Use the showlast procedure to show the results of the last test run.

    + +

    Retrieve Test Status

    + +

    + The success and failure functions return the status of the most recently + executed test. +

    + +
    +FUNCTION utResult.success RETURN BOOLEAN;
    +FUNCTION utResult.failure RETURN BOOLEAN;
    +
    + +

    Scan Results Array

    + +

    + The utPLSQL.show procedure iterates through the contents of the utResult + array and displays the information found there. You can write the same + kind of logic by calling a combination of the following programs: +

    + +
    +PROCEDURE utResult.firstresult;
     
     FUNCTION utResult.nextresult RETURN utResult.result_rt;
     
    @@ -108,16 +147,21 @@ 

    case_indx_out OUT PLS_INTEGER ); -FUNCTION utResult.resultcount RETURN PLS_INTEGER;

    +FUNCTION utResult.resultcount RETURN PLS_INTEGER; +
    + +

    Control the Display of Success Messages

    + +

    + The following procedures turn on or off the display of success messages. In other words, + when turned on (as is the default) a message will be displayed for each successful assertion. + The specifications are as follows: +

    -

    - Control the Display of Success Messages

    -

    The following procedures turn on or off the display of success messages. In other words, -when turned on (as is the default) a message will be displayed for each successful assertion. -The specifications are as follows:

     procedure include_successes;
    -procedure ignore_successes; 

    +procedure ignore_successes; +
    diff --git a/documentation/src/writedoc.html b/documentation/src/writedoc.html index 4ea640123..8f7059173 100644 --- a/documentation/src/writedoc.html +++ b/documentation/src/writedoc.html @@ -1,42 +1,67 @@ - -How to add to the utPLSQL documentation set - + + + + + How to add to the utPLSQL documentation set + -

    Writing Documentation

    -

    -The utPLSQL documentation is built from a series of simple HTML files in the -src directory. These files have none of the navigation bars, logos or -next/previous links which appear in the final documentation. They are also -stripped of font, color and style information at compile-time to let the -stylesheet (utplsql.css) determine the overall look-and-feel.

    - -

    Unlike the code (at the time of writing), the documentation is held with CVS. So to make changes, you should set yourself up with access to the utPLSQL CVS repository. If you don't have the privileges, mail one of the Project Admins. Check out the latest version and you're ready to go.

    - -

    The HTML Files

    -

    As described above, the base files in the src directory are used to generate the final -product. To add new documentation to one of these files, or to correct errors, -simply edit it. It makes sense to follow the layout that is already present in the -file, adding links at the top of the page where appropriate. The HTML should be -kept simple, so use the relevant header styles (<H1>...<H6>) to label your sections -and subsections, use <pre> to mark sections of code etc. Let the stylesheet -do the work of setting the colors and fonts.

    - -

    If you are adding an entirely new file to the documentation, use the file -template.html as a basis. This contains the relevant comment -lines which tell the scripts which parts of the file to use -(see the note below). Finally, you will need to -edit map.txt to ensure that the file is linked from the other pages in -the documentation. This is described in the next section.

    - -

    The Control Files

    - -

    The files are compiled into a documentation set situated in the top-level -documentation directory using the 2 control files, map.txt and authors.txt. -The first of these is the driving file, giving a list of the files to be -included. The second gives a list of authors to be included in the copyright -notice on each page and referenced in the Meta tags.

    - -

    The format of map.txt is as follows:

    + +

    Writing Documentation

    + +

    + The utPLSQL documentation is built from a series of simple HTML files in the + src directory. These files have none of the navigation bars, logos or + next/previous links which appear in the final documentation. They are also + stripped of font, color and style information at compile-time to let the + stylesheet (utplsql.css) determine the overall look-and-feel. +

    + +

    + Like the code, the documentation is held within + SVN. So to make changes, you should checkout the latest version from the + trunk, make your changes, then submit an SVN "diff" file to a + ticket +

    + +

    The HTML Files

    + +

    + As described above, the base files in the src directory are used to generate the final + product. To add new documentation to one of these files, or to correct errors, + simply edit it. It makes sense to follow the layout that is already present in the + file, adding links at the top of the page where appropriate. The HTML should be + kept simple, so use the relevant header styles (<H1>...<H6>) to label your sections + and subsections, use <pre> to mark sections of code etc. Let the stylesheet + do the work of setting the colors and fonts. +

    + +

    + If you are adding an entirely new file to the documentation, use the file + template.html as a basis. This contains the relevant comment + lines which tell the scripts which parts of the file to use + (see the note below). Finally, you will need to + edit map.txt to ensure that the file is linked from the other pages in + the documentation. This is described in the next section. +

    + +

    The Control Files

    + +

    + The files are compiled into a documentation set situated in the top-level + documentation directory using the 3 control files: map.txt, authors.txt and copyright_years.txt. + The first of these is the driving file, giving a list of the files to be + included. The second gives a list of authors to be included in the copyright + notice on each page and referenced in the Meta tags (this is for + historical reasons and lists the original contributors of the + documentation - to keep it in line with the policy for source-code, all + future contributions will go under the name of "the utPLSQL Project"). The + third file lists the years for the copyright statement - i.e. years when + significant changes were published. +

    + +

    The format of map.txt is as follows:

    +
        # Any line starting with a # is 
        # considered a comment
    @@ -44,50 +69,81 @@ 

    The Control Files

    index.html,Home* started.html,Getting Started* another.html,Further Docs - another2.html,Yet more docs
    + another2.html,Yet more docs +
    + +

    + Each line consists of the filename to be included and the title of the page, + separated with a comma. Any file whose title is followed by an asterisk is + considered the start of a new section. This means a link to the file will + appear in the navigation bar at the top of each page and it will appear in + bold in the document map. Note that the document map itself does not appear + in map.txt, but is always added at the end and is considered a new section. + This page is entirely generated at compile-time. +

    + +

    + To add a new page to the documentation, simply add it to this file in the + correct position. Note that generally you will not be adding a new section! +

    + +

    The format of authors.txt is as follows:

    -

    Each line consists of the filename to be included and the title of the page, -separated with a comma. Any file whose title is followed by an asterisk is -considered the start of a new section. This means a link to the file will -appear in the navigation bar at the top of each page and it will appear in -bold in the document map. Note that the document map itself does not appear -in map.txt, but is always added at the end and is considered a new section. -This page is entirely generated at compile-time.

    - -

    To add a new page to the documentation, simply add it to this file in the -correct position. Note that generally you will not be adding a new section!

    - -

    The format of authors.txt is as follows:

        # Again, lines starting # are ignored
        #
        Steven Feuerstein,steven@stevenfeuerstein.com
        Chris Rimmer,c@24.org.uk
    -   A N Other,ano@ther.net
    - -

    Each line in this file simply gives the name of the author and their email - address, separated with a comma. So if you've made a contribution and your name - is not listed, add it!

    + A N Other,ano@ther.net +
    -

    The Scripts

    -

    The 2 Perl scripts used to build the documentation are clean_html.pl and - build_docs.pl.

    - -

    The first of these simply strips HTML files down to the basics, removing -everything from the header and removing Javascript, fonts, color etc. It -requires the HTML::TagFilter module which in turn also requires the -HTML::Parser and HTML::Tagset modules (all available from search.cpan.org).

    +

    + Each line in this file simply gives the name of the author and their email + address, separated with a comma. So if you've made a contribution and your name + is not listed, add it! +

    + +

    The format of copyright_years.txt is as follows:

    -

    The second script goes through each file listed in map.txt, cleans it using -the previous script and then adds logos, navigation bars, next/previous links, -copyright information etc. The resulting files are put in the top-level -documentation directory.

    +
    +   # Again, lines starting # are ignored
    +   #
    +   2000-2005
    +   2014
    +
    -

    NOTE: Anything within a source file before the -<!-- Begin utPLSQL Body --> comment line and after the -<!-- End utPLSQL Body --> comment line is ignored.

    +

    + Each line will be separated by a comma in the copyright statement, so the + above will generate: "2000-2005, 2014" +

    -Chris Rimmer, c@24.org.uk March 2002 +

    The Scripts

    + +

    + The Perl script used to build the documentation is build_docs.pl. +

    + +

    + The script goes through each file listed in map.txt, cleans it up + and then adds logos, navigation bars, next/previous links, + copyright information etc. The resulting files are put in the top-level + documentation directory. +

    + +

    + The "cleaning" strips the source HTML files down to the basics, removing + everything from the header and removing Javascript, fonts, color, etc. It + requires the HTML::TagFilter module which in turn also requires the + HTML::Parser and HTML::Tagset modules (all available from search.cpan.org). +

    + +

    + NOTE: Anything within a source file before the + <!-- Begin utPLSQL Body --> comment line and after the + <!-- End utPLSQL Body --> comment line is ignored. +

    + +

    Copyright 2002, 2014 Chris Rimmer and the utPLSQL Project. All rights reserved

    diff --git a/website/Doc/admin.html b/website/Doc/admin.html deleted file mode 100644 index 30a128ba4..000000000 --- a/website/Doc/admin.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - -Administrative Topics - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: The Four Step Program to using utPLSQL | Next Section: Build Test Packages >

    - - -

    -Administrative Topics

    - -

    -Configuring UTL_FILE

    - -

    -Join the Project Team

    - -

    -Reporting Bugs and Enhancement Requests

    - -

    -Administrative Topics

    - -

    -Configuring UTL_FILE

    -If you want utPLSQL to automatically recompile your test packages, you -will need to make sure that UTL_FILE is enabled in your database (this -allows you to read/write operating system files). The database initialization -parameter file (aka, the "init.ora" file) must have at least one utl_file_dir -parameter in it for this to work. Here is some background and guidelines -for working with UTL_FILE: -

    UTL_FILE lets you read and write files accessible from the server on -which your database is running. So, theoretically, you could use UTL_FILE -to write right over your tablespace data files, control files and so on. -That is, of course, a very bad idea. Server security requires the ability -to place restrictions on where you can read and write your files. -

    UTL_FILE implements this security by limiting access to files that reside -in one of the directories specified in the init.ora file (parameter initialization -file) for the database instance on which UTL_FILE is running. -

    When you call UTL_FILE.FOPEN to open a file, you must specify both the -location and the name of the file, in separate arguments. This file location -is then checked against the list of accessible directories. -

    The format of the parameter for file access in the init.ora file is: -

    -utl_file_dir = <directory>
    -
    -Include a parameter for utl_file_dir for each directory you want to make -accessible for UTL_FILE operations. The following entries, for example, -enable four different directories in Unix: -
    -utl_file_dir = /tmp
    -utl_file_dir = /ora_apps/hr/time_reporting
    -utl_file_dir = /ora_apps/hr/time_reporting/log
    -utl_file_dir = /users/test_area
    -
    -To bypass server security and allow read/write access to all directories, -you can use this special syntax: -
    -utl_file_dir = *
    -
    -You should not use this option on production systems. In a development -system, this entry certainly makes it easier for developers to get up and -running on UTL_FILE and test their code. You should, however, only allow -access to a few specific directories when you move the application to production. -

    Some observations on working with and setting up accessible directories -with UTL_FILE:

    -

    Access is not recursive through subdirectories. If the following lines -were in your init.ora file, for example, -

    -utl_file_dir = c:\group\dev1
    -utl_file_dir = c:\group\prod\oe
    -utl_file_dir = c:\group\prod\ar
    -
    -then you would not be able to open a file in the c:\group\prod\oe\reports -subdirectory. -

    Do not include the following entry in Unix systems: -

    -utl_file_dir = .
    -
    -This would allow you to read/write on the current directory in the operating -system. -

    Do not enclose the directory names within single or double quotes. -

    In the UNIX environment, a file created by UTL_FILE.FOPEN has as its -owner the shadow process running the Oracle instance. This is usually the -oracle owner. If you try to access these files outside of UTL_FILE, you -will need to have the correct privileges (or be logged in as oracle) to -access or change these files. -

    You should not end your directory name with a delimiter, such as the -forward slash in Unix. The following specification of a directory will -result in problems when trying to read from or write to the directory: -

    -utl_file_dir = /tmp/orafiles/
    -
    -After you modify your parameter initialization file, you will need to stop -and then restart your database instance. -

    Test UTL_FILE Access

    -

    If you have never before used or relied on UTL_FILE, you should write -a simple test to verify that UTL_FILE is now working. You can use the code -shown below (after changing your directory names and names for existing -and new files) to make sure you've got it running properly. -

     
    -SET SERVEROUTPUT ON
    -DECLARE
    -   fid UTL_FILE.FILE_TYPE;
    -   v VARCHAR2(32767);
    -   PROCEDURE recNgo (str IN VARCHAR2)
    -   IS
    -   BEGIN
    -      DBMS_OUTPUT.PUT_LINE ('UTL_FILE error ' || str);
    -
    -      UTL_FILE.FCLOSE (fid);
    -   END;
    -BEGIN
    -   /* Change the directory name to one to which you at least 
    -   || THINK you have read/write access.
    -   */
    -   fid := UTL_FILE.FOPEN ('e:\demo', 'existing_file', 'R');
    -   UTL_FILE.GET_LINE (fid, v);
    -   dbms_output.put_line (v);
    -   UTL_FILE.FCLOSE (fid);
    -
    -   fid := UTL_FILE.FOPEN ('e:\demo', 'new_file', 'W');
    -   UTL_FILE.PUT_LINE (fid, v);
    -   UTL_FILE.FCLOSE (fid);
    -EXCEPTION
    -   WHEN UTL_FILE.INVALID_PATH
    -    THEN recNgo ('invalid_path');
    -   WHEN UTL_FILE.INVALID_MODE
    -    THEN recNgo ('invalid_mode');
    -   WHEN UTL_FILE.INVALID_FILEHANDLE
    -    THEN recNgo ('invalid_filehandle');
    -   WHEN UTL_FILE.INVALID_OPERATION
    -    THEN recNgo ('invalid_operation');
    -   WHEN UTL_FILE.READ_ERROR
    -    THEN recNgo ('read_error');
    -   WHEN UTL_FILE.WRITE_ERROR
    -    THEN recNgo ('write_error');
    -   WHEN UTL_FILE.INTERNAL_ERROR
    -    THEN recNgo ('internal_error');
    -END;
    -/
    -If an error occurs, it will be displayed on your screen (note: the "set -serveroutput on" is not required for UTL_FILE to work, but simply to display -any errors which might occur). -
    -

    -Join the utPLSQL Project Team

    - -To take part in the utPLSQL project, first please join -the utPLSQL Forum. Go to -http://utplsql.oracledeveloper.nl -and join in the discussions. Once you are up to speed on the project, you -can go to the SourceForge site, choose a task and begin -to contribute. - -

    -Reporting Bugs and Enhancement Requests

    - -To identify the version of utPLSQL you are running, -you can execute the following program in SQL*Plus: - -
    SQL> set serveroutput on
    -SQL> exec dbms_output.put_line (utPLSQL.version)
    - -You can also look inside the utPLSQL package (utPLSQL.pkb) -and check the value of the g_version private variable. - - -

    < Previous Section: The Four Step Program to using utPLSQL | Next Section: Build Test Packages >

    -
    - - \ No newline at end of file diff --git a/website/Doc/buildpack.html b/website/Doc/buildpack.html deleted file mode 100644 index 7ed3dd6f9..000000000 --- a/website/Doc/buildpack.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - -Build Test Packages - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: Administrative Topics | Next Section: How to build a test package >

    - - -

    -Build Test Packages

    - -

    We learn best by following the examples of those who have gone before -us. So you will find in this document sample test packages and different -approaches to using utPLSQL to test your PL/SQL code like it has never -been tested before! -

    Spend some time in the general How to Build a Test -Package so that you are comfortable with the basic steps necessary -to integrate your test code into the utPLSQL framework. The Test Run section -offers a narrative presentation of building a test package; it makes a -nice follow-up to the How To section if you still feel any uncertainty. -Then you will be more than ready to explore the Examples. -

    -How to Build a Test Package

    - -

    -A "Test Run" with utPLSQL

    - - -

    < Previous Section: Administrative Topics | Next Section: How to build a test package >

    -
    - - \ No newline at end of file diff --git a/website/Doc/defsuite.html b/website/Doc/defsuite.html deleted file mode 100644 index d13b70223..000000000 --- a/website/Doc/defsuite.html +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - -Defining Test Suites - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: utRecEq Package | Next Section: Custom Reporter Packages >

    - - -

    -Defining Test Suites

    - -If you define test suites and register packages -within those suites, then utPLSQL will run an unlimited number of -tests with a single command. - -

    Note

    - -
      -
    • -All suite names are stored in upper case.
    • - -
    • -If you do not specify a directory (dir_in), -you will need to call utConfig.setdir if you want automatic compilation -of your packages to occur.
    • - -
    • If you supply a value for seq_in, packages -will be compiled and tested in ascending numeric sequence order.
    • - -
    • When you call utSuite.rem, it will remove all -packages for that suite by calling utPackage.rem.
    • -
    - -

    -utSuite - Define Test Suites

    - -To create and remove test suites, call these programs: - -
    -   PROCEDURE utSuite.add (
    -      name_in IN VARCHAR2,
    -      desc_in IN VARCHAR2 := NULL,
    -      rem_if_exists_in IN BOOLEAN := TRUE
    -      );
    -
    -   PROCEDURE utSuite.rem (name_in IN VARCHAR2);
    - -These programs manipulate the contents of the ut_suite -table. See the tables.sql file for the DDL creating this table. - -

    - utPackage - Define Test Packages for a Suite

    - -To register a package in a suite, call the following: - -
       PROCEDURE utPackage.add (
    -      suite_in IN VARCHAR2,
    -      package_in IN VARCHAR2,
    -      samepackage_in IN BOOLEAN := FALSE,
    -      prefix_in IN VARCHAR2 := NULL,
    -      dir_in IN VARCHAR2 := NULL,
    -      seq_in IN PLS_INTEGER := NULL,
    -      owner_in IN VARCHAR2 := NULL,
    -      add_tests_in IN BOOLEAN := FALSE,
    -      test_overloads_in IN BOOLEAN := FALSE
    -   );
    - -This manipulates the contents of the ut_package -table. See the tables.sql file for the DDL creating this table. - -Here is a sample script that defines a very small -portion of the PL/Vision test suite: - -
    BEGIN
    -   utSuite.add ('PLVision');
    -  
    -   utPackage.add
    -      'PLVision', 'PLVstr', dir_in => 'e:\utplsql\test');
    -  
    -   utPackage.add (
    -      'PLVision', 'PLVdate', dir_in => 'e:\utplsql\test'');
    -  
    -   utPLSQL.testsuite ('PLVision', recompile_in => TRUE);
    -END;
    -/
    - - -

    < Previous Section: utRecEq Package | Next Section: Custom Reporter Packages >

    -
    - - \ No newline at end of file diff --git a/website/Doc/examples.html b/website/Doc/examples.html deleted file mode 100644 index 079f56ed9..000000000 --- a/website/Doc/examples.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - -Examples - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: A "Test Run" with utPLSQL | Next Section: Test a Procedure >

    - - -

    -Examples

    - -

    We learn best by following the examples of those who have gone before -us. So you will find in this document sample test packages and different -approaches to using utPLSQL to test your PL/SQL code like it has never -been tested before! -

    -Test a Procedure

    - -

    -Test a Function

    - -

    -Test an Entire Package API

    - -

    -Put Test Code in Same Package

    - -

    -Use Non-Default Prefix

    - -

    -Create and Run a Test Suite

    - -

    < Previous Section: A "Test Run" with utPLSQL | Next Section: Test a Procedure >

    -
    - - \ No newline at end of file diff --git a/website/Doc/fileout.html b/website/Doc/fileout.html deleted file mode 100644 index d7f64d031..000000000 --- a/website/Doc/fileout.html +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - - - -Configuring the File Reporter - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: Custom Reporter Packages | Next Section: Release Notes >

    - - -

    -Configuring the File Reporter -

    - -

    -Outline -

    -By default, the results of a test run are written to the screen -(via the default Output Reporter). The subprograms described in this section were created -by Rainer Medert to allow these results to be written to file instead. -They form part of the utConfig package. -Don't forget that you will first need to enable file output from the database -via the UTL_FILE_DIR parameter in order to do this. - -

    -Turning file output on -

    - -

    To turn on file output, you will need to switch to using the File Reporter, or a custom reporter -that uses it. See this page for details.

    - -

    -Setting the directory to be used -

    - -

    Once file output has been turned on, you can specify which directory the -files will be written to using the following procedure:

    - -
    PROCEDURE setfiledir (
    -  dir_in IN VARCHAR2 := NULL, 
    -  username_in IN VARCHAR2 := NULL
    -);
    - -

    the directory given will have to have been specified for output in a -UTL_FILE_DIR database parameter, as mentioned above.

    - -

    To see which directory is being used for output, use the following:

    - -
    FUNCTION filedir (username_in IN VARCHAR2 := NULL) RETURN VARCHAR2;
    - -

    -Formatting the output filenames -

    - -

    The structure of the filenames used for output is as follows:

    - -
    <user-prefix>_[program-name_]<date><extension>
    - -

    Each of these elements can be configured using the following procedures.

    - -

    The user-prefix is an arbitrary string. It defaults to the username of the currently connected user, but can be set (and returned) using the following:

    - -
    -- Set the file prefix for a user
    -PROCEDURE setuserprefix (
    -  userprefix_in IN VARCHAR2 := NULL, 
    -  username_in IN VARCHAR2 := NULL
    -);
    -
    --- Get the file prefix for a user
    -FUNCTION userprefix (username_in IN VARCHAR2 := NULL) RETURN VARCHAR2;
    - - -

    The program-name is the name of the tested program, or the test suite -being run. By default, this is element is not used in the generated filename. -To turn this on or off (and to determine the current setting), use the -following:

    - -
    -- Set the include program name flag for a user
    -PROCEDURE setincludeprogname (
    -  incname_in IN BOOLEAN := FALSE, 
    -  username_in IN VARCHAR2 := NULL
    -);
    -
    --- Get the include program name flag for a user
    -FUNCTION includeprogname (username_in IN VARCHAR2 := NULL) RETURN BOOLEAN;
    - - -

    The date element of the filename is simply SYSDATE converted to a string. The default format is 'YYYYDDMMHH24MISS', but this can be set (and returned) using the following:

    - -
    -- Set the date format for a user
    -PROCEDURE setdateformat (
    -  dateformat_in IN VARCHAR2 := 'yyyyddmmhh24miss', 
    -  username_in IN VARCHAR2 := NULL
    -);
    -          
    --- Get the date format for a user
    -FUNCTION dateformat (username_in IN VARCHAR2 := NULL) RETURN VARCHAR2;
    - - -

    The final element of the filename that can be configured is the extension. -This defaults to ".UTF" but can be set (and returned) using the following:

    - -
    -- Set the file extension for a user
    -PROCEDURE setfileextension (
    -  fileextension_in IN VARCHAR2 := '.UTF', 
    -  username_in IN VARCHAR2 := NULL
    -);
    -
    --- Get the file extension for a user
    -FUNCTION fileextension (username_in IN VARCHAR2 := NULL) RETURN VARCHAR2;
    - -

    Note The initial dot must be included, otherwise there will be none -in the resulting filename!

    - -

    -Setting all the parameters at once -

    - -

    It is possible to set all the file output parameters at once using the following procedure:

    - -
    PROCEDURE setfileinfo ( 
    -  dir_in IN VARCHAR2 := NULL,
    -  userprefix_in IN VARCHAR2 := NULL, 
    -  incname_in IN BOOLEAN := FALSE,     
    -  dateformat_in IN VARCHAR2 := 'yyyyddmmhh24miss', 
    -  fileextension_in IN VARCHAR2 := '.UTF',
    -  username_in IN VARCHAR2 := NULL
    -);
    - -

    To get back all of the file output parameters simultaneously, use the following function:

    - -

    FUNCTION fileinfo (username_in IN VARCHAR2 := NULL) RETURN rec_fileinfo;
    - -

    The record type rec_fileinfo is defined in the utConfig package and has one field for each of the parameters.

    - -

    - - -

    < Previous Section: Custom Reporter Packages | Next Section: Release Notes >

    -
    - - \ No newline at end of file diff --git a/website/Doc/fourstep.html b/website/Doc/fourstep.html deleted file mode 100644 index f5a550eba..000000000 --- a/website/Doc/fourstep.html +++ /dev/null @@ -1,581 +0,0 @@ - - - - - - - - -The Four Step Program to using utPLSQL - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: Glossary and Requirements | Next Section: Administrative Topics >

    - - -

    The Four Step Program to Using utPLSQL

    - -

    Step 1. Install utPLSQL.

    - -

    Step 2. Choose a program to test and identify the test -cases.

    - -

    Step 3. Build a test package.

    - -

    Step 4. Run your test.

    - -

    A note on which schemas to use

    - -

    Where to go from here

    - -

    Step 1. Install (and Upgrade) utPLSQL.

    - -

    Note: if you have already installed a previous version of -utPLSQL, you will use these same steps to perform your install. The -installation procedure does not remove any objects, such as tables, -prior to installation. If you wish to install a fresh copy of utPLSQL, and not upgrade -over the existing installation, please follow the steps below for removing -utPLSQL.

    - -

    Connect via SQL*Plus to the session that will own the -utPLSQL components. If you do not already have a schema defined, then you must -create it. The utPLSQL schema must have the authority to:

    - -
      -
    • Create a session.
    • -
    • Create tables, views, packages and sequences.
    • -
    - -

    If you like, you can install utPLSQL into the SYSTEM schema, which will avoid the need to create -a new user. However, you may prefer to keep everything in a separate place. -The following is an example script submitted by Bill Pribyl, which creates a user "UTP" with sufficient privileges -to install utPLSQL. Obviously it is only an example and will need to be changed for your environment:

    - -
    connect system/manager
    -create user utp identified by utp default tablespace
    -  users temporary tablespace temp;
    -
    -grant create session, create table, create procedure,
    -  create sequence, create view, create public synonym,
    -  drop public synonym to utp;
    -
    -alter user utp quota unlimited on users;
    -
    - -

    Note If the schema in question does not have the ability to create and drop public synonyms -or execute privilege on DBMS_PIPE, you -may get error messages when installing. However, utPLSQL will still function correctly.

    - -

    Once you have connected to the schema, run the ut_i_do.sql -file with the parameter "install" to install all utPLSQL objects. You should ensure that -the working directory of your SQL*Plus -session is the directory holding the utPLSQL files, then issue this as follows:

    - -

    - -
    SQL> @ut_i_do install
    - 
    - - -

    This file will create all tables, packages and other objects needed. -Note that the installation script -creates some files dynamically using the SPOOL command. For this reason, it is -necessary that you have write permission in the directory.

    - -

    - -

    To check the installation of utPLSQL, examine the -ut_i_install.log file.

    - -

    Removing utPLSQL

    - -

    To de-install the product, run the ut_i_do.sql -script again, but with the parameter "uninstall", as in:

    - -

    - -
    SQL> @ut_i_do uninstall
    - 
    - -

    Step 2. Choose a program to test and identify the test -cases.

    - -

    You may want to test a single stand-alone procedure or -function, or a set of programs in a package. Pick the program and then come up -with the set of different cases you want to test. This data will determine what -kind of and how many tests you run for your program.

    - -

    Suppose, for example, that I have created a stand alone function called -betwnStr (a variation on SUBSTR that returns a sub-string based on a starting -and ending location) that is stored in betwnstr.sf(1): -

    - -
    CREATE OR REPLACE FUNCTION betwnStr (
    -   string_in IN VARCHAR2,
    -   start_in IN INTEGER,
    -   end_in IN INTEGER
    -   )
    -   RETURN VARCHAR2
    -IS
    -BEGIN
    -   RETURN (
    -      SUBSTR (
    -         string_in,
    -         start_in,
    -         end_in – start_in + 1
    -         )
    -      );
    -END;
    - -

    To test this function, I will want to pass in a variety of -inputs, as shown in this table:
    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -

    Start

    -
    -

    End

    -
    -

    Result

    -
    -

    NULL

    -
    -

    NOT NULL

    -
    -

    NULL

    -
    -

    NOT NULL

    -
    -

    NULL

    -
    -

    NULL

    -
    -

    NULL

    -
    -

    NULL

    -
    -

    NULL

    -
    -

    3 (positive number)

    -
    -

    1 (smaller positive number)

    -
    -

    NULL

    -
    -

    3 (positive number)

    -
    -

    100 (larger than length of string)

    -
    -

    Remainder of string from 3

    -
    - -

    So now I know what I want to test and how I want to test it.
    -

    - -

    Step 3. Build a test package.

    - -

    utPLSQL offers an easy, automated way to run your tests. To -work automatically, though, you have to follow some rules so that utPLSQL can -find and execute your test code. Here are the rules:

    - -

    - -The test code must be placed inside a -test package. - -

    - -

    - -The test package specification should -be stored in a file named ut_<program>.pks and the body must be stored in -a file named ut_<program>.pkb (by following this naming convention, -utPLSQL can be set to automatically recompile your test package before each -test). - -

    - -

    - -The test package must contain a setup procedure called ut_setup and a teardown procedure called ut_teardown, neither of -which take any arguments. - -

    - -

    - -The test package should have a -separate procedure for each program to be tested in this package. - -

    - -

    Now, you should know that there are a number of bells and -whistles in utPLSQL that allow you to change many default values (such as the -prefixes used for the setup, teardown and test procedures) and behavior of the -utPLSQL packages. While you are "Getting Started", however, we will -rely completely on the defaults and get you up and testing ASAP.

    - -

    So if I am going to test the stand-alone procedure, betwnstr, my test -package specification, saved in ut_betwnstr.pks(1), -will look like this:

    - -
    CREATE OR REPLACE PACKAGE ut_betwnstr
    -IS
    -   PROCEDURE ut_setup;
    -   PROCEDURE ut_teardown;
    - 
    -   PROCEDURE ut_betwnstr;
    -END ut_betwnstr;
    -/
    - -

    Now let's build the package body, saved in ut_betwnstr.pkb(1). In this very simple -case, I don't have to set up any data structures and I do not, therefore, have -to tear anything down. My teardown procedure can be empty (but it must -be present). So I have:

    - -
    CREATE OR REPLACE PACKAGE BODY ut_betwnstr
    -IS
    -   PROCEDURE ut_setup IS
    -   BEGIN
    -      NULL;
    -   END;
    - 
    -   PROCEDURE ut_teardown
    -   IS
    -   BEGIN
    -      NULL;
    -   END;
    - -

    Time to build the unit test procedure. To do this, I need to -go back to my grid of test cases and translate those sets of data inputs and -results into calls to programs in the utAssert -package.

    - -

    utAssert offers a number of "assertion routines" that test the -values or expression you pass to them and then record the results in utPLSQL. -You can, with utAssert, test for equality between two strings or files or -tables or collections. You can test to see if an expression evaluates to NULL. -I can use both of these types of assertions (equality and IS NULL) for my test -cases, which I repeat below:
    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -

    Start

    -
    -

    End

    -
    -

    Result

    -
    -

    NULL

    -
    -

    NOT NULL

    -
    -

    NULL

    -
    -

    NOT NULL

    -
    -

    NULL

    -
    -

    NULL

    -
    -

    NULL

    -
    -

    NULL

    -
    -

    NULL

    -
    -

    3 (positive number)

    -
    -

    1 (smaller positive number)

    -
    -

    NULL

    -
    -

    3 (positive number)

    -
    -

    100 (larger than length of string)

    -
    -

    Remainder of string

    -
    - -

    Here's how it works: for each test case, I provide a string description of -the case, then the expression I want to evaluate. Let's start with -"typical valid usage". I pass a string "abcdefg", a start -location of 3 and end location of 5, and betwnstr should return -"cde". I express that in my unit test procedure as follows:

    - -
       PROCEDURE ut_betwnstr IS
    -   BEGIN
    -      utAssert.eq (
    -         'Typical valid usage',
    -         BETWNSTR(
    -            STRING_IN => 'abcdefg'
    -            ,
    -            START_IN => 3
    -            ,
    -            END_IN => 5
    -            ),
    -         'cde'
    -         );
    - -

    Notice that I call utAssert.eq because I want to compare the -value returned by betwnstr with the string "cde". They should -be equal.

    - -

    I can now write another call to a utAssert program for each of my cases. In -this very next example, I call utAssert.isnull, because I am expecting betwnstr -to return a NULL value.

    - -
          utAssert.isnull (
    -         'NULL start',
    -         BETWNSTR(
    -            STRING_IN => 'abcdefg'
    -            ,
    -            START_IN => NULL
    -            ,
    -            END_IN => 5
    -            )
    -         );
    - 
    -      utAssert.isnull (
    -         'NULL end',
    -         BETWNSTR(
    -            STRING_IN => 'abcdefg'
    -            ,
    -            START_IN => 2
    -            ,
    -            END_IN => NULL
    -            )
    -         );
    -         
    -      utAssert.isnull (
    -         'End smaller than start',
    -         BETWNSTR(
    -            STRING_IN => 'abcdefg'
    -            ,
    -            START_IN => 5
    -            ,
    -            END_IN => 2
    -            )
    -         );
    -         
    -      utAssert.eq (
    -         'End larger than string length',
    -         BETWNSTR(
    -            STRING_IN => 'abcdefg'
    -            ,
    -            START_IN => 3
    -            ,
    -            END_IN => 200
    -            ),
    -         'cdefg'
    -         );
    -         
    -   END ut_BETWNSTR;
    - 
    -END ut_betwnstr;
    -/
    - -

    I have now created my unit test program for the betwnstr -function. I will compile both these files to make sure there are no compile -errors:

    - -
    SQL> @ut_betwnstr.pks
    - 
    -Package created.
    - 
    -SQL> @ut_betwnstr.pkb
    - 
    -Package body created.
    - -

    Note: when you run your test, utPLSQL will by default -attempt to recompile your test package to ensure that the latest changes are -incorporated into the test. It is still worth doing an initial compile to make -sure you built your test properly. You will also need to make sure that UTL_FILE is installed and configured so that your -test package files can be read and compiled by utPLSQL.

    - -

    So with the test package in place and compiling, now let's -see how we go about running the test.
    -

    - -

    Step 4. Run your test.

    - -

    You've built your code, you've built your test package, -you've compiled that test package. Now it's time to run the test. Start up -SQL*Plus and connect to the schema owning the code you want to test.

    - -

    Then run your test package within the utPLSQL testing framework by calling utPLSQL.test:

    - -
    SQL> exec utplsql.test ('betwnstr', recompile_in => FALSE)
    - -

    That second parameter in the call to utplsql.test, -"recompile_in => FALSE", tells utPLSQL that you have already -compiled your test package. You can also have utPLSQL automatically recompile your test package -each time you run a test.

    - -

    If the test does not find any errors (which means that the assertion -programs did not detect any conflicts), you will see this output:

    - -
    SQL> exec utplsql.test ('betwnstr', recompile_in => FALSE)
    -SUCCESS: "betwnstr"
    - -

    If the test detected a failure, you will see output along -these lines:

    - -
    SQL> exec utplsql.test ('betwnstr', recompile_in => FALSE)
    -FAILURE: "betwnstr"
    -BETWNSTR: IS NULL: NULL start
    -BETWNSTR: End larger than string length; expected "cdeg", got "cdefg"
    - -

    As you can see, utPLSQL tells you the description of the -test case that failed, and also shows you as much as it can about what caused -the failure.

    - -

    You have now successfully installed utPLSQL, written a test package and run -your test!

    - -

    Automatic Recompilation of Test Package

    - -

    utPLSQL will, by default, attempt to recompile your test package code -(which must be put in two files <name>.pks for the package specification -and <name>.pkb for the package body). This of course assumes that the files -are situated on the same machine as your database. If this is not the case, you can -turn off this functionality by calling utConfig.autocompile -as follows:

    - -
    utConfig.autocompile(false);
    - -

    If you do wish to use this functionality, utPLSQL needs -the UTL_FILE package provided by Oracle to read the source code files and then -compile the code found in those files. Before using UTL_FILE you must configure it for use from within PL/SQL. -Once you have confirmed that UTL_FILE works in your database instance, you -must tell utPLSQL where the test package is located by calling utConfig.setdir. -If you do not do this, then utPLSQL will not be able to recompile your test -package before each run, and instead will display an error message.

    - -

    Call the utConfig.setdir program to tell -utPLSQL the location of your source code. Suppose that I stored all my code in e:\utplsql\testall. Then I would make this -call in SQL*Plus:

    - -
    SQL> exec utConfig.setdir ('e:\utplsql\testall')
    - -

    A note on which schemas to use

    - -

    In step 1, above, we described which user should own the objects which make up the utPLSQL framework. -However, there has often been confusion about which schema should contain the test packages and which schema to connect as -when running the tests. There are many ways to do it, but the simplest is as follows: -

      -
    • It doesn't matter which schema owns utPLSQL itself, so long as other users have access to it.
    • -
    • The test packages should go in the same schema as the code that is being tested.
    • -
    • You should connect as the user who owns the test packages (and hence the tested code) when running the tests
    • -

    - -

    Where to go from here

    - -

    If you proceeded through all four steps, you should now have -used utPLSQL successfully to test a very simple function (betwnstr) or your own -functionality. This will undoubtedly leave you very excited about using utPLSQL -to handle much more complex code and elaborate testing requirements.

    - -

    To find out more about the different features and -functionality available in utPLSQL, visit the User -Guide.

    - -

    To read through a more thorough presentation of how to build -test packages in utPLSQL, visit How to -Build Test Packages.

    - -

    To see a wide array of examples of building test cases and -different kinds of test packages, visit the Examples -document.

    - -
    - -

    Footnotes

    - -

    1. This file is to be found in the Examples directory of the utPLSQL distribution.

    - - -

    < Previous Section: Glossary and Requirements | Next Section: Administrative Topics >

    -
    - - \ No newline at end of file diff --git a/website/Doc/glossreq.html b/website/Doc/glossreq.html deleted file mode 100644 index 6f89da03b..000000000 --- a/website/Doc/glossreq.html +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - -Glossary and Requirements - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: Getting Started | Next Section: The Four Step Program to using utPLSQL >

    - - -

    -Glossary and Requirements

    - -

    -Glossary

    - -Before diving into the details, let's make sure -we have a common vocabulary. - -

    -Unit Test

    - -A test of a single unit or program. Suppose you -have built product.total_sales, a function to calculate and return total -sales of the specified product for a given date period. You will then build -a single procedure to perform the test for that function. - -

    -Test Case

    - -Individual cases or test scenarios for a unit test. -You will want to try out different scenarios (valid and invalid product -Ids, various date ranges, etc.). Each different combination of inputs (parameter -values) is a different test case. These are bundled up and executed within -the single unit test procedure. - -

    -Package Test

    - -A set of unit tests which test the functionality -of all programs in a single PL/SQL package (or a single stand-alone program -unit – procedure or function). - -The way utPLSQL works today, you must define -your various tests cases and unit tests within a test package (though it -could -be the same package containing the functionality). - -

    -Test Suite

    - -A series of package tests. Obviously, any application -of non-trivial complexity will consist of multiple packages, each covering -their own area of functionality. A test suite contains a series of packages -that can then be tested in sequence by executing the test suite as a whole. - -

    -Requirements

    - -If you are using Oracle8i or above, utPLSQL takes advantage -of a number of Oracle8i features, including autonomous transactions, invoker -rights and native dynamic SQL. utPLSQL will however still run on Oracle7 -(7.3.4 and above) and Oracle8. - -Requirements for using utPLSQL include: -
      -
    • -

      -The schema owning utPLSQL objects must have the ability to create tables and packages. -

    • -
    • -

      -If you want utPLSQL to automatically recompile test packages for you, you -will need to have UTL_FILE installed and -configured to read from the directory or directories in which your package -source files are located. -

    • -
    • -

      -Optional: -The Ability to create public synonyms. The installation script will attempt -to create public synonyms. If your schema does not hae the authority to -do so, these commands will fail, but utPLSQL will still be available for -use in the owning schema. -

    • -
    • Optional: -Execute privilege on the DBMS_PIPE package. Without this, the UTPIPE package will not compile. -However, this is only required if you want to test data accessed via DBMS_PIPE.
    • -
    -

    -Requirements for Executing Test Code

    -

    - -If you install and use utPLSQL from within a single schema (ie, the same schema that owns utPLSQL code and tables owns the code -you want to test, as well as the test packages), then no additional privileges are needed. -

    -If, however, you install utPLSQL in a shared schema and then access it from other schemas, you may need to grant additional -privileges to the utPLSQL schema. utPLSQL uses dynamic PL/SQL to run the test code. It therefore requires directly granted -EXECUTE privileges on those code elements (both the code to be tested and the test packages) -- or the AUTHID CURRENT_USER -capability of Oracle8i and above. -

    -

    For Oracle8i and above

    -

    -You do not need to grant any additional privileges, unless you want to test code owned by one schema from another schema. -In that case, you will need to grant EXECUTE to the schema from which you run your tests on both the code to be tested and the test package. -

    -

    For Oracle7 and Oracle8

    -

    -You must grant EXECUTE to the utPLSQL schema on both the code to be tested and the test package. -These grants must be made directly and not through roles. - - - -

    < Previous Section: Getting Started | Next Section: The Four Step Program to using utPLSQL >

    -
    - - \ No newline at end of file diff --git a/website/Doc/howto.html b/website/Doc/howto.html deleted file mode 100644 index 7d064e579..000000000 --- a/website/Doc/howto.html +++ /dev/null @@ -1,465 +0,0 @@ - - - - - - - - -How to build a test package - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: Build Test Packages | Next Section: A "Test Run" with utPLSQL >

    - - -

    -How to build a test package

    - -

    -Instructions

    -To use utPLSQL, you will build a test package containing your unit tests. -This test package must conform to the API (application programmatic interface) -rules of utPLSQL, so that utPLSQL can run your tests automatically. -

    Every test package must have: -

    -

    -A setup procedure - register your unit test and set -up any data structures needed for testing.

    - -

    -A teardown procedure - remove any data structures -created for testing.

    - -

    -One or more unit test procedures - perform the -unit tests.

    -
    -The names you give to your test package, setup, teardown and unit test -proceedures must also follow the utPLSQL Naming Conventions. -

    -Setup Procedure

    - -The utPLSQL.test and utPLSQL.testsuite programs -will call the setup procedure of your test package before it runs any unit -tests. Use this procedure to define your unit tests and also initialize -any data structures needed for your units. The package specification header -for this procedure must be of this form: - -
    CREATE OR REPLACE PACKAGE <prefix><package>
    -IS
    -   PROCEDURE <prefix>setup;
    - -where <prefix> is the unit test prefix and <package> -is the name of the package (or stand alone program) to be tested. The default -naming convention is that your test package and all utPLSQL programs, including -the setup procedure, have a prefix of "ut_", as in: - -
    CREATE OR REPLACE PACKAGE ut_<program>
    -IS
    -   PROCEDURE ut_setup;
    - -Note: if you are using manual -registration of unit tests (which is not the default setting -and is not recommeded), see Naming Conventions -for details on when and how to apply prefixes to your package and procedure -names. - -Now let's take a look at the body/implementation -of the setup procedure and how you can use it to define test data structures -and, optionally, register unit tests. - -

    -Define test data structures

    -You should use the setup procedure to define data structures you -need in one or more of your tests. You might, for example, want to create -a temporary table to hold information for comparison. You might populate -a collection or a record a scalar global variable. -

    Here is an example of such a procedure (see the file ut_te_employee.pkb -in the Examples directory of the utPLSQL distribution for the full implementation): -

    PROCEDURE ut_setup
    -IS
    -BEGIN
    -   ut_teardown;
    -   EXECUTE IMMEDIATE 'CREATE TABLE ut_employee AS
    -         SELECT * FROM employee';
    -
    -   EXECUTE IMMEDIATE 'CREATE TABLE ut_DEL1 AS
    -         SELECT * FROM employee';
    -
    -   EXECUTE IMMEDIATE 'CREATE TABLE ut_DELBY_EMP_DEPT_LOOKUP AS
    -         SELECT * FROM employee';
    -END;
    -For each of my tests, I create a separate table to modify and then use -in my utAssert comparison. -

    You could place these statements in each of the individual unit test -procedures. The advantage of storing them all in the single setup procedure -is that they are easier to manage -- and also easier to tear down or destroy -when you are done. -

    -Manual registration of unit tests

    - -If you have decided to choose manual -registration of your unit test procedures, then you will need to register -each procedure with a call to utPLSQL.registertest -in the setup procedure. This is not recommended. But if you insist... - -Here is an example of a setup procedure for the -PLVdate package: - -
    CREATE OR REPLACE PACKAGE BODY ut_plvdate
    -IS
    -   PROCEDURE ut_setup
    -   IS
    -   BEGIN
    -      utplsql.addtest ('ut_to_date');
    -      utplsql.addtest ('ut_to_char');
    -   END;
    - -The names passed to the utPLSQL.addtest procedure -must match the interface of the defined unit test procedures -with the following interface. So the above two calls to addtest tell utPLSQL -to look for two unit test procedures named ut_to_date and ut_to_char. - -

    -Teardown Procedure

    - -The utPLSQL.test and utPLSQL.testsuite programs -will call the teardown procedure of your test package after it runs all -unit tests. Use this procedure to destroy or remove any data structures -that were needed for your units. The contents of this procedure should, -in general, be the logical reverse of the contents of the setup -procedure. The package specification header for this procedure must -be of this form: - -
    CREATE OR REPLACE PACKAGE <prefix><package>
    -IS
    -   PROCEDURE <prefix>teardown;
    - -where <prefix> is the unit test prefix and <package> -is the name of the package (or stand alone program) to be tested. - -The default naming convention is that your test -package and all utPLSQL programs, including the teardown procedure, have -a prefix of "ut_", as in: - -
    CREATE OR REPLACE PACKAGE ut_<program>
    -IS
    -   PROCEDURE ut_teardown;
    - -Note: if you are using manual -registration of unit tests (which is not the default setting -and is not recommeded), see Naming Conventions -for details on when and how to apply prefixes to your package and procedure -names. - -Now let's take a look at the body/implementation -of the teardown procedure and how you can use it to remove test data structures. - -Here is an example of the most common type of teardown -procedure -- it does nothing: - -
    CREATE OR REPLACE PACKAGE ut_sales_pkg
    -IS
    -   PROCEDURE teardown
    -   IS
    -   BEGIN
    -      NULL;
    -   END;
    - -This is what your teardown procedure will look like -when you do not need to create any special data structures for your tests. -If I were testing a simple string utility, for example, I do not need a -database table or collection to run my tests. Note that even if your teardown -procedure does nothing, it still must be present in the package specification -and body. utPLSQL will look for and try to execute the procedure as -part of its S.O.P. (standard operating procedure). - -Now, if your setup procedure creates something, -you should probably destroy it in teardown. You might drop or truncate -tables, do a ROLLBACK or simply make sure files and cursors are closed. -Here is an example of such a procedure: - -
    PROCEDURE teardown
    -IS
    -BEGIN
    -   mycollection.DELETE;
    -   EXECUTE IMMEDIATE 'TRUNCATE TABLE ' || workspace_tab;
    -   DBMS_SESSION.FREE_UNUSED_USER_MEMORY;
    -END;
    - -

    -The Unit Test Procedure

    - -The unit test procedure is, of course, where it -gets really interesting and very application specific. - -The general format for a test procedure is as follows: - -
    CREATE OR REPLACE PACKAGE <prefix><package>
    -IS
    -   PROCEDURE <prefix><program>;
    - -where <prefix> is the unit test prefix and <package> -is the name of the package (or stand alone program) to be tested. The default -naming convention is that your test package and the unit test procedure -each have a prefix of "ut_". You can override that prefix with another -of your own choosing in your call to utPLSQL.test -or utPLSQL.testsuite. Under some circumstances, you can drop -the prefix on the unit test procedure, but this is not recommended. see -Naming -Conventions. for details. - -Here is a very generic version of a unit test package -specification and a single unit test procedure: - -
    -- Test package for stand alone program
    -CREATE OR REPLACE PACKAGE ut_<package>
    -IS
    -   PROCEDURE ut_setup;
    -   PROCEDURE ut_teardown;
    -   PROCEDURE ut_<program>;
    -END;
    - -The body of your unit test procedure is, well, mostly -yours to figure out, since we don't know what you are testing and how you -need to test it. The basic format of this test procedure, however, should -be: - -
    PROCEDURE <myprogram>
    -IS
    -BEGIN
    -   <run package.myprogram or set up for test>
    -
    -   -- call a utAssert assertion to check results:
    -   utAssert.<assertion> (...);
    -
    -   <repeat of the above for different test cases>
    -EXCEPTION
    -   WHEN OTHERS
    -   THEN
    -      utAssert.this (
    -         'Unknown failure of <package.myprogram>: ' || SQLERRM,
    -         FALSE);
    -END;
    -You should include a call to a utAssert assertion program in the exception -section to trap unexpected errors and register a test failure (I pass FALSE -for the second argument, which guarantees a failure!). You might, of course, -have other handlers to trap specific exceptions like NO_DATA_FOUND and -either register a failure or ignore the exception, since it might not be -an actual test failure. -

    Here is an example of a unit test procedure that contains multiple calls -to assertion programs for different test cases. -

    PROCEDURE ut_BETWNSTR IS
    -BEGIN
    -   utAssert.eq (
    -      'Typical valid usage',
    -      BETWNSTR(
    -         STRING_IN => 'abcdefg'
    -         ,
    -         START_IN => 3
    -         ,
    -         END_IN => 5
    -         ),
    -      'cde'
    -      );
    -      
    -   utAssert.isnull (
    -      'NULL start',
    -      BETWNSTR(
    -         STRING_IN => 'abcdefg'
    -         ,
    -         START_IN => NULL
    -         ,
    -         END_IN => 5
    -         )
    -      );
    -
    -   utAssert.isnull (
    -      'NULL end',
    -      BETWNSTR(
    -         STRING_IN => 'abcdefg'
    -         ,
    -         START_IN => 2
    -         ,
    -         END_IN => NULL
    -         )
    -      );
    -      
    -   utAssert.isnull (
    -      'End smaller than start',
    -      BETWNSTR(
    -         STRING_IN => 'abcdefg'
    -         ,
    -         START_IN => 5
    -         ,
    -         END_IN => 2
    -         )
    -      );
    -      
    -   utAssert.eq (
    -      'End larger than string length',
    -      BETWNSTR(
    -         STRING_IN => 'abcdefg'
    -         ,
    -         START_IN => 3
    -         ,
    -         END_IN => 200
    -         ),
    -      'cdefg'
    -      );
    -      
    -END ut_BETWNSTR;
    -In the above case, I am testing a function, so I call the function "in -line" with the assertion program. When testing a procedure, you will call -the procedure first and then call the appropriate assertion program to -test the outcome. -

    Explore the Examples to learn about different -ways to write unit test procedures. -

    -Naming Conventions

    -When you execute a test or test suite, utPLSQL looks for a test package, -based on the name of the program you are testing. It then attempts to execute -specific programs within that package. utPLSQL allows you to test stand-alone -programs (procedure or function) or package-based programs. When testing -the contents of a package, you can place your unit test procedures in the -same -package or a separate test package. That's a lot of flexibility, and -flexibility generally leads to confusion. -

    To make things as simple as possible, the default mode of utPLSQL follows -this simple rule: - -

    Your unit test package and each utPLSQL-related program in that package -(setup, teardown and unit tests) must all use the same prefix. - -

    The default prefix is "ut_", but you can override that with your own. -If you follow this rule (and you can follow it very easily by using the -utGen -package to generate a starting point for your test packages), utPLSQL -

    If you are following the utPLSQL defaults and letting the utility automatically -detect and execute unit tests, do not read any further! -

    If you choose to perform manual -registration of your unit tests, then read the following sections carefully, -as there is a scenario in which you should not apply the utPLSQL -prefix to your unit test procedures. -

    This section describes the conventions or rules that utPLSQL follows -to locate and execute your unit tests. There are three different "scenarios" -to consider: -

    Separate test package to test package-based programs -

    Separate test package to test a stand-alone program -

    Single package containing both source to be tested and -unit test programs -

    While these rules might seem confusing at first glance, you will find -over time that they are designed to make the issue of what things are named -as transparent as possible when you run your tests. In other words, you -simply ask to test "mypackage"; you don't have to run some oddly-named -program with a prefix in front of it. -

    In addition, you can use the utGen package to -generate a starting point for your test packages. utGen will automatically -follow the rules; you only need to "fill in the blanks" of your unit test -procedures within the established headers. -

    -Separate test package to test package-based programs

    -If you are placing your unit test code in a package separate from your -source code (the default setting), then the name of that test package must -be of the form: -
    <prefix><package>
    -where <prefix> is the utPLSQL prefix and <package> is the name of -the package containing the programs to be tested. -

    You specify the prefix in one of the following ways: -

      -
    • -When you call utPLSQL.test or utPLSQL.testsuite, you can pass a value for -the prefix_in parameter (the default is "ut_").
    • - -When you call utPackage.add to add a package -to a suite, you can pass a value for the prefix_in parameter (the default -is "ut_"). This prefix is then stored in the ut_package table. -
    -The names of the test package programs, on the other hand, should not -have a prefix before them. These prefixes are not necessary to distinguish -the test procedure with the program being tested, since they are defined -in different packages. -

    -Separate test package to test a stand-alone program

    -If you are placing your unit test code in a package separate from your -source code (the default setting), then the name of that test package must -be of the form: -
    <prefix><program>
    -where <prefix> is the utPLSQL prefix and <program> is the name of -the stand-alone program you plan to test. -

    You specify the prefix in one of the following ways: -

      -
    • -When you call utPLSQL.test or utPLSQL.testsuite, you can pass a value for -the prefix_in parameter (the default is "ut_").
    • - -When you call utPackage.add to add a package -to a suite, you can pass a value for the prefix_in parameter (the default -is "ut_"). This prefix is then stored in the ut_package table. -
    -The names of the test package programs, on the other hand, also must have -the same prefix. This is necessary to avoid confusing naming conflicts -between the program you are testing and the name of the unit test procedure -for that program, as in the following package that tests the betwnstr function: -
    CREATE OR REPLACE PACKAGE ut_betwnstr
    -IS
    -   PROCEDURE ut_setup;
    -   PROCEDURE ut_teardown;
    -   PROCEDURE ut_betwnstr;
    -END ut_betwnstr;
    -/
    -I suppose that looks odd; I have created a function named ut_betwnstr.ut_betwnstr -and it would be very strange to write code like that. But that is the whole -point of utPLSQL: I don't have to write code like that. I just run -my test with nothing more than this: -
    SQL> exec utPLSQL.test ('betwnstr')
    - -

    -Single package containing both source to be tested and -unit test programs

    -Finally, there is the scenario in which a developer places all of her test -programs (setup, teardown and unit tests) in the same package as the code -to be tested. In this case, there is no separate test package, so all of -the test programs must use the utPLSQL prefix, as in: -
    CREATE OR REPLACE PACKAGE str
    -IS
    -   FUNCTION betwn (
    -      string_in IN VARCHAR2,
    -      start_in IN PLS_INTEGER,
    -      end_in IN PLS_INTEGER
    -   )
    -      RETURN VARCHAR2;
    -      
    -   PROCEDURE ut_setup;
    -   PROCEDURE ut_teardown;
    -   PROCEDURE ut_betwn;
    -      
    -END str;
    -/
    -You specify the prefix in one of the following ways: -
    -
  • -When you call utPLSQL.test or utPLSQL.testsuite, you can pass a value for -the prefix_in parameter (the default is "ut_"). When you call utPackage.add -to add a package to a suite, you can pass a value for the prefix_in parameter -(the default is "ut_"). This prefix is then stored in the ut_package table.
  • -
    - - -

    < Previous Section: Build Test Packages | Next Section: A "Test Run" with utPLSQL >

    -
    - - \ No newline at end of file diff --git a/website/Doc/index.html b/website/Doc/index.html deleted file mode 100644 index f8bbf4324..000000000 --- a/website/Doc/index.html +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - -Home - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    Next Section: Getting Started >

    - - -

    -Table of Contents

    - -

    -Welcome to utPLSQL - -a unit testing framework for the Oracle -PL/SQL Language

    - -

    -Getting Started

    - -
    This document tells you the minimum you need -to know in order to get started with utPLSQL: how to install the software, -build simple test packages, and run your tests.
    - -

    -Build Test Packages

    - -
    utPLSQL provides with you a framework in which -to run your tests. You still have to write your test code, and that code -must follow some rules if utPLSQL is going to know how to run those tests.
    - -

    -Examples

    - -
    There is no better way to learn how to build -and run utPLSQL test packages than to work from the many examples found -here.
    - -

    -User Guide

    - -
    Once you are familiar with utPLSQL basics, have -run some tests, and are ready to learn and use more of the many utPLSQL -features, the User Guide will tell you all you need to know about the different -features and programs of utPLSQL.
    - -

    -Release Notes

    - -
    Well, you know what these are: a description -of fixes and enhancements in the latest release!
    - -

    -Document Map

    - -
    The full list of the pages in the documentation
    - -

    The utPLSQL project is hosted at Sourceforge - the home page is to be -found at http://utplsql.sourceforge.net. From here, there are links to the various resources available and details on how to get involved in the project. Discussion of utPLSQL takes place at -the utPLSQL Forum, so to ask further questions, or for help with problems visit -http://utplsql.oracledeveloper.nl.

    - - -

    Next Section: Getting Started >

    -
    - - \ No newline at end of file diff --git a/website/Doc/map.html b/website/Doc/map.html deleted file mode 100644 index 2740b07c9..000000000 --- a/website/Doc/map.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - -Document Map - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: Release Notes

    -

    Document Map

    -Home
    -Getting Started
    -  Glossary and Requirements
    -  The Four Step Program to using utPLSQL
    -  Administrative Topics
    -Build Test Packages
    -  How to build a test package
    -  A "Test Run" with utPLSQL
    -Examples
    -  Test a Procedure
    -  Test a Function
    -  Test an Entire Package API
    -  Put Test Code in Same Package
    -  Use Non-Default Prefix
    -  Create and Run a Test Suite
    -User Guide
    -  utPLSQL Package
    -  utConfig Package
    -  utResult Package
    -  utAssert Package
    -  utGen Package
    -  utOutput Package
    -  utRecEq Package
    -  Defining Test Suites
    -  Custom Reporter Packages
    -  Configuring the File Reporter
    -Release Notes
    -Document Map
    -

    < Previous Section: Release Notes

    -
    - - \ No newline at end of file diff --git a/website/Doc/prefix.html b/website/Doc/prefix.html deleted file mode 100644 index 046837a33..000000000 --- a/website/Doc/prefix.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - -Use Non-Default Prefix - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: Put Test Code in Same Package | Next Section: Create and Run a Test Suite >

    - - -

    -Use Non-Default Prefix

    - -

    The default prefix for utPLSQL is "ut_", but you don't have to use that -prefix. There are some situations where you absolutely will not want to -use the default prefix. Suppose, for example, that you have written a package -with ten procedures, each of which already have "ut_" as a prefix -(it might stand for "Unified Technologies" or "Underside Treatment: or...well, -you get the picture). -

    Since this prefix is not hard-coded into utPLSQL, you can very easily -specify your own prefix. You can do this when you run a test, as in: -

    SQL> utPLSQL.test ('te_employee', prefix_in => 'test_');
    -You can also specify a prefix when you add a package to a test suite, as -in: -
    SQL> utPackage.add ('mysuite', 'mypackage' prefix_in => 'test_');
    -Of course, when you specify a non-default prefix, you must also build your -test package using that prefix. If you plan to generate a starting point -for your package with utGen, be sure to specify your prefix at that point, -as in: -
    SQL> utGen.testpkg('mypackage' prefix_in => 'test_');
    -For an example of a package with a non-default prefix, check out test_te_employee.pks -and test_te_employee.pkb (Both to be found in the Examples directory of the utPLSQL distribution). - - -

    < Previous Section: Put Test Code in Same Package | Next Section: Create and Run a Test Suite >

    -
    - - \ No newline at end of file diff --git a/website/Doc/release.html b/website/Doc/release.html deleted file mode 100644 index 87711a971..000000000 --- a/website/Doc/release.html +++ /dev/null @@ -1,654 +0,0 @@ - - - - - - - - -Release Notes - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: Configuring the File Reporter | Next Section: Document Map >

    - - -

    Release Notes

    - -

    Known Issues

    -

    utPLSQL version 2.x

    -
      -
    • There is an issue surrounding the use of utPLSQL on Oracle 8.1.7 where -the tests use database links. This is because Oracle will consider -the transaction to be distributed and utPLSQL v2 uses autonomous transactions -while the tests are running. This situation causes ORA-00164 in 8.1.7 -(and apparently should not have been allowed in 8.1.5 or 8.1.6 either). It -is possible to work around this problem by turning off autonomous transactions -, but this can cause other problems if the tests themselves have rollbacks -within them.
      -
    • -
    • The utAssert.eqtable assertion program will not work with tables that - contain non-scalar datatypes, such as LOBs, XMLType, collections and so on. -
    • -
    -

    Change History
    -

    -

    utPLSQL version 2.2

    -
      -
    • - This version introduces the concept of Output Reporters. The existing code to output to DBMS_OUPUT or to file has been refactored to - fit into this framework. As a result of this, the pl procedure in the utplsql package has been moved to the utreport package. -
    • -
    • -The installation procedure has been changed so that the database version is picked up more robustly. Version 2.2 works with 10g, -which previous versions did not. It should also work with future versions (so long as the version is to be found in the same place -in the data dictionary). -
    • -
    • -There are also a variety of small fixes in this release. -
    • -
    -

    utPLSQL version 2.1.1

    -
      -
    • -This version has a variety of small fixes and is released to coincide -with OUnit version 1.0. -
    • -
    • -The installation procedure has been changed and a variety of bugs with it have been fixed. -
    • -
    • -utGen.exe has been removed from the "core" utPLSQL distribution. The functionallity it supplied will be included in a future version of Ounit. -
    • -
    -

    utPLSQL version 2.0.10.1

    -
      -
    • -Allow user to specify (as part of their individual configuration) that they -only want to show failed tests, and then whether all information or just the -description (request from Heinz of UBS). Supersedes the -utresult.ignore_successes and utresult.include_successes (whose settings do not -persist across sessions). -
    • -
    • -Support for testing contents of REF CURSORs (cursor variables) has been added -(provided by Venky Mangapillai) with the eq_refc_table and eq_refc_query -assertion routines. -
    • -
    • -Adds testpkg_from_table to utgen to allow generation of a test package directly -from the new ut_grid table (provided by Patrick Barel). Patrick has also built -a Windows-based front end, utGen.exe, that allows us to populate this grid very -easily. Thanks, Patrick! -
    • -
    • -Add ut_outcome_seq sequence for ut_outcome table. -
    • -
    • -Add control_info and test_info columns to ut_outcome table. -
    • -
    • -Add ability to direct output from utPLSQL's test run (the test results) to a -file instead of to the screen. This functionality was provided by Rainer -Medert. The documentation for this feature has not yet been integrated into the -documentation set. You will find the "beta" documentation in the -file_output_spec.doc in the doc directory. -
    • -
    -

    utPLSQL version 2.0.9.2

    -
      -
    • Surround - AUTHID CURRENT_USER clause of utreceq.pks to allow for installation on - Oracle7 and Oracle8.
    • -
    • Add - override_package_in argument to utPLSQL.test so that you can bypass the - standard ut_<package> naming conventions for testing. This is useful - when your package name's length is 28 or above. By passing in the override - package name, you can avoid the name limitation.
    • -
    • New - assertion programs to validate DBMS_OUTPUT text that is generated from - within a program.
    • -
    • Add - utplsql.run and utplsql.runsuite to run a named test package directly, and - not correlate it via the name of the program being tested.
    • -
    -

    utPLSQL version 2.0.9.1

    - -
      - -
    • -Add ut_reqeq table and utreceq package to support the creation of "record -equal" functions (contributed by Dan Spencer).
    • - -
    • -Modify utPLSQL.test so that the record comparison functions are generated -and recompiled whenever the source code is recompiled. - Call utreceq.add to register a package-table combination. -
    • - -
    • -Modified utpackage.id_from_name to take an owner_in parameter with a -NULL default value. v_owner is set to nvl(owner_in,user). added -owner = v_owner and suite_id is null to the WHERE clause.
    • - -
    • -Modified utpackage.add to add in a record with suite_id NULL if one -doesn't exist.
    • - -
    • -Modified utpackage.upd - changed parameter suite_in to suite_id_in (the -type was INTEGER). Changed the UPDATE WHERE clause first line -to NVL(suite_id,0) = NVL(suite_id_in,0).
    • - -
    • -Modified utplsql.testsuite - v_suite (the suite id) was in the -call to utplsql.test while the utplsql.test parameter list was expecting -the suite name. The results of a test run are now logged to the -appropriate record in ut_package [the record for the suite if run from -testsuite, the record with suite_id NULL if run via an EXEC UTPLSQL.TEST('packagename')].
    • - -
    • -Add objExists and objNotExists assertion programs
    • - -
    • -Changes to utPLSQL.test engine so that you can test programs define -in one schema from another schema.
    • - -
    • -Add previous_passed and previous_failed to utAssert and utAssert2
    • - -
    • -Set order in which test case results are displayed to the order in which -they are run by adding the tc_run_id to the utr_outcome table.
    • - -
    - -

    utPLSQL version 2.0.8.2

    - -
      - -
    • -Change ut_utp LOB column to VARCHAR2 for the time being.
    • - -
    • -Fixed ALTER TABLE statement in ut_config.tab.
    • - -
    • -Change utplsql.test to allow for compilation of test package before -extracting list of test procedures from that package (avoids the " -Warning...no tests were identified for execution!" message).
    • - -
    • -Add utAssert2.eval generic comparison program, and also utAssert.eval, -with an overloading for just two values, to make it really easy to use.
    • - -
    • -Add utGen.receq_package procedure. It currently ONLY writes the code -out to the screen via DBMS_OUTPUT.PUT_LINE. It does not, in other words, -support the multiple outputs of utGen.testpkg.
    • - -
    • -Update the utplsql_install.sql script to recognize Oracle9.0 and Oracle9.1 - versions and install all 8i features for those versions (there is nothing - specific to 9i at this time).
    • - -
    - -

    utPLSQL version 2.0.8.1

    - -
      - -
    • -Fixes to a number of minor installation errors.
    • - -
    • -Offers option in utPLSQL.test to request that setup and teardown is -executed with each test procedure and not the test package level. -Implements a new features in utPLSQL.test that allows you to specify -that you want to run the setup and teardown procedures before and after -EACH unit test procedure, as opposed to running them once for the unit -test package as a whole. To utilize this feature, simply pass a value -of TRUE to the new per_method_setup_in parameter of utPLSQL.test as -shown below:
    • - -
    - -

    -SQL> exec utplsql.test ('str', per_method_setup_in => true)
    -

    - -

    utPLSQL version 2.0.7

    - -
      -
    • Revamp -utAssert2.define_message implement to simplify creation of new assertion -programs
    • - -
    • Modify -implementation if ieqminus to avoid duplicate column
    • - -
    • Change -naming conventions for utPLSQL2 from prefix to delimiter driven (utconfig.delimiter): -QU##NNN. This affects only those test packages which use the utPLSQL2.test -program to run the tests (ie for version 1 utPLSQL test packages and utPLSQL.test, -you can still use your prefix-based approaches).
    • - -
    • Add -utAssert2.fileExists
    • - -
    • Compile -utAssert2 with AUTHID CURRENT_USER for Oracle8i and above.
    • - -
    • (2.0.7.2) -Fix index creation for ut_assertion table.
    • - -
    • (2.0.7.2) -Fix foreign key definition in ut_argument.
    • - -
    • (2.0.7.2) -Fix foreign key definition in uta_eq.
    • -
    - -

    utPLSQL version 2.0.6

    - -
      -
    • Fix -to utgen.pkb to allow generation of procedure bodies when no grid is used.
    • - -
    • Allow -developers to turn off display of successful results (utResult.include_successes)
    • -
    - -

    utPLSQL version 2.0.5

    - -
      -
    • Allow -user to specify individual program or programs (via wildcard) to be tested -from a whole package.
    • - -
    • Add -ut_deterministic and ut_deterministic_arg tables to facilitate generate of -test packages for deterministic functions.
    • - -
    • Add -ut_deterministic.fmx Oracle Forms GUI to allow easy generation of test packages -for deterministic functions.
    • -
    - -

    utPLSQL version 2.0.4

    - -
      -
    • Implement -test suite execution in utPLSQL2.
    • - -
    • Implement -ut_suite_utp table (and the corresponding utsuiteutp package) as an intersection -of ut_suite and ut_utp, defining all those UTPs in a given suite.
    • - -
    • Improved -error handling with utrerror assertions and general reporting mechanisms. -Assertion and error handling logic applied to define-time packages like utsuite -and utsuiteutp.
    • - -
    • Revamp -installation process; no longer use OraShare, remove testcase2 entirely. -
    • - -
    • Create -stand alone utverify procedure.
    • -
    - -

    utPLSQL version 2.0.3

    - -
      -
    • Add -utr_error table and utrerror package; now all errors are logged to the table -for viewing afterwards. utPLSQL NEVER passes back an unhandled exception -to the console.
    • - -
    • utAssert.eqfile -now flags problems when opening files.
    • -
    - -

    utPLSQL version 2.0.2

    - -
      -
    • -clarify how that null_ok_in is supposed to work. For utAssert.this, it should -mean that if the value of the Boolean expression coming in is null, then -that means "success". For eq, it shoudl mean that if BOTH values coming in -are NULL, that is "success". For eqfile, if both files are empty...etc.
    • - -
    • -add null_ok_in to eqqueryvalue assertions.
    • - -
    • -add utassert.eqqueryvalue for NUMBER
    • - -
    • -Enhance utgen to properly generate code for overloaded programs in packages
    • -
    - -

    utPLSQL version 2.0.1

    - -
      -
    • -store results in utr_outcome tables
    • - -
    • -support results reporting compatibility with V1
    • - -
    • -display results of all test, success and failure.
    • -
    - -

    utPLSQL version 1.5.6

    - -
      - -
    • -New version of documentation courtesy of Chris Rimmer. Thanks, Chris!
    • - -
    • -utAssert fix in eqcoll to check for both values being null.
    • - -
    • -Enhancements to utGen to generate more self-explanatory code; comments -are now inserted to show the different sections in a standard test case -sequence.
    • - -
    • -Revamped installation procedure based on OraShare utility.
    • - -
    • -Add utGen.testpkg overloadings and new programs to support passing of -argument grids via collection, file or string (this feature is currently -undocumented outside of the release notes).
    • - -
    - -

    utPLSQL version 1.5.5

    - -

    Bug Fixes

    - -
      - -
    • -Change calls from DBMS_OUTPUT.PUT_LINE to utPLSQL.pl to avoid output -errors.
    • - -
    • -Avoid use of DBMS_SQL to obtain sequence values for Oracle7 and Oracle8 -installations of utPLSQL.
    • - -
    - -

    Enhancements

    - -
      - -
    • -Addition of utConfig package (created and integrated by Chris Rimmer) -to isolate all tester configuration information.
    • - -
    - -

    utPLSQL version 1.5.4

    - -

    Bug Fixes

    - -
      -
    • - utPLSQL.setconfig now sets the user information properly when -the package is first initialized (bug introduced in 1.5.3). -
    • -
    - -

    utPLSQL version 1.5.3

    - -

    Documentation and Usage Changes

    - -
      - -
    • -If you choose to manually register your tests with calls to utPLSQL.addtest -in your setup procedure, you must now INCLUDE the unit test prefix, -as in:
    • - - -
      utPLSQL.addtest ('ut_betwnstr');
      - -utPLSQL -will no longer add the prefix for you. This means that you may need to change -your calls to addtest -- or remove them entirely and rely on auto-registration. -
    - -

    -Bug Fixes

    - -
      - -
    • -Auto-registration (using the ALL_ARGUMENTS data dictionary view) now -correctly ignores the setup and teardown procedures.
    • - -
    - -

    -Enhancements

    - -
      - -
    • -If no tests are run for the specified program, then a warning is displayed, -after which the SUCCESS message is displayed.
    • - -
    - -

    -utPLSQL version 1.5.2

    - -

    -Bug Fixes

    - -
      - -
    • -Fix setting of default prefix value in utPLSQL.pkb.
    • - -
    • -If you request execution of a test suite that does not exist, that failure -will be reported.
    • - -
    • -If you request execution of a test for a program or package that does -not exist, that failure will be reported.
    • - -
    • -Unique index on ut_package changed to allow multiple entries for same -package, in different suites.
    • - -
    - -

    -Known Problems

    - -
      - -
    • -When running a suite of test packages, the SUCCESS and FAILURE headers -will display for each package, and not for the overall suite.
    • - -
    - -

    -Enhancements

    - -
      - -
    • -The utAssert package now offers isnull and isnotnull assertions overloaded -for Boolean values..
    • - -
    - -

    -utPLSQL version 1.5.1

    - -

    -Support for Oracle7.3, Oracle8 and Oracle8i

    - -

    -utPLSQL can now be used on any version of Oracle from 7.3.4 and above! The -installation script automatically detects your Oracle RDBMS version and adjusts -the code accordingly (Using a great SQL*Plus trick, courtesy of Vladimir -Trusevich; check out the references to &start81 and &start73 in the -source code, as well as the queries in code.sql, to get a sense of how we -can maintain a single base of code for all these versions!).

    - -

    -There are some differences in how the code works:

    - -
      - -
    • -In Oracle8i, the autonomous transaction feature is used to immediately -COMMIT any changes to underlying utPLSQL tables (such as defining a -test suite). In earlier versions, no COMMITs are performed by utPLSQL.
    • - -
    - - -

    -In Oracle8i, the Invoker Rights model is used to allow all of utPLSQL code -to run under the authority of the invoker, not the owner/definer. In earlier -versions, the Definer Rights model is followed. So if you define utPLSQL -in a central schema and then share it with others via GRANTs and synonyms, -you may need to grant additional authority to the utPLSQL schema.

    - - -

    -Stores Additional Configuration Information

    - -

    -When you set the directory for your test code (through a call to -utPLSQL.setdir -, utPLSQL.test or utPLSQL.testsuite), that value is stored in the uPLSQL -configuration table (ut_config). It will be used for current and future sessions -as the default, until you change it.

    - -

    -The prefix you specify in calls to utPLSQL.setprefix -, utPLSQL.test or utPLSQL.testsuite will also be saved in the uPLSQL configuration -table. It will be used for current and future sessions as the default, until -you change it.

    - -

    -Shows All Configuration Information

    - -

    -Call the utPLSQL.showconfig - procedure to display all of the stored configuration values for the specified -schema.

    - -

    -utPLSQL version 1.4.1

    - -

    -Automatic Test Registration

    - -

    -You no longer have to manually register -your unit test procedures - in the setup procedure. Instead, utPLSQL will (in default mode) read and -execute the list of public procedures and functions from the ALL_ARGUMENTS -data dictionary view that conform to utPLSQL naming conventions. This enhancement -makes utPLSQL much easier and simpler to use than before. Simply use the -designated prefix (default being "ut_") on your program names, and they will -be executed.

    - -

    -Improved error handling and reporting

    - -

    -Rather than display a small, easily missed test result, as in :

    - -
    SUCCESS: PLVstr
    - -

    -utPLSQL now displays a much more noticeable (though still lacking in -colors, as in red for failure and green for success) display of the "big -picture", as in:

    - -
    SQL> exec utplsql.test ('str', dir_in=>'e:\openoracle\utplsql\utinstall\examples')
    -.
    ->    SSSS   U     U   CCC     CCC   EEEEEEE   SSSS     SSSS
    ->   S    S  U     U  C   C   C   C  E        S    S   S    S
    ->  S        U     U C     C C     C E       S        S
    ->   S       U     U C       C       E        S        S
    ->    SSSS   U     U C       C       EEEE      SSSS     SSSS
    ->        S  U     U C       C       E             S        S
    ->         S U     U C     C C     C E              S        S
    ->   S    S   U   U   C   C   C   C  E        S    S   S    S
    ->    SSSS     UUU     CCC     CCC   EEEEEEE   SSSS     SSSS
    -.
    - SUCCESS: "str"
    - -

    -utPLSQL version 1.3.2

    - -

    -Improved Statistics Recording

    - -

    -utPLSQL will now record the status of the last test run in the ut_package -and ut_suite tables. It also correctly updates those tables with a count -of executions and failures. Finally, it is no longer necessary to define -your package in and run it from a test suite for results to be recorded. -

    - -

    -New Assertions and Assertion Features

    - -

    -utAssert now offers assertion routines that allow you to easily validate -the contents of PL/SQL collections (index-by tables, nested tables and varying -arrays) by running either the utassert.eqcoll -or utassert.ecollAPI - assertions.

    - -

    -You can also now request that utAssert show the -results of a test immediately - after execution. This allows you to build small test scripts without have -to create a test package and run it through the utPLSQL test engine.

    - -

    -Bug Fixes

    - -

    -Generally, error handling is now improved, particularly for compile errors -on test packages and modifications to underlying tables, such as ut_package. -

    - -

    -When a test has been completed, utPLSQL clears out the results information. -

    - - -

    < Previous Section: Configuring the File Reporter | Next Section: Document Map >

    -
    - - \ No newline at end of file diff --git a/website/Doc/reporter.html b/website/Doc/reporter.html deleted file mode 100644 index 21db1dabb..000000000 --- a/website/Doc/reporter.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - -Custom Reporter Packages - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: Defining Test Suites | Next Section: Configuring the File Reporter >

    - - -

    Custom Reporter Packages

    -

    Generally, the default output provided by utPLSQL is sufficient. This -just writes to the screen using DBMS_OUTPUT. If you are running it -interactively while doing some development, you just need to know if the tests -are passing and details of the failing tests. -However, there are cases where you'd like the results to be reported in a -different format, especially when the tests are being run in batch mode. To -support this, utPLSQL has the concept of Reporter Packages. utPLSQL is -distributed with the following reporter packages as standard:

    - - - -The naming convention is that reporter packages are called -UT<NAME>REPORTER. To set which reporter is used, you will -need to call utConfig.Setreporter, passing the name of the reporter. -To use the HTML reporter for example, you should issue the following command: -
    BEGIN
    -   utConfig.setreporter('HTML');
    -END; 
    - -For more details of how to develop your own custom -reporter package, see below. - -

    Output Reporter

    - -

    Contained in the UTOUTPUTREPORTER package, this simply encapsulates the -standard behaviour, whereby the output is written out to DBMS_OUTPUT. When a -problem occurs with another reporter, utPLSQL will automatically fall back on -this mechanism to report problems. This means it is wise to have DBMS_OUTPUT -enabled even if you are using another output method.

    - -

    File Reporter

    - -

    This reporter, contained in the UTFILEREPORTER package, writes test results -out to a file. For details on how to configure this process, see the details -which can be found here. This functionality was -available before version 2.2 of utPLSQL, but has now been moved into its own -package.

    - -

    HTML Reporter

    - -

    The package UTHTMLREPORTER is really just an example package to be used as -a basis for your own custom reporters. It builds on the filereporter described above to -send results to a file. The difference is that the results are presented in a (rather crude) -HTML table.

    - -

    Writing your own Reporter

    - -

    To define your own reporter package you need it conform to a particular API. The various -procedures are then registered as 'callbacks' for utPLSQL to use. -An example package spec is given below. -

    -CREATE OR REPLACE PACKAGE utMyRssReporter
    -IS
    -
    -   PROCEDURE open;
    -   PROCEDURE pl (str IN VARCHAR2);
    -   
    -   PROCEDURE before_results(run_id IN utr_outcome.run_id%TYPE);
    -   PROCEDURE show_failure;
    -   PROCEDURE show_result;
    -   PROCEDURE after_results(run_id IN utr_outcome.run_id%TYPE);
    -   
    -   PROCEDURE before_errors(run_id IN utr_error.run_id%TYPE);
    -   PROCEDURE show_error;
    -   PROCEDURE after_errors(run_id IN utr_error.run_id%TYPE);   
    -   
    -   PROCEDURE close;
    -
    -END utMyRssReporter;
    -/
    -
    -

    -Your reporter package can define other functions and procedures, for example to allow configuration, but all the procedures shown above should be defined. -The usage of these procedures follows. Note If you want to keep the -format of the output the same as for the Output Reporter, but wish to send -it elsewhere, you can define open, close and pl, but simply call the equivalent -procedure in utOutputReporter for the others. For an example of this, see the File Reporter. -

    open

    -

    This is called at the very start of the process and is the ideal place to do initialization, such as opening any files that you will be writing to.

    - -

    pl

    -

    This is a general routine to simply write out the given string for purposes of logging etc. -If you don't want this to show up in your output, you can simply call utoutputreporter.pl to send this to DBMS_OUTPUT instead.

    - -

    before_results

    -

    As the name suggests, this is called before the results are output. Note that the tests have already completed at this point, -so it is possible to call utresult.success (run_id) to determine if the run was a success or not and display a large banner.

    - -

    show_failure

    -

    This is called when a failure is reported and we are only showing failures (i.e. utconfig.showfailuresonly has been set). -To get details of the failure, you will need to examine the package level record utreport.outcome.

    - -

    show_result

    -

    This is called whenever a result is reported and we are showing all results. To get details, you will need to examine utreport.outcome. See below for details.

    - -

    after_results

    -

    This is called after all the results have been sent for output.

    - -

    before_errors

    -

    This is called before any errors are sent for output.

    - -

    show_error

    -

    This is called for each error to output. To get details, you will need to examine the package level record utreport.error. See below for details.

    - -

    after_errors

    -

    This is called after any errors have been sent for output.

    - -

    Outcome and Error records

    -

    In order to keep the API as simple as possible, many of the procedures defined above take no parameters. In particular, details of the outcome or error which -triggered the callback are not passed through to your procedure. These are stored as package level records in the utReport package as shown below. - -

    outcome utr_outcome%ROWTYPE;
    -error utr_error%ROWTYPE;
    - -The important fields in the outcome record are: -
      -
    • status - This is a string which is either "SUCCESS" or "FAILURE" depending on the outcome of this test.
    • -
    • description - The text describing the success or failure.
    • -
    - -The important fields in the error record are: -
      -
    • errlevel - The Error Level
    • -
    • errcode - The Error Code
    • -
    • errtext - The Description of the error that occurred
    • -
    -

    - -

    Using Your Custom Reporter

    -To use your custom reporter, you simply call utConfig.Setreporter with the name of your reporter. So if -you have defined your reporter in the utMyRssReporter package, you need to call: - -
    BEGIN
    -   utConfig.setreporter('MyRss');
    -END; 
    - -Then you just run your tests as usual and hopefully your reporter will format the results as you expect. - -

    Sending output to the current reporter

    -If you wish to send output to the current reporter, for example, for logging purposes, you should call utReport.pl. -This is part of the utReport package, which acts as a facade and passes any calls through to the current reporter package. -So if you have set up a custom reporter package 'utMyRssReporter' as shown above and called utConfig.setreporter('MyRss'), -any calls such as the following: - -
    BEGIN
    -  utReport.pl('Logging Message');
    -END;
    - -will be equivalent to - -
    BEGIN
    -  utMyRssReporter.pl('Logging Message');
    -END;
    - - -

    < Previous Section: Defining Test Suites | Next Section: Configuring the File Reporter >

    -
    - - \ No newline at end of file diff --git a/website/Doc/samepack.html b/website/Doc/samepack.html deleted file mode 100644 index 86cebc6de..000000000 --- a/website/Doc/samepack.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - - -Put Test Code in Same Package - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: Test an Entire Package API | Next Section: Use Non-Default Prefix >

    - - -

    -Put Test Code in Same Package

    - -

    In some cases (usually when your packages are small and the code you -need to write to construct your tests is also constrained), you will not -want to bother with creating a separate package to test your code. To do -this, you will put the setup, teardown and unit test procedures inside -the package specification and body. We look at two examples: -

    - -

    - - Testing a simple string function

    -Suppose I have my basic sting package, containing (for now at least) just -a single function: -
    /*file str.pks */
    -CREATE OR REPLACE PACKAGE str
    -IS
    -   FUNCTION betwn (
    -      string_in IN VARCHAR2,
    -      start_in IN PLS_INTEGER,
    -      end_in IN PLS_INTEGER
    -   )
    -      RETURN VARCHAR2;
    -END str;
    -/
    -Now it is time to test the function. I really don't want to bother with -a separate package; let's keep it together. To do this, I change the specification -to: -
    CREATE OR REPLACE PACKAGE str
    -IS
    -   FUNCTION betwn (
    -      string_in IN VARCHAR2,
    -      start_in IN PLS_INTEGER,
    -      end_in IN PLS_INTEGER
    -   )
    -      RETURN VARCHAR2;
    -      
    -   PROCEDURE ut_setup;
    -   PROCEDURE ut_teardown;
    - 
    -   -- For each program to test...
    -   PROCEDURE ut_betwn;
    -      
    -END str;
    -/
    -The package body contains nothing unusual; it is the same test for str.betwn -that you can find in the Testing -a Scalar Function example. But when I execute my test, I need to tell -utPLSQL that my test code is located in the same package: -
    SQL> exec utconfig.showconfig
    -=============================================================
    -utPLSQL Configuration for SCOTT
    -   Directory: e:\openoracle\utplsql\utinstall\examples
    -   Autcompile? Y
    -   Manual test registration? N
    -   Prefix = ut_
    -=============================================================
    -
    -PL/SQL procedure successfully completed.
    -
    -SQL> exec utPLSQL.test ('str', samepackage_in => TRUE)
    -.
    ->    SSSS   U     U   CCC     CCC   EEEEEEE   SSSS     SSSS
    ->   S    S  U     U  C   C   C   C  E        S    S   S    S
    ->  S        U     U C     C C     C E       S        S
    ->   S       U     U C       C       E        S        S
    ->    SSSS   U     U C       C       EEEE      SSSS     SSSS
    ->        S  U     U C       C       E             S        S
    ->         S U     U C     C C     C E              S        S
    ->   S    S   U   U   C   C   C   C  E        S    S   S    S
    ->    SSSS     UUU     CCC     CCC   EEEEEEE   SSSS     SSSS
    -.
    - SUCCESS: "str"
    - -

    - Testing the population of a collection

    -Collections are very useful structures, but they can be difficult to analyze -and compare. utPLSQL provides the utAssert.eqColl and utAssert.eqCollAPI -programs to help you do this. -

    For this example, consider the fileIO package: it implements a path -feature for the UTL_FILE package. In other words, you request to open a -file and your file-opening program will search through each of the directories -in the path in sequence until it finds the file or exhausts the list. Here -is the specification of this package: -

    /*file filepath1.pkg */
    -CREATE OR REPLACE PACKAGE fileIO
    -IS
    -   c_delim CHAR(1) := ';';
    -   
    -   dirs dirs_tabtype := dirs_tabtype ();
    -   
    -   -- Unit test list
    -   ut_dirs dirs_tabtype := dirs_tabtype ();
    -   
    -   PROCEDURE setpath (str IN VARCHAR2, delim IN VARCHAR2 := c_delim);
    -   FUNCTION path RETURN VARCHAR2;
    -   FUNCTION pathlist RETURN dirs_tabtype;
    -
    -   FUNCTION open (file IN VARCHAR2, loc IN VARCHAR2 := NULL) RETURN UTL_FILE.FILE_TYPE;
    -   
    -   -- Unit test code in same package
    -   PROCEDURE ut_setup;
    -   PROCEDURE ut_teardown;
    -   PROCEDURE ut_setpath;
    -END;
    -/
    -A few things to notice about this package: -
      -
    • -It declares a publicly available collection, fileIO.dirs, in which the -path is deposited. Because it is declared in the package specification, -I can use the utAssert.eqColl procedure (if the collection was hidden in -the package body, I would have to use utAssert.eqCollAPI).
    • - -The test code is in the same package: the setup, -teardown and test pogram for fileIO.setpath. - -I declare a second, publicly available collection, -fileIO.ut_dirs, against which I will compare the path that is populated -by fileIO.setpath. -
    -Given that, let's take a look at the implementation of the test program: -
    PROCEDURE ut_setpath
    -IS
    -BEGIN
    -   /* Populate base collection */
    -   ut_dirs.DELETE;
    -   
    -   ut_dirs.EXTEND(2);
    -   ut_dirs(1) := 'c:\temp';
    -   ut_dirs(2) := 'e:\demo';
    -   
    -   /* Call setpath to do the work */
    -   setpath ('c:\temp;e:\demo');
    -   
    -   utAssert.eqColl (
    -      'Valid double entry',
    -      'fileio.dirs',
    -      'fileio.ut_dirs'
    -      );
    -END;
    -This program consists of three steps: -
    -
  • -Populate the test collection with direct assignments. Call the setPath -program to populate the actual collection (fileIO.dirs). Call the assertion -program to compare the two. Notice that I pass the names of the -collections to the assertion program. utAssert uses dynamic SQL to build -a PL/SQL block "on the fly" that compares values from the collections.
  • -
    - - -

    < Previous Section: Test an Entire Package API | Next Section: Use Non-Default Prefix >

    -
    - - \ No newline at end of file diff --git a/website/Doc/started.html b/website/Doc/started.html deleted file mode 100644 index 31ec12b8a..000000000 --- a/website/Doc/started.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - -Getting Started - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: Home | Next Section: Glossary and Requirements >

    - - -

    -Getting Started

    - -

    This document gives you all the information you need to get started -with utPLSQL: how to install the product, build a test package and run -your test. If you are new to unit testing, you should take a few moments -to review the Glossary to familiarize yourself with the terminology. -

    And it is always worthwhile reviewing requirements before installing -the software! -

    -What is utPLSQL and what do I need?

    - -
    -

    -Glossary

    - -

    -Requirements

    -
    - -

    -The Four Step Program to Using utPLSQL

    - -
    -

    -Step 1. Install utPLSQL.

    - -

    -Step 2. Choose a program to test and identify -the test cases.

    - -

    -Step 3. Build a test package.

    - -

    -Step 4. Run your test.

    - -

    -Where -To Go From Here

    -
    - -

    -Administrative Topics

    - -
    -

    -Configuring UTL_FILE

    - -

    -Join the Project Team

    - -

    -Reporting Bugs and Enhancement Requests

    - -
    - -

    < Previous Section: Home | Next Section: Glossary and Requirements >

    -
    - - \ No newline at end of file diff --git a/website/Doc/suite.html b/website/Doc/suite.html deleted file mode 100644 index f766e7d81..000000000 --- a/website/Doc/suite.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - -Create and Run a Test Suite - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: Use Non-Default Prefix | Next Section: User Guide >

    - - -

    -Create and Run a Test Suite

    - -

    Usually our applications are composed of multiple packages. To test -our application, we must test all of the packages. utPLSQL makes it easier -for you to do that by offering test suites. -

    Here is an example of a script that defines a (partial) test suite for -PL/Vision, a code library available from RevealNet -as part of its Active PL/SQL Knowledge Base: -

    /*file plvision.tst */
    -BEGIN
    -   -- Define a test suite for PL/Vision
    -   utsuite.add ('PLVision');
    -   
    -   -- Add packages for testing
    -   utpackage.add (
    -      'PLVision', 'PLVstr', dir_in => 'e:\openoracle\utplsql\examples');
    -   utpackage.add (
    -      'PLVision', 'PLVdate', dir_in => 'e:\openoracle\utplsql\examples');
    -END;   
    -/
    -This is a very simple test suite definition. I rely on all defaults, but -I specify a location for my test package code. By doing this, utPLSQL will -be able to find my test packages even if the default/current utPLSQL directory -is set to another location. -

    If I want to, I can also specify the order in which packages are tested -by passing a value for the seq_in argument. I can request that the test -code be looked for in the same package as the source code, and so on. Here -is a rewriting of the above sutie creation script that demonstrates these -options: -

    BEGIN
    -   utsuite.add ('PLVision');
    -
    -   utpackage.add ('PLVision',
    -      'PLVstr',
    -      dir_in => 'e:\openoracle\utplsql\examples',
    -      seq_in => 1,
    -      samepackage_in => TRUE
    -   );
    -
    -   utpackage.add ('PLVision',
    -      'PLVdate',
    -      dir_in => 'e:\openoracle\utplsql\examples',
    -      seq_in => 2,
    -      samepackage_in => TRUE
    -   );
    -END;
    -/
    - - -

    < Previous Section: Use Non-Default Prefix | Next Section: User Guide >

    -
    - - \ No newline at end of file diff --git a/website/Doc/testapi.html b/website/Doc/testapi.html deleted file mode 100644 index 59748c164..000000000 --- a/website/Doc/testapi.html +++ /dev/null @@ -1,294 +0,0 @@ - - - - - - - - -Test an Entire Package API - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: Test a Function | Next Section: Put Test Code in Same Package >

    - - -

    -Test an Entire Package API

    - -

    Most packages consist of lots more than a single program, and you will -generally want to test each and every of the programs listed in the package -specification. When you generate a test package with utGen, -it will produce a template unit test procedure for each program in the -package specification. You will then need to modify each of these programs. -

    One example of this more complex package structure is the table encapsulation -package. This kind of package establishes a layer of code and therefore -control between application requirements and underlying data structures. -While the building of such a layer is uncommon in the world of PL/SQL developers, -it is strongly recommended practice. A variety of tools, in fact, offer -automated table encapsulation package generation, including Oracle -Designer, RevealNet's PL/Generator -and a variety of IDE (integrated development environment) tools. -

    Suppose, then, that I used PL/Generator to generate a table encapsulation -package for the employee table. It would look like the code found in te_employee.pks -and te_employee.pkb(1) (being rather -lengthy, we will not reproduce it in the documentation. If you take a look, -you will see that their are dozens of programs in the API, which means -that you would have lots of work to do in building your unit test cases. -In addition, many of the programs will be performing DML operations (updating, -deleting, inserting). How you can easily and dependably test those programs? -

    When you are dealing with lots of programs that have a uniform structure -and behavior (which should be the case if you are building table -API packages), then you should look for ways to generate, rather -than write manually, your test package. utGen cannot do this generation -work for you, since the logic in your encapsulation package is specific -to your environment. -

    You can, instead, build your own custom generator or use an existing -generator that is sufficiently flexible to meet your needs. The original -creator of utPLSQL, Steven Feuerstein, -has also been working on generator utilities for a number of years. One -of these utilities, currently "code named" GenX, came in very handy for -creating a test package for his PL/Generator-generated encapsulation packages. -

    Using CGML (Code Generation Markup Language), Steven created a template -(See te_utpkg.gdr in the Examples directory of the utPLSQL distribution) -that reads information from the data dictionary and defines the setup, -teardown and at least a good starting point for the unit test procedures. -Here is the template logic for the setup procedure: -

       PROCEDURE {utprefix}setup
    -   IS
    -   BEGIN
    -      -- Clean start
    -      {utprefix}teardown;
    -[ASIS]   
    -      -- Generic copy of base table for testing 
    -      EXECUTE IMMEDIATE 
    -         'CREATE TABLE {tabprefix}[objname] AS
    -            SELECT * FROM [objname]';
    -            
    -[ENDASIS]   
    -   [FOREACH]prog
    -   [IF]{allprogs}[EQ]Y[OR][progname][LIKE]UPD%[OR][progname][LIKE]INS%[OR][progname][LIKE]DEL%
    -      -- Create copy of base table for this unit test.
    -      EXECUTE IMMEDIATE 
    -         'CREATE TABLE ^{progtab}^ AS
    -[ASIS]   
    -            SELECT * FROM [objname]';
    -[ENDASIS]   
    -            
    -   [ENDIF]
    -   [ENDFOREACH]
    -   END;
    -You are not, of course, expected to understand all the logic and syntax -in this fragment. If you are interested in pursuing these sorts of genreation -opportunities and would like to check out GenX, drop a note to Steven -Feuerstein. -

    Here is a portion of the generated logic (found in ut_te_employee.pks -and ut_te_employee.pkb"(1)), the -program that tests the delete operation in the encapsulation package: -

       PROCEDURE ut_del1
    -   IS
    -      fdbk PLS_INTEGER;
    -   BEGIN
    -      /* Delete that finds now rows. */
    -
    -      EXECUTE IMMEDIATE '
    -      DELETE FROM ut_DEL1
    -       WHERE employee_id = -1
    -      ';
    -      te_employee.del (-1, rowcount_out => fdbk);
    -      -- Test results
    -      utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1');
    -      /* Successful delete */
    -
    -      EXECUTE IMMEDIATE '
    -      DELETE FROM ut_DEL1
    -       WHERE employee_id between 7800 and 7899
    -      ';
    -
    -      FOR rec IN (SELECT *
    -                    FROM employee
    -                   WHERE employee_id BETWEEN 7800 AND 7899)
    -      LOOP
    -         te_employee.del (
    -            rec.employee_id,
    -            rowcount_out => fdbk
    -         );
    -      END LOOP;
    -
    -      -- Test results
    -      utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1');
    -      ROLLBACK;
    -   EXCEPTION
    -      WHEN OTHERS
    -      THEN
    -         utassert.this (
    -            'DEL1 exception ' || SQLERRM,
    -            SQLCODE = 0
    -         );
    -   END;
    -In this procedure, I test for two scenarios: a delete that removes zero -rows and a delete that removes a specific set of rows. In both cases, I -perform the explicit (non-encapsulated) DML logic against a copy -of the actual table (this copy is created in the setup -procedure; that is the reason I use dynamic SQL to refer to this table --- it doesn't exist when the package is compiled!). Then I do the (hopefully) -same operation by using the API program. Finally, I call the appropriate -utAssert assertion program to compare the results -- and at the end of -the procedure issue a ROLLBACK so that my "source" table (employee, in -this case), i set back to the original data state. Notice that I also put -an assertion program in the exception section to trap any errors and flag -it as a failed test. -

    That should give you a good feel for the kind of code you might write -to test a table encapsulation package. The next two sections show you how -I used the setup and teardown procedures to manage the data structures -I use in my tests. -

    -Set Up Data Structures

    -As I contemplated how best to test these large packages, I revisited some -of my testing principles and found one to be of particular importance: - -

    Build isolated tests. - -

    This principle is important because it allows you to run one, all or -a subset of your tests without having to worry about the impact or dependencies -on the other tests. And test isolation is particularly important -when testing DML operations. The way to validate a successful DML operation -is by analyzing the contents of the "source" table against a "test" table. -If all the tests modify the same test table, ti will be very difficult -if not impossible to verify success or notice failure. -

    So I decided that the best way to run my unit tests for DML operations -was to create a separate test table for each unit test. As a consequence, -my setup procedure for the te_employee package looks like this: -(See ut_te_employee.pkb in the Examples directory of the utPLSQL distribution) -

       PROCEDURE ut_setup
    -   IS
    -   BEGIN
    -      ut_teardown;
    -      EXECUTE IMMEDIATE 'CREATE TABLE ut_employee AS
    -            SELECT * FROM employee';
    -      EXECUTE IMMEDIATE 'CREATE TABLE ut_DEL1 AS
    -            SELECT * FROM employee';
    -      EXECUTE IMMEDIATE 'CREATE TABLE ut_DELBY_EMP_DEPT_LOOKUP AS
    -            SELECT * FROM employee';
    -      EXECUTE IMMEDIATE 'CREATE TABLE ut_DELBY_EMP_JOB_LOOKUP AS
    -            SELECT * FROM employee';
    -      EXECUTE IMMEDIATE 'CREATE TABLE ut_DELBY_EMP_MGR_LOOKUP AS
    -            SELECT * FROM employee';
    -      EXECUTE IMMEDIATE 'CREATE TABLE ut_INS1 AS
    -            SELECT * FROM employee';
    -      EXECUTE IMMEDIATE 'CREATE TABLE ut_UPD1 AS
    -            SELECT * FROM employee';
    -      EXECUTE IMMEDIATE 'CREATE TABLE ut_UPD$HIRE_DATE1 AS   
    -            SELECT * FROM employee';
    -      EXECUTE IMMEDIATE 'CREATE TABLE ut_UPD$SALARY1 AS
    -            SELECT * FROM employee';
    -   END;
    -I first remove all my data structures using the teardown procedure to make -sure I have a clean start. Then I use dynamic SQL (the Oracle8i version) -to create all my tables. I must rely on dynamic SQL because PL/SQL does -not yet support native DDL statements, such as CREATE TABLE. -

    Then I am set to test. -

    -Tear Down Data Structures

    -Well, if I am going to create a whole bunch of data structures to run my -tests, I had better get rid of those structures when I am done. Here is -the teardown program I generated for the te_employee package: -
       PROCEDURE ut_teardown
    -   IS
    -   BEGIN
    -      BEGIN
    -         EXECUTE IMMEDIATE 'DROP TABLE ut_employee';
    -      EXCEPTION
    -         WHEN OTHERS
    -         THEN
    -            NULL;
    -      END;
    -
    -      BEGIN
    -         EXECUTE IMMEDIATE 'DROP TABLE ut_DEL1';
    -      EXCEPTION
    -         WHEN OTHERS
    -         THEN
    -            NULL;
    -      END;
    -
    -      BEGIN
    -         EXECUTE IMMEDIATE 'DROP TABLE ut_DELBY_EMP_DEPT_LOOKUP';
    -      EXCEPTION
    -         WHEN OTHERS
    -         THEN
    -            NULL;
    -      END;
    -
    -      BEGIN
    -         EXECUTE IMMEDIATE 'DROP TABLE ut_DELBY_EMP_JOB_LOOKUP';
    -      EXCEPTION
    -         WHEN OTHERS
    -         THEN
    -            NULL;
    -      END;
    -
    -      BEGIN
    -         EXECUTE IMMEDIATE 'DROP TABLE ut_DELBY_EMP_MGR_LOOKUP';
    -      EXCEPTION
    -         WHEN OTHERS
    -         THEN
    -            NULL;
    -      END;
    -
    -      BEGIN
    -         EXECUTE IMMEDIATE 'DROP TABLE ut_INS1';
    -      EXCEPTION
    -         WHEN OTHERS
    -         THEN
    -            NULL;
    -      END;
    -
    -      BEGIN
    -         EXECUTE IMMEDIATE 'DROP TABLE ut_UPD1';
    -      EXCEPTION
    -         WHEN OTHERS
    -         THEN
    -            NULL;
    -      END;
    -
    -      BEGIN
    -         EXECUTE IMMEDIATE 'DROP TABLE ut_UPD$HIRE_DATE1';
    -      EXCEPTION
    -         WHEN OTHERS
    -         THEN
    -            NULL;
    -      END;
    -
    -      BEGIN
    -         EXECUTE IMMEDIATE 'DROP TABLE ut_UPD$SALARY1';
    -      EXCEPTION
    -         WHEN OTHERS
    -         THEN
    -            NULL;
    -      END;
    -
    -   END;
    -Again, I use dynamic SQL, but enclose each DROP TABLE statement inside -its own exception section so that if for any reason the DROP fails, I continue -on in an attempt to get as much done as possible. -
    -

    Footnotes

    -1. These files are in the Examples directory of the utPLSQL distribution. - -

    < Previous Section: Test a Function | Next Section: Put Test Code in Same Package >

    -
    - - \ No newline at end of file diff --git a/website/Doc/testfunc.html b/website/Doc/testfunc.html deleted file mode 100644 index b900d035a..000000000 --- a/website/Doc/testfunc.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - -Test a Function - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: Test a Procedure | Next Section: Test an Entire Package API >

    - - -

    -Test a Function

    - -

    As with the procedure, there are a couple of scenarios to consider: -

      -
    • -The function returns a scalar value (number, -date, string, Boolean). In this case, you can embed your call to the function -directly inside a call to a uAssert assertion program, making your test -procedure very concise and easy to write.
    • - - -
    • -The function returns a non-scalar value, -such as an object or a collection. In this case, you will need to call -the function and then evaluate the contents of the returned structure.
    • - - - -
    • -A third situation to consider is that your function returns a value, but -it also takes a number of other actions, the success of which is not reflected -in the returned value. Fully testing such a function (one with "side effects") -can be very difficult, since you must test for a variety of conditions.
    • - -
    - -

    -Testing a Scalar Function

    -First, a test of a function returning a scalar value. Consider the following -packaged function: -
    /*file str.pks and str.pkb */
    -CREATE OR REPLACE PACKAGE str
    -IS
    -   FUNCTION betwn (
    -      string_in IN VARCHAR2,
    -      start_in IN PLS_INTEGER,
    -      end_in IN PLS_INTEGER
    -   )
    -      RETURN VARCHAR2;
    -END str;
    -/
    -The str.betwn function returns the sub-string of a string_in that is found -between the start and end locations specified by start_in and end_in. -

    So...time to test! I generate a test package -and then modify the unit test procedure to check for various conditions: -

    /*file ut_str.pkb */
    -CREATE OR REPLACE PACKAGE BODY ut_str
    -IS
    -   PROCEDURE ut_setup
    -   IS
    -   BEGIN
    -      NULL;
    -   END;
    -   
    -   PROCEDURE ut_teardown
    -   IS
    -   BEGIN
    -      NULL;
    -   END;
    -
    -   -- For each program to test...
    -   PROCEDURE ut_betwn IS
    -   BEGIN
    -      utAssert.eq (
    -         'Typical Valid Usage',
    -         str.betwn ('this is a string', 3, 7),
    -         'is is' 
    -         );
    -         
    -      utAssert.eq (
    -         'Test Negative Start',
    -         str.betwn ('this is a string', -3, 7),
    -         'ing'
    -         );
    -         
    -      utAssert.isNULL (
    -         'Start bigger than end',
    -         str.betwn ('this is a string', 3, 1)
    -         );
    -   END ut_betwn;
    -
    -END ut_str;
    -/
    -As you can see, my calls to str.betwn are embedded right within calls to -utAssert.eq and utAssert.isNULL, making my test code compact. - - -

    < Previous Section: Test a Procedure | Next Section: Test an Entire Package API >

    -
    - - \ No newline at end of file diff --git a/website/Doc/testproc.html b/website/Doc/testproc.html deleted file mode 100644 index 1ae04a8d7..000000000 --- a/website/Doc/testproc.html +++ /dev/null @@ -1,280 +0,0 @@ - - - - - - - - -Test a Procedure - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: Examples | Next Section: Test a Function >

    - - -

    -Test a Procedure

    - -

    There are a couple of scenarios to consider: -

      -
    • -The procedure runs some code and then passes back results through the parameter -list. In this case, I can write a unit test that analyzes the OUT and IN -OUT argument values.
    • - -The procedure runs some code, which changes -other elements of the application (such as a database table or a file). -The parameter list does not contain arguments that can be analyzed for -successful execution. So to assert success, I will need to analyze/compare -the data structures that have been modified. -
    - -

    -Test Success Through Parameters

    - -We'll start with a really simple example. I -have built a procedure that accepts two dates and returns the number of -seconds between them. Here it is: - -
    /*file calc_secs_between.sp */
    -CREATE OR REPLACE PROCEDURE calc_secs_between (
    -   date1 IN DATE,
    -   date2 IN DATE,
    -   secs OUT NUMBER)
    -IS
    -BEGIN
    -   -- 24 hours in a day, 
    -   -- 60 minutes in an hour,
    -   -- 60 seconds in a minute...
    -   secs := (date2 - date1) * 24 * 60 * 60;
    -END;
    -/
    - -After compiling my code cleanly, I generate -my test package: - -
    SQL> SET SERVEROUTPUT ON FORMAT WRAPPED
    -SQL> exec utGen.testpkg ('calc_secs_between ')
    -CREATE OR REPLACE PACKAGE ut_calc_secs_between
    -IS
    -   PROCEDURE ut_setup;
    -   PROCEDURE ut_teardown;
    -
    -   -- For each program to test...
    -   PROCEDURE ut_CALC_SECS_BETWEEN;
    -END ut_calc_secs_between;
    -/
    -CREATE OR REPLACE PACKAGE BODY ut_calc_secs_between
    -IS
    -   PROCEDURE ut_setup
    -   IS
    -   BEGIN
    -      NULL;
    -   END;
    -
    -   PROCEDURE ut_teardown
    -   IS
    -   BEGIN
    -      NULL;
    -   END;
    -
    -   -- For each program to test...
    -   PROCEDURE ut_CALC_SECS_BETWEEN IS
    -   BEGIN
    -      CALC_SECS_BETWEEN (
    -            DATE1 => ''
    -            ,
    -            DATE2 => ''
    -            ,
    -            SECS => ''
    -       );
    -
    -      utAssert.this (
    -         'Test of CALC_SECS_BETWEEN',
    -         '<boolean expression>'
    -         );
    -   END ut_CALC_SECS_BETWEEN;
    -
    -END ut_calc_secs_between;
    -/
    - -I generated the output to the screen, but it -is actually easier to deposit the code directly into two separate files -for package spec and body, ut_calc_secs_between.pks and ut_calc_secs_between.pkb, -which I do as follows: - -
    SQL> exec utGen.testpkg ('calc_secs_between ', output_type_in => utGen.c_file)
    - -By conforming to this standard, utPLSQL can -automatically compile this code before each test. I now edit the ut_calc_secs_between -procedure to test for various cases: - -
    PROCEDURE ut_CALC_SECS_BETWEEN 
    -IS
    -   secs PLS_INTEGER;
    -BEGIN
    -   CALC_SECS_BETWEEN (
    -         DATE1 => SYSDATE
    -         ,
    -         DATE2 => SYSDATE
    -         ,
    -         SECS => secs
    -    );
    -
    -   utAssert.eq (
    -      'Same dates',
    -      secs, 
    -      0
    -      );
    -      
    -   CALC_SECS_BETWEEN (
    -         DATE1 => SYSDATE
    -         ,
    -         DATE2 => SYSDATE+1
    -         ,
    -         SECS => secs
    -    );
    -
    -   utAssert.eq (
    -      'Exactly one day',
    -      secs, 
    -      24 * 60 * 60
    -      );
    -      
    -END ut_CALC_SECS_BETWEEN;
    - -and now I can run my test: - -
    SQL> exec utplsql.test ('calc_secs_between')
    -.
    ->    SSSS   U     U   CCC     CCC   EEEEEEE   SSSS     SSSS
    ->   S    S  U     U  C   C   C   C  E        S    S   S    S
    ->  S        U     U C     C C     C E       S        S
    ->   S       U     U C       C       E        S        S
    ->    SSSS   U     U C       C       EEEE      SSSS     SSSS
    ->        S  U     U C       C       E             S        S
    ->         S U     U C     C C     C E              S        S
    ->   S    S   U   U   C   C   C   C  E        S    S   S    S
    ->    SSSS     UUU     CCC     CCC   EEEEEEE   SSSS     SSSS
    -.
    - SUCCESS: "calc_secs_between"
    - -Certainly, there are a variety of other conditions -to test, but this should give you a good idea of how to go about it! - -

    -Test Success by Analyzing Impact

    - -Now let's consider a more complicated situation. -I have a procedure that truncates all the rows in the specified table. -To do this I just use dynamic SQL, as you can see in: - -
    /*file truncit.sp */
    -CREATE OR REPLACE PROCEDURE truncit (
    -   tab IN VARCHAR2,
    -   sch IN VARCHAR2 := NULL
    -)
    -IS
    -BEGIN
    -   EXECUTE IMMEDIATE 'truncate table ' || NVL (sch, USER) || '.' || tab;
    -END;
    -/
    - -After I run this test, I cannot simply check -the value returned by the procedure. Instead, I must check to see how many -rows are left in the table. Fortunately, I have another dynamic SQL utility -to help me out here, one that returns the count of rows in any table: -(Note that you could also use utAssert.eqqueryvalue here.) - -
    /*file tabcount.sf */
    -CREATE OR REPLACE FUNCTION tabcount (
    -   sch IN VARCHAR2,
    -   tab IN VARCHAR2)
    -   RETURN INTEGER
    -IS
    -   retval  INTEGER;
    -BEGIN
    -   EXECUTE IMMEDIATE 
    -      'SELECT COUNT(*) FROM ' || sch || '.' || tab
    -      INTO retval; 
    -   RETURN retval;
    -EXCEPTION
    -    WHEN OTHERS 
    -    THEN
    -       RETURN NULL; 
    -END;
    -/
    - -So I will generate a package -to test truncit and then modify the package body: - -
    SQL> SET SERVEROUTPUT ON FORMAT WRAPPED
    -SQL> exec utGen.testpkg ('truncit', output_type_in => utGen.c_file)
    - -To run my test, I need to truncate a table. -That is an irreversible action, so I will create a "temporary" table in -the setup procedure and drop it in the teardown procedure. Then I will -run my code and use tabCount to validate the results: - -
    /*file ut_truncit.pkb */
    -CREATE OR REPLACE PACKAGE BODY ut_truncit
    -IS
    -   PROCEDURE ut_setup
    -   IS
    -   BEGIN
    -      EXECUTE IMMEDIATE 
    -         'CREATE TABLE temp_emp AS SELECT * FROM employee';
    -   END;
    -   
    -   PROCEDURE ut_teardown
    -   IS
    -   BEGIN
    -      EXECUTE IMMEDIATE 
    -         'DROP TABLE temp_emp';
    -   END;
    -
    -   -- For each program to test...
    -   PROCEDURE ut_TRUNCIT IS
    -   BEGIN
    -      TRUNCIT (
    -            TAB => 'temp_emp'
    -            ,
    -            SCH => USER
    -       );
    -
    -      utAssert.eq (
    -         'Test of TRUNCIT',
    -         tabcount (USER, 'temp_emp'),
    -         0
    -         );
    -   END ut_TRUNCIT;
    -
    -END ut_truncit;
    -/
    - -Not quite as straightforward as checking values -returned in OUT or IN OUT arguments, but not too awful, right? Of course, -things can get considerably more complicated as your code (and the results -you must test for) grows more complex. Regardless, you will find it easier -to build and run your tests through utPLSQL than through more ad hoc and -considerably less organized approaches. - - - -

    < Previous Section: Examples | Next Section: Test a Function >

    -
    - - \ No newline at end of file diff --git a/website/Doc/testrun.html b/website/Doc/testrun.html deleted file mode 100644 index 650f78ad5..000000000 --- a/website/Doc/testrun.html +++ /dev/null @@ -1,332 +0,0 @@ - - - - - - - - -A "Test Run" with utPLSQL - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: How to build a test package | Next Section: Examples >

    - - -

    -A "Test Run" with utPLSQL

    - -

    I will put utPLSQL to work in a small-scale development -effort, to show you how it all hangs together. I've got a "hangnail" in -my PL/SQL development work, called SUBSTR. This function bothers me and -I want to take care of it. What's the problem? SUBSTR is great when you -know the starting location of a string and number of characters you want. In -many situations, though, I have the start and end locations and I need -to figure out the number of characters I then want. Is it: -

    mystring := SUBSTR (full_string, 5, 17); -- start and end? Nah...
    -mystring := SUBSTR (full_string, 5, 12); -- end – start?
    -mystring := SUBSTR (full_string, 5, 13); -- end – start + 1?
    -mystring := SUBSTR (full_string, 5, 11); -- end – start 1 1?
    - -Why should I have to remember stuff like this? I -never do, and so I take out a scrap of paper, write down 'abcdefgh', put -a mark over the "c" and another over the "g", count on my fingers and then -remember that of course the formula is "end – start + 1". - -All right, so I did that a dozen times, I am sick -of it and determined to stop wasting my time in the future. I will write -a function called "str.betwn" (the betwn function defined in the str package) -that does the work and the remembering for me. - -Instead of immediately coding the function, however, -I will first write my unit tests with utPLSQL! Since my source package -is named "str", I will create a test package named "ut_str". I am a lazy -fellow, so I will take the lazy way out and generate the starting point -for my package: - -
    SQL> exec utgen.testpkg ('str', output_type_in => utplsql.c_file)
    - -Note: for the above call to work, I must have already -set my default directory for utPLSQL, which I do via a SQL*Plus login script -that looks like this: - -
    exec utConfig.setdir ('e:\utplsql\test')
    -SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED
    - -Otherwise, I would need to specify the directory -in my call to genpkg, as in: - -
    SQL> exec utgen.testpkg ('str', output_type_in => utplsql.c_file, dir_in => 'e:\utplsql\test')
    - -I then will find this package spec in the ut_str.pks -file: - -
    CREATE OR REPLACE PACKAGE ut_str
    -IS
    -   PROCEDURE ut_setup;
    -   PROCEDURE ut_teardown;
    -  
    -   -- For each program to test...
    -   PROCEDURE ut_betwn;
    -END ut_str;
    -/
    - -And I don't really have to modify the specification -at all. The body will, on the other hand, require some work, since I haven't -yet figured out a way to automatically generate the test code itself. Here -is the purely generated test package body found -in the ut_str.pkb file: - -
    CREATE OR REPLACE PACKAGE BODY ut_str
    -IS
    -   PROCEDURE ut_setup
    -   IS
    -   BEGIN
    -      NULL;
    -   END;
    -  
    -   PROCEDURE ut_teardown
    -   IS
    -   BEGIN
    -      NULL;
    -   END;
    -  
    -   -- For each program to test...
    -   PROCEDURE ut_betwn
    -   IS
    -   BEGIN
    -      utAssert.this (
    -         'Test of betwn',
    -         <boolean expression>,
    -         );
    -   END;
    -  
    -END ut_str;
    -/
    - -The setup and teardown procedures are fine (I don't -have any special setup and therefore teardown requirements), but the ut_betwn -needs lots of work. It doesn't really test anything yet. - -Before I start writing my test code, however, I -will just sit back and think about what I want to test. Here are some inputs -that I can think of: - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -String - -Start - -End - -Expected Result -
    -"this is a string" - -3 (positive number) - -7 (bigger positive number) - -"is is" -
    -"this is a string" - --3 (invalid negative number) - -7 (bigger positive number) - -"ing" (consistent with SUBSTR behavior) -
    -"this is a string" - -3 (positive number) - -1 (smaller positive number) - -NULL -
    - - -

    We could easily come up with a whole lot more test -cases – and if this was real life and not product documentation, I would -not move forward until I had identified all interesting tests. So let's -suppose I have done that and now I am ready to do some coding. Since I -am testing a function, I will want to compare the result of the function -call to my expected results. I will therefore change my assertion from -the generic "assert this" procedure to the utAssert.eq program, and put -the call to the function right into the assertion routine. Here, then, -is my first crack at transforming my ut_betwn procedure: -

    PROCEDURE ut_betwn IS
    -BEGIN
    -   utAssert.eq (
    -      'Test of betwn',
    -      str.betwn ('this is a string', 3, 7),
    -      'is is'
    -      );
    -END;
    - -Following the Extreme Programming philosophy ("code -a little, test a lot"), I will test this test case before I add all the -other test cases. I do this with a very simple call: - -
    SQL> exec utplsql.test ('str')
    -
    ->    SSSS   U     U   CCC     CCC   EEEEEEE   SSSS     SSSS
    ->   S    S  U     U  C   C   C   C  E        S    S   S    S
    ->  S        U     U C     C C     C E       S        S
    ->   S       U     U C       C       E        S        S
    ->    SSSS   U     U C       C       EEEE      SSSS     SSSS
    ->        S  U     U C       C       E             S        S
    ->         S U     U C     C C     C E              S        S
    ->   S    S   U   U   C   C   C   C  E        S    S   S    S
    ->    SSSS     UUU     CCC     CCC   EEEEEEE   SSSS     SSSS
    -
    ->SUCCESS: "str"
    - -Now, you could say: "Great it worked!" Or you could -say: "I have no idea if it worked. Maybe it always says success." -I go for the latter, so let's deliberately cause a failure: - -
    PROCEDURE ut_betwn IS
    -BEGIN
    -   utAssert.eq (
    -      'Test of betwn',
    -      str.betwn ('this is a string', 3, 7),
    -      'this is a pipe'
    -      );
    -END;
    - -Saving the file (but not bothering to recompile, -since utPLSQL will do it for me automagically), -I then run my test again: - -
    SQL> exec utplsql.test ('str', recompile_in=>false)
    -
    ->  FFFFFFF   AA     III  L      U     U RRRRR   EEEEEEE
    ->  F        A  A     I   L      U     U R    R  E
    ->  F       A    A    I   L      U     U R     R E
    ->  F      A      A   I   L      U     U R     R E
    ->  FFFF   A      A   I   L      U     U RRRRRR  EEEE
    ->  F      AAAAAAAA   I   L      U     U R   R   E
    ->  F      A      A   I   L      U     U R    R  E
    ->  F      A      A   I   L       U   U  R     R E
    ->  F      A      A  III  LLLLLLL  UUU   R     R EEEEEEE
    -
    -FAILURE: "str"
    -
    -BETWN: Typical Valid Usage; expected "is is", got "this is a pipe"
    - -Now I have a higher degree of confidence that I -am getting this right. Excellent! Now I will add the other test cases: - -
    PROCEDURE ut_betwn IS
    -BEGIN
    -   utAssert.eq (
    -      'Typical Valid Usage',
    -      str.betwn ('this is a string', 3, 7),
    -      'is is'
    -      );
    -     
    -   utAssert.eq (
    -      'Test Negative Start',
    -      str.betwn ('this is a string', -3, 7),
    -      'ing'
    -      );
    -     
    -   utAssert.isNULL (
    -      'Start bigger than end',
    -      str.betwn ('this is a string', 3, 1)
    -      );
    -END;
    - -I will deliberately cause each of these tests to -fail, to give you a sense of the quality of feedback: - -
    >  FFFFFFF   AA     III  L      U     U RRRRR   EEEEEEE
    ->  F        A  A     I   L      U     U R    R  E
    ->  F       A    A    I   L      U     U R     R E
    ->  F      A      A   I   L      U     U R     R E
    ->  FFFF   A      A   I   L      U     U RRRRRR  EEEE
    ->  F      AAAAAAAA   I   L      U     U R   R   E
    ->  F      A      A   I   L      U     U R    R  E
    ->  F      A      A   I   L       U   U  R     R E
    ->  F      A      A  III  LLLLLLL  UUU   R     R EEEEEEE
    -
    -FAILURE: "str"
    -betwn: Typical Valid Usage; expected "is is", got "this is a pipe"
    -betwn: Test Negative Start; expected "ing", got "BRRRING"
    -betwn: IS NOT NULL: Start bigger than end
    - -Faced with these results, I can zoom in on the code -within str.betwn that is causing these incorrect results. I resist the -temptation to fix the code for all my tests all at once. Instead, I make -one change at a time, then run my test again. I do that over and over again -until the failure for the single test case goes away. Then I move to the -next one. Eventually, I get a green light and am highly confident of my -program – if, of course, I really did come up with an exhaustive list of -tests. - -As I think of another test case, I add a call to -utAssert to run that test. - -As a bug is reported to me, I add a call to utAssert -to reproduce that bug. Then I repair my code. - - -

    < Previous Section: How to build a test package | Next Section: Examples >

    -
    - - \ No newline at end of file diff --git a/website/Doc/userguide.html b/website/Doc/userguide.html deleted file mode 100644 index 829b49ede..000000000 --- a/website/Doc/userguide.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - -User Guide - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: Create and Run a Test Suite | Next Section: utPLSQL Package >

    - - -

    -User Guide

    - -

    The utPLSQL unit testing framework consists of several different elements: -

      -
    • -A set of tables to hold information about unit tests and test suites.
    • -
    • A set of packages that allow you to run tests, -build test packages and access information about tests you have run.
    • -
    -This document tells you how to use those utPLSQL packages: -

    -utPLSQL - Register and run test packages

    - -

    -utConfig - Set how tests are run

    - -

    -utResult - Analyze and display results -of unit tests

    - -

    -utAssert - Assert that code works -properly

    - -

    -utGen - Generate test packages

    - -

    - utOutput - Handling DBMS_OUTPUT for testing

    - -

    - utRecEq - Generate functions to compare record types

    - -

    -Define Test Suites

    - -

    -Using and defining Custom Reporter Packages - -

    -Configuring the File Reporter - - -

    < Previous Section: Create and Run a Test Suite | Next Section: utPLSQL Package >

    -
    - - \ No newline at end of file diff --git a/website/Doc/utassert.html b/website/Doc/utassert.html deleted file mode 100644 index 096e02ba4..000000000 --- a/website/Doc/utassert.html +++ /dev/null @@ -1,927 +0,0 @@ - - - - - - - - -utAssert Package - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: utResult Package | Next Section: utGen Package >

    - - -

    utAssert Package

    - -

    This package contains the following procedures and functions:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    utAssert.thisGeneric "Assert This" Procedure
    utAssert.isnull
    - utAssert.isnotnull
    Check for NULL and NOT NULL values
    utAssert.eqCheck Equality of Scalar Values
    utAssert.eqtableCheck Equality of Database Tables
    utAssert.eqtabcountCheck Equality of Table Counts
    utAssert.eqqueryCheck Equality of Queries
    utAssert.eqqueryvalueCheck Equality of Query against single value
    utAssert.eqfileCheck Equality of Files
    utAssert.eqpipeCheck Equality of Database Pipes
    utAssert.eqcoll
    - utAssert.eqcollapi
    Check Equality of Collections
    utAssert.throwsCheck a procedure or function throws an exception
    utAssert.previous_passed
    -utAssert.previous_failed

    -
    Check if the previous assertion -passed or failed
    -
    utAssert.eqoutputCheck Equality of DBMS_OUTPUT Collections
    utAssert.objexists
    - utAssert.objnotexists
    Check for existence of database objects
    utAssert.eq_refc_queryCheck Equality of RefCursor and Query
    utAssert.eq_refc_tableCheck Equality of RefCursor and Database Table
    - The utAssert package provides a set of assertion routines ("assert that -the following condition is true") that you will use to register the outcome -of a test case. You must call a utAssert assertion program after (or containing) -a test case so that the results of that test can be recorded and then reported. -See Build Test Packages for many examples and -more details on this process. Here is a very simple example, though, to give -you an idea of the code you would write:

       PROCEDURE ut_BETWNSTR IS
    BEGIN
    utAssert.eq (
    'Typical valid usage',
    BETWNSTR(
    STRING_IN => 'abcdefg'
    ,
    START_IN => 3
    ,
    END_IN => 5
    ),
    'cde'
    );
    END;
    - utAssert offers a wide (and ever expanding) set of assertion programs that -allow you to efficiently (a) test the outcome of your unit test and (b) report -the results of that test to utPLSQL. You should review -Common Assertion Parameters and Behavior before using any specific assertion -program. It is also possible to build your own assertion -routine. Note: all utAssert assertions are defined in the ut_assertion -table, as well as actually coded in the utAssert package.

    -

    Common Assertion Parameters and Behavior

    - Each type of assertion routine accepts different kinds of data, but there -are lots of similarities between the assertions, as well. Here is an explanation -of the common assertion parameters: - - - - - - - - - - - - - - - - - - - - - - - - -
    msg_in A message to be displayed if the assertion -fails. This is the first argument and is mandatory, because the tests need -to be self documenting.
    check_this_in The value to be checked.. If a Boolean expression, -this will usually include the invocation of the method being tested, resulting -in a single line of code for the entire test case.
    against_this_in For assert_eq, the assertion routine will -check the check_this_in value against the against_this_in value. This parameter -should be the certifiably correct value.
    null_ok_in TRUE if a NULL value should be interpreted -as a successful test, FALSE if NULL indicates failure.
    raise_exc_in TRUE if it is OK for the assertion routine -to allow an exception to be propagated out unhandled.
    - -

    Generic "Assert This" Assertion Procedure

    - This most generic assertion program simply says "assert this" and passes -a Boolean expression. It is used by all the other assertion routines, which -construct a Boolean expression from their specific values and logic. -
       PROCEDURE utAssert.this (
    -      msg_in IN VARCHAR2,
    -      check_this_in IN BOOLEAN,
    -      null_ok_in IN BOOLEAN := FALSE,
    -      raise_exc_in IN BOOLEAN := FALSE
    -   );
    - Use utAssert.this when you have a Boolean expression that you want to check, -as in:.
    BEGIN
    -   ...
    -   utAssert.this (
    -      'Boolean function result',
    -      is_valid_account (my_account)
    -      );
    - You can also use this assertion to register a failure, most usually in -an exception section, as in:
    EXCEPTION
    -   WHEN OTHERS
    -   THEN
    utAssert.this ( - SQLERRM, - FALSE);
    - Generally, you should avoid utAssert.this and instead use a specialized -assertion routine, documented below. Most of the assertions give you the -ability check for equality (of scalars, such as strings, or more complex -data structures like tables, pipes and files): does the data generated by -my code match the expected value(s)? -

    Check for NULL and NOT NULL Values

    - You can check to see if a value is NULL or is NOT NULL with the following -assertions:
    PROCEDURE utAssert.isnotnull (
    msg_in IN VARCHAR2,
    check_this_in IN VARCHAR2,
    null_ok_in IN BOOLEAN := FALSE,
    raise_exc_in IN BOOLEAN := FALSE
    );

    PROCEDURE utAssert.isnull (
    msg_in IN VARCHAR2,
    check_this_in IN VARCHAR2,
    null_ok_in IN BOOLEAN := FALSE,
    raise_exc_in IN BOOLEAN := FALSE
    );

    PROCEDURE utAssert.isnotnull (
    msg_in IN VARCHAR2,
    check_this_in IN BOOLEAN,
    null_ok_in IN BOOLEAN := FALSE,
    raise_exc_in IN BOOLEAN := FALSE
    );

    PROCEDURE utAssert.isnull (
    msg_in IN VARCHAR2,
    check_this_in IN BOOLEAN,

    null_ok_in IN BOOLEAN := FALSE,
    raise_exc_in IN BOOLEAN := FALSE
    );
    - Use these assertions when you simply want to check if a scalar expression -(string, date, number and Boolean are supported) is NULL or NOT NULL, as -in:
    -
    -
    BEGIN
    -   ...
    -   utAssert.isNULL (
    -      'Should be nothing left',
    -      TRANSLATE (digits_in_string, 'A1234567890', 'A')
    -      );
    - -

    Check Equality of Scalar Values

    - If you need to compare two dates or two strings or two numbers or two Booleans, -use the utAssert.eq assertion program. -

    Here is the header for the scalar equality check assertion:

    PROCEDURE utAssert.eq (
    -   msg_in IN VARCHAR2,
    -   check_this_in IN VARCHAR2|BOOLEAN|DATE|NUMBER,
    -   against_this_in IN VARCHAR2|BOOLEAN|DATE|NUMBER,
    -   null_ok_in IN BOOLEAN := FALSE,
    -   raise_exc_in IN BOOLEAN := FALSE
    -);
    - If the two values are equal, your code gets a green light. Otherwise, utAssert -writes the test results to the utResult package, resulting in a red light -for the test. If NULL values are considered value for this test, pass TRUE -for null_ok_in. If you want the assertion to raise an exception on failure -and stop the test from proceeding, pass TRUE for raise_exc_in. Here is an -example of using the utAssert.eq program:
       PROCEDURE ut_emp_dept_lookuprowcount
    IS - l_rowcount1 PLS_INTEGER;
    l_rowcount2 PLS_INTEGER;
    BEGIN
    -- Run baseline code.
    SELECT COUNT (*)
    INTO l_rowcount1
    FROM employee
    WHERE department_id = 30; - - -- Compare to program call:
    l_rowcount2 :=
    te_employee.emp_dept_lookuprowcount (30); - - -- Test results
    utassert.eq (
    'Successful EMP_DEPT_LOOKUPROWCOUNT',
    l_rowcount2,
    l_rowcount1
    );
    END;
    -

    -

    Check Equality of DatabaseTables

    - If your test performs DML operations (update, insert or delete), you will -need to check your results in a database table. You could do this by querying -the results into local variables and then calling utAssert.eq to check those -values against your expected data. That can be a very laborious process, -so utAssert offers the eqtable and equerry assertion routines to streamline -the process. Both these procedures use the MINUS SQL operator to essentially -"subtract" the contents of one table (query) from the other. If anything -is left, then the two tables (queries) are not the same and the test is given -a red light. As you can probably see, the structure of the two tables (queries) -must be identical for this assertion to work properly. The utAssert.eqtable -allows you to compare the contents of your data table (changed by your code) -against another table, which you can preset with the data you expect to see -after the test. Here is the header for eqtable:
    PROCEDURE utAssert.eqtable (
    -   msg_in IN VARCHAR2,
    -   check_this_in IN VARCHAR2,
    -   against_this_in IN VARCHAR2,
    -   check_where_in IN VARCHAR2 := NULL,
    -   against_where_in IN VARCHAR2 := NULL,
    -   raise_exc_in IN BOOLEAN := FALSE
    -);
    - where check_this_in and against_this_in are the names of tables or views. -You can supply an optional WHERE clause to restrict the rows you wish to -compare. Here is an example that calls eqTable twice, to test two different -conditions.
    PROCEDURE ut_del1
    IS
    fdbk PLS_INTEGER;
    BEGIN
    /* Delete that finds now rows. */

    EXECUTE IMMEDIATE '
    DELETE FROM ut_DEL1
    WHERE employee_id = -1
    ';
    te_employee.del (-1, rowcount_out => fdbk); - -- Test results
    utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1');
    /* Successful delete */

    EXECUTE IMMEDIATE '
    DELETE FROM ut_DEL1
    WHERE employee_id between 7800 and 7899
    ';

    FOR rec IN (SELECT *
    FROM employee
    WHERE employee_id BETWEEN 7800 AND 7899)
    LOOP
    te_employee.del (
    rec.employee_id,
    rowcount_out => fdbk
    );
    END LOOP;

    -- Test results
    utassert.eqtable ('Delete rows', 'EMPLOYEE', 'ut_DEL1');
    ROLLBACK;
    EXCEPTION
    WHEN OTHERS
    THEN
    utassert.this (
    'DEL1 exception ' || SQLERRM,
    SQLCODE = 0
    );
    END;
    - -

    Check Equality of Table Counts

    - If your tests simply produce the right number of rows in a table but not -a fixed set of values, you will not be able to use -utAssert.eqtable above. However, utAssert.eqtabcount allows you to simply -test that the numbers of rows are equal. The declaration of the procedure -is as follows:
    PROCEDURE utAssert.eqtabcount (
    -   msg_in IN VARCHAR2,
    -   check_this_in IN VARCHAR2,
    -   against_this_in IN VARCHAR2,
    -   check_where_in IN VARCHAR2 := NULL,
    -   against_where_in IN VARCHAR2 := NULL,
    -   raise_exc_in IN BOOLEAN := FALSE
    -);
    - where check_this_in and against_this_in are the names of tables or views. -As in utAssert.eqtable, you can supply an optional WHERE clause to restrict -the rows you wish to compare. The following test will compare the number -of rows in the CD_COLLECTION and UT_TEST_5_1 tables where the given condition -holds:
    utassert.eqtabcount('Test 5.1: Insert new rows',
    -                    'CD_COLLECTION',
    -                    'UT_TEST_5_1',
    -                    'ARTIST = ''The Fall''',
    -                    'ARTIST = ''The Fall''');
    - -

    Asserting Query Equality

    - The utAssert.eqquery allows you to compare the data returned by two queries -(strings that are contained in the check_this_in and against_this_in parameters). -In this case, you specify the full SELECT statements for each query as the -parameters. By using equery, you may be able to avoid constructing a separate -table with preset data.
    PROCEDURE utAssert.eqquery (
    -   msg_in IN VARCHAR2,
    -   check_this_in IN VARCHAR2,
    -   against_this_in IN VARCHAR2,
    -   raise_exc_in IN BOOLEAN := FALSE
    -);
    - If you want the assertion to raise an exception on failure and stop the -test from proceeding, pass TRUE for raise_exc_in. Here is an example of -using eqQuery:
    PROCEDURE ut_upd1
    IS
    BEGIN
    /* Update 3 columns by ID */

    EXECUTE IMMEDIATE '
    UPDATE ut_UPD1 SET
    FIRST_NAME = ''SILLY'',
    HIRE_DATE = trunc (SYSDATE+100),
    COMMISSION = 5000
    WHERE
    EMPLOYEE_ID = 7600
    ';
    te_employee.upd (
    7600,
    first_name_in => 'SILLY',
    commission_in => 5000,
    hire_date_in => TRUNC (SYSDATE + 100),
    rowcount_out => fdbk
    );
    -- Test results (audit fields are different so do a query)
    utassert.eqquery (
    'Update three columns',
    'select first_name, commission, hire_date from EMPLOYEE',
    'select first_name, commission, hire_date from ut_upd1'
    );
    ROLLBACK;
    END;
    - -

    Check Query Equality against a Single Value

    - Often we will wish to test the result of a query against a single value rather -than another query as in utAssert.eqquery above. -It is possible to get around this problem by using a trivial query of the -form:
    SELECT fixed_value
    FROM DUAL;
    - Unfortunately, if the query returns multiple values or the wrong value we -will only be told that the test has failed with no details. This is where -utAssert.eqqueryvalue comes to the rescue. The procedure is declared as -follows:
    PROCEDURE utAssert.eqqueryvalue (
    -      msg_in IN VARCHAR2,
    -      check_query_in IN VARCHAR2,
    -      against_value_in IN VARCHAR2|NUMBER|DATE,
    -      raise_exc_in IN BOOLEAN := FALSE
    -);
    - Where check_query_in is the query in question and against_value_in is the -value to check it against. If the query returns more than one value, the -resulting error message will tell you this. Similarly, if the query returns -the wrong value, the message will state the expected and obtained values. - The following call compares the maximum value found in a table against a -given number value:
    utAssert.eqqueryvalue('Maximum value test',
    -                      'SELECT MAX(MEMORY)
    -                       FROM COMPUTERS
    -                       WHERE OS IN (''Linux'', ''Unix'')',
    -                       256);
    - Obviously this should only return a single value, but if it returns something -other than 256, we'll know about it. -

    Check Equality of Files

    - Many programs generate output to operating system files; alternatively, -you might write data to a file simply to test results. Use the eqfile assertion -for either of these scenarios. This procedure uses PL/SQL's UTL_FILE package -to compare the contents of two different files. Note: If you have not used -UTL_FILE in the past, you must configure - it before it can be used -- by utPLSQL or by your own code. UTL_FILE must -be allowed accss to either or both of the directories you specify (this involves -setting the utl_file_dir database parameter).
    PROCEDURE utAssert.eqfile (
    -   msg_in IN VARCHAR2,
    -   check_this_in IN VARCHAR2,
    -   check_this_dir_in IN VARCHAR2,
    -   against_this_in IN VARCHAR2,
    -   against_this_dir_in IN VARCHAR2 := NULL,
    -   raise_exc_in IN BOOLEAN := FALSE
    -);
    - If you want the assertion to raise an exception on failure and stop the -test from proceeding, pass TRUE for raise_exc_in. You must specify the directory -containing the "check this" file; if you do not specify a directory for the -"against this" file, the "check this" directory will be used. Here is an -example of using eqFile (see ut_DEPARTMENT2file.pkg in the Examples directory -for the full implementation):
    PROCEDURE ut_DEPARTMENT2FILE IS
    BEGIN
    DEPARTMENT2FILE (
    LOC => 'c:\temp',
    FILE => 'department.dat',
    DELIM => '***'
    );

    utAssert.eqfile (
    'Test of DEPARTMENT2FILE',
    'department.dat',
    'c:\temp',
    'department.tst',
    'c:\temp'
    );
    END ut_DEPARTMENT2FILE;
    - -

    Check Equality of Database Pipes

    - Database pipes offer a handy mechanism for passing data between different -sessions connected to the RDBMS. It is important to know that pipes are being -filled properly; use the eqpipe to check this condition. With the eqpipe -procedure, you compare the contents of two different pipes.
    PROCEDURE utAssert.eqpipe (
    -   msg_in IN VARCHAR2,
    -   check_this_in IN VARCHAR2,
    -   against_this_in IN VARCHAR2,
    -   raise_exc_in IN BOOLEAN := FALSE
    -);
    - If you want the assertion to raise an exception on failure and stop the -test from proceeding, pass TRUE for raise_exc_in. To check the contents -of a pipe based on the execution of code, you will need to populate a pipe -against which to test equality. The employee_pipe.pkg file in the Examples -directory contains a demonstration of the kind of code you might write to -do this. This package contains all of the unit test code within the same -package. Here is my unit test program, which relies on the utAssert.eqpipe -program:
    PROCEDURE ut_fillpipe IS
    stat PLS_INTEGER;
    BEGIN
    emptypipe ('emps');
    emptypipe ('emps2');

    fillpipe ('emps');

    /* Direct filling of pipe. */

    FOR rec IN (SELECT *
    FROM employee)
    LOOP
    DBMS_PIPE.RESET_BUFFER;
    DBMS_PIPE.PACK_MESSAGE (rec.EMPLOYEE_ID);
    DBMS_PIPE.PACK_MESSAGE (rec.LAST_NAME);
    DBMS_PIPE.PACK_MESSAGE (rec.FIRST_NAME);
    DBMS_PIPE.PACK_MESSAGE (rec.MIDDLE_INITIAL);
    DBMS_PIPE.PACK_MESSAGE (rec.JOB_ID);
    DBMS_PIPE.PACK_MESSAGE (rec.MANAGER_ID);
    DBMS_PIPE.PACK_MESSAGE (rec.HIRE_DATE);
    DBMS_PIPE.PACK_MESSAGE (rec.SALARY);
    DBMS_PIPE.PACK_MESSAGE (rec.COMMISSION);
    DBMS_PIPE.PACK_MESSAGE (rec.DEPARTMENT_ID);
    DBMS_PIPE.PACK_MESSAGE (rec.CHANGED_BY);
    DBMS_PIPE.PACK_MESSAGE (rec.CHANGED_ON);

    stat := DBMS_PIPE.SEND_MESSAGE ('emps2', 0);
    END LOOP;

    /* Compare the two */
    utassert.eqpipe (
    'Two employee pipes', 'emps', 'emps2');

    END ut_fillpipe;
    - Since I have stored my unit test logic with my source code package, I would -run my test as follows:
    SQL> exec utplsql.test ('employee_pipe', samepackage_in=>TRUE)
    FAILURE: "employee_pipe"
    fillpipe: Pipes equal? Compared "emps" against "emps2"
    - -

    Check Equality of Collections

    - Collections are as close as you come to arrays in PL/SQL. They are very -useful for managing lists of information, but can be difficult to debug and -maintain. With the eqcoll and eqcollAPI procedures, you can compare the -contents of two different arrays. Use the eqColl procedure when you want -to compare two collections that are defined in the specification of a package. -Use the eqCollAPI procedure when you want to compare two collections that -are defined in the body of a package, with programs defined in the specification -(an API) to access and manipulate the collections. The collection equality -check headers are:
       /* Direct access to collections */
    -   PROCEDURE utAssert.eqcoll (
    -      msg_in IN VARCHAR2,
    -      check_this_in IN VARCHAR2, /* pkg1.coll */
    -      against_this_in IN VARCHAR2, /* pkg2.coll */
    -      eqfunc_in IN VARCHAR2 := NULL,
    -      check_startrow_in IN PLS_INTEGER := NULL,
    -      check_endrow_in IN PLS_INTEGER := NULL,
    -      against_startrow_in IN PLS_INTEGER := NULL,
    -      against_endrow_in IN PLS_INTEGER := NULL,
    -      match_rownum_in IN BOOLEAN := FALSE,
    -      null_ok_in IN BOOLEAN := TRUE,
    -      raise_exc_in IN BOOLEAN := FALSE
    -   );
    -  
    -   /* API based access to collections */
    -   PROCEDURE utAssert.eqcollapi (
    -      msg_in IN VARCHAR2,
    -      check_this_pkg_in IN VARCHAR2,
    -      against_this_pkg_in IN VARCHAR2,
    -      eqfunc_in IN VARCHAR2 := NULL,
    -      countfunc_in IN VARCHAR2 := 'COUNT',
    -      firstrowfunc_in IN VARCHAR2 := 'FIRST',
    -      lastrowfunc_in IN VARCHAR2 := 'LAST',
    -      nextrowfunc_in IN VARCHAR2 := 'NEXT',
    -      getvalfunc_in IN VARCHAR2 := 'NTHVAL',
    -      check_startrow_in IN PLS_INTEGER := NULL,
    -      check_endrow_in IN PLS_INTEGER := NULL,
    -      against_startrow_in IN PLS_INTEGER := NULL,
    -      against_endrow_in IN PLS_INTEGER := NULL,
    -      match_rownum_in IN BOOLEAN := FALSE,
    -      null_ok_in IN BOOLEAN := TRUE,
    -      raise_exc_in IN BOOLEAN := FALSE
    -   );
    - where the eqcoll-specific parameters are as follows: - - - - - - - - - - - - - - - - - - - - -
    ParameterDescription
    msg_in The message to be displayed if the test failes -
    check_this_in The name of the collection to be checked. -Format: package.collection. In other words, the collection must be defined -in a package specification. Use eqCollAPI (and check_this_pkg_in) if you -want to hide the declaration of your collection in your package body (recommended). -
    against_this_in The name of the collection to be checked -against. Format: package.collection. In other words, the collection must -be defined in a package specification. Use eqCollAPI (and check_this_pkg_in) -if you want to hide the declaration of your collection in your package body -(recommended).
    - -

    and the eqcollAPI-specific parameters are as follows:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ParameterDescription
    msg_in The message to be displayed if the test failes -
    check_this_pkg_in The name of the package that contains the -collection to be checked.
    against_this_pkg_in The name of the package that contains the -collection to be checked against.
    countfunc_in The name of the function in the package that -returns the number of rows defined in the collection.
    firstrowfunc_in The name of the function in the package that -returns the first definedrow in the collection.
    lastrowfunc_in The name of the function in the package that -returns the last definedrow in the collection.
    nextrowfunc_in The name of the function in the package that -returns the next definedrow in the collection from the specified row.
    getvalfunc_in The name of the function in the package that -returns the contents of the specified row.
    -

    -

    The parameters common to both eqColl and eqCollAPI are as follows
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ParameterDescription
    eqfunc_in The function used to determine if the contents -of each row of the two collections are the same. If you pass NULL for this -argument, then a standard equality check will be used. This is fine for scalar -values, but will not work, for example, with tables of records.
    check_startrow_in The starting row in the check collection -for comparison. If NULL, then first row is used.
    check_endrow_in The ending row in the check collection for -comparison. If NULL, then last row is used.
    against_startrow_in The starting row in the against collection -for comparison. If NULL, then first row is used.
    against_endrow_in The ending row in the against collection -for comparison. If NULL, then last row is used.
    match_rownum_in Pass TRUE if you want to make sure that the -same row numbers are used in each collection. If FALSE, then the row numbers -can be different, but the contents of each corresponding row must be the same. -
    null_ok_in Pass TRUE if the assertion routine should -consider two NULL collections to be equal.
    raise_exc_in If you want the assertion to raise an exception -on failure and stop the test from proceeding, pass TRUE for raise_exc_in. -
    -

    -

    Here is an example of a script that uses utAssert.eqColl (taken from filepath1.pkg -in the Examples directory):

    PROCEDURE ut_setpath
    IS
    BEGIN
    /* Populate base collection */
    ut_dirs.DELETE;
    ut_dirs.EXTEND(2);
    ut_dirs(1) := 'c:\temp';
    ut_dirs(2) := 'e:\demo';

    /* Call setpath to do the work */
    setpath ('c:\temp;e:\demo');

    utAssert.eqColl (
    'Valid double entry',
    'fileio.dirs',
    'fileio.ut_dirs'
    );
    END;
    -

    -

    Checking a Procedure or Function throws an exception

    - Sometimes we design a procedure or function to throw an exception under certain -circumstances. This is something we'd like to be able to test for. Obviously -this is not particularly easy due to the way exceptions propagate through -the call stack. If we simply call the procedure in our test code, the exception -will have no chance of being caught within the utAssert package! Therefore, -we need to pass the tested call in to the package as a string. The procedure -utAssert.throws allows us to do this:
    PROCEDURE throws (
    -      msg_in VARCHAR2,
    -      check_call_in IN VARCHAR2,
    -      against_exc_in IN VARCHAR2|NUMBER
    -   );
    - Where check_call_in is the call to be made, complete with parameters and -terminating semicolon. The argument against_exc_in is the exception we expect -to be thrown. This can be specified either as a named exception, or a SQLCODE -value. -

    The following example shows both usages:

    /* Test the Except Function */
    PROCEDURE ut_except
    IS
    BEGIN

    /* Call the procedure with a negative number */
    /* We expect a NO_DATA_FOUND exception */
    utAssert.throws('Negative Number',
    'Except(-1);',
    'NO_DATA_FOUND'
    );

    /* Call the procedure with zero and a string */
    /* over 2 in length - We expect a SQLCODE of -1 */
    utAssert.throws('Zero and String',
    'Except(0, ''Hello'');',
    -1
    );
    END;
    - Note how we have to quote the string parameters to the call and terminate -the string with a semicolon.
    -

    -

    Check if the Previous Assertion Passed or Failed

    -Sometimes, a procedure may have a large number of effects that need to be -tested. For example, it might insert and update data in a series of -tables. To test all of these changes, it will be necessary to make -a series of calls to utAssert. This can have the effect that if the -procedure is not behaving as expected, then the user is presented with a -screenful of errors. To avoid this and just present them with a single -error, the functions previous_passed and previous_failed can be used. -These return a BOOLEAN argument giving the success or failure of the previously -called assertion.
    -
    -The following example gives a demonstration:
    -
    /* Test the BookTrips Procedure */
    -PROCEDURE ut_bookTrips
    -IS 
    -BEGIN
    -
    -  /* Call the procedure */
    -  Vacation.bookTrips(5, 'Rio de Janeiro');
    -  
    -  /* Did it insert 5 rows into TRIPS table */
    -  utAssert.eqqueryvalue('Insert 5 rows',
    -    'SELECT COUNT(*)
    -    FROM TRIPS
    -    WHERE CITY = ''Rio de Janeiro''',
    -    5);
    -    
    -  /* If that worked, look in more detail */
    -  IF utAssert.previous_passed THEN
    -    
    -    /* Do they all have today's date? */
    -    utAssert.eqqueryvalue('All with todays date',
    -      'SELECT COUNT(*)
    -       FROM TRIPS
    -       WHERE CITY = ''Rio de Janeiro'''
    -       AND TRUNC(CREATED) = TRUNC(SYSDATE)',
    -       5);
    -     
    -    /* Do they all have a hotel specified? */
    -    utAssert.eqqueryvalue('Hotel Specfied',
    -      'SELECT COUNT(*)
    -       FROM TRIPS T, HOTELS H
    -       WHERE T.CITY = ''Rio de Janeiro'''
    -       AND T.HOTEL = H.ID',
    -       5);
    -     
    - END IF;
    -   
    -END;
    - -

    Comparing output from DBMS_OUTPUT

    - -

    To complement the utOutput package, these -assertions allow you to easily compare collections of the type -DBMS_OUTPUT.CHARARR. Unlike the eqcoll and - eqcollapi assertions, this allows the comparison of locally defined -collections. The procedures are declared as follows:

    - -
    -PROCEDURE eqoutput (
    -   msg_in                IN   VARCHAR2,
    -   check_this_in         IN   DBMS_OUTPUT.CHARARR,
    -   against_this_in       IN   DBMS_OUTPUT.CHARARR,
    -   ignore_case_in        IN   BOOLEAN := FALSE,
    -   ignore_whitespace_in  IN   BOOLEAN := FALSE,
    -   null_ok_in            IN   BOOLEAN := TRUE,
    -   raise_exc_in          IN   BOOLEAN := FALSE
    -);
    -
    -PROCEDURE eqoutput (
    -   msg_in                IN   VARCHAR2,
    -   check_this_in         IN   DBMS_OUTPUT.CHARARR,
    -   against_this_in       IN   VARCHAR2,
    -   line_delimiter_in     IN   CHAR := NULL,
    -   ignore_case_in        IN   BOOLEAN := FALSE,
    -   ignore_whitespace_in  IN   BOOLEAN := FALSE,
    -   null_ok_in            IN   BOOLEAN := TRUE,
    -   raise_exc_in          IN   BOOLEAN := FALSE
    -);
    -
    - -

    The first version simply compares two collections, whereas the second compares a collection against a delimited string. The delimiter -can be specified by the line_delimiter_in parameter. If NULL is passed in (which is the default) then the lines are delimited by carriage returns. -Thus to test a collection mybuff which should look like:

    - -
    -   mybuff(0) := 'Zidane';
    -   mybuff(1) := 'Ronaldo';
    -   mybuff(2) := 'Kahn';
    -
    - -

    we could pass in parameters:

    - -
    -   check_this_in => 'Zidane|Ronaldo|Kahn';
    -   line_delimiter_in => '|';
    -
    - -

    or:

    - -
    -   check_this_in => 
    -'Zidane
    -Ronaldo
    -Kahn';
    -   line_delimiter_in => NULL;
    -
    - -

    There are also the following flags to modify the way that the line-by-line comparisons are carried out:

    - -
      -
    • ignore_case_in - this specifies that case should be ignored when comparing lines.
    • -
    • ignore_whitespace_in - this specifies that whitespace differences should be ignored when comparing lines.
    • -
    - -

    Finally, note that only the text itself is compared. These assertions do -not care about how the records within the collections are numbered.

    - -

    Check for Existence of Database Objects

    - -

    The following assertions (created by Raji) check that a named database -object exists or does not exist: - -

    PROCEDURE objExists (
    -   msg_in            IN   VARCHAR2,
    -   check_this_in     IN   VARCHAR2,
    -   null_ok_in        IN   BOOLEAN := FALSE,
    -   raise_exc_in      IN   BOOLEAN := FALSE
    -);
    -
    -PROCEDURE objnotExists (
    -   msg_in            IN   VARCHAR2,
    -   check_this_in     IN   VARCHAR2,
    -   null_ok_in        IN   BOOLEAN := FALSE,
    -   raise_exc_in      IN   BOOLEAN := FALSE
    -);
    - -In both cases, the check_this_in parameter gives the name of the object to -check for. So passing 'MYTHING' will check if the MYTHING object exists. This -is assumed to be in the current schema. To check for objects in a schema other -than the current one, simply add the name of the schema, separated by a dot. -So passing 'ANOTHER.THATTHING' will check for the existence of the THATTHING -object in the ANOTHER schema.

    - -

    Check Equality of RefCursor and Query

    - If you have a procedure or function that returns a REF CURSOR type you often would like to compare the data of the REF CURSOR against a query (if your REF CURSOR returns a complete table you can use utAssert.eq_refc_table below). In this case, you specify the REF CURSOR of the procedure or function and the full SELECT statement as parameters. By using eq_refc_query, you may be able to avoid the huge workload of constructing separate tables with preset data. - -

    Before calling the comparison you have to specifiy the parameters of the procedure or function you are going to use. -This is done with the procedures utPLSQL_Util.reg_In_Param, utPLSQL_Util.reg_InOut_Param or utPLSQL_Util.reg_Out_Param. -The details of the parameters are built up in a variable of type utplsql_util.utplsql_params, which is then passed into eq_refc_query. - -

    -PROCEDURE utPLSQL_Util.reg_In_Param (
    -   par_pos            PLS_INTEGER,
    -   par_val            VARCHAR2 | NUMBER | DATE,
    -   params    IN OUT   utplsql_util.utplsql_params );
    -
    -PROCEDURE utPLSQL_Util.reg_InOut_Param (
    -   par_pos            PLS_INTEGER,
    -   par_val            VARCHAR2 | NUMBER | DATE,
    -   params    IN OUT   utplsql_util.utplsql_params );
    -
    -PROCEDURE utPLSQL_Util.reg_Out_Param (
    -   par_pos            PLS_INTEGER,
    -   par_type           VARCHAR2,
    -   params    IN OUT   utplsql_util.utplsql_params );
    -
    - -

    Having specified all the parameters for the procedure or function returning the REF CURSOR, the comparison can be started. - -

    -PROCEDURE utAssert.eq_refc_query (
    -   p_msg_nm          IN   VARCHAR2,
    -   proc_name         IN   VARCHAR2,
    -   params            IN   utplsql_util.utplsql_params,
    -   cursor_position   IN   PLS_INTEGER,
    -   qry               IN   VARCHAR2 );
    -
    - - where the reg_In_Param, reg_InOut_Param and reg_Out_Param-specific parameters are as follows: - - - - - - - - - - - - - - - - - - - -
    ParameterDescription
    par_pos Defines the parameter position beginning with 1, or 0 specifying the return value -
    par_type Specifies the data type of the return value and must be one out of 'NUMBER', 'VARCHAR', 'CHAR' or 'REFCURSOR' -
    params The local variable to keep the values that is used as a parameter for eq_refc_query -
    - -

    and the eq_refc_query-specific parameters are as follows: - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ParameterDescription
    p_msg_nm The message to be displayed if the test fails -
    proc_name Specifies the procedure or function that delivers the REF CURSOR -
    params The parameter setting for the procedure or function -
    cursor_position Position of the REF CURSOR parameter to be checked, beginning with 1, or 0 to specify the return value of a function -
    qry The SELECT statement to be checked against -
    - -

    Finally, note that only the record itself is compared. These assertions do not care about how the records within the cursor are numbered.

    - - -

    Check Equality of RefCursor and Database Table

    - - If you have a procedure or function that returns a REF CURSOR type that represents a complete table or view you - often would like to compare the data of this REF CURSOR against the table or view - (if your REF CURSOR doesn't return a complete table or view you can use utAssert.eq_refc_query above). - In this case, you specify the REF CURSOR of the procedure or function and the table or view name as parameters. - By using eq_refc_table, you may be able to avoid the huge workload of constructing separate tables with preset data. - -

    Before calling the comparison you have to specifiy the parameters of the procedure or function you are going to use. -This is done with the procedures utPLSQL_Util.reg_In_Param, utPLSQL_Util.reg_InOut_Param or utPLSQL_Util.reg_Out_Param. -The details of the parameters are built up in a variable of type utplsql_util.utplsql_params, which is then passed into eq_refc_query. - -

    -PROCEDURE utPLSQL_Util.reg_In_Param (
    -   par_pos            PLS_INTEGER,
    -   par_val            VARCHAR2 | NUMBER | DATE,
    -   params    IN OUT   utplsql_util.utplsql_params );
    -
    -PROCEDURE utPLSQL_Util.reg_InOut_Param (
    -   par_pos            PLS_INTEGER,
    -   par_val            VARCHAR2 | NUMBER | DATE,
    -   params    IN OUT   utplsql_util.utplsql_params );
    -
    -PROCEDURE utPLSQL_Util.reg_Out_Param (
    -   par_pos            PLS_INTEGER,
    -   par_type           VARCHAR2,
    -   params    IN OUT   utplsql_util.utplsql_params );
    -
    - -

    Having specified all the parameters for the procedure or function returning the REF CURSOR, the comparison can be started. - -

    -PROCEDURE utAssert.eq_refc_table (
    -   p_msg_nm          IN   VARCHAR2,
    -   proc_name         IN   VARCHAR2,
    -   params            IN   utplsql_util.utplsql_params,
    -   cursor_position   IN   PLS_INTEGER,
    -   table_name        IN   VARCHAR2 );
    -
    - - where the reg_In_Param, reg_InOut_Param and reg_Out_Param-specific parameters are as follows: - - - - - - - - - - - - - - - - - - - -
    ParameterDescription
    par_pos Defines the parameter position beginning with 1, or 0 specifying the return value -
    par_type Specifies the data type of the return value and must be one out of 'NUMBER', 'VARCHAR', 'CHAR' or 'REFCURSOR' -
    params The local variable to keep the values that is used as a parameter for eq_refc_query -
    - -

    and the eq_refc_query-specific parameters are as follows: - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ParameterDescription
    p_msg_nm The message to be displayed if the test fails -
    proc_name Specifies the procedure or function that delivers the REF CURSOR -
    params The parameter setting for the procedure or function -
    cursor_position Position of the REF CURSOR parameter to be checked, beginning with 1, or 0 to specify the return value of a function -
    table_name The name of the table name or view to be checked against -
    - -

    Finally, note that only the record itself is compared. These assertions do not care about how the records within the cursor are numbered.

    - -

    Building Your Own Assertion

    - You may want to build assertion routines that fit your specific needs. -If PL/SQL supported inheritance, you could extend the utAssert assertion -routines and then customize them through polymorphism. Lacking this feature, -however, you will write your own procedures that follow the same steps as -the pre-build assertions. In order to integrate the results of your assertion -test into the utResult package, you will want to mimic the utAssert.this procedure. -Here is its current implementation (Release 1.3.2); check the body of the -utAssert package for any changes.
    PROCEDURE this (
    msg_in IN VARCHAR2,
    check_this_in IN BOOLEAN,
    null_ok_in IN BOOLEAN := FALSE,
    raise_exc_in IN BOOLEAN := FALSE,
    register_in IN BOOLEAN := TRUE
    )
    IS
    BEGIN
    IF NOT check_this_in
    OR ( check_this_in IS NULL
    AND NOT null_ok_in)
    THEN
    IF register_in
    THEN - -- Registers the results in the utResult databank.
    utresult.report (msg_in);
    ELSE
    utreport.pl (msg_in); -- used to be utplsql.pl (msg_in) (PBA 20050621)
    END IF;

    IF showing_results AND register_in
    THEN - -- Show the results of the test more recently run.
    utresult.showlast;
    END IF;

    IF raise_exc_in
    THEN
    RAISE test_failure;
    END IF;
    END IF;
    END;
    - The most important statement to include in your assertion routine is the - call to utResult.report, which will log the results of the test. - - -

    < Previous Section: utResult Package | Next Section: utGen Package >

    -
    - - \ No newline at end of file diff --git a/website/Doc/utconfig.html b/website/Doc/utconfig.html deleted file mode 100644 index 57e3c2b16..000000000 --- a/website/Doc/utconfig.html +++ /dev/null @@ -1,499 +0,0 @@ - - - - - - - - -utConfig Package - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: utPLSQL Package | Next Section: utResult Package >

    - - -

    -utConfig Package

    - -

    This package contains the following functions and procedures: -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    utConfig.testerReturn whose configuration is used
    utConfig.settesterSet whose configuration is used
    utConfig.showconfigView a schema's configuration
    utConfig.setdirSet the directory containing the test package code
    utConfig.dirReturn the directory containing the test package code
    utConfig.setprefixSet the default unit test prefix for your code
    utConfig.prefixReturn the default unit test prefix for your code
    utConfig.registertestSet the registration mode (manual or automatic)
    utConfig.registeringReturn the registration mode
    utConfig.autocompileSet autocompile feature
    utConfig.autocompilingReturn the autocompile flag
    utConfig.setdelimiterSet the V2 delimiter
    utConfig.delimiterReturn the V2 delimiter
    utConfig.showfailuresonlyTurn off the display of successful tests
    utConfig.showingfailuresonlyReturn whether successful test results are shown or not
    utConfig.setreporterSets the default Output Reporter to use
    utConfig.getreporterGets the name of the default Output Reporter to use
    utConfig.setfiledirSet the directory for file output
    utConfig.filedirReturn which directory is used for file output
    utConfig.setuserprefixSet the user prefix for output file names
    utConfig.userprefixReturn the user prefix for output file names
    utConfig.setincludeprognameSet whether to include the name of the program being tested in output file names
    utConfig.includeprognameReturn whether to include the name of the program being tested in output file names
    utConfig.setdateformatSet the date format for the date portion of output file names
    utConfig.dateformatReturn the date format used to construct output file names
    utConfig.setfileextensionSet the file extension for output file names
    utConfig.fileextensionReturn the file extension used for output file names
    utConfig.setfileinfoSet all of the above file output related items
    utConfig.fileinfoReturn all of the above file output related items
    - -

    To make it as easy as possible for you to run your tests, utPLSQL stores -various pieces of configuration data in the ut_config table. This data -is stored by schema name and is automatically loaded into utPLSQL the first -time you use this utility in your session. This configuration information -is also automatically updated whenever you call utPLSQL.test -- or any -of the utPLSQL programs specifically designed to change the configuration -settings. -

    You can at any time view the utPLSQL configuration for the currently-connected -schema or for another schema (there is not at this point any schema-level -security; all utPLSQL users can view the configurations of all other users). -

    The data that is currently maintained for a utPLSQL user are: -

    Test package directory - the location of the test package code -you want to run. You must specify a directory in order to allow utPLSQL -to automatically compile your test packages before each test run. -

    Unit test prefix - the prefix used for test package names and -the program names within the package. If you do not specify a prefix, the -default of "ut_" is automatically applied. -

    Unit test registration mode - This setting determines whether -utPLSQL will automatically identify the unit tests to be run (strongly -recommended) or if you have chosen to manually register your unit tests -in the test package setup procedure. -

    Auto-compilation of test packages - By default, utPLSQL will -recompile your test package before execution. You can turn off this feature -and manually recompile only when you desire (a fine idea if your test package -has gotten very large!). -

    -Return whose configuration is being used

    -By default, the configuration stored for the currently-connected user will -be used. However, it is possible to use configurations stored against -other usernames. To show whose configuration is currently being used -the following function is used: -
    FUNCTION utConfig.tester RETURN VARCHAR2;
    - -

    -Set whose configuration is being used

    -This returns the configuration that will be used whenever a username is -not specified. To set this, the following procedure is used: -
    PROCEDURE utConfig.settester (username_in IN VARCHAR2 := USER);
    - -

    -View a schema's configuration

    -Call the utconfig.showconfig procedure to view the configuration for a specified -schema. The header is: -
    PROCEDURE utConfig.showconfig (username_in IN VARCHAR2 := NULL);
    -If you do not specify a schema, then the currently -used configuration is returned. Here is an example of output from this -procedure: -
    SQL> exec utconfig.showconfig
    -=============================================================
    -utPLSQL Configuration for SCOTT
    -   Directory: /apps/utplsql/code
    -   Autcompile? Y
    -   Manual test registration? N
    -   Prefix = test_
    -=============================================================
    -And here is an example of calling showConfig for a different schema: -
    SQL> exec utconfig.showconfig ('COMP')
    -=============================================================
    -utPLSQL Configuration for COMP
    -   Directory: M:\shared_apps\utplsql\comp
    -   Autcompile? N
    -   Manual test registration? N
    -   Prefix = ut_
    -=============================================================
    -You might want to put a call to showConfig in your SQL*Plus login file -so that you are reminded on startup as to what the current settings are. -Here is such a script (to be found in Examples\login_sample.sql): -
    exec utconfig.setdir ('e:\openoracle\utplsql\utinstall\examples')
    -SET SERVEROUTPUT ON SIZE 1000000 FORMAT WRAPPED
    -exec utconfig.showconfig
    - -

    -Set the directory containing the test package code

    -If you want utPLSQL to compile your test package, you must tell it the -directory in which your code is found. You can do this either when you -define -your test suite and packages within the suite, or you can call the -utConfig.setdir procedure to set the directory for your current session. -

    Note: as of v1.5.1, the value you pass in any of these programs is saved -in the configuration table and will be used in the future -- until you -change it by passing a different value. -

    The header for this procedure is: -

    PROCEDURE utConfig.setdir (dir_in IN VARCHAR2, username_in IN VARCHAR2 := NULL);
    -where dir_in is the directory and username_in is the name of the schema -to which this directory applies (NULL means the currently -used configuration is set), as in: -
    SQL> exec utconfig.setdir ('e:\demo\utplsql');
    -or, with the specification of a non-current schema: -
    SQL> exec utconfig.setdir ('e:\demo\utplsql', 'ANALYSIS');
    -Note that this directory must be accessible through UTL_FILE. -

    You might consider putting the the call to utConfig.setdir into your -login.sql so that it is run automatically, each time your start up SQL*Plus --- if you are always working from the same directory. -

    -Return the directory containing the test package code

    -You can obtain the current directory with a call to utConfig.dir: -
    FUNCTION utConfig.dir (username_in IN VARCHAR2 := NULL)
    -      RETURN VARCHAR2;
    - -

    -Set the default unit test prefix for your code.

    -The unit test prefix is very important in utPLSQL; the utility uses the -prefix to associate source code to be tested with the test package. The -prefix also allows utPLSQL to automatically identify the programs within -a test package that are to be executed as unit tests. -

    The default prefix in utPLSQL is "ut_", but you can override this when -you call utPLSQL.test or by calling the utConfig.setprefix procedure: -

    PROCEDURE utConfig.setPrefix (
    -   prefix_in IN VARCHAR2, username_in IN VARCHAR2 := NULL)
    -where prefix_in is the prefix and username_in is the name of the schema -to which this prefix applies (NULL means the currently -used configuration is set), as in: -
    SQL> exec utconfig.setPrefix ('tst#');
    -or, with the specification of a non-current schema: -
    SQL> exec utconfig.setPrefix ('t_', 'ANALYSIS');
    - -

    -Return the default unit test prefix for your code.

    -You can obtain the current prefix with a call to utConfig.prefix: -
    FUNCTION utConfig.prefix (username_in IN VARCHAR2 := NULL)
    -      RETURN VARCHAR2;
    -uPLSQL currently does not support the use of a suffix, or combination of -suffix and prefix, to identify test packages and unit test procedures. -

    -Set the registration mode (manual or automatic).

    -As of utPLSQL v1.5.1, you no longer have to register your unit test procedures -in the setup procedure of your test package. Instead, utPLSQL will scan -the data dictionary (via theALL_ARGUMENTS view) for the names of all the -unit test procedures you have defined, and then run them. utPLSQL identifies -these programs by looking for all programs whose names start with the specified -prefix. -

    If you so choose, you can request that utPLSQL turn off automatic detection -of unit test procedures and only run those programs listed in the setup -procedure. To do this, you call the utConfig.registerTest procedure: -

    PROCEDURE utConfig.registerTest (
    -      onoff_in IN BOOLEAN,
    -      username_in IN VARCHAR2 := NULL
    -   );
    -as in: -
    SQL> exec utConfig.registerTest (TRUE)
    -Note: if you are using automatic unit test detection, any calls to utPLSQL.addtest -in the setup procedure will be ignored. - -

    You can return the current registration mode using the following function: -

    FUNCTION registeringtest (username_in IN VARCHAR2 := NULL)
    -   RETURN BOOLEAN;
    -This returns TRUE if the registration mode has been set to manual and FALSE otherwise. -

    - -

    -Set autocompile feature

    - -The default settings for utPLSQL is to re-compile -your base package before each unit test. This guarantees that any recent -changes will be tested. It also saves you the step of doing an explicit -compile. - -In order to perform automatic compilation: - -
      -Your schema will need to -have either CREATE PROCEDURE or CREATE ANY PROCEDURE privileges granted -directly; -you cannot grant these privileges through roles. - -You will need to set or -pass the location of the source code. You can do this by calling utConfig.setdir -or by including the directory location in your call to utPLSQL.test -or utPLSQL.testsuite (the dir_in -parameter). - -The package specification -must be contained in a file named <package>.pks; the body must be stored -in <package>.pkb. - -You must have configured -the -UTL_FILE built-in package for use -on your database instance. -
    - -In general (and the default), you should allow your -test package to be recompiled with each execution. You might want to avoid -recompilation if: - -
      -You have made a copy of the package body with some -temporary changes and already compiled that. If you recompile automatically, -you will wipe out those changes. - -You have not set up UTL_FILE -and you don't want to deal with it. - -You are running the tests -on a server to which you have no access other than via a database connection. -
    - -

    -Turning off Auto-compile

    - -If you are working with products like SQL*Navigator, -you may be always editing from code stored in the database. In this case, -you will never want to have utPLSQL recompile your code for you – it will -already be compiled and you do not need to hassle with UTL_FILE. - -You can avoid auto-recompilation in two ways: - -1. Pass a value of FALSE for the recompile_in argument -to utPLSQL.test or utPLSQL.testsuite. Here is an example: - -
    BEGIN
    -   -- Define a test suite for PL/Vision
    -   utsuite.add ('PLVision');
    -  
    -   -- Add two packages for testing
    -   utsuite.addpkg (
    -      'PLVision', 'PLVstr', dir_in => 'e:\utplsql');
    -   utsuite.addpkg (
    -      'PLVision', 'PLVdate', dir_in => 'e:\utplsql');
    -  
    -   -- Run the test suite
    -   utplsql.testsuite (
    -      'PLVision', recompile_in => FALSE);
    -END;
    -/
    - -If you know that you will never want to recompilation, -however, you can set the default behavior at the schema level by calling -the autocompile procedure - -
       PROCEDURE utConfig.autocompile (
    -      onoff_in IN BOOLEAN,
    -      username_in IN VARCHAR2 := NULL
    -   );
    - 
    - -So I can make the following -call to turn off autocompilation for the SCOTT schema: - -
    -
    -
    SQL> exec utconfig.autocompile (FALSE, 'SCOTT') 
    -This program updates the ut_config table with your information and then -commits the setting. - -

    You can determine the current -setting for auto-compilation at any time by calling the following function: -

    -   FUNCTION utConfig.autocompiling (username_in IN VARCHAR2 := NULL)
    -      RETURN BOOLEAN;
    - -Note: When you set the schema-level recompilation -value to FALSE, that will override anything you pass in a call to utPLSQL.test -or utPLSQL.testsuite. - -

    - V2 Delimiter

    -

    You can set the delimiter to be used in V2 procedure names using the following procedure: -

    PROCEDURE setdelimiter (
    -  delimiter_in IN VARCHAR2, 
    -  username_in IN VARCHAR2 := NULL
    -); 
    -while the current delimiter can be obtained by the function: -
    FUNCTION delimiter (username_in IN VARCHAR2 := NULL)
    -  RETURN VARCHAR2;
    -

    - -

    - Turn off the display of successful test results -

    -

    -By default, the results of all the tests are shown. This includes both successful and unsuccessful -results. The following procedure allows you to limit the tests shown to only those that have failed: -

    PROCEDURE showfailuresonly (
    -     onoff_in      IN   BOOLEAN,
    -     username_in   IN   VARCHAR2 := NULL
    -   );
    -the current setting can be obtained by the function: -
    FUNCTION showingfailuresonly (username_in IN VARCHAR2 := NULL)
    -      RETURN BOOLEAN;
    -

    - - -

    - Set and Get the default output reporter -

    -

    -By default, all results are sent to the screen via DBMS_OUTPUT. However, it is possible to use other output reporters as described in more detail -on this page. The following procedure allows you to set which output reporter should be used by default: -

    PROCEDURE setreporter (
    -      reporter_in   IN   VARCHAR2
    -     ,username_in   IN   VARCHAR2 := NULL
    -   );
    -
    -as usual, the current setting can be obtain by the following function: -
    FUNCTION getreporter (username_in IN VARCHAR2 := NULL)
    -      RETURN VARCHAR2;
    -
    -

    - - -

    < Previous Section: utPLSQL Package | Next Section: utResult Package >

    -
    - - \ No newline at end of file diff --git a/website/Doc/utgen.html b/website/Doc/utgen.html deleted file mode 100644 index 65fafe457..000000000 --- a/website/Doc/utgen.html +++ /dev/null @@ -1,752 +0,0 @@ - - - - - - - - -utGen Package - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: utAssert Package | Next Section: utOutput Package >

    - - -

    -utGen Package

    - -

    This package contains the following procedures and functions: -
    - - - - - - - - - - - - - - - - - - - - - - - - - -
    utGen.testpkg (basic version)Generate skeleton test packages
    - utGen.testpkg (grid version)
    - utGen.testpkg_from_file
    - utGen.testpkg_from_string -
    Generate skeleton test packages with test cases
    utGen.pkgstringGet skeleton as a string
    utGen.countRows -
    utGen.firstRow -
    utGen.firstBodyRow -
    utGen.atFirstRow -
    utGen.lastRow -
    utGen.atLastRow -
    utGen.setRow -
    utGen.getRow -
    utGen.nextRow -
    utGen.prevRow -
    utGen.showRows -
    utGen.nthRow
    Get rows from generated skeleton test package as array
    - - -

    -Generate Skeleton Test Packages

    -The utGen contains a procedure that allows you to generate a starting point -for a unit test package. This package can be sent to the screen, -a file, a delimited string or -an array (best for interfacing with a front end). -You can generate a stand-alone test package or code "fragments" to be placed -inside an existing source package. - -We strongly recommend that you use utGen.testpkg -as a starting point for all of your utPLSQL unit test construction. By -taking this approach, you will most easily (and transparently) conform -to the most up to date guidelines for utPLSQL test packages. - -Note: While utGen.testpkg goes as far as -possible to generate sensible unit test code, you will need to edit this -code before you can compile and use it. - -Here is the header of the testpkg procedure: - -
       PROCEDURE utGen.testpkg (
    -      package_in IN VARCHAR2,
    -      program_in IN VARCHAR2 := '%',
    -      samepackage_in IN BOOLEAN := FALSE,
    -      prefix_in IN VARCHAR2 := NULL,
    -      schema_in IN VARCHAR2 := NULL,
    -      output_type_in IN PLS_INTEGER := c_screen,
    -      dir_in IN VARCHAR2 := NULL,
    -      delim_in IN VARCHAR2 := c_delim
    -   );
    - -And here is a description of the parameters: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Parameter NameUsage
    -package_in - -The name of the package or stand-alone program for -which a test package is to be generated. -
    -program_in - -The filter to be applied to the list of programs -for which unit test procedures will be generated. So if you only wanted -to generate unit tests for programs that start with "UPD", you would pass -'UPD%' for this argument. -
    -samepackage_in - -TRUE if you plan to insert the generated code into -the source package, FALSE if you want a stand-alone test package. -
    -prefix_in - -The prefix to be used for the test package and/or -unit test procedures. See section " Organizing Your Test Code" for details. -
    -schema_in - -The schema that owns the package or program specified -by package_in. The default is the currently connected schema. -
    -output_type_in - -The type of output that will receive the generated -code. Valid options are defined as packaged constants: - -
      -
    • utGen.c_file
    • - -
    • utGen.c_screen
    • - -
    • utGen.c_string
    • - -
    • utGen.c_array
    • -
    - -The following sections explain the way you would -work with these constants and the resulting generated code. -
    -dir_in - -The location of the file containing the generated -code. Used only if you specify utGen.c_file for the output type. -
    -delim_in - -The delimiter used to separate lines of generated -code. Used only if you specify utGen.c_string for the output type. -
    - - -

    Before you use utGen.testpkg, you should make a few -decisions about your generated code: -

      -
    • -Do you want the generated test code to be a stand-alone package or to be -inserted into an existing package? The default is stand-alone. Pass TRUE -for samepackage_in if you want to generate code that can be easily cut -and pasted into your source package. Note that utGen.testpkg does not -actually modify your source package.
    • - -Do you want to generate a unit test program -for every procedure and function in your package? If so, then go with the -default for program_in. If, on the other hand, your package has one hundred -programs and you only want to test, say, only those programs that perform -updates, you might want to pass a non-trivial filter, such as "UPD%". - -Where do you want to send your output? You -can display to the screen, which can then be grabbed and put into a file -(or in SQL*Plus spool it directly to a file). You can send the code to -a file. You can deposit the code in a delimited string and then parse it -within your own environment. Finally -- and of most relevance if you are -building a GUI interface to utPLSQL -- you can generate to an internal -array and then retrieve individual rows of the arrays through the utGen -API. -
    - -Here are some examples of using utGen.testpkg: - -
      -
    1. -Generate to the screen a stand-alone test package for the STR package:
    2. -
    - -
    -
    -
    SQL> exec utGen.testpkg ('str')
    -
    -
    - -
      -
    1. -Generate to the screen unit test code to be embedded inside the STR package:
    2. -
    - -
    -
    -
    SQL> exec utGen.testpkg ('str', samepackage_in => TRUE)
    -
    -
    - -
      -
    1. -Generate to the screen unit test code for all programs whose names contain -"STR" to be embedded inside the STR package,.
    2. -
    - -
    -
    -
    SQL> exec utGen.testpkg ('str', '%STR%', samepackage_in => TRUE)
    -
    -
    - -Now let's explore how to direct the generated code -to different types of output. - -

    -Generating to Screen

    - -The default behavior of utGen.testpkg is to generate -code to your screen (via DBMS_OUTPUT.PUT_LINE). So unless you specify some -other value for output_type_in, the code will be displayed on your screen -or within a window of your PL/SQL IDE (such as TOAD or SQL*Programmer and -so on). You can then transfer that content to a file, or move it to another -window for immediate editing and compilation. - -Here is an example of using utGen.testpkg, while -also spooling to a file: - -
    SQL> set serveroutput on size 1000000
    -SQL> spool str.pkg
    -SQL> exec utgen.testpkg ('str')
    - -...out comes the code... - -
    SQL> spool off
    - -If DBMS_OUTPUT is not enabled in your session, then -utGen.testpkg will not generate any output. - -

    -Generating to File

    - -If you are working with utGen in a command line -style (ie, you are not using a utGen-enabled GUI), then you will probably -find it most useful to generate testing code directly to file. You do this -by specifying utGen.c_file for the output type. You must also specify the -directory in which you want the files (one for the package specification -and another for the body)created. - -Here's a generation request that creates two files -named ut_str.pks and ut_str.pkb in the /newcode directory: - -
    SQL> exec utgen.testpkg ('str', output_type_in => utGen.c_file, dir_in => '/newcode')
    - -Notes on generating to file: - - -
      -
    1. -You do not have to specify a directory if you have previously (in your -current session) called utConfig.setdir to set the default directory for -all file-related utPLSQL operations. The following two lines of code are, -in other words, equivalent to the single line shown above:
    2. -
    - - -
    -
    -
    SQL> exec utconfig.setdir ('/newcode')
    -SQL> exec utgen.testpkg ('str', output_type_in => utGen.c_file);
    -
    -
    - -
      -
    1. -You set up the UTL_FILE package (add at least one utl_file_dir entry in -your database parameter initialization file) and make sure your directory -is accessible through UTL_FILE, before this operation can succeed.
    2. -
    - -

    -Generating to String

    - -If you are accessing utPLSQL functionality through -a GUI, you might find it more useful to direct output to a string (or array, -see next section). You probably don't want to hassle with UTL_FILE (server-based -file IO) and grabbing information from DBMS_OUTPUT.PUT_LINE is just a general -hassle. - -If you generate to a string, you can then retrieve -that string value into a local variable and then parse it for display and -manipulation. Here is an example of redirection to string: - -
    BEGIN
    -   utgen.testpkg ('str', output_type_in => utGen.c_string);
    -END;
    - -The generated code is composed of multiple lines -of information, so they need to be separated by a delimiter. The default -delimiter is the vertical bar, '|'. You can override that and provide your -own delimiter. In the following example, I have decided to use the carriage -return character as my delimiter: - -
    BEGIN
    -   utgen.testpkg (
    -      'str',
    -      output_type_in => utGen.c_string,
    -      delim_in => CHR(10));
    -END;
    - -Great, so the code has been put in a string. How -do you get all that generated code? Call the utGen.pkgstring function: - -
    FUNCTION utGen.pkgString RETURN VARCHAR2;
    - -

    -Generating to Array

    - -If you are accessing utPLSQL functionality through -a GUI, you might find it more useful to direct output to an array. You -probably don't want to hassle with UTL_FILE (server-based file IO) and -grabbing information from DBMS_OUTPUT.PUT_LINE is just a general hassle. - -If you generate to an array, you can then retrieve -the individual lines of code in the array through an API provided by utGen -(the array itself is "hidden"). Here is an example of redirection to the -utGen array: - -
    BEGIN
    -   utgen.testpkg ('str', output_type_in => utGen.c_array);
    -END;
    - -Great, so the code has been put in an array. How -do you get all that generated code? Take advantage of the utGen -API to retrieve individual rows in the array, which offers these features: - -Get the number of rows currently in the array: - -
       FUNCTION utGen.countRows RETURN PLS_INTEGER;
    - -Get the absolute index of the first row in the array: - -
       FUNCTION utGen.firstRow RETURN PLS_INTEGER;
    - -Get the absolute index of the last row in the array: - -
       FUNCTION utGen.lastRow RETURN PLS_INTEGER;
    - -The API offers a set of programs to iterate through -the array, by maintaining a "current row" inside the package. You can: - -Find out if you are positioned at the first row -in the set: - -
       FUNCTION utGen.atFirstRow RETURN BOOLEAN;
    - -Find out if you are positioned at the last row in -the set: - -
       FUNCTION utGen.atLastRow RETURN BOOLEAN;
    - -Find the first relative row containing the start -of the package body definition. This is handy when you want to put the -code for the specification and body in separate windows and/or files: - -
       FUNCTION utGen.firstBodyRow RETURN PLS_INTEGER;
    - -Retrieve the text in the Nth row of the array. This -gives you "random access" to the contents of the array. You can even specify -a negative direction to get the Nth row from the end of the array. - -
       FUNCTION utGen.nthRow (nth IN PLS_INTEGER, direction utGen.IN SIGNTYPE := 1) RETURN codeline_t;
    - -Set the pointer in the array to the specified row -number. This allows you then move either forward or backward from that -row in the array (using nextRow and prevRow, respectively): - -
       PROCEDURE utGen.setRow (nth IN PLS_INTEGER);
    - -Retrieve the line of code stored in the current -row in the array (set via setRow, nextRow or prevRow): - -
       FUNCTION utGen.getRow RETURN codeline_t;
    - -Go to the next row in the array: - -
       PROCEDURE utGen.nextRow;
    - -Go to the previous row in the array: - -
       PROCEDURE utGen.prevRow;
    - -Show the contents of the array using DBMS_OUTPUT.PUT_LINE: - -
       PROCEDURE utGen.showRows (
    -      startRow IN PLS_INTEGER := NULL,
    -      endRow IN PLS_INTEGER := NULL);
    - -Here is the code I would write in PL/SQL using this -API to display the contents of the array (actually, it is the implementation -of showRows): - -
       PROCEDURE showrows (
    -      startrow IN PLS_INTEGER := NULL,
    -      endrow IN PLS_INTEGER := NULL
    -   )
    -   IS
    -      v_start PLS_INTEGER
    -                    := NVL (startrow, 1);
    -      v_end PLS_INTEGER
    -         := NVL (endrow, utGen.countRows);
    -   BEGIN
    -      FOR indx IN 1 .. utGen.countRows
    -      LOOP
    -         DBMS_OUTPUT.put_line (utGen.getRow (indx));
    -      END LOOP;
    -   END;
    - -Here is the code I would write to separate out the -contents of the specification from the body: - -
       PROCEDURE showrows (
    -      startrow IN PLS_INTEGER := NULL,
    -      endrow IN PLS_INTEGER := NULL
    -   )
    -   IS
    -      v_start PLS_INTEGER
    -                    := NVL (startrow, 1);
    -      v_end PLS_INTEGER
    -         := NVL (endrow, utGen.countRows);
    -   BEGIN
    -      FOR indx IN 1 .. utGen.countRows
    -      LOOP
    -         IF indx = utGen.firstBodyRow
    -         THEN
    -            -- switch to Body window or file
    -         END IF;
    -         write_to_target (utGen.getRow (indx));
    -      END LOOP;
    -   END;
    - - -

    - Generating Test Packages with Test Cases

    - -

    The procedures to generate test packages with test cases are similar to testpkg above, but with a number of extra parameters:

    - -
     PROCEDURE testpkg (
    -      package_in           IN   VARCHAR2,
    -      grid_in              IN   grid_tt,
    -      program_in           IN   VARCHAR2 := '%',
    -      samepackage_in       IN   BOOLEAN := FALSE,
    -      prefix_in            IN   VARCHAR2 := NULL,
    -      schema_in            IN   VARCHAR2 := NULL,
    -      output_type_in       IN   PLS_INTEGER := c_screen,
    -      dir_in               IN   VARCHAR2 := NULL,
    -      delim_in             IN   VARCHAR2 := c_delim,
    -      date_format_in       IN   VARCHAR2 := 'MM/DD/YYYY',
    -      only_if_in_grid_in   IN   BOOLEAN := FALSE
    -   );
    -
    -   PROCEDURE testpkg_from_file (
    -      package_in           IN   VARCHAR2,
    -      gridfile_loc_in      IN   VARCHAR2,
    -      gridfile_in          IN   VARCHAR2,
    -      program_in           IN   VARCHAR2 := '%',
    -      samepackage_in       IN   BOOLEAN := FALSE,
    -      prefix_in            IN   VARCHAR2 := NULL,
    -      schema_in            IN   VARCHAR2 := NULL,
    -      output_type_in       IN   PLS_INTEGER := c_screen,
    -      dir_in               IN   VARCHAR2 := NULL,
    -      field_delim_in       IN   VARCHAR2 := '|',
    -      arg_delim_in         IN   VARCHAR2 := c_delim,
    -      date_format_in       IN   VARCHAR2 := 'MM/DD/YYYY',
    -      only_if_in_grid_in   IN   BOOLEAN := FALSE
    -   );
    -
    -   PROCEDURE testpkg_from_string (
    -      package_in           IN   VARCHAR2,
    -      grid_in              IN   VARCHAR2,
    -      program_in           IN   VARCHAR2 := '%',
    -      samepackage_in       IN   BOOLEAN := FALSE,
    -      prefix_in            IN   VARCHAR2 := NULL,
    -      schema_in            IN   VARCHAR2 := NULL,
    -      output_type_in       IN   PLS_INTEGER := c_screen,
    -      dir_in               IN   VARCHAR2 := NULL,
    -      line_delim_in        IN   VARCHAR := CHR (10),
    -      field_delim_in       IN   VARCHAR2 := '|',
    -      arg_delim_in         IN   VARCHAR2 := c_delim,
    -      date_format_in       IN   VARCHAR2 := 'MM/DD/YYYY',
    -      only_if_in_grid_in   IN   BOOLEAN := FALSE
    -   ); 
    - -

    In each case, the idea is the same. We have to provide not only the -arguments supplied to the basic version of testpkg, but also details of each of -the test cases in a grid. In the first case, this is as a PL/SQL table, in the -second this is as a file and in the final case, this is as a string.

    - -

    The PL/SQL table passed to testpkg is defined as follows:

    - -

     TYPE grid_rt IS RECORD (
    -      progname                      VARCHAR2 (100),
    -      overload                      PLS_INTEGER,
    -      tcname                        VARCHAR2 (100),
    -      message                       VARCHAR2 (2000),
    -      arglist                       VARCHAR2 (2000),
    -      return_value                  VARCHAR2 (2000),
    -      assertion_type                VARCHAR2 (100));
    -
    -   TYPE grid_tt IS TABLE OF grid_rt
    -      INDEX BY BINARY_INTEGER; 
    - -

    Where the definitions of the fields are as follows:

    - -
      - -
    1. progname - This is the name of the subprogram to be tested.
    2. - -
    3. overload - This is the version of the subprogram where - overladed versions exist. (You may have to look in the data dictionary to - work this out).
    4. - -
    5. tcname - The name of the test case.
    6. - -
    7. message - The message to be used in the assertion - code.
    8. - -
    9. arglist - The list of arguments to be passed to the - subprogram.
    10. - -
    11. return_value - The return value to be checked against.
    12. - -
    13. assertion_type - The type of assertion to be used. - Currently this is ignored unless it contains 'EQ' or 'ISNULL'
    14. - -
    - -

    In testpkg_from_file and testpkg_from_string, exactly the same fields need -to be passed (and in the same order). These fields are separated by the -character given by the field_delim_in parameter which defaults to '|', the pipe -symbol. In the case of testpkg_from_string, we can also specify the line -delimiter in the line_delim_in parameter, which defaults to an ASCII linefeed -character.

    - -

    In all cases, the arguments specified in the arglist field are separated -by yet another delimiter, which is passed in the arg_delim_in parameter (or just delim_in in the case of testpkg). This defaults to a semicolon.

    - -

    The remaining arguments passed to these routines are date_format_in and only_if_in_grid_in. The former gives the date format used in dates passed through the arglist and return_values fields. The latter specifies if tests should only be generated for subprograms listed in the grid or not.

    - -

    An Example

    - -

    All of this is probably best explained with an example. Suppose I have a package defined as:

    - -
    -CREATE OR REPLACE PACKAGE lottery AS
    -  FUNCTION Draw (seed_in NUMBER := NULL, when_in DATE := NULL) RETURN VARCHAR2;
    -END;
    -
    - -

    This returns a string describing a lottery draw, given a seed and a date. I -want to test the following conditions: (It doesn't make much sense, but hey, -it's only an example) - -

      - -
    • Passing both parameters as NULL, we should get back '01 02 03 04 05 - 06'.
    • - -
    • Passing in 7 for the seed and 1 January 2001 for the date, we should get back '23 24 27 37 39 48'.
    • - -
    • Passing in 0 for the seed and today's date, we should get back NULL
    • - -
    So to generate the skeleton I require I could run the following through -SQL*Plus:

    - -
    set serveroutput on size 1000000
    -declare
    -  a_grid utgen.grid_tt;
    -begin
    -  
    -  a_grid(0).progname := 'Draw';
    -  a_grid(0).tcname := 'Test Case 1';
    -  a_grid(0).message := 'The First Test';
    -  a_grid(0).return_value := '01 02 03 04 05 06';
    -  a_grid(0).assertion_type := 'EQ';
    -  a_grid(1).progname := 'Draw';
    -  a_grid(1).tcname := 'Test Case 2';
    -  a_grid(1).message := 'The Second Test';
    -  a_grid(1).arglist := '7;2001-01-01';
    -  a_grid(1).return_value := '23 24 27 37 39 48';
    -  a_grid(1).assertion_type := 'EQ';
    -  a_grid(2).progname := 'Draw';
    -  a_grid(2).tcname := 'Test Case 3';
    -  a_grid(2).message := 'The Third Test';
    -  a_grid(2).return_value := NULL;
    -  a_grid(2).arglist := '0;!SYSDATE';
    -  a_grid(2).assertion_type := 'ISNULL';
    -  
    -  utgen.testpkg(
    -    package_in => 'LOTTERY', 
    -    grid_in => a_grid, 
    -    date_format_in => 'YYYY-MM-DD');
    -end;
    -/
    - -

    or the equivalent:

    - -
    set serveroutput on size 1000000
    -begin
    -  utgen.testpkg_from_string (
    -      package_in => 'LOTTERY',
    -      grid_in =>
    -'Draw||Test Case 1|The First Test||01 02 03 04 05 06|EQ
    -Draw||Test Case 2|The Second Test|7;2001-01-01|23 24 27 37 39 48|EQ
    -Draw||Test Case 3|The Third Test|0;!SYSDATE||ISNULL',
    -      date_format_in => 'YYYY-MM-DD'
    -   );
    -end;
    -/ 
    - -

    which generate the following for the body of ut_draw (tidied up a little for compactness):

    - -
    PROCEDURE ut_DRAW
    -IS
    -   -- Verify and complete data types.
    -   against_this VARCHAR2(2000);
    -   check_this VARCHAR2(2000);
    -BEGIN
    -   
    -   -- Define "control" operation for "Test Case 1"
    -   against_this := '01 02 03 04 05 06';
    -    
    -   -- Execute test code for "Test Case 1"
    -   check_this := 
    -   LOTTERY.DRAW (SEED_IN => '', WHEN_IN => '');
    -    
    -   -- Assert success for "Test Case 1"
    -   -- Compare the two values.
    -   utAssert.eq ( 'The First Test', check_this, against_this);
    -
    -   -- End of test for "Test Case 1"
    -   
    -   -- Define "control" operation for "Test Case 2"
    -   against_this := '23 24 27 37 39 48';
    -    
    -   -- Execute test code for "Test Case 2"
    -   check_this := LOTTERY.DRAW (SEED_IN => 7, WHEN_IN => TO_DATE ('2001-01-01', 'YYYY-MM-DD'));
    -    
    -   -- Assert success for "Test Case 2"
    -   -- Compare the two values.
    -   utAssert.eq ( 'The Second Test', check_this, against_this);
    -
    -   -- End of test for "Test Case 2"
    -   
    -   -- Define "control" operation for "Test Case 3"
    -   against_this := NULL;
    -    
    -   -- Execute test code for "Test Case 3"
    -   check_this := 
    -   LOTTERY.DRAW (SEED_IN => 0, WHEN_IN => SYSDATE);
    -    
    -   -- Assert success for "Test Case 3"
    -   -- Check for NULL return value.
    -   utAssert.isNULL ( 'The Third Test', check_this);
    -
    -   -- End of test for "Test Case 3"
    -   
    -END ut_DRAW; 
    - -

    Note that the different data types are handled automatically. So '2001-01-01' is converted to -a date using TO_DATE and the specified date format. However, we wanted to enter SYSDATE for our -argument in one of these cases. How do we stop this being converted into a date? The answer -is that we need to prefix the value with a '!' (an exclamation mark). This causes utGen to -pass this along 'as is' without attempting any conversion. Note that this cannot currently -be overridden, so if your data starts with an exclamation mark, you'll have to work around -this problem.

    - - -

    < Previous Section: utAssert Package | Next Section: utOutput Package >

    -
    - - \ No newline at end of file diff --git a/website/Doc/utoutput.html b/website/Doc/utoutput.html deleted file mode 100644 index 3a38366d6..000000000 --- a/website/Doc/utoutput.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - - - -utOutput Package - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: utGen Package | Next Section: utRecEq Package >

    - - -

    -utOutput Package

    - -

    This package contains the following procedures and functions: -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    utOutput.saveTurn on the 'save' flag
    utOutput.nosaveTurn off the 'save' flag
    utOutput.savingReturn the 'save' flag
    utOutput.extractPull text from the DBMS_OUTPUT buffer
    utOutput.replaceReplace saved output in the DBMS_OUTPUT buffer
    utOutput.nextLinePull the next line from the DBMS_OUTPUT buffer
    utOutput.countCount the lines in the DBMS_OUTPUT buffer
    - -

    Outline of Usage

    - -

    The problem with attempting to test output in PL/SQL is that there is a single -DBMS_OUTPUT buffer. When your test is run, there may already be output in the -buffer from other tests, or from the tested code. So what state should you -leave it in once you have finished? Perhaps you want all the output created by -your tested code to end up in the buffer as if it had been run normally (i.e. -not from within utPLSQL), or maybe you want only the text that was in the -buffer before you started to be left.

    - -

    This package attempts to allow to do any of these. There is a flag in the -package to determine whether text pulled from the output buffer should be -saved. This is set with 'save' and 'nosave' and returned by -'saving'. Data is pulled from the buffer using 'extract', -while the procedure 'replace' puts any saved data back into the output -buffer.

    - -

    The intent is that it is used like this:

    - -
    -PROCEDURE ut_my_test IS
    -BEGIN
    -
    -  --Pull out any text already in the output buffer
    -  utoutput.save;
    -  utoutput.extract;
    -
    -  --Your testing code here, with saving turned on or off as you see fit
    -
    -  --Put text back in the output buffer 
    -  utoutput.replace;
    -
    -END;
    -
    - -

    So to start with, we save any text already in the buffer. We then carry out -our testing. If we want the output generated by the testing to end up back in -the output buffer, we turn on saving. Finally, we put the saved text back.

    - -

    Warning

    -

    In the current version of utPLSQL (2.0.9.1) use of this package is virtually impossible with -utPLSQL tracing turned on. The reason for this is that this facility writes output using -DBMS_OUTPUT every time an assertion is called.

    - -

    Saving Output

    - -

    The three routines for handling the save flag are:

    -
    -PROCEDURE save;
    -
    -PROCEDURE nosave;
    -
    -FUNCTION saving RETURN BOOLEAN;
    -
    - -

    Quite simply, 'save' turns the flag on, 'nosave' turns it off and 'saving' -returns its current value.

    - -

    Extracting Output

    - -

    There are 4 versions of the extract routine to get text from the output buffer:

    - -
    -FUNCTION extract (
    -   buffer_out    OUT DBMS_OUTPUT.CHARARR,
    -   max_lines_in  IN INTEGER := NULL,
    -   save_in       IN BOOLEAN := saving
    -) RETURN INTEGER;
    -
    -PROCEDURE extract (
    -   buffer_out    OUT DBMS_OUTPUT.CHARARR,
    -   max_lines_in  IN INTEGER := NULL,
    -   save_in       IN BOOLEAN := saving
    -);
    -
    -FUNCTION extract(
    -   max_lines_in  IN INTEGER := NULL,
    -   save_in       IN BOOLEAN := saving
    -) RETURN INTEGER;
    -
    -PROCEDURE extract(
    -   max_lines_in  IN INTEGER := NULL,
    -   save_in       IN BOOLEAN := saving
    -);
    -
    - -

    The function versions return the number of lines extracted from the -DBMS_OUTPUT buffer. The other parameters are used as follows: -

      -
    • buffer_out - This is a buffer in which to put the extracted text.
    • -
    • max_lines_in - This is the maximum number of lines to be extracted. If NULL is passed in (the default) then all the lines are extracted.
    • -
    • save_in - This specifies if the extracted output should be saved. It overrides the global save flag.
    • -
    -

    - -

    Replacing Output

    - -

    The replace procedure takes no parameters:

    -
    -PROCEDURE replace;   
    -
    -

    It simply puts the saved text back into the DBMS_OUTPUT buffer. Note that the buffer is emptied at this point.

    - -

    Checking Output Line-by-Line

    - -

    The nextLine function makes it easy to check output line-by-line as it -simply extracts and returns the next line of output:

    - -
    -FUNCTION nextLine(
    -  raise_exc_in BOOLEAN := TRUE, 
    -  save_in BOOLEAN := saving
    -) RETURN VARCHAR2;   
    -
    - -

    The raise_exc_in flag determines if the function should throw the exception utOutput.EMPTY_OUTPUT_BUFFER when asked for the next line from an empty buffer. If no exception is thrown, NULL is returned. As with extract, the save_in flag simply overrides the global save flag setting. -

    - -

    Size of Output

    - -

    This function simply counts the number of lines present in the output buffer:

    - -
    -FUNCTION count RETURN INTEGER;   
    -
    - -

    Note that the output itself is left untouched.

    - - -

    < Previous Section: utGen Package | Next Section: utRecEq Package >

    -
    - - \ No newline at end of file diff --git a/website/Doc/utplsql.css b/website/Doc/utplsql.css deleted file mode 100644 index fe4a5d0e5..000000000 --- a/website/Doc/utplsql.css +++ /dev/null @@ -1,39 +0,0 @@ -/* utPLSQL Stylesheet */ -/*$Id$*/ - -/* For top-level headings and utPLSQL logo, we want a - purple bar across the page */ -H1, .purple_bar {font-family: Arial, Helvetica, Sans-Serif; - color: #ffffff; - background: #800080; - margin-left: 0px; - margin-right: 0px; - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px} - -/* Second level headings in purple */ -H2 {font-family: Arial, Helvetica, Sans-Serif; - color: #800080} - -/* Other headings in Sans Serif Font */ -H3, H4, H5, H6 {font-family: Arial, Helvetica, Sans-Serif} - -/* Pre formatted code is in a gray box, in monotype */ -Pre {font-family: Courier, Monotype; - font-size: smaller; - color: #000000; - background: #f0f0f0; - margin-left: 20px; - margin-right: 20px; - padding-left: 10px; - padding-top: 5px; - padding-bottom: 5px; - padding-right: 10px} - -/* Code in monotype */ -Code {font-family: Courier, Monotype; - font-size: smaller;} - -/* Copyright notice is tiny */ -.copyright {font-size: xx-small} diff --git a/website/Doc/utplsql.html b/website/Doc/utplsql.html deleted file mode 100644 index 57c85907a..000000000 --- a/website/Doc/utplsql.html +++ /dev/null @@ -1,617 +0,0 @@ - - - - - - - - -utPLSQL Package - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: User Guide | Next Section: utConfig Package >

    - - -

    utPLSQL Package

    - -

    The utPLSQL package offers the following capabilities:
    -

    - - - - - - - - - - - - - - - - - - - - - - - -
    -

    utPLSQL.test
    - utPLSQL.run

    -
    -

    Run a test

    -
    -

    utPLSQL.testsuite
    - utPLSQL.runsuite

    -
    -

    Run a test suite

    -
    -

    utPLSQL.version

    -
    -

    Get the version of utPLSQL

    -
    -

    utPLSQL.trc
    - utPLSQL.notrc
    - utPLSQL.tracing

    -
    -

    Control utPLSQL's tracing mechanism

    -
    -

    utPLSQL.addtest

    -
    -

    Register a unit test in a test package

    -
    - -

    Run a Test or Test Suite

    - -

    With utPLSQL, you can run all the unit tests contained in a -single test package, or run the tests for a series of test packages defined in -a test suite.

    - -

    The utPLSQL package offers two procedures, test and testsuite, to make it -easy for you to run "red light, green light" tests. Before you can -use these programs, however, you must build -your own test package.

    - -

    To run a test for a single package, use the utPLSQL.test procedure:

    - -
    PROCEDURE utPLSQL.test (
    -   package_in IN VARCHAR2,
    -   samepackage_in IN BOOLEAN := FALSE,
    -   prefix_in IN VARCHAR2 := NULL,
    -   recompile_in IN BOOLEAN := TRUE,
    -   dir_in IN VARCHAR2 := NULL,
    -   suite_in in VARCHAR2 := NULL,
    -   owner_in IN VARCHAR2 := NULL,
    -   reset_results_in IN BOOLEAN := TRUE ,
    -   from_suite_in         IN   BOOLEAN := FALSE,
    -   subprogram_in         IN   VARCHAR2 := '%',
    -   per_method_setup_in   IN   BOOLEAN := FALSE
    -);
    - -

    where the parameters are defined as follows:
    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -

    package_in

    -
    -

    The name of the package or stand-alone program to be - tested.

    -
    -

    samepackage_in

    -
    -

    Pass TRUE if your unit test programs are defined in the same - package as the source code to be tested. The default is that you have created - a separate package.

    -
    -

    prefix_in

    -
    -

    The prefix to be appended to package_in to come up with - the name of the test package. If you do not provide a value, the last prefix - you specified (or the default) will be used.

    -
    -

    recompile_in

    -
    -

    Pass FALSE if you do not want utPLSQL to automatically recompile your test package - before running the test.

    -
    -

    dir_in

    -
    -

    The directory containing the test package source code. If - you do not provide a value in your call to utPLSQL.test (the default) and if - you have not turned off automatic recompilation, utPLSQL will look for the - test package source code in the directory specified by a call to utConfig.setdir. If you do not provide a - value, the last directory you specified (if any) will be used.

    -
    -

    suite_in

    -
    -

    The name of the suite that contains the specified test - package. This is an optional value and is used to update statistics - for the test.

    -
    -

    owner_in

    -
    -

    The name of the schema that was specified when the test - suite was defined and the packaged added to the suite. This is an - optional value and is used to update statistics for - the test.

    -
    -

    reset_results_in

    -
    -

    Pass FALSE to tell utPLSQL to not reset the results - information, in which case you will still be able to view results by calling utResult.show . Otherwise, utPLSQL clears the result - data after each test.

    -
    -

    from_suite_in

    -
    -

    Pass TRUE to tell utPLSQL that this test is being run from - within a test suite (for internal use only).

    -
    -

    subprogram_in

    -
    -

    Pass a string to restrict which of the test procedures - will be executed for this run. Default of % means all tests will be run.

    -
    -

    per_method_setup_in

    -
    -

    Pass TRUE to run the setup and teardown procedure before - and after each unit test procedure is executed. Default of FALSE means that - these programs will be run once, at the start and end of the package test - execution as a whole.

    -
    -

    override_package_in

    -
    -

    Override the automatic determination of package names thus removing the - one to one relationship between test package and package to test. - Default is NULL. Instead of using this parameter consider the procedure run.

    -
    - -

    Here are some examples of using the utPLSQL.test procedure:

    - -

    1. Run the unit test for the betwnstr function (by executing the ut_betwnstr -test package, since the default prefix is used). Do not recompile the test -package.

    - -
    SQL> exec utPLSQL.test ('betwnstr', recompile_in => FALSE)
    - -

    2. Run all of the unit tests for the te_employee package, -stored in a test package called "test_te_employee" in the /tmp -directory. Recompile the test package before execution.

    - -
    SQL> exec utPLSQL.test ('te_employee', prefix_in => 'test_', dir_in => '/tmp')
    - -

    3. Run all the unit tests for the corporate_polluters -package, located in the same package as the source code.

    - -
    SQL> exec utPLSQL.test ('te_employee', samepackage_in => TRUE)
    - -

    Since utPLSQL follows the red light-green light approach on -reporting results, each time you run utPLSQL.test, it will display the results. -If successful, you will see output like this:

    - -
    SUCCESS: "betwnstr"
    - -

    If the test fails at some point, you will see output like -this:

    - -
    FAILURE: "betwnstr"
    -BETWNSTR: IS NULL: NULL start
    -BETWNSTR: End larger than string length; expected "cdeg", got "cdefg"
    - - -

    Running a Test the other way

    - -

    The normal usage of the test procedure as described above assumes that for -each package you want to test, say mypackage, has a package for -testing this package having the same name but with an additional prefix: -ut_mypackage. Instead of using this approach, you can use the procedure -run. This procedure runs a test package directly without any further -conditions on the name or other packages. The only condition that still applies -is the naming conventions necessary to make it a valid test package. -

    -
    -PROCEDURE run (
    -    testpackage_in      IN VARCHAR2,
    -    prefix_in           IN VARCHAR2 := NULL,
    -    suite_in            IN VARCHAR2 := NULL,
    -    owner_in            IN VARCHAR2 := NULL,
    -    reset_results_in    IN BOOLEAN  := TRUE,
    -    from_suite_in       IN BOOLEAN  := FALSE,
    -    subprogram_in       IN VARCHAR2 := '%',
    -    per_method_setup_id IN BOOLEAN  := FALSE);
    -
    - -

    where the parameters are defined as follows:
    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -

    test_package_in

    -
    -

    The name of the test package to run.

    -
    -

    prefix_in

    -
    -

    The prefix to be appended to package_in to come up with - the name of the test package. If you do not provide a value, NULL is used as - a default. i.e. the package name is used as provided in the first parameter

    -
    -

    suite_in

    -
    -

    The name of the suite that contains the specified test - package. This is an optional value and is used to update statistics - for the test.

    -
    -

    owner_in

    -
    -

    The name of the schema that was specified when the test - suite was defined and the packaged added to the suite. This is an - optional value and is used to update statistics for - the test.

    -
    -

    reset_results_in

    -
    -

    Pass FALSE to tell utPLSQL to not reset the results - information, in which case you will still be able to view results by calling utResult.show . Otherwise, utPLSQL clears the result - data after each test.

    -
    -

    from_suite_in

    -
    -

    Pass TRUE to tell utPLSQL that this test is being run from - within a test suite (for internal use only).

    -
    -

    subprogram_in

    -
    -

    Pass a string to restrict which of the test procedures - will be executed for this run. Default of '%' means all tests will be run.

    -
    -

    per_method_setup_in

    -
    -

    Pass TRUE to run the setup and teardown procedure before - and after each unit test procedure is executed. Default of FALSE means that - these programs will be run once, at the start and end of the package test - execution as a whole.

    -
    - - - -

    Running a Test Suite

    - -

    In addition to running a test for a single test package, you -can set up a test suite that consists of one or more test packages. You can -then run an entire suite of tests with a call to utPLSQL.testsuite:

    - -
    PROCEDURE utPLSQL.testsuite (
    -   suite_in IN VARCHAR2,
    -   recompile_in IN BOOLEAN := TRUE,
    -   reset_results_in IN BOOLEAN := TRUE
    -   per_method_setup_in in BOOLEAN := FALSE
    -   );
    - -

    where suite_in is the name of the suite and recompiled_in -determines the auto compilation behavior. -

    - -

    Here is an example of the call I would make to run all my tests for the -PL/Vision library:

    - -
    SQL> exec utplsql.testsuite ('plvision');
    - -

    The parameter list for utPLSQL.testSuite is much shorter -than utPLSQL.test; rather than pass information like directory, owner name and -same-package through a parameter list, you define these characteristics in the -suite itself (stored in a series of utPLSQL tables).

    - -

    Before you can test an entire suite, you must define -the suite.

    - - -

    Running a Test Suite the other way

    - -

    Similiar to the run procedure for single packages, there is the -runsuite procedure to run testsuites. When you use this procedure -there is no relationship assumed between the names of test packages specified in the -test suite and the procedures to be tested. -

    - -
    PROCEDURE utPLSQL.runsuite (
    -   suite_in IN VARCHAR2,
    -   reset_results_in IN BOOLEAN := TRUE
    -   per_method_setup_in in BOOLEAN := FALSE
    -   );
    - -

    -The usage of the parameters is just as in testsuite. -

    - - -

    Recording and Accessing Test Statistics

    - -

    If you have defined test suites, and packages within those -test suites, utPLSQL will update those definitions with the follow statistics -after each test is run:

    - -
      -
    • Status of last run: success - or failure?
    • -
    • Start and end times of last - run
    • -
    • Total number of failures
    • -
    • Total number of executions of - the test
    • -
    - -

    All of this is done for you automatically. You can then write queries and reports against the -ut_package and ut_suite tables.

    - - -

    Return utPLSQL version

    - -

    Run the utPLSQL.version function to return the version of -utPLSQL you have installed:

    - -
    FUNCTION utPLSQL.version RETURN VARCHAR2
    - -

    utPLSQL Trace

    - -

    These routines are very simple and take no arguments:

    - -
    -PROCEDURE trc;
    -
    -PROCEDURE notrc;
    -
    -FUNCTION tracing RETURN BOOLEAN;
    -
    - -

    The procedures trc and notrc are used to turn tracing on and off -respectively. The function tracing returns TRUE if tracing is currently turned -on and FALSE otherwise. This facility is useful when writing code in utPLSQL -(the framework itself, not your test code). An example of the output generated -is:

    - -
    -Initialized utPLSQL session...
    -Setpkg to Lottery
    -Package and program = ut_Lottery
    -Same package? N
    -Is package? Y
    -Prefix = ut_
    -Recompiling ut_Lottery in
    -Runprog of ut_SETUP
    -Package and program = ut_Lottery.ut_SETUP
    -Same package? N
    -Is package? Y
    -Prefix = ut_
    -Addtest
    -Package and program = Lottery.UT_DRAW
    -Same package? N
    -Override? Y
    -Prefix = ut_
    -Runprog of UT_DRAW
    -Package and program = ut_Lottery.UT_DRAW
    -Same package? N
    -Is package? Y
    -Prefix = ut_
    -.
    ->  FFFFFFF   AA     III  L      U     U RRRRR   EEEEEEE
    ->  F        A  A     I   L      U     U R    R  E
    ->  F       A    A    I   L      U     U R     R E
    ->  F      A      A   I   L      U     U R     R E
    ->  FFFF   A      A   I   L      U     U RRRRRR  EEEE
    ->  F      AAAAAAAA   I   L      U     U R   R   E
    ->  F      A      A   I   L      U     U R    R  E
    ->  F      A      A   I   L       U   U  R     R E
    ->  F      A      A  III  LLLLLLL  UUU   R     R EEEEEEE
    -.
    -FAILURE: "Lottery"
    -.
    -> Individual Test Case Results:
    ->
    -FAILURE - EQ "Test of DRAW" Expected "01 02 05 27 43 49" and got "02 04 27 28 31 33"
    ->
    ->
    -> Errors recorded in utPLSQL Error Log:
    ->
    -> NONE FOUND
    -Runprog of ut_TEARDOWN
    -Package and program = ut_Lottery.ut_TEARDOWN
    -Same package? N
    -Is package? Y
    -Prefix = ut_
    -
    -PL/SQL procedure successfully completed.
    -
    - -

    Register a Unit Test

    - -

    As of version 1.4.1, you -no longer have to explicitly register a unit test! The default -behavior of utPLSQL is now to extract from the data dictionary (via the -ALL_ARGUMENTS data dictionary view) the names of all the unit test procedures -you have defined, and then run them. utPLSQL identifies these programs by -looking for all programs whose names start with the specified prefix.

    - -

    If you decide that you want to explicitly register your unit -tests, then you will need to turn on manual registration:

    - -
    SQL> exec utConfig.registertest (TRUE)
    - -

    This setting is immediately saved in the database for your -schema. To turn off manual registration:

    - -
    SQL> exec utConfig.registertest (FALSE)
    - -

    So read no further unless you have turned on manual -registration! You might do this, for example, if you have already built a -number of test packages in a version of utPLSQL prior to 1.4.1 and do not want -to make any changes to your test package code.

    - -

    All aspects of manual registration of unit tests for a -program or package actually occur within the Unit Test Package itself, in the setup procedure. No persistent unit test information -is stored between runs of the unit test, unless you define that unit test -within a test suite.

    - -

    Use the utPLSQL.addtest procedure to register a unit test.

    - -
       PROCEDURE utPLSQL.addtest (
    -      NAME_IN IN VARCHAR2,
    -      utprefix_in IN VARCHAR2,
    -      iterations_in IN PLS_INTEGER := 1
    -   );
    - 
    -   PROCEDURE utPLSQL.addtest (
    -      package_in IN VARCHAR2,
    -      NAME_IN IN VARCHAR2,
    -      utprefix_in IN VARCHAR2,
    -      iterations_in IN PLS_INTEGER := 1
    -   );
    - -

    where

    - -

    name_in is the name of the program you are -testing. Note that this is the name of the unit test procedure itself, -including the unit test prefix..

    - -

    utprefix_in is the prefix to be applied to -name_in to construct the unit tst procedure. This is currently NOT IN USE; only -the package prefix specified in your call to utPLSQL.test and utPLSQL.testsuite -is used.

    - -

    iterations_in is the number of times you wish to -run the test (currently NOT IN USE).

    - -

    package_in is the name of the package containing -the unit test procedure. If you provide a package name when you call -utPLSQL.addtest, you will override the package name set when you called -utPLSQL.test -- but only for that one test. We recommend that you not change -the package name.

    - -

    Here is a setup procedure that sets up a series of tests for -a query-only encapsulation of the employee table:

    - -
    CREATE OR REPLACE PACKAGE BODY ut_te_employee
    -IS
    -   PROCEDURE ut_setup
    -   IS
    -   BEGIN
    -      utplsql.addtest ('UT_EMP_DEPT_LOOKUPROWCOUNT');
    -      utplsql.addtest ('UT_EMP_JOB_LOOKUPROWCOUNT');
    -      utplsql.addtest ('UT_EMP_MGR_LOOKUPROWCOUNT');
    -      utplsql.addtest ('UT_HIRE_DATE$VAL');
    -      utplsql.addtest ('UT_I_EMPLOYEE_NAME$ROW');
    -      utplsql.addtest ('UT_I_EMPLOYEE_NAME$VAL');
    -      utplsql.addtest ('UT_ONEROW');
    -      utplsql.addtest ('UT_PKYROWCOUNT');
    -      utplsql.addtest ('UT_ROWCOUNT');
    -      utplsql.addtest ('UT_SALARY$VAL');
    -   END;
    - -

    Once you have placed your addtest programs into your test -package's setup procedure, you are ready to build your own unit tests.

    - - - -

    < Previous Section: User Guide | Next Section: utConfig Package >

    -
    - - \ No newline at end of file diff --git a/website/Doc/utplsql.jpg b/website/Doc/utplsql.jpg deleted file mode 100644 index 288ee26221acdeda86f80b235faa70a695ef4c57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9388 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 N6eYm^e;S;b{{fh-?mz$l diff --git a/website/Doc/utreceq.html b/website/Doc/utreceq.html deleted file mode 100644 index 70ab2073b..000000000 --- a/website/Doc/utreceq.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - -utRecEq Package - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: utOutput Package | Next Section: Defining Test Suites >

    - - -

    - utRecEq Package -

    - -

    This package contains the following procedures and functions: -
    - - - - - - - - - - - - - - -
    utRecEq.addAdd a record type comparison function
    utRecEq.compileCompile a package's record type comparison functions
    utRecEq.remRemove record type comparison functions
    - -

    Generate functions to compare record types

    - -

    This package (created by Dan Spencer) allows the creation of functions to -allow the comparison of record types based on tables or views (%ROWTYPE -records in other words). They are generated by the add procedure: - -

    PROCEDURE add(
    -   pkg_name_in IN ut_package.name%TYPE,
    -   record_in  IN ut_receq.name%TYPE,
    -   rec_owner_in  IN ut_receq.created_by%TYPE := USER
    -);
    - -The pkg_name_in parameter contains the name of a tested package you wish to -associate with this record type. Note that this package name should already -exist in the ut_package table. The record_in parameter contains the name of -the view or table whose record type is to be compared. The final (optional) -parameter contains the name of the schema in which the table or view exists. -It defaults to the current user.

    - -

    The generated function will be named EQ_{Record_Schema_}Record_Name. The -schema is only inserted when the record type is not within the current one. The -function will return TRUE if the two records are identical on a field-by-field -comparison and FALSE otherwise. Note that NULL fields are considered -equal.

    - -

    The details of the EQ_* functions and their association with tested packages held in two tables: -

      - -
    • UT_RECEQ - This table holds a list of the EQ_* functions including the - target table/view and the schema in which it is found.
    • - -
    • UT_RECEQ_PKG - This table cross-references the tested packages against the functions listed in UT_RECEQ.
    • - -

    - -

    Compile a package's record comparison functions

    - -

    This routine recompiles all the EQ_* functions associated with a given package: - -

    PROCEDURE compile(pkg_name_in IN ut_package.name%TYPE);
    - -when autocompiling is turned on, this is called by -utplsql.test or utplsql.testsuite before the test packages themselves are recompiled.

    - -

    Remove record comparison functions

    - -

    To remove record comparison functions, use the following: - -

    PROCEDURE rem(
    -   name_in  IN ut_receq.name%TYPE,
    -   rec_owner_in   IN ut_receq.created_by%TYPE := USER
    -   for_package_in IN BOOLEAN := FALSE
    -);
    - -If for_package_in is FALSE, then name_in is taken to refer to a record type to -remove, with rec_owner_in specifying the schema the record type is in. All package associations for this record type are removed and the EQ_* function is dropped.

    - -

    On the other hand, if for_package_in is TRUE, then name_in is taken to refer -to a package. In this case, all the package's associations are removed. If no -other package is associated with a given record, then the EQ_* function is -dropped. (Note that the rec_owner_in parameter is ignored here).

    - - -

    < Previous Section: utOutput Package | Next Section: Defining Test Suites >

    -
    - - \ No newline at end of file diff --git a/website/Doc/utresult.html b/website/Doc/utresult.html deleted file mode 100644 index 11ea9a961..000000000 --- a/website/Doc/utresult.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - -utResult Package - - - - - - - -
    -

    [ Home - | Getting Started - | Build Test Packages - | Examples - | User Guide - | Release Notes - | Document Map ]

    -

    < Previous Section: utConfig Package | Next Section: utAssert Package >

    - - -

    -utResult Package

    - -

    This package contains the following procedures and functions: -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    utResult.initInitialize the results data
    utResult.show -
    utResult.showone -
    utResult.showlast
    Show results
    utResult.success -
    utResult.failure
    Show the success or failure of the last test
    utResult.firstresult -
    utResult.nextresult -
    utResult.nthresult -
    utResult.resultcount
    Iterate through the results array
    utResult.include_successes
    - utResult.ignore_successes
    Control the display of passed tests
    - -The utResult package offers an API to the information -sent by the various utAssert assertion routines after a test is run. If -you employ the utPLSQL.test and utPLSQL.testsuite to run your tests, then -the results will be displayed by calling the utResult.show procedure. - -So, generally, you do not have to do anything to see or evaluate the results of -a test (or suite of tests). The information will be displayed on your screen -using DBMS_OUTPUT, or elsewhere if you use a custom output reporter. You might, -however, want to access this information in another environment (say, Oracle -Forms or Java, etc.). You might also want to build your own assertion logic or -test engine. In either of these cases, you will want to use the programs in the -utResult package. - -

    -Initialize

    -Initialize the utResult data, setting it all back to NULL: -
    PROCEDURE utResult.init;
    - -

    -Show Results

    -Show the results of your test with one of the following three procedures. -
    PROCEDURE utResult.show (reset_in IN BOOLEAN := FALSE);
    -PROCEDURE utResult.showone (indx_in in pls_integer);
    -PROCEDURE utResult.showlast;
    -Use the show procedure to display the full set of results stored -in the utResult array. If you pass TRUE for its single argument, the results -informatino will be initialized. -

    Use the showone procedure to show the Nth result. -

    Use the showlast procedure to show the results of the last test -run. -

    -Retrieve Test Status

    -The success and failure functions return the status of the most recently -executed test. -
    FUNCTION utResult.success RETURN BOOLEAN;
    -FUNCTION utResult.failure RETURN BOOLEAN;
    - -

    -Scan Results Array

    -The utPLSQL.show procedure iterates through the contents of the utResult -array and displays the information found there. You can write the same -kind of logic by calling a combination of the following programs: -
    PROCEDURE utResult.firstresult;
    -
    -FUNCTION utResult.nextresult RETURN utResult.result_rt;
    -
    -PROCEDURE utResult.nextresult (
    -   name_out OUT VARCHAR2,
    -   msg_out OUT VARCHAR2,
    -   case_indx_out OUT PLS_INTEGER
    -);
    -
    -FUNCTION utResult.nthresult (indx_in IN PLS_INTEGER)
    -   RETURN utResult.result_rt;
    -
    -PROCEDURE utResult.nthresult (
    -   indx_in IN PLS_INTEGER,
    -   name_out OUT VARCHAR2,
    -   msg_out OUT VARCHAR2,
    -   case_indx_out OUT PLS_INTEGER
    -);
    -
    -FUNCTION utResult.resultcount RETURN PLS_INTEGER;
    - -

    - Control the Display of Success Messages

    -

    The following procedures turn on or off the display of success messages. In other words, -when turned on (as is the default) a message will be displayed for each successful assertion. -The specifications are as follows: -

    -procedure include_successes;
    -procedure ignore_successes; 

    - - -

    < Previous Section: utConfig Package | Next Section: utAssert Package >

    -
    - - \ No newline at end of file diff --git a/website/index.html b/website/index.html index 317e50340..be6011134 100644 --- a/website/index.html +++ b/website/index.html @@ -1,120 +1,118 @@ - - - - - - Welcome to the utPLSQL Project - - - - - - - -
    - - - - - -
    - -
    - -

    Project Summary | -Home Page | -Background Info | -Discussions | -Downloads | -Documentation

    - -

    Welcome to the utPLSQL Project

    - -

    This is the utPLSQL Sourceforge site for developers using and developing utPLSQL. The Sourceforge project summary is here.

    - -

    What is it?

    -

    utPLSQL is a unit testing framework for programmers using Oracle's PL/SQL language. -Developed by Steven Feuerstein, author of many books on the subject, it allows the -automated testing of packages, functions and procedures. -For background on the project and the reasons why this sort of unit testing is a -good idea, visit the utPLSQL site -of the O'Reilly and Associates Oracle Resource Center.

    - -

    Where can I get more details?

    -

    The documentation is available as part of the utPLSQL download -and also online. -Discussion about utPLSQL takes place at the forum at utplsql.oracledeveloper.nl. -This has been put together by Patrick Barel, a utPLSQL contributor. -This should be your first call for questions, suggestions and help with utPLSQL. -For announcements about utPLSQL (mainly new releases) register with the -Yahoo! utPLSQL-Info group. Discussions until Sept 2002 are also here. -Finally, there is archived copy of the former O'Reilly utPLSQL Webboard available -here. -This is somewhere else to look to see if your question has already been asked (and hopefully answered). - -

    - - - - - - - -
    -Subscribe to the utPLSQL anouncement list on Yahoo! -
    - -
    -
    -

    - -

    It doesn't do what I need / Doesn't work!

    - -

    Again, your first call should be the utPLSQL Forum. -If your feature request or bug is accepted, it will be added to the list of tasks. -Of course, if you find a bug the best thing to do is to post a fix!

    - -

    How do I get involved?

    - -

    If you want to help develop utPLSQL, you should: -

      -
    1. Register at SourceForge (if you have not yet done so). This -means you will then have a "unix name". -
    2. -
    3. Mail Me your "unix name" and I will add you as a -utPLSQL project developer. -
    4. -
    5. Then you can get involved, logging bugs, volunteering for jobs, etc. -To download the utPLSQL software and see the other utPLSQL project -information, visit the Project Summary Page -
    6. -
    -The tasks are maintained in the Project Task Manager. -When you have found one you'd like to try, get one of the project administrators to assign the task to you. -Then grab the latest version of the code from CVS and start coding. Once you are done, you should send your -changes to the administrators list. We will then merge your -changes into the CVS source tree. If you write lots of good code, we'll give you commit privileges on CVS. -

    - -

    - -SourceForge Logo -

    - - - - - -
    - -
    -Author: Chris Rimmer
    -Copyright 2001-2003, all rights reserved
    -
    - -
    - - - + + + + + + Welcome to the utPLSQL Project + + + + + + +
    + + + + +
    + utPLSQL Logo +
    + +

    + Project Summary | + Home Page | + Support | + Discussions | + Downloads | + Documentation +

    + +

    Welcome to the utPLSQL Project

    + +

    + This is the utPLSQL Sourceforge + site for developers using and developing utPLSQL. The Sourceforge + project summary is at https://sourceforge.net/projects/utplsql. +

    + +

    What is it?

    + +

    + utPLSQL is a unit testing framework for programmers using Oracle's PL/SQL language. + Developed by Steven Feuerstein, author of many books on the subject, it allows the + automated testing of packages, functions and procedures. + For background on the project and the reasons why this sort of unit testing is a + good idea, visit the old utPLSQL site + of the O'Reilly and Associates Oracle Resource Center. +

    + +

    Where can I get more details?

    + +

    + The documentation is available as part of the utPLSQL download + and also online. + Discussions about utPLSQL take place on the forums. + These, along with the Ticket Trackers should be your first call for questions, suggestions and help with utPLSQL. + For announcements about utPLSQL (mainly new releases) check the News page. +

    +

    + For historical information, there is the old + Yahoo! utPLSQL-Info group (discussions until Sept 2002 are also there). + Also, there is an archived copy of the former O'Reilly utPLSQL Webboard available. + This is somewhere else to look to see if your question has already been asked (and hopefully answered). +

    + +

    It doesn't do what I need / doesn't work!

    + +

    + Again, your first call should be the Ticket Trackers. + If your feature request or bug is accepted, it will be added to the list of tasks. + Of course, if you find a bug the best thing to do is to post a fix! +

    + +

    How do I get involved?

    + +

    If you want to help develop utPLSQL, you should:

    + + + +

    + The tasks are maintained in the Bugs and Feature Requests Ticket Trackers. + When you have found one you'd like to try, get one of the project administrators to assign the task to you (you can do this by adding a note to the ticket). + Then grab the latest version of the code from the SVN trunk and start coding. Once you are done, you should add your + changes to the ticket in the form of an SVN "diff" file. We will then merge your + changes into a development branch where it can be tested before before being merged into the trunk, ready for a future release. +

    +

    + + SourceForge Logo + +

    + + + + + +
    utPLSQL Logo
    + +
    +

    + Author: Chris Rimmer and the utPLSQL Project
    + Copyright 2001-2003, 2014, all rights reserved +

    +
    +

    + + Valid XHTML 1.0 Strict + +

    +
    + + From 51a2ca6c8d644f7881df65c0fd5d6c98d59d4a7b Mon Sep 17 00:00:00 2001 From: p72endragon Date: Sat, 5 Apr 2014 15:43:54 +0000 Subject: [PATCH 113/143] Updated changelog and version numbers in preparation for a release --- documentation/src/release.html | 14 ++++++++++++++ source/ut_plsql.pkb | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/documentation/src/release.html b/documentation/src/release.html index 241163497..80449c142 100644 --- a/documentation/src/release.html +++ b/documentation/src/release.html @@ -32,6 +32,20 @@

    utPLSQL version 2.x

    Change History

    +

    utPLSQL version 2.2.1

    + +
      +
    • + Bug 29: Fixed issue with the Uninstall leaving two views behind. +
    • +
    • + Bug 38: Fixed issue which prevented building the documentation depending on the build environment. +
    • +
    • + Feature Request 6: Updated documentation and made it all valid XHTML. +
    • +
    +

    utPLSQL version 2.2