summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--acconfig.h3
-rw-r--r--acinclude.m422
-rw-r--r--configure.in4
-rw-r--r--extra/my_print_defaults.c14
-rw-r--r--extra/resolveip.c6
-rw-r--r--libmysql/dll.c13
-rw-r--r--myisam/mi_dynrec.c13
-rw-r--r--myisam/mi_open.c4
-rwxr-xr-xmyisam/mi_test_all.sh2
-rw-r--r--mysql-test/include/check_var_limit.inc2
-rw-r--r--mysql-test/r/myisam.result8
-rw-r--r--mysql-test/t/myisam.test6
-rw-r--r--mysql-test/t/query_cache_merge.test4
-rw-r--r--mysys/default.c133
-rw-r--r--mysys/my_pthread.c14
-rw-r--r--sql/log.cc17
16 files changed, 182 insertions, 83 deletions
diff --git a/acconfig.h b/acconfig.h
index 4b4fde6bff6..825842d256a 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -173,6 +173,9 @@
/* Define if the system files define ulong */
#undef HAVE_ULONG
+/* Define if the system files define in_addr_t */
+#undef HAVE_IN_ADDR_T
+
/* UNIXWARE7 threads are not posix */
#undef HAVE_UNIXWARE7_THREADS
diff --git a/acinclude.m4 b/acinclude.m4
index 3b9b7ce13b6..f6bd1d9e83e 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -204,6 +204,28 @@ fi
])
+AC_DEFUN(MYSQL_CHECK_IN_ADDR_T,
+[AC_MSG_CHECKING(for type in_addr_t)
+AC_CACHE_VAL(ac_cv_in_addr_t,
+[AC_TRY_RUN([#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+int main(int argc, char **argv)
+{
+ in_addr_t foo;
+ exit(0);
+}], ac_cv_in_addr_t=yes, ac_cv_in_addr_t=no, ac_cv_in_addr_t=no)])
+AC_MSG_RESULT($ac_cv_in_addr_t)
+if test "$ac_cv_in_addr_t" = "yes"
+then
+ AC_DEFINE(HAVE_IN_ADDR_T)
+fi
+])
+
+
AC_DEFUN(MYSQL_PTHREAD_YIELD,
[AC_CACHE_CHECK([if pthread_yield takes zero arguments], ac_cv_pthread_yield_zero_arg,
[AC_TRY_LINK([#define _GNU_SOURCE
diff --git a/configure.in b/configure.in
index 64d291dccf7..f894cb5cb2a 100644
--- a/configure.in
+++ b/configure.in
@@ -1721,8 +1721,10 @@ MYSQL_CHECK_ULONG
MYSQL_CHECK_UCHAR
# Do the system files define uint
MYSQL_CHECK_UINT
-#Check for fp_except in ieeefp.h
+# Check for fp_except in ieeefp.h
MYSQL_CHECK_FP_EXCEPT
+# Check for IN_ADDR_T
+MYSQL_CHECK_IN_ADDR_T
# Do the c++ compiler have a bool type
MYSQL_CXX_BOOL
# Check some common bugs with gcc 2.8.# on sparc
diff --git a/extra/my_print_defaults.c b/extra/my_print_defaults.c
index 549b2124b55..41c26e73dff 100644
--- a/extra/my_print_defaults.c
+++ b/extra/my_print_defaults.c
@@ -136,18 +136,18 @@ int main(int argc, char **argv)
arguments[0]=my_progname;
arguments[1]=0;
if ((error= load_defaults(config_file, (const char **) load_default_groups,
- &count, &arguments)) > 1)
+ &count, &arguments)))
{
if (verbose && opt_defaults_file_used)
{
- if (error == 2)
- fprintf(stderr, "WARNING: Defaults file (%s) not found!\n",
+ if (error == 1)
+ fprintf(stderr, "WARNING: Defaults file '%s' not found!\n",
config_file);
- if (error == 3)
- fprintf(stderr, "WARNING: Defaults file (%s) is not a regular file!\n",
+ if (error == 2)
+ fprintf(stderr, "WARNING: Defaults file '%s' is not a regular file!\n",
config_file);
}
- exit(2); // Non-fatal error
+ error= 2;
}
for (argument= arguments+1 ; *argument ; argument++)
@@ -155,5 +155,5 @@ int main(int argc, char **argv)
my_free((char*) load_default_groups,MYF(0));
free_defaults(arguments);
- exit(0);
+ exit(error);
}
diff --git a/extra/resolveip.c b/extra/resolveip.c
index 9851ec49605..91f23bf5b00 100644
--- a/extra/resolveip.c
+++ b/extra/resolveip.c
@@ -36,6 +36,10 @@
extern int h_errno;
#endif
+#ifndef HAVE_IN_ADDR_T
+#define in_addr_t u_long
+#endif
+
static my_bool silent;
@@ -91,8 +95,6 @@ static int get_options(int *argc,char ***argv)
{
int ho_error;
- /* load_defaults("my",load_default_groups,argc,argv); */
-
if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
exit(ho_error);
diff --git a/libmysql/dll.c b/libmysql/dll.c
index f0a67d8f091..92aa611000b 100644
--- a/libmysql/dll.c
+++ b/libmysql/dll.c
@@ -112,12 +112,13 @@ int _export FAR PASCAL libmain(HANDLE hModule,short cbHeapSize,
#ifdef OS2
-//
-// This function is called automatically by _DLL_InitTerm
-// Every dll runtime enviroment is not tz enabled, so tzset()
-// must be called to enable TZ handling
-// Also timezone is fixed.
-//
+/*
+ This function is called automatically by _DLL_InitTerm
+ Every dll runtime enviroment is not tz enabled, so tzset()
+ must be called to enable TZ handling
+ Also timezone is fixed.
+*/
+
extern "C" unsigned long _System DllMain(unsigned long modhandle,
unsigned long flag)
{
diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c
index faf86c3ffbd..eb38a058b0b 100644
--- a/myisam/mi_dynrec.c
+++ b/myisam/mi_dynrec.c
@@ -58,11 +58,11 @@ int _mi_write_blob_record(MI_INFO *info, const byte *record)
{
byte *rec_buff;
int error;
- ulong reclength,extra;
+ ulong reclength,reclength2,extra;
extra= (ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
MI_DYN_DELETE_BLOCK_HEADER+1);
- reclength= (info->s->base.pack_reclength + info->s->base.pack_bits +
+ reclength= (info->s->base.pack_reclength +
_my_calc_total_blob_length(info,record)+ extra);
#ifdef NOT_USED /* We now support big rows */
if (reclength > MI_DYN_MAX_ROW_LENGTH)
@@ -76,10 +76,13 @@ int _mi_write_blob_record(MI_INFO *info, const byte *record)
my_errno=ENOMEM;
return(-1);
}
- reclength=_mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
- record);
+ reclength2= _mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
+ record);
+ DBUG_PRINT("info",("reclength: %lu reclength2: %lu",
+ reclength, reclength2));
+ DBUG_ASSERT(reclength2 <= reclength);
error=write_dynamic_record(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
- reclength);
+ reclength2);
my_afree(rec_buff);
return(error);
}
diff --git a/myisam/mi_open.c b/myisam/mi_open.c
index 59fae36ac33..857ca1486fd 100644
--- a/myisam/mi_open.c
+++ b/myisam/mi_open.c
@@ -595,7 +595,7 @@ byte *mi_alloc_rec_buff(MI_INFO *info, ulong length, byte **buf)
/* to simplify initial init of info->rec_buf in mi_open and mi_extra */
if (length == (ulong) -1)
{
- length= max(info->s->base.pack_reclength+info->s->base.pack_bits,
+ length= max(info->s->base.pack_reclength,
info->s->base.max_key_length);
/* Avoid unnecessary realloc */
if (newptr && length == old_length)
@@ -650,6 +650,8 @@ void mi_setup_functions(register MYISAM_SHARE *share)
share->compare_unique=_mi_cmp_dynamic_unique;
share->calc_checksum= mi_checksum;
+ /* add bits used to pack data to pack_reclength for faster allocation */
+ share->base.pack_reclength+= share->base.pack_bits;
if (share->base.blobs)
{
share->update_record=_mi_update_blob_record;
diff --git a/myisam/mi_test_all.sh b/myisam/mi_test_all.sh
index a2d57ea1a83..07e71d65675 100755
--- a/myisam/mi_test_all.sh
+++ b/myisam/mi_test_all.sh
@@ -3,7 +3,9 @@
# Execute some simple basic test on MyISAM libary to check if things
# works at all.
+valgrind="valgrind --alignment=8 --leak-check=yes"
silent="-s"
+
if test -f mi_test1$MACH ; then suffix=$MACH else suffix=""; fi
mi_test1$suffix $silent
myisamchk$suffix -se test1
diff --git a/mysql-test/include/check_var_limit.inc b/mysql-test/include/check_var_limit.inc
index 5f26e2b99a9..f955aeb345e 100644
--- a/mysql-test/include/check_var_limit.inc
+++ b/mysql-test/include/check_var_limit.inc
@@ -5,5 +5,5 @@
#
-- require r/check_var_limit.require
disable_query_log;
-eval select SUBSTRING_INDEX($LIMIT, "\t", 2) BETWEEN $MIN_LIMIT AND $MAX_LIMIT as "limit";
+eval select SUBSTRING_INDEX("$LIMIT", "\\t", -1) BETWEEN $MIN_LIMIT AND $MAX_LIMIT as "limit";
enable_query_log;
diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result
index c4368384bf8..e78e12c01d5 100644
--- a/mysql-test/r/myisam.result
+++ b/mysql-test/r/myisam.result
@@ -121,7 +121,6 @@ check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
-drop table if exists t1;
create table t1 (i1 int, i2 int, i3 int, i4 int, i5 int, i6 int, i7 int, i8
int, i9 int, i10 int, i11 int, i12 int, i13 int, i14 int, i15 int, i16 int, i17
int, i18 int, i19 int, i20 int, i21 int, i22 int, i23 int, i24 int, i25 int,
@@ -286,7 +285,12 @@ insert into t1 values (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, "Sergei");
-drop table if exists t1;
+update t1 set b=repeat('a',256);
+update t1 set i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
CREATE TABLE `t1` (
`post_id` mediumint(8) unsigned NOT NULL auto_increment,
`topic_id` mediumint(8) unsigned NOT NULL default '0',
diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test
index 2ae3c27f699..02c92109816 100644
--- a/mysql-test/t/myisam.test
+++ b/mysql-test/t/myisam.test
@@ -127,7 +127,6 @@ drop table t1;
# test of myisam with huge number of packed fields
#
-drop table if exists t1;
create table t1 (i1 int, i2 int, i3 int, i4 int, i5 int, i6 int, i7 int, i8
int, i9 int, i10 int, i11 int, i12 int, i13 int, i14 int, i15 int, i16 int, i17
int, i18 int, i19 int, i20 int, i21 int, i22 int, i23 int, i24 int, i25 int,
@@ -292,7 +291,10 @@ insert into t1 values (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, "Sergei");
-drop table if exists t1;
+update t1 set b=repeat('a',256);
+update t1 set i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0;
+check table t1;
+drop table t1;
#
# Test of REPAIR that once failed
diff --git a/mysql-test/t/query_cache_merge.test b/mysql-test/t/query_cache_merge.test
index 9d9e311af06..02e316932a3 100644
--- a/mysql-test/t/query_cache_merge.test
+++ b/mysql-test/t/query_cache_merge.test
@@ -2,8 +2,8 @@
--source include/have_query_cache.inc
let $LIMIT=`SHOW VARIABLES LIKE 'open_files_limit'`;
-let $MIN_LIMIT=100
-let $MAX_LIMIT=65536
+let $MIN_LIMIT=600;
+let $MAX_LIMIT=65536;
--source include/check_var_limit.inc
SET @@global.query_cache_size=1355776;
diff --git a/mysys/default.c b/mysys/default.c
index 716be6fc2bb..2fadda6a2fe 100644
--- a/mysys/default.c
+++ b/mysys/default.c
@@ -15,22 +15,22 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/****************************************************************************
-** Add all options from files named "group".cnf from the default_directories
-** before the command line arguments.
-** On Windows defaults will also search in the Windows directory for a file
-** called 'group'.ini
-** As long as the program uses the last argument for conflicting
-** options one only have to add a call to "load_defaults" to enable
-** use of default values.
-** pre- and end 'blank space' are removed from options and values. The
-** following escape sequences are recognized in values: \b \t \n \r \\
-**
-** The following arguments are handled automaticly; If used, they must be
-** first argument on the command line!
-** --no-defaults ; no options are read.
-** --defaults-file=full-path-to-default-file ; Only this file will be read.
-** --defaults-extra-file=full-path-to-default-file ; Read this file before ~/
-** --print-defaults ; Print the modified command line and exit
+ Add all options from files named "group".cnf from the default_directories
+ before the command line arguments.
+ On Windows defaults will also search in the Windows directory for a file
+ called 'group'.ini
+ As long as the program uses the last argument for conflicting
+ options one only have to add a call to "load_defaults" to enable
+ use of default values.
+ pre- and end 'blank space' are removed from options and values. The
+ following escape sequences are recognized in values: \b \t \n \r \\
+
+ The following arguments are handled automaticly; If used, they must be
+ first argument on the command line!
+ --no-defaults ; no options are read.
+ --defaults-file=full-path-to-default-file ; Only this file will be read.
+ --defaults-extra-file=full-path-to-default-file ; Read this file before ~/
+ --print-defaults ; Print the modified command line and exit
****************************************************************************/
#include "mysys_priv.h"
@@ -72,6 +72,39 @@ static int search_default_file(DYNAMIC_ARRAY *args,MEM_ROOT *alloc,
static char *remove_end_comment(char *ptr);
+
+/*
+ Read options from configurations files
+
+ SYNOPSIS
+ load_defaults()
+ conf_file Basename for configuration file to search for.
+ If this is a path, then only this file is read.
+ groups Which [group] entrys to read.
+ Points to an null terminated array of pointers
+ argc Pointer to argc of original program
+ argv Pointer to argv of original program
+
+ IMPLEMENTATION
+
+ Read options from configuration files and put them BEFORE the arguments
+ that are already in argc and argv. This way the calling program can
+ easily command line options override options in configuration files
+
+ NOTES
+ In case of fatal error, the function will print a warning and do
+ exit(1)
+
+ To free used memory one should call free_defaults() with the argument
+ that was put in *argv
+
+ RETURN
+ 0 ok
+ 1 The given conf_file didn't exists
+ 2 The given conf_file was not a normal readable file
+*/
+
+
int load_defaults(const char *conf_file, const char **groups,
int *argc, char ***argv)
{
@@ -101,7 +134,7 @@ int load_defaults(const char *conf_file, const char **groups,
(*argc)--;
*argv=res;
*(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
- return 0;
+ DBUG_RETURN(0);
}
/* Check if we want to force the use a specific default file */
@@ -131,13 +164,13 @@ int load_defaults(const char *conf_file, const char **groups,
if (forced_default_file)
{
if ((error= search_default_file(&args, &alloc, "",
- forced_default_file, "", &group)) == 1)
+ forced_default_file, "", &group)) < 0)
goto err;
}
else if (dirname_length(conf_file))
{
if ((error= search_default_file(&args, &alloc, NullS, conf_file,
- default_ext, &group)) == 1)
+ default_ext, &group)) < 0)
goto err;
}
else
@@ -145,28 +178,36 @@ int load_defaults(const char *conf_file, const char **groups,
#ifdef __WIN__
char system_dir[FN_REFLEN];
GetWindowsDirectory(system_dir,sizeof(system_dir));
- if ((error= search_default_file(&args, &alloc, system_dir, conf_file,
- windows_ext, &group)) == 1)
+ if ((search_default_file(&args, &alloc, system_dir, conf_file,
+ windows_ext, &group)))
goto err;
#endif
#if defined(__EMX__) || defined(OS2)
if (getenv("ETC") &&
- (error= search_default_file(&args, &alloc, getenv("ETC"), conf_file,
- default_ext, &group)) == 1)
+ (search_default_file(&args, &alloc, getenv("ETC"), conf_file,
+ default_ext, &group)) < 0)
goto err;
#endif
for (dirs=default_directories ; *dirs; dirs++)
{
if (**dirs)
- error= search_default_file(&args, &alloc, *dirs, conf_file,
- default_ext, &group);
+ {
+ if (search_default_file(&args, &alloc, *dirs, conf_file,
+ default_ext, &group) < 0)
+ goto err;
+ }
else if (defaults_extra_file)
- error= search_default_file(&args, &alloc, NullS, defaults_extra_file,
- default_ext, &group);
- if (error == 1)
- goto err;
+ {
+ if (search_default_file(&args, &alloc, NullS, defaults_extra_file,
+ default_ext, &group) < 0)
+ goto err; /* Fatal error */
+ }
}
}
+ /*
+ Here error contains <> 0 only if we have a fully specified conf_file
+ or a forced default file
+ */
if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
(args.elements + *argc +1) *sizeof(char*))))
goto err;
@@ -202,13 +243,13 @@ int load_defaults(const char *conf_file, const char **groups,
for (i=1 ; i < *argc ; i++)
printf("%s ", (*argv)[i]);
puts("");
- exit(1);
+ exit(0);
}
- return error;
+ DBUG_RETURN(error);
err:
- fprintf(stderr,"Program aborted\n");
- return(error);
+ fprintf(stderr,"Fatal error in defaults handling. Program aborted\n");
+ exit(1);
}
@@ -221,10 +262,22 @@ void free_defaults(char **argv)
/*
- Return values: 0 Success
- 1 Fatal error, abort
- 2 File not found, continue
- 3 File is not a regular file, continue
+ Open a configuration file (if exists) and read given options from it
+
+ SYNOPSIS
+ search_default_file()
+ args Store pointer to found options here
+ alloc Allocate strings in this object
+ dir directory to read
+ config_file Name of configuration file
+ ext Extension for configuration file
+ group groups to read
+
+ RETURN
+ 0 Success
+ -1 Fatal error, abort
+ 1 File not found (Warning)
+ 2 File is not a regular file (Warning)
*/
static int search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
@@ -254,7 +307,7 @@ static int search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
{
MY_STAT stat_info;
if (!my_stat(name,&stat_info,MYF(0)))
- return 2;
+ return 1;
/*
Ignore world-writable regular files.
This is mainly done to protect us to not read a file created by
@@ -268,7 +321,7 @@ static int search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
return 0;
}
else if ((stat_info.st_mode & S_IFMT) != S_IFREG)
- return 3;
+ return 2;
}
#endif
if (!(fp = my_fopen(fn_format(name,name,"","",4),O_RDONLY,MYF(0))))
@@ -374,7 +427,7 @@ static int search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
err:
my_fclose(fp,MYF(0));
- return 1;
+ return -1; /* Fatal error */
}
diff --git a/mysys/my_pthread.c b/mysys/my_pthread.c
index 4f472f61593..5be38fad734 100644
--- a/mysys/my_pthread.c
+++ b/mysys/my_pthread.c
@@ -92,7 +92,7 @@ void *my_pthread_getspecific_imp(pthread_key_t key)
#ifdef __NETWARE__
/*
-don't kill the LibC Reaper thread or the main thread
+ Don't kill the LibC Reaper thread or the main thread
*/
#include <nks/thread.h>
#undef pthread_exit
@@ -105,8 +105,10 @@ void my_pthread_exit(void *status)
NXThreadGetContext(tid, &ctx);
NXContextGetName(ctx, name, PATH_MAX);
- // "MYSQLD.NLM's LibC Reaper" or "MYSQLD.NLM's main thread"
- // with a debug build of LibC the reaper can have different names
+ /*
+ "MYSQLD.NLM's LibC Reaper" or "MYSQLD.NLM's main thread"
+ with a debug build of LibC the reaper can have different names
+ */
if (!strindex(name, "\'s"))
{
pthread_exit(status);
@@ -114,8 +116,10 @@ void my_pthread_exit(void *status)
}
#endif
-/* Some functions for RTS threads, AIX, Siemens Unix and UnixWare 7
- (and DEC OSF/1 3.2 too) */
+/*
+ Some functions for RTS threads, AIX, Siemens Unix and UnixWare 7
+ (and DEC OSF/1 3.2 too)
+*/
int my_pthread_create_detached=1;
diff --git a/sql/log.cc b/sql/log.cc
index ce06092cfb7..bd5aeb02121 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1059,8 +1059,9 @@ bool MYSQL_LOG::write(Log_event* event_info)
*/
if (is_open())
{
- bool should_rotate = 0;
- const char *local_db = event_info->get_db();
+ bool should_rotate= 0;
+ const char *local_db= event_info->get_db();
+ IO_CACHE *file= &log_file;
#ifdef USING_TRANSACTIONS
/*
Should we write to the binlog cache or to the binlog on disk?
@@ -1071,13 +1072,11 @@ bool MYSQL_LOG::write(Log_event* event_info)
trans/non-trans table types the best possible in binlogging)
- or if the event asks for it (cache_stmt == true).
*/
- IO_CACHE *file = ((event_info->get_cache_stmt() ||
- my_b_tell(&thd->transaction.trans_log)) ?
- &thd->transaction.trans_log :
- &log_file);
-#else
- IO_CACHE *file = &log_file;
-#endif
+ if (opt_using_transactions &&
+ (event_info->get_cache_stmt() ||
+ (thd && my_b_tell(&thd->transaction.trans_log))))
+ file= &thd->transaction.trans_log;
+#endif
DBUG_PRINT("info",("event type=%d",event_info->get_type_code()));
/*
In the future we need to add to the following if tests like