# Boost regression-testing Jamfile
#  (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and
#  distribute this software is granted provided this copyright notice appears in
#  all copies. This software is provided "as is" without express or implied
#  warranty, and with no claim as to its suitability for any purpose.

subproject status ;

# ----------- Jam rules for testing; test invocations at bottom ----------------#

# boost-test sources : type : requirements [ : name ]
#
# Declares a test target. If name is not supplied, it is taken from the name of
# the first source file, sans extension and directory path.
#
# type should be a target type (e.g. OBJ, DLL, LIB, EXE)
#
# RETURNS the name(s) of the generated test target(s).
rule boost-test
{
    local result ;
    {
        local requirements = $(3) ;
        local name = $(4) ;
        name ?= $(<[1]:D=:S=) ;

        # Make sure that targets don't become part of "all"
        local gSUPPRESS_FAKE_TARGETS = true ;
        
        result = [
            declare-local-target $(name)
            : $(<:R=$(BOOST_ROOT)) # sources
            : $(requirements) <include>$(BOOST_ROOT) # requirements
            :             # default build
            : $(>)     # target type
        ] ;
    }
    Clean clean : $(result) ;
    type-DEPENDS $(<:B:S=) : $(result) ;
    type-DEPENDS test : $(result) ;
    return $(result) ;
}

#######

# failed-test-file test-file : fail-to-build-file
#
# a utility rule which causes test-file to be built successfully, only if
# fail-to-build-file fails to build. Used for expected-failure tests.
rule failed-test-file
{
    DEPENDS $(<) : $(>) ;
    FAIL_EXPECTED $(>) ;
}
# to avoid building the test-file when it's actually up-to-date,
# we need to put something in place of the thing it depends on.
actions failed-test-file
{
    echo building "$(>)" failed as expected > $(>)
    echo building "$(>)" failed as expected > $(<)
}

# declare-build-fail-test test-type : dependency-type
#
# A utility rule which declares test-type to be a target type which depends on
# the /failed/ construction of a target of type dependency-type.
rule declare-build-fail-test
{
    gGENERATOR_FUNCTION($(<)) = fail-to-build ;
    gDEPENDENCY_TYPE($(<)) = $(>) ;
    SUF$(<) = .fail ;
}

# fail-to-build target.test : sources : requirements
#
# A target generator function for target types declared with
# declare-build-fail-test, above.
rule fail-to-build
{
    # Get the target type of the current target out of the build properties
    local target-type = [ get-values <target-type> : $(gBUILD_PROPERTIES) ] ;

    # Get the type of target which will (hopefully) fail to build.
    local dependency-type = $(gDEPENDENCY_TYPE($(target-type))) ;

    # Get the actual name of the target which should fail to build
    local fail-target = $(<[1]:S=$(SUF$(dependency-type))) ;

    # Call dependency-type's generator function to (fail to) build the target
    local ignored = [
        $(gGENERATOR_FUNCTION($(dependency-type))) $(fail-target) : $(>) : $(3) ] ;

    # Generator functions don't handle this job for us; perhaps they should.
    set-target-variables $(fail-target)
    
    # The .test file goes with the other subvariant targets
    MakeLocate $(<) : $(LOCATE_TARGET) ;

    # Establish the dependency
    failed-test-file $(<) : $(fail-target) ;
}

### Rules for testing whether a file compiles ###

# Establish the rule which generates targets of type "OBJ". Should really go
# into basic build system, but wasn't needed 'till now.
gGENERATOR_FUNCTION(OBJ) = Object ;
declare-build-fail-test COMPILE_FAIL : OBJ ;

# Test that the given source-file(s) compile
rule compile # source-file : fail : requirements
{
    return [ boost-test $(<) : OBJ : $(3) ] ;
}

# Test that the given source-file(s) fail to compile
rule compile-fail # source-file : requirements
{
    return [ boost-test $(<) : COMPILE_FAIL : $(2) ] ;
}


### Rules for testing whether a program runs ###

gGENERATOR_FUNCTION(RUN_TEST) = run-test ;
SUFRUN_TEST = .test ;
rule run-test # target : sources : requirements
{
    local executable = $(<:S=$(SUFEXE)) ; 
    executable-file $(executable) : $(>) : $(3) ;
    set-target-variables $(executable) ;
    
    # Ugly hack to get the pathes transferred. See the link rule in boost-base.jam.
    RUN_PATH on $(<) = [ join $(gRUN_PATH($(executable))) $(RUN_PATH) : $(SPLITPATH) ] ;
    if $(UNIX) 
    {
    	RUN_LD_LIBRARY_PATH on $(<) = [ join $(gRUN_LD_LIBRARY_PATH($(executable))) $(RUN_LD_LIBRARY_PATH) : $(SPLITPATH) ] ;
    }

    # The .test file goes with the other subvariant targets
    # normalization is a hack to get the slashes going the right way on Windoze
    local LOCATE_TARGET = [ FDirName [ split-path $(LOCATE_TARGET) ] ] ;
    MakeLocate $(<) : $(LOCATE_TARGET) ;
    
    DEPENDS $(<) : $(executable) $(gRUN_TEST_INPUT_FILES) ;
    INPUT_FILES on $(<) = $(gRUN_TEST_INPUT_FILES) ;
    ARGS on $(<) = $(gRUN_TEST_ARGS) ;
    capture-run-output $(<) : $(executable) ;
    
    if $(RUN_ALL_TESTS)
    {
        ALWAYS $(<) ;
    }
}

# The rule is just used for argument checking
rule capture-run-output ( target : executable + ) { }
if $(UNIX)  
{
    actions capture-run-output bind INPUT_FILES
    {
        $(SHELL_SET)PATH=$(RUN_PATH) 
    	$(SHELL_EXPORT)PATH
    	$(SHELL_SET)LD_LIBRARY_PATH=$(RUN_LD_LIBRARY_PATH)
    	$(SHELL_EXPORT)LD_LIBRARY_PATH
        $(>) $(ARGS) $(INPUT_FILES) > $(<:S=.error)
        $(CP) $(<:S=.error) $(<)
        $(RM) $(<:S=.error)
    }
}
else
{
    actions capture-run-output bind INPUT_FILES
    {
        $(SHELL_SET)PATH=$(RUN_PATH) 
        $(SHELL_EXPORT)PATH
        $(>) $(ARGS) $(INPUT_FILES) > $(<:S=.error)
        $(CP) $(<:S=.error) $(<)
        $(RM) $(<:S=.error)
    }
}

rule run # sources : args : input-files : requirements
{
    local gRUN_TEST_ARGS = $(2) ;
    local gRUN_TEST_INPUT_FILES = $(3) ;
    SEARCH on $(3) = $(LOCATE_SOURCE) ;
    return [ boost-test $(<) : RUN_TEST : $(4) ] ;
}

declare-build-fail-test RUN_FAIL : RUN_TEST ;
rule run-fail # sources : args : input-files : requirements
{
    local gRUN_TEST_ARGS = $(2) ;
    local gRUN_TEST_INPUT_FILES = $(3) ;
    SEARCH on $(3) = $(LOCATE_SOURCE) ;
    return [ boost-test $(<) : RUN_FAIL : $(4) ] ;
}

### Rules for testing whether a program links

declare-build-fail-test LINK_FAIL : EXE ;
rule link-fail # sources : requirements
{
    return [ boost-test $(<) : LINK_FAIL : $(2) ] ;
}

### Rules for grouping tests into suites:

rule test-suite # pseudotarget-name : test-targets...
{
    NOTFILE $(<) ;
    type-DEPENDS $(<) : $(>) ;
}

# ----------- Actual test invocations follow ----------------#

test-suite "bind"
    : [ run libs/bind/bind_test.cpp ]
      [ run libs/bind/bind_test.cpp ]
      [ run libs/bind/mem_fn_test.cpp ]
      [ run libs/bind/mem_fn_void_test.cpp ]
    ;

test-suite config
    : [ run libs/config/test/config_test.cpp ]
      [ run libs/config/test/limits_test.cpp ]
    ;
    
run libs/any/any_test.cpp ;

run libs/array/array1.cpp ;

test-suite concept_check
    : [ compile libs/concept_check/concept_check_test.cpp ]
      [ compile libs/concept_check/class_concept_check_test.cpp ]
      [ link-fail libs/concept_check/concept_check_fail_expected.cpp ]
      [ link-fail libs/concept_check/class_concept_fail_expected.cpp ]
    ;

test-suite conversion
    : [ run libs/conversion/cast_test.cpp ]
      [ run libs/conversion/lexical_cast_test.cpp ]
    ;
    
run libs/crc/crc_test.cpp ;

run libs/function/test/function_test.cpp ;

run libs/functional/function_test.cpp ;

run libs/graph/test/graph.cpp ;


test-suite integer
    : [ run libs/integer/cstdint_test.cpp ]
      [ run libs/integer/integer_test.cpp ]
      [ run libs/integer/integer_traits_test.cpp ]
    ;

test-suite math
    : [ run libs/math/test/common_factor_test.cpp ]
      [ run libs/math/octonion/octonion_test.cpp ]
      [ run libs/math/quaternion/quaternion_test.cpp ]
      [ run libs/math/special_functions/special_functions_test.cpp ]
    ;

run libs/pool/test/test_pool_alloc.cpp ;

test-suite rational
    : [ run libs/rational/rational_example.cpp ]
      [ run libs/rational/rational_test.cpp ]
    ;

test-suite random
    : [ run libs/random/random_test.cpp ]
      [ run libs/random/random_demo.cpp ]
    ;

run libs/utility/ref_test.cpp ;

test-suite regex
    : [ run libs/regex/test/regress/regex_test.cpp : :
        $(BOOST_ROOT)/libs/regex/test/regress/tests.txt ]
      [ run libs/regex/test/regress/wregex_test.cpp : :
        $(BOOST_ROOT)/libs/regex/test/regress/tests.txt ]
    ;

run libs/smart_ptr/smart_ptr_test.cpp ;

test-suite static_assert
    : [ compile libs/static_assert/static_assert_test.cpp ]
      [ compile-fail libs/static_assert/static_assert_test_fail_1.cpp ]
      [ compile-fail libs/static_assert/static_assert_test_fail_2.cpp ]
      [ compile-fail libs/static_assert/static_assert_test_fail_3.cpp ]
      [ compile-fail libs/static_assert/static_assert_test_fail_4.cpp ]
      [ compile-fail libs/static_assert/static_assert_test_fail_5.cpp ]
      [ compile-fail libs/static_assert/static_assert_test_fail_6.cpp ]
      [ compile-fail libs/static_assert/static_assert_test_fail_7.cpp ]
      [ link-fail libs/static_assert/static_assert_test_fail_8.cpp ]
    ;
    
run libs/test/example/test_tools_example.cpp ;

run-fail libs/test/test/test_tools_fail2.cpp ;

compile libs/timer/timer_test.cpp ;

test-suite tokenizer
    : [ run libs/tokenizer/examples.cpp ]
      [ run libs/tokenizer/simple_example_1.cpp ]
      [ run libs/tokenizer/simple_example_2.cpp ]
      [ run libs/tokenizer/simple_example_3.cpp ]
      [ run libs/tokenizer/simple_example_4.cpp ]
      [ run libs/tokenizer/simple_example_5.cpp ]
    ;

test-suite type_traits
    : [ run libs/type_traits/tests/alignment_test.cpp ]
      [ run libs/type_traits/tests/arithmetic_traits_test.cpp ]
      [ run libs/type_traits/tests/composite_traits_test.cpp ]
      [ run libs/type_traits/tests/cv_traits_test.cpp ]
      [ run libs/type_traits/tests/is_function_test.cpp ]
      [ run libs/type_traits/tests/is_convertible_test.cpp ]
      [ run libs/type_traits/tests/is_same_test.cpp ]
      [ run libs/type_traits/tests/object_type_traits_test.cpp ]
      [ run libs/type_traits/tests/transform_traits_test.cpp ]
    ;
    
run libs/utility/call_traits_test.cpp : -u ;

compile-fail libs/utility/checked_delete_test.cpp ;

run libs/utility/compressed_pair_test.cpp : -u ;

test-suite iterator_adaptors
    : [ run libs/utility/counting_iterator_test.cpp : # args
        : # input files
        : # requirements
        
        # borland warns incorrectly in this case, so often that
        # successful compilation is prevented.
        <borland><*><cxxflags>"-w-8091 -w-8092"
      ]
        
      [ run libs/utility/iterator_adaptor_test.cpp ] 
      [ compile-fail libs/utility/iter_adaptor_fail_expected1.cpp ] 
      [ compile-fail libs/utility/iter_adaptor_fail_expected2.cpp ]
      [ run libs/utility/transform_iterator_test.cpp ]
      [ run libs/utility/indirect_iterator_test.cpp ]
      [ run libs/utility/iter_traits_gen_test.cpp ]
      
      [ run libs/utility/iterator_adaptor_examples.cpp ]
      [ run libs/utility/counting_iterator_example.cpp ]
      [ run libs/utility/filter_iterator_example.cpp ]
      [ run libs/utility/fun_out_iter_example.cpp ]
      [ run libs/utility/indirect_iterator_example.cpp ]
      [ run libs/utility/projection_iterator_example.cpp ]
      [ run libs/utility/reverse_iterator_example.cpp ]
      [ run libs/utility/transform_iterator_example.cpp ]
    ;


run libs/utility/iterator_traits_test.cpp ;

run libs/utility/iterators_test.cpp ;

compile-fail libs/utility/noncopyable_test.cpp ;

run libs/utility/numeric_traits_test.cpp ;

run libs/utility/operators_test.cpp ;

run libs/utility/tie_example.cpp ;

run libs/utility/binary_search_test.cpp ;
