Below is the list of changes that have just been committed into a local
5.1 repository of mats. When mats does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2006-10-20 22:56:03+02:00, mats@romeo.(none) +3 -0
Merge romeo.(none):/home/bkroot/mysql-5.1-new-rpl
into romeo.(none):/home/bk/mytap-mysql-5.1-new
MERGE: 1.2245.7.2
unittest/README.txt@stripped, 2006-10-20 22:55:58+02:00, mats@romeo.(none) +0 -7
Manual merge
MERGE: 1.3.2.1
unittest/mytap/tap.c@stripped, 2006-10-20 22:39:02+02:00, mats@romeo.(none) +0 -1
Auto merged
MERGE: 1.5.1.1
unittest/mytap/tap.h@stripped, 2006-10-20 22:55:58+02:00, mats@romeo.(none) +7 -2
Manual merge
MERGE: 1.5.1.1
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: mats
# Host: romeo.(none)
# Root: /home/bk/mytap-mysql-5.1-new/RESYNC
--- 1.6/unittest/mytap/tap.c 2006-10-20 22:56:11 +02:00
+++ 1.7/unittest/mytap/tap.c 2006-10-20 22:56:11 +02:00
@@ -29,11 +29,17 @@
#include <signal.h>
/**
+ @defgroup MyTAP_Internal MyTAP Internals
+
+ Internal functions and data structures for the MyTAP implementation.
+*/
+
+/**
Test data structure.
Data structure containing all information about the test suite.
- @ingroup MyTAP
+ @ingroup MyTAP_Internal
*/
static TEST_DATA g_test = { 0, 0, 0, "" };
@@ -41,6 +47,8 @@
Output stream for test report message.
The macro is just a temporary solution.
+
+ @ingroup MyTAP_Internal
*/
#define tapout stdout
@@ -50,7 +58,7 @@
To emit the directive, use the emit_dir() function
- @ingroup MyTAP
+ @ingroup MyTAP_Internal
@see emit_dir
@@ -59,7 +67,7 @@
@param ap Vararg list for the description string above.
*/
static void
-emit_tap(int pass, char const *fmt, va_list ap)
+vemit_tap(int pass, char const *fmt, va_list ap)
{
fprintf(tapout, "%sok %d%s",
pass ? "" : "not ",
@@ -80,18 +88,22 @@
not ok 2 # todo some text explaining what remains
@endcode
+ @ingroup MyTAP_Internal
+
@param dir Directive as a string
- @param exp Explanation string
+ @param why Explanation string
*/
static void
-emit_dir(const char *dir, const char *exp)
+emit_dir(const char *dir, const char *why)
{
- fprintf(tapout, " # %s %s", dir, exp);
+ fprintf(tapout, " # %s %s", dir, why);
}
/**
Emit a newline to the TAP output stream.
+
+ @ingroup MyTAP_Internal
*/
static void
emit_endl()
@@ -190,7 +202,7 @@
if (!pass && *g_test.todo == '\0')
++g_test.failed;
- emit_tap(pass, fmt, ap);
+ vemit_tap(pass, fmt, ap);
va_end(ap);
if (*g_test.todo != '\0')
emit_dir("todo", g_test.todo);
@@ -215,7 +227,7 @@
while (how_many-- > 0)
{
va_list ap;
- emit_tap(1, NULL, ap);
+ vemit_tap(1, NULL, ap);
emit_dir("skip", reason);
emit_endl();
}
@@ -308,7 +320,7 @@
@section UnitTest Writing unit tests
The purpose of writing unit tests is to use them to drive component
- development towards a solution that the tests. This means that the
+ development towards a solution that passes the tests. This means that the
unit tests has to be as complete as possible, testing at least:
- Normal input
@@ -317,29 +329,240 @@
- Error handling
- Bad environment
- We will go over each case and explain it in more detail.
+ @subsection NormalSubSec Normal input
+
+ This is to test that the component have the expected behaviour.
+ This is just plain simple: test that it works. For example, test
+ that you can unpack what you packed, adding gives the sum, pincing
+ the duck makes it quack.
+
+ This is what everybody does when they write tests.
+
+
+ @subsection BorderlineTests Borderline cases
+
+ If you have a size anywhere for your component, does it work for
+ size 1? Size 0? Sizes close to <code>UINT_MAX</code>?
+
+ It might not be sensible to have a size 0, so in this case it is
+ not a borderline case, but rather a faulty input (see @ref
+ FaultyInputTests).
+
+
+ @subsection FaultyInputTests Faulty input
+
+ Does your bitmap handle 0 bits size? Well, it might not be designed
+ for it, but is should <em>not</em> crash the application, but
+ rather produce an error. This is called defensive programming.
- @subsection NormalSSec Normal input
+ Unfortunately, adding checks for values that should just not be
+ entered at all is not always practical: the checks cost cycles and
+ might cost more than it's worth. For example, some functions are
+ designed so that you may not give it a null pointer. In those
+ cases it's not sensible to pass it <code>NULL</code> just to see it
+ crash.
- @subsection BorderlineSSec Borderline cases
+ Since every experienced programmer add an <code>assert()</code> to
+ ensure that you get a proper failure for the debug builds when a
+ null pointer passed (you add asserts too, right?), you will in this
+ case instead have a controlled (early) crash in the debug build.
- @subsection FaultySSec Faulty input
- @subsection ErrorSSec Error handling
+ @subsection ErrorHandlingTests Error handling
- @subsection EnvironmentSSec Environment
+ This is testing that the errors your component is designed to give
+ actually are produced. For example, testing that trying to open a
+ non-existing file produces a sensible error code.
+
+
+ @subsection BadEnvironmentTests Environment
Sometimes, modules has to behave well even when the environment
- fails to work correctly. Typical examples are: out of dynamic
- memory, disk is full,
+ fails to work correctly. Typical examples are when the computer is
+ out of dynamic memory or when the disk is full. You can emulate
+ this by replacing, e.g., <code>malloc()</code> with your own
+ version that will work for a while, but then fail. Some things are
+ worth to keep in mind here:
+
+ - Make sure to make the function fail deterministically, so that
+ you really can repeat the test.
+
+ - Make sure that it doesn't just fail immediately. The unit might
+ have checks for the first case, but might actually fail some time
+ in the near future.
- @section UnitTestSec How to structure a unit test
+
+ @section UnitTest How to structure a unit test
In this section we will give some advice on how to structure the
- unit tests to make the development run smoothly.
+ unit tests to make the development run smoothly. The basic
+ structure of a test is:
+
+ - Plan
+ - Test
+ - Report
+
+
+ @subsection TestPlanning Plan the test
+
+ Planning the test means telling how many tests there are. In the
+ event that one of the tests causes a crash, it is then possible to
+ see that there are fewer tests than expected, and print a proper
+ error message.
+
+ To plan a test, use the @c plan() function in the following manner:
+
+ @code
+ int main(int argc, char *argv[])
+ {
+ plan(5);
+ .
+ .
+ .
+ }
+ @endcode
+
+ If you don't call the @c plan() function, the number of tests
+ executed will be printed at the end. This is intended to be used
+ while developing the unit and you are constantly adding tests. It
+ is not indented to be used after the unit has been released.
- @subsection PieceSec Test each piece separately
- Don't test all functions using size 1, then all functions using
- size 2, etc.
+ @subsection TestRunning Execute the test
+
+ To report the status of a test, the @c ok() function is used in the
+ following manner:
+
+ @code
+ int main(int argc, char *argv[])
+ {
+ plan(5);
+ ok(ducks == paddling_ducks,
+ "%d ducks did not paddle", ducks - paddling_ducks);
+ .
+ .
+ .
+ }
+ @endcode
+
+ This will print a test result line on the standard output in TAP
+ format, which allows TAP handling frameworks (like Test::Harness)
+ to parse the status of the test.
+
+ @subsection TestReport Report the result of the test
+
+ At the end, a complete test report should be written, with some
+ statistics. If the test returns EXIT_SUCCESS, all tests were
+ successfull, otherwise at least one test failed.
+
+ To get a TAP complient output and exit status, report the exit
+ status in the following manner:
+
+ @code
+ int main(int argc, char *argv[])
+ {
+ plan(5);
+ ok(ducks == paddling_ducks,
+ "%d ducks did not paddle", ducks - paddling_ducks);
+ .
+ .
+ .
+ return exit_status();
+ }
+ @endcode
+
+ @section DontDoThis Ways to not do unit testing
+
+ In this section, we'll go through some quite common ways to write
+ tests that are <em>not</em> a good idea.
+
+ @subsection BreadthFirstTests Doing breadth-first testing
+
+ If you're writing a library with several functions, don't test all
+ functions using size 1, then all functions using size 2, etc. If a
+ test for size 42 fails, you have no easy way of tracking down why
+ it failed.
+
+ It is better to concentrate on getting one function to work at a
+ time, which means that you test each function for all sizes that
+ you think is reasonable. Then you continue with the next function,
+ doing the same. This is usually also the way that a library is
+ developed (one function at a time) so stick to testing that is
+ appropriate for now the unit is developed.
+
+ @subsection JustToBeSafeTest Writing unnecessarily large tests
+
+ Don't write tests that use parameters in the range 1-1024 unless
+ you have a very good reason to belive that the component will
+ succeed for 562 but fail for 564 (the numbers picked are just
+ examples).
+
+ It is very common to write extensive tests "just to be safe."
+ Having a test suite with a lot of values might give you a warm
+ fuzzy feeling, but it doesn't really help you find the bugs. Good
+ tests fail; seriously, if you write a test that you expect to
+ succeed, you don't need to write it. If you think that it
+ <em>might</em> fail, <em>then</em> you should write it.
+
+ Don't take this as an excuse to avoid writing any tests at all
+ "since I make no mistakes" (when it comes to this, there are two
+ kinds of people: those who admit they make mistakes, and those who
+ don't); rather, this means that there is no reason to test that
+ using a buffer with size 100 works when you have a test for buffer
+ size 96.
+
+ The drawback is that the test suite takes longer to run, for little
+ or no benefit. It is acceptable to do a exhaustive test if it
+ doesn't take too long to run and it is quite common to do an
+ exhaustive test of a function for a small set of values.
+ Use your judgment to decide what is excessive: your milage may
+ vary.
+*/
+
+/**
+ @example simple.t.c
+
+ This is an simple example of how to write a test using the
+ library. The output of this program is:
+
+ @code
+ 1..1
+ # Testing basic functions
+ ok 1 - Testing gcs()
+ @endcode
+
+ The basic structure is: plan the number of test points using the
+ plan() function, perform the test and write out the result of each
+ test point using the ok() function, print out a diagnostics message
+ using diag(), and report the result of the test by calling the
+ exit_status() function. Observe that this test does excessive
+ testing (see @ref JustToBeSafeTest), but the test point doesn't
+ take very long time.
+*/
+
+/**
+ @example todo.t.c
+
+ This example demonstrates how to use the <code>todo_start()</code>
+ and <code>todo_end()</code> function to mark a sequence of tests to
+ be done. Observe that the tests are assumed to fail: if any test
+ succeeds, it is considered a "bonus".
+*/
+
+/**
+ @example skip.t.c
+
+ This is an example of how the <code>SKIP_BLOCK_IF</code> can be
+ used to skip a predetermined number of tests. Observe that the
+ macro actually skips the following statement, but it's not sensible
+ to use anything than a block.
+*/
+
+/**
+ @example skip_all.t.c
+
+ Sometimes, you skip an entire test because it's testing a feature
+ that doesn't exist on the system that you're testing. To skip an
+ entire test, use the <code>skip_all()</code> function according to
+ this example.
*/
--- 1.7/unittest/mytap/tap.h 2006-10-20 22:56:11 +02:00
+++ 1.8/unittest/mytap/tap.h 2006-10-20 22:56:11 +02:00
@@ -33,6 +33,8 @@
/**
Data about test plan.
+ @ingroup MyTAP_Internal
+
@internal We are using the "typedef struct X { ... } X" idiom to
create class/struct X both in C and C++.
*/
@@ -61,6 +63,14 @@
#endif
/**
+ @defgroup MyTAP_API MyTAP API
+
+ MySQL support for performing unit tests according to TAP.
+
+ @{
+*/
+
+/**
Set number of tests that is planned to execute.
The function also accepts the predefined constant
@@ -101,11 +111,14 @@
/**
Skip a determined number of tests.
- Function to print that <em>how_many</em> tests have been
- skipped. The reason is printed for each skipped test. Observe
- that this function does not do the actual skipping for you, it just
- prints information that tests have been skipped. It shall be used
- in the following manner:
+ Function to print that <em>how_many</em> tests have been skipped.
+ The reason is printed for each skipped test. Observe that this
+ function does not do the actual skipping for you, it just prints
+ information that tests have been skipped. This function is not
+ usually used, but rather the macro @c SKIP_BLOCK_IF, which does the
+ skipping for you.
+
+ It shall be used in the following manner:
@code
if (ducks == 0) {
@@ -192,8 +205,8 @@
return exit_status();
@endcode
- @returns EXIT_SUCCESS if all tests passed, EXIT_FAILURE if one or
- more tests failed.
+ @returns @c EXIT_SUCCESS if all tests passed, @c EXIT_FAILURE if
+ one or more tests failed.
*/
int exit_status(void);
@@ -242,6 +255,7 @@
void todo_end();
+/** @} */
#ifdef __cplusplus
}
--- 1.5/unittest/README.txt 2006-10-20 22:56:11 +02:00
+++ 1.6/unittest/README.txt 2006-10-20 22:56:11 +02:00
@@ -46,6 +46,8 @@
Documentation
-------------
-There is Doxygen-generated documentation available at:
+The generated documentation is temporarily placed at:
- https://intranet.mysql.com/~mkindahl/mytap/html/
+ http://www.kindahl.net/mytap/doc/
+
+I will move it to a better place once I figure out where and how.
| Thread |
|---|
| • bk commit into 5.1 tree (mats:1.2309) | Mats Kindahl | 20 Oct |