# Hand crafted tests for GNU M4. -*- Autotest -*- # Copyright (C) 2001, 2006, 2007 Free Software Foundation, Inc. # This file is part of GNU M4. # # GNU M4 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 3 of the License, or # (at your option) any later version. # # GNU M4 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. If not, see . AT_BANNER([Module support.]) ## --------- ## ## modfreeze ## ## --------- ## AT_SETUP([Freezing modules]) AT_KEYWORDS([frozen]) AT_CHECK_DYNAMIC_MODULE AT_DATA([[frozen.m4]], [[divert(1)dnl define(`test', `local::`test'')dnl define(`test1', defn(`test'))dnl ->test load(`modtest') define(`test2', defn(`test'))dnl ->test load(`shadow') define(`test3', defn(`test'))dnl ->test ]]) AT_DATA([[unfrozen.m4]], [[undivert(1)dnl test1 test2 test3 ]]) # First generate the `expout' ouput by running over the sources before # freezing. AT_CHECK_M4([-M "$abs_builddir" -m load frozen.m4 unfrozen.m4], [0], [stdout], [stderr]) mv stdout expout mv stderr experr # Now freeze the first source file. AT_CHECK_M4([-M "$abs_builddir" -m load -F frozen.m4f frozen.m4], [0], [], [ignore]) # Now rerun the original sequence, but using the frozen file. AT_CHECK_M4([-M "$abs_builddir" -R frozen.m4f unfrozen.m4], [0], [expout], [experr]) AT_CLEANUP([frozen.m4f]) ## ------------------ ## ## module test macros ## ## ------------------ ## AT_SETUP([module test macros]) AT_CHECK_DYNAMIC_MODULE AT_CHECK_GMP AT_DATA([in], [[load(`mpeval') -__load__-__mpeval__- unload(`mpeval') -__load__-__mpeval__- unload(`load') -__load__-__mpeval__- ]]) AT_CHECK_M4([-m load in], [0], [[ --- --__mpeval__- -__load__-__mpeval__- ]]) AT_CLEANUP ## ---------------------------- ## ## Exercising the test module. ## ## ---------------------------- ## # AT_CHECK_M4_MODTEST(TITLE, ENV-VARS, M4-OPTIONS) # ------------------------------------------------ # Add a test named TITLE, running m4 with either ENV-VARS in the environment # or M4-OPTIONS set to pick up test modules. m4_define([AT_CHECK_M4_MODTEST], [AT_SETUP([$1]) AT_CHECK_DYNAMIC_MODULE AT_DATA([input.m4], [[load(`modtest') test Dumpdef: dumpdef(`test'). unload(`modtest') test Dumpdef: dumpdef(`test'). ]]) dnl Fortunately, all tests within AT_SETUP are in the same subshell, so dnl setting the environment now will impact the AT_CHECK_M4, but not dnl carry over to the next AT_SETUP. m4_ifval([$2], [$2 export m4_substr([$2], [0], m4_index([$2], [=]))]) AT_CHECK_M4([-m load $3 input.m4], [0], [[ Test module called. Dumpdef: . test Dumpdef: . ]], [[Test module loaded. test: Test module unloaded. m4:input.m4:6: Warning: dumpdef: undefined macro `test' ]]) AT_CLEANUP ]) AT_CHECK_M4_MODTEST([--module-directory: absolute path], [], [-M "$abs_builddir"]) AT_CHECK_M4_MODTEST([--module-directory: relative path], [], [-M "$top_build_prefix/tests"]) AT_CHECK_M4_MODTEST([M4MODPATH: absolute path], [M4MODPATH="$abs_builddir"], []) AT_CHECK_M4_MODTEST([M4MODPATH: relative path], [M4MODPATH="$top_build_prefix/tests"], []) AT_CHECK_M4_MODTEST([LTDL_LIBRARY_PATH: absolute path], [LTDL_LIBRARY_PATH="$abs_builddir"], []) AT_CHECK_M4_MODTEST([LTDL_LIBRARY_PATH: relative path], [LTDL_LIBRARY_PATH="$top_build_prefix/tests"], []) ## ------ ## ## shadow ## ## ------ ## AT_SETUP([modules: shadow]) AT_CHECK_DYNAMIC_MODULE AT_DATA([[input.m4]], [[# no modules loaded yet test shadow # define our own macros for `test' and `shadow' define(`test', `local::`test'') define(`shadow', `local::`shadow'') test shadow # module Shadow defines `shadow' and `test' macros load(`shadow') dumpdef(`test') dumpdef(`shadow') test shadow # save the definition of `test' from the Shadow module define(`Shadow::test', defn(`test')) # module Modtest also defines a `test' macro load(`modtest') dumpdef(`test') dumpdef(`shadow') test shadow # Reloading Shadow shouldn't affect anything load(`shadow') dumpdef(`test') dumpdef(`shadow') test shadow # Unloading Modtest will unshadow the test definition in Shadow unload(`modtest') dumpdef(`test') dumpdef(`shadow') test shadow # Unloading Shadow once has no effect (we loaded it twice) unload(`shadow') dumpdef(`test') dumpdef(`shadow') test shadow # Unloading Shadow again will revert to copying `test' and the local # `shadow' macro. unload(`shadow') test shadow ]]) AT_DATA([[expout]], [[# no modules loaded yet test shadow # define our own macros for `test' and `shadow' local::test local::shadow # module Shadow defines `shadow' and `test' macros Shadow module loaded. Shadow::test called. Shadow::shadow called. # save the definition of `test' from the Shadow module # module Modtest also defines a `test' macro Test module called. Shadow::shadow called. # Reloading Shadow shouldn't affect anything Test module called. Shadow::shadow called. # Unloading Modtest will unshadow the test definition in Shadow Shadow::test called. Shadow::shadow called. # Unloading Shadow once has no effect (we loaded it twice) Shadow::test called. Shadow::shadow called. # Unloading Shadow again will revert to copying `test' and the local # `shadow' macro. local::test local::shadow ]]) AT_DATA([[experr]], [[test: shadow: Test module loaded. test: shadow: test: shadow: Test module unloaded. test: shadow: test: shadow: ]]) AT_CHECK_M4([-M "$abs_builddir" -m load input.m4], [0], [expout], [experr]) AT_CLEANUP ## ------ ## ## unload ## ## ------ ## AT_SETUP([modules: unload]) AT_CHECK_DYNAMIC_MODULE AT_DATA([[input.m4]], [[test __test__ load(`modtest') test __test__ load(`shadow') test __test__ unload(`modtest') test __test__ load(`modtest') test __test__ unload(`modtest') test __test__ unload(`shadow') test __test__ ]]) AT_DATA([[expout]], [[test __test__ Test module called. modtest Shadow module loaded. Shadow::test called. shadow Shadow::test called. shadow Test module called. modtest Shadow::test called. shadow test __test__ ]]) AT_DATA([[experr]], [[Test module loaded. Test module unloaded. Test module loaded. Test module unloaded. ]]) AT_CHECK_M4([-M "$abs_builddir" -m load input.m4], [0], [expout], [experr]) AT_CLEANUP ## ----------------------- ## ## module symbol importing ## ## ----------------------- ## # Importing a symbol from a not yet loaded module # This test is ugly, because we need to canonicalize strerror strings # to match our test. So we save STDERR to a file, and run another check # which edits that file and compares it to the canonical STDERR output # from the first command: AT_SETUP([modules: importing]) AT_CHECK_DYNAMIC_MODULE AT_DATA([[input.m4]], [[import load(`import') import unload(`modtest') import symbol_fail module_fail ]]) AT_DATA([[expout]], [[import import::import called. import::import called. import::symbol_fail called. ]]) AT_DATA([[experr]], [[Test module loaded. TRUE Test module unloaded. Test module loaded. TRUE m4:input.m4:6: cannot load symbol `no_such' from module `modtest' m4:input.m4:7: cannot open module `no_such' ]]) AT_CHECK_M4([-M "$abs_builddir" -m load input.m4], [1], [expout], [experr]) AT_CLEANUP ## -------------------- ## ## trace module symbols ## ## -------------------- ## # The trace bit should not be lost if a builtin is unloaded from # memory and then redefined by a subsequent load. AT_SETUP([modules: trace]) AT_CHECK_DYNAMIC_MODULE AT_DATA([[input.m4]], [[test load(`shadow') test unload(`shadow') test load(`shadow') test ]]) AT_DATA([[expout]], [[test Shadow module loaded. Shadow::test called. test Shadow module loaded. Shadow::test called. ]]) AT_DATA([[experr]], [[m4trace: -1- test -> `Shadow::`test' called.' m4trace: -1- test -> `Shadow::`test' called.' ]]) AT_CHECK_M4([-M "$abs_builddir" -m load -t test input.m4], [0], [expout], [experr]) AT_CLEANUP ## ----------------- ## ## unload gnu module ## ## ----------------- ## AT_SETUP([unload gnu module]) AT_CHECK_DYNAMIC_MODULE dnl Ensure that the gnu module does not leak memory. I don't know how dnl to portably artificially limit the heap to cause an out-of-memory dnl condition in the case of a leak, but examining the run of this test dnl in a debugger can show whether it is leaking. AT_DATA([input.m4], [[divert(-1) define(`forloop', `pushdef(`$1', `$2')_forloop(`$1', `$2', `$3', `$4')popdef(`$1')') define(`_forloop', `$4`'ifelse($1, `$3', `', `define(`$1', incr($1))_forloop(`$1', `$2', `$3', `$4')')') forloop(`i', `1', `5000', `unload(`gnu')load(`gnu')regexp(`123', `\(4\)?2')') ]]) AT_CHECK_M4([-m load input.m4], [0]) AT_CLEANUP ## ------------------ ## ## unload load module ## ## ------------------ ## AT_SETUP([unload load module]) AT_CHECK_DYNAMIC_MODULE dnl Ensure that the load module can be unloaded and reloaded (obviously, dnl it can't reload itself; the reload occurs on the command line). Since dnl the module must be resident (after all, the `unload' builtin had better dnl not unmap the memory for the code it is currently executing), make sure dnl that resident modules are handled gracefully. AT_DATA([in1.m4], [[__load__ 1 unload(`load') 2 __load__ 3 ]]) AT_DATA([in2.m4], [[__load__ 4 load(`load') 5 __load__ 6 unload(`load') 7 __load__ 8 unload(`load') 9 __load__ 10 ]]) AT_CHECK_M4([-m load in1.m4 -m load in2.m4], [0], [[ 1 2 __load__ 3 4 5 6 7 8 9 __load__ 10 ]]) AT_CLEANUP