###########################################################################
# A module with regression test suite
#
# Copyright (C) 2009-2011 Institute for System Programming, RAS
# Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies)
# Copyright (C) 2012-2018 Andrey Ponomarenko's ABI Laboratory
#
# Written by Andrey Ponomarenko
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA  02110-1301 USA
###########################################################################
use strict;

loadModule("ElfTools");

sub testTool()
{
    if($In::Opt{"UserLang"} ne "C++") {
        testC();
    }
    
    if($In::Opt{"UserLang"} ne "C") {
        testCpp();
    }
}

sub testCpp()
{
    printMsg("INFO", "Verifying detectable C++ library changes");
    my ($HEADER1, $SOURCE1, $HEADER2, $SOURCE2) = ();
    
    my $DECL_SPEC = "";
    my $EXTERN = "";
    
    if($In::Opt{"OS"} eq "windows")
    {
        $DECL_SPEC = "__declspec( dllexport )";
        $EXTERN = "extern "; # add "extern" for CL compiler
    }
    
    # Class outside namespace
    $HEADER1 .= "
        class $DECL_SPEC OutsideNS {
        public:
            int someMethod();
            int field;
        };";
    $SOURCE1 .= "
        int OutsideNS::someMethod() { return 0; }";
    
    $HEADER2 .= "
        class $DECL_SPEC OutsideNS {
        public:
            int someMethod();
            int field;
            int field2;
        };";
    $SOURCE2 .= "
        int OutsideNS::someMethod() { return 0; }";
    
    # Begin namespace
    $HEADER1 .= "namespace TestNS {\n";
    $HEADER2 .= "namespace TestNS {\n";
    $SOURCE1 .= "namespace TestNS {\n";
    $SOURCE2 .= "namespace TestNS {\n";
    
    # Changed template internals
    # $HEADER1 .= "
    #     template <typename T, int _P>
    #     class $DECL_SPEC ChangedTemplate {
    #     public:
    #         T value;
    #         T*const field;
    #         T array[_P];
    #         typedef int My;
    #         My var;
    #     };
    #     ChangedTemplate<int, 1>* changedTemplate();";
    # $SOURCE1 .= "
    #     ChangedTemplate<int, 1>* changedTemplate() { return new ChangedTemplate<int, 1>(); }";
    # 
    # $HEADER2 .= "
    #     template <typename T, int _P>
    #     class $DECL_SPEC ChangedTemplate {
    #     public:
    #         double value;
    #         T* field;
    #         double array[_P];
    #         typedef int My;
    #         My var;
    #     };
    #     ChangedTemplate<int, 1>* changedTemplate();";
    # $SOURCE2 .= "
    #     ChangedTemplate<int, 1>* changedTemplate() { return new ChangedTemplate<int, 1>(); }";
    
    # Removed inline method
    $HEADER1 .= "
        class $DECL_SPEC RemovedInlineMethod {
        public:
            int someMethod();
            inline int removedMethod() { return 0; };
            int field;
        };";
    $SOURCE1 .= "
        int RemovedInlineMethod::someMethod() { return removedMethod(); }";
    
    $HEADER2 .= "
        class $DECL_SPEC RemovedInlineMethod {
        public:
            int someMethod();
            int field;
        };";
    $SOURCE2 .= "
        int RemovedInlineMethod::someMethod() { return 0; }";
    
    # Pure_Virtual_Replacement
    $HEADER1 .= "
        class $DECL_SPEC PureVirtualReplacement {
        public:
            virtual int methodOld(int param) = 0;
            int otherMethod();
        };
        
        class $DECL_SPEC PureVirtualReplacement_Derived: public PureVirtualReplacement {
        public:
            int methodOld(int param);
        };";
    $SOURCE1 .= "
        int PureVirtualReplacement::otherMethod() { return 0; }
        int PureVirtualReplacement_Derived::methodOld(int param) { return 0; }";
    
    $HEADER2 .= "
        class $DECL_SPEC PureVirtualReplacement {
        public:
            virtual int methodNew(int param) = 0;
            int otherMethod();
        };
        
        class $DECL_SPEC PureVirtualReplacement_Derived: public PureVirtualReplacement {
        public:
            int methodNew(int param);
        };";
    $SOURCE2 .= "
        int PureVirtualReplacement::otherMethod() { return 0; }
        int PureVirtualReplacement_Derived::methodNew(int param) { return 0; }";
    
    # Virtual_Replacement
    $HEADER1 .= "
        class $DECL_SPEC VirtualReplacement {
        public:
            virtual int methodOld(int param);
        };";
    $SOURCE1 .= "
        int VirtualReplacement::methodOld(int param) { return 0; }";
    
    $HEADER2 .= "
        class $DECL_SPEC VirtualReplacement {
        public:
            virtual int methodNew(int param);
        };";
    $SOURCE2 .= "
        int VirtualReplacement::methodNew(int param) { return 0; }";
    
    # Removed_Symbol (renamed, source-compatible)
    $HEADER1 .= "
        int $DECL_SPEC renamedFunc(int param);";
    $SOURCE1 .= "
        int renamedFunc(int param) { return 0; }";
    
    $HEADER2 .= "
        int $DECL_SPEC renamedFunc_NewName(int param);
        #define renamedFunc renamedFunc_NewName";
    $SOURCE2 .= "
        int renamedFunc_NewName(int param) { return 0; }";
    
    # Removed_Symbol
    $HEADER1 .= "
        int $DECL_SPEC functionBecameInline(int param);";
    $SOURCE1 .= "
        int functionBecameInline(int param) { return 0; }";
    
    $HEADER2 .= "
        inline int functionBecameInline(int param) { return 0; }";
    
    # Removed_Symbol (safe)
    $HEADER1 .= "
        inline int removedInlineFunction(int param) { return 0; }";
    
    # Became Non-Opaque
    $HEADER1 .= "
        struct OpaqueStruct;
        int paramBecameNonOpaque(OpaqueStruct* p);";
    $SOURCE1 .= "
        int paramBecameNonOpaque(OpaqueStruct* p) { return 0; }";
    
    $HEADER2 .= "
        struct OpaqueStruct
        {
            int i;
            short j;
            OpaqueStruct();
        };
        int paramBecameNonOpaque(OpaqueStruct* p);";
    $SOURCE2 .= "
        int paramBecameNonOpaque(OpaqueStruct* p) { return 0; }";
    
    # Field_Became_Const
    # Typedef
    $HEADER1 .= "
        typedef int*const CONST_INT_PTR;
        class $DECL_SPEC FieldBecameConstTypedef {
        public:
            int* f;
            int*const f2;
            int method(CONST_INT_PTR p);
        };";
    $SOURCE1 .= "
        int FieldBecameConstTypedef::method(CONST_INT_PTR p) { return 0; }";
    
    $HEADER2 .= "
        typedef int*const CONST_INT_PTR;
        class $DECL_SPEC FieldBecameConstTypedef {
        public:
            CONST_INT_PTR f;
            int*const f2;
            int method(CONST_INT_PTR p);
        };";
    $SOURCE2 .= "
        int FieldBecameConstTypedef::method(CONST_INT_PTR p) { return 0; }";
    
    # Field_Removed_Const
    $HEADER1 .= "
        class $DECL_SPEC FieldRemovedConst {
        public:
            int*const*const f;
            int method();
        };";
    $SOURCE1 .= "
        int FieldRemovedConst::method() { return 0; }";
    
    $HEADER2 .= "
        class $DECL_SPEC FieldRemovedConst {
        public:
            int**const f;
            int method();
        };";
    $SOURCE2 .= "
        int FieldRemovedConst::method() { return 0; }";
    
    # Field_Became_Const
    $HEADER1 .= "
        class $DECL_SPEC FieldBecameConst {
        public:
            int* f;
            int method();
        };";
    $SOURCE1 .= "
        int FieldBecameConst::method() { return 0; }";
    
    $HEADER2 .= "
        class $DECL_SPEC FieldBecameConst {
        public:
            int*const f;
            int method();
        };";
    $SOURCE2 .= "
        int FieldBecameConst::method() { return 0; }";
    
    # Field_Became_Private
    $HEADER1 .= "
        class $DECL_SPEC FieldBecamePrivate {
        public:
            int* f;
            int method();
        };";
    $SOURCE1 .= "
        int FieldBecamePrivate::method() { return 0; }";
    
    $HEADER2 .= "
        class $DECL_SPEC FieldBecamePrivate {
        private:
            int* f;
        public:
            int method();
        };";
    $SOURCE2 .= "
        int FieldBecamePrivate::method() { return 0; }";
    
    # Field_Became_Protected
    $HEADER1 .= "
        class $DECL_SPEC FieldBecameProtected {
        public:
            int* f;
            int method();
        };";
    $SOURCE1 .= "
        int FieldBecameProtected::method() { return 0; }";
    
    $HEADER2 .= "
        class $DECL_SPEC FieldBecameProtected {
        protected:
            int* f;
        public:
            int method();
        };";
    $SOURCE2 .= "
        int FieldBecameProtected::method() { return 0; }";
    
    # Global_Data_Became_Private
    $HEADER1 .= "
        class $DECL_SPEC GlobalDataBecamePrivate {
        public:
            static int data;
            
        };";
    $SOURCE1 .= "
        int GlobalDataBecamePrivate::data = 10;";
    
    $HEADER2 .= "
        class $DECL_SPEC GlobalDataBecamePrivate {
        private:
            static int data;
            
        };";
    $SOURCE2 .= "
        int GlobalDataBecamePrivate::data = 10;";
    
    # Method_Became_Private
    $HEADER1 .= "
        class $DECL_SPEC MethodBecamePrivate {
        public:
            int method();
        };";
    $SOURCE1 .= "
        int MethodBecamePrivate::method() { return 0; }";
    
    $HEADER2 .= "
        class $DECL_SPEC MethodBecamePrivate {
        private:
            int method();
        };";
    $SOURCE2 .= "
        int MethodBecamePrivate::method() { return 0; }";

    # Method_Became_Protected
    $HEADER1 .= "
        class $DECL_SPEC MethodBecameProtected {
        public:
            int method();
        };";
    $SOURCE1 .= "
        int MethodBecameProtected::method() { return 0; }";
    
    $HEADER2 .= "
        class $DECL_SPEC MethodBecameProtected {
        protected:
            int method();
        };";
    $SOURCE2 .= "
        int MethodBecameProtected::method() { return 0; }";

    # Method_Became_Public
    $HEADER1 .= "
        class $DECL_SPEC MethodBecamePublic {
        protected:
            int method();
        };";
    $SOURCE1 .= "
        int MethodBecamePublic::method() { return 0; }";
    
    $HEADER2 .= "
        class $DECL_SPEC MethodBecamePublic {
        public:
            int method();
        };";
    $SOURCE2 .= "
        int MethodBecamePublic::method() { return 0; }";
    
    # Removed_Const_Overload
    $HEADER1 .= "
        class $DECL_SPEC RemovedConstOverload {
        public:
            int removed();
            int removed() const;
        };";
    $SOURCE1 .= "
        int RemovedConstOverload::removed() { return 0; }
        int RemovedConstOverload::removed() const { return 0; }";
    
    $HEADER2 .= "
        class $DECL_SPEC RemovedConstOverload {
        public:
            int removed();
        };";
    $SOURCE2 .= "
        int RemovedConstOverload::removed() { return 0; }";
    
    # Inline method
    $HEADER1 .= "
        class $DECL_SPEC InlineMethod {
        public:
            inline int foo() { return 0; }
        };";
    
    $HEADER2 .= "
        class $DECL_SPEC InlineMethod {
        public:
            inline long foo() { return 0; }
        };";
    
    # Global_Data_Became_Non_Const
    $HEADER1 .= "
        $EXTERN $DECL_SPEC const int globalDataBecameNonConst = 10;";
    
    $HEADER2 .= "
        extern $DECL_SPEC int globalDataBecameNonConst;";
    $SOURCE2 .= "
        int globalDataBecameNonConst = 15;";

    # Global_Data_Became_Non_Const
    # Class Member
    $HEADER1 .= "
        class $DECL_SPEC GlobalDataBecameNonConst {
        public:
            static const int data;
        };";
    $SOURCE1 .= "
        const int GlobalDataBecameNonConst::data = 10;";
    
    $HEADER2 .= "
        class $DECL_SPEC GlobalDataBecameNonConst {
        public:
            static int data;
        };";
    $SOURCE2 .= "
        int GlobalDataBecameNonConst::data = 10;";

    # Global_Data_Became_Const
    $HEADER1 .= "
        extern $DECL_SPEC int globalDataBecameConst;";
    $SOURCE1 .= "
        int globalDataBecameConst = 10;";
    
    $HEADER2 .= "
        $EXTERN $DECL_SPEC const int globalDataBecameConst = 15;";

    # Global_Data_Became_Const
    # Class Member
    $HEADER1 .= "
        class $DECL_SPEC GlobalDataBecameConst {
        public:
            static int Data;
        };";
    $SOURCE1 .= "
        int GlobalDataBecameConst::Data = 10;";
    
    $HEADER2 .= "
        class $DECL_SPEC GlobalDataBecameConst {
        public:
            static const int Data = 15;
        };";

    # Global_Data_Value_Changed
    $HEADER1 .= "
        class $DECL_SPEC GlobalDataValue {
        public:
            static const int Integer = 10;
            static const char Char = \'o\';
        };";
    
    $HEADER2 .= "
        class $DECL_SPEC GlobalDataValue {
        public:
            static const int Integer = 15;
            static const char Char = \'N\';
        };";
    
    # Global_Data_Value_Changed
    # Integer
    $HEADER1 .= "
        $EXTERN $DECL_SPEC const int globalDataValue_Integer = 10;";
    
    $HEADER2 .= "
        $EXTERN $DECL_SPEC const int globalDataValue_Integer = 15;";

    # Global_Data_Value_Changed
    # Character
    $HEADER1 .= "
        $EXTERN $DECL_SPEC const char globalDataValue_Char = \'o\';";
    
    $HEADER2 .= "
        $EXTERN $DECL_SPEC const char globalDataValue_Char = \'N\';";
    
    # Parameter_Became_Restrict
    $HEADER1 .= "
        class $DECL_SPEC ParameterBecameRestrict {
        public:
            int method(int* param);
        };";
    $SOURCE1 .= "
        int ParameterBecameRestrict::method(int* param) { return 0; }";
    
    $HEADER2 .= "
        class $DECL_SPEC ParameterBecameRestrict {
        public:
            int method(int* __restrict param);
        };";
    $SOURCE2 .= "
        int ParameterBecameRestrict::method(int* __restrict param) { return 0; }";

    # Parameter_Became_Non_Restrict
    $HEADER1 .= "
        class $DECL_SPEC ParameterBecameNonRestrict {
        public:
            int method(int* __restrict param);
        };";
    $SOURCE1 .= "
        int ParameterBecameNonRestrict::method(int* __restrict param) { return 0; }";
    
    $HEADER2 .= "
        class $DECL_SPEC ParameterBecameNonRestrict {
        public:
            int method(int* param);
        };";
    $SOURCE2 .= "
        int ParameterBecameNonRestrict::method(int* param) { return 0; }";
    
    # Field_Became_Volatile
    $HEADER1 .= "
        class $DECL_SPEC FieldBecameVolatile {
        public:
            int method(int param);
            int f;
        };";
    $SOURCE1 .= "
        int FieldBecameVolatile::method(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC FieldBecameVolatile {
        public:
            int method(int param);
            volatile int f;
        };";
    $SOURCE2 .= "
        int FieldBecameVolatile::method(int param) { return param; }";

    # Field_Became_Non_Volatile
    $HEADER1 .= "
        class $DECL_SPEC FieldBecameNonVolatile {
        public:
            int method(int param);
            volatile int f;
        };";
    $SOURCE1 .= "
        int FieldBecameNonVolatile::method(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC FieldBecameNonVolatile {
        public:
            int method(int param);
            int f;
        };";
    $SOURCE2 .= "
        int FieldBecameNonVolatile::method(int param) { return param; }";

    # Field_Became_Mutable
    $HEADER1 .= "
        class $DECL_SPEC FieldBecameMutable {
        public:
            int method(int param);
            int f;
        };";
    $SOURCE1 .= "
        int FieldBecameMutable::method(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC FieldBecameMutable {
        public:
            int method(int param);
            mutable int f;
        };";
    $SOURCE2 .= "
        int FieldBecameMutable::method(int param) { return param; }";

    # Field_Became_Non_Mutable
    $HEADER1 .= "
        class $DECL_SPEC FieldBecameNonMutable {
        public:
            int method(int param);
            mutable int f;
        };";
    $SOURCE1 .= "
        int FieldBecameNonMutable::method(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC FieldBecameNonMutable {
        public:
            int method(int param);
            int f;
        };";
    $SOURCE2 .= "
        int FieldBecameNonMutable::method(int param) { return param; }";
    
    # Method_Became_Const
    # Method_Became_Volatile
    $HEADER1 .= "
        class $DECL_SPEC MethodBecameConstVolatile {
        public:
            int method(int param);
        };";
    $SOURCE1 .= "
        int MethodBecameConstVolatile::method(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC MethodBecameConstVolatile {
        public:
            int method(int param) volatile const;
        };";
    $SOURCE2 .= "
        int MethodBecameConstVolatile::method(int param) volatile const { return param; }";
    
    # Method_Became_Const
    $HEADER1 .= "
        class $DECL_SPEC MethodBecameConst {
        public:
            int method(int param);
        };";
    $SOURCE1 .= "
        int MethodBecameConst::method(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC MethodBecameConst {
        public:
            int method(int param) const;
        };";
    $SOURCE2 .= "
        int MethodBecameConst::method(int param) const { return param; }";

    # Method_Became_Non_Const
    $HEADER1 .= "
        class $DECL_SPEC MethodBecameNonConst {
        public:
            int method(int param) const;
        };";
    $SOURCE1 .= "
        int MethodBecameNonConst::method(int param) const { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC MethodBecameNonConst {
        public:
            int method(int param);
        };";
    $SOURCE2 .= "
        int MethodBecameNonConst::method(int param) { return param; }";
    
    # Method_Became_Volatile
    $HEADER1 .= "
        class $DECL_SPEC MethodBecameVolatile {
        public:
            int method(int param);
        };";
    $SOURCE1 .= "
        int MethodBecameVolatile::method(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC MethodBecameVolatile {
        public:
            int method(int param) volatile;
        };";
    $SOURCE2 .= "
        int MethodBecameVolatile::method(int param) volatile { return param; }";
    
    # Virtual_Method_Position
    # Multiple bases
    $HEADER1 .= "
        class $DECL_SPEC PrimaryBase
        {
        public:
            virtual ~PrimaryBase();
            virtual void foo();
        };
        class $DECL_SPEC SecondaryBase
        {
        public:
            virtual ~SecondaryBase();
            virtual void bar();
        };
        class UnsafeVirtualOverride: public PrimaryBase, public SecondaryBase
        {
        public:
            UnsafeVirtualOverride();
            ~UnsafeVirtualOverride();
            void foo();
        };";
    $SOURCE1 .= "
        PrimaryBase::~PrimaryBase() { }
        void PrimaryBase::foo() { }
        
        SecondaryBase::~SecondaryBase() { }
        void SecondaryBase::bar() { }
        
        UnsafeVirtualOverride::UnsafeVirtualOverride() { }
        UnsafeVirtualOverride::~UnsafeVirtualOverride() { }
        void UnsafeVirtualOverride::foo() { }";
    
    $HEADER2 .= "
        class $DECL_SPEC PrimaryBase
        {
        public:
            virtual ~PrimaryBase();
            virtual void foo();
        };
        class $DECL_SPEC SecondaryBase
        {
        public:
            virtual ~SecondaryBase();
            virtual void bar();
        };
        class UnsafeVirtualOverride: public PrimaryBase, public SecondaryBase
        {
        public:
            UnsafeVirtualOverride();
            ~UnsafeVirtualOverride();
            void foo();
            void bar();
        };";
    $SOURCE2 .= "
        PrimaryBase::~PrimaryBase() { }
        void PrimaryBase::foo() { }
        
        SecondaryBase::~SecondaryBase() { }
        void SecondaryBase::bar() { }
        
        UnsafeVirtualOverride::UnsafeVirtualOverride() { }
        UnsafeVirtualOverride::~UnsafeVirtualOverride() { }
        void UnsafeVirtualOverride::foo() { }
        void UnsafeVirtualOverride::bar() { }";
    
    # Removed_Interface (inline virtual d-tor)
    $HEADER1 .= "
        template <typename T>
        class $DECL_SPEC BaseTemplate {
        public:
            BaseTemplate() { }
            virtual int method(int param) { return param; };
            virtual ~BaseTemplate() { };
        };
        class $DECL_SPEC RemovedVirtualDestructor: public BaseTemplate<int> {
        public:
            RemovedVirtualDestructor() { };
            virtual int method2(int param);
        };";
    $SOURCE1 .= "
        int RemovedVirtualDestructor::method2(int param) { return param; }";
    
    $HEADER2 .= "
        template <typename T>
        class $DECL_SPEC BaseTemplate {
        public:
            BaseTemplate() { }
            virtual int method(int param) { return param; };
            //virtual ~BaseTemplate() { };
        };
        class $DECL_SPEC RemovedVirtualDestructor: public BaseTemplate<int> {
        public:
            RemovedVirtualDestructor() { };
            virtual int method2(int param);
        };";
    $SOURCE2 .= "
        int RemovedVirtualDestructor::method2(int param) { return param; }";
    
    # Added_Virtual_Method_At_End
    $HEADER1 .= "
        class $DECL_SPEC DefaultConstructor {
        public:
            DefaultConstructor() { }
            virtual int method(int param);
        };";
    $SOURCE1 .= "
        int DefaultConstructor::method(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC DefaultConstructor {
        public:
            DefaultConstructor() { }
            virtual int method(int param);
            virtual int addedMethod(int param);
        };";
    $SOURCE2 .= "
        int DefaultConstructor::method(int param) { return addedMethod(param); }
        int DefaultConstructor::addedMethod(int param) { return param; }";
    
    # Added_Enum_Member
    $HEADER1 .= "
        enum AddedEnumMember {
            OldMember
        };
        $DECL_SPEC int addedEnumMember(enum AddedEnumMember param);";
    $SOURCE1 .= "
        int addedEnumMember(enum AddedEnumMember param) { return 0; }";
    
    $HEADER2 .= "
        enum AddedEnumMember {
            OldMember,
            NewMember
        };
        $DECL_SPEC int addedEnumMember(enum AddedEnumMember param);";
    $SOURCE2 .= "
        int addedEnumMember(enum AddedEnumMember param) { return 0; }";
    
    # Parameter_Type_Format (Safe)
    $HEADER1 .= "
        struct DType
        {
            int i;
            double j;
        };
        $DECL_SPEC int parameterTypeFormat_Safe(struct DType param);";
    $SOURCE1 .= "
        int parameterTypeFormat_Safe(struct DType param) { return 0; }";
    
    $HEADER2 .= "
        class DType
        {
            int i;
            double j;
        };
        $DECL_SPEC int parameterTypeFormat_Safe(class DType param);";
    $SOURCE2 .= "
        int parameterTypeFormat_Safe(class DType param) { return 0; }";
    
    # Type_Became_Opaque (Struct)
    $HEADER1 .= "
        struct StructBecameOpaque
        {
            int i, j;
        };
        $DECL_SPEC int structBecameOpaque(struct StructBecameOpaque* param);";
    $SOURCE1 .= "
        int structBecameOpaque(struct StructBecameOpaque* param) { return 0; }";
    
    $HEADER2 .= "
        struct StructBecameOpaque;
        $DECL_SPEC int structBecameOpaque(struct StructBecameOpaque* param);";
    $SOURCE2 .= "
        int structBecameOpaque(struct StructBecameOpaque* param) { return 0; }";
    
    # Type_Became_Opaque (Union)
    $HEADER1 .= "
        union UnionBecameOpaque
        {
            int i, j;
        };
        $DECL_SPEC int unionBecameOpaque(union UnionBecameOpaque* param);";
    $SOURCE1 .= "
        int unionBecameOpaque(union UnionBecameOpaque* param) { return 0; }";
    
    $HEADER2 .= "
        union UnionBecameOpaque;
        $DECL_SPEC int unionBecameOpaque(union UnionBecameOpaque* param);";
    $SOURCE2 .= "
        int unionBecameOpaque(union UnionBecameOpaque* param) { return 0; }";
    
    # Field_Type_Format
    $HEADER1 .= "
        struct DType1
        {
            int i;
            double j[7];
        };
        struct FieldTypeFormat
        {
            int i;
            struct DType1 j;
        };
        $DECL_SPEC int fieldTypeFormat(struct FieldTypeFormat param);";
    $SOURCE1 .= "
        int fieldTypeFormat(struct FieldTypeFormat param) { return 0; }";
    
    $HEADER2 .= "
        struct DType2
        {
            double i[7];
            int j;
        };
        struct FieldTypeFormat
        {
            int i;
            struct DType2 j;
        };
        $DECL_SPEC int fieldTypeFormat(struct FieldTypeFormat param);";
    $SOURCE2 .= "
        int fieldTypeFormat(struct FieldTypeFormat param) { return 0; }";
    
    # Field_Type_Format (func ptr)
    $HEADER1 .= "
        typedef void (*FuncPtr_Old) (int a);
        struct FieldTypeFormat_FuncPtr
        {
            int i;
            FuncPtr_Old j;
        };
        $DECL_SPEC int fieldTypeFormat_FuncPtr(struct FieldTypeFormat_FuncPtr param);";
    $SOURCE1 .= "
        int fieldTypeFormat_FuncPtr(struct FieldTypeFormat_FuncPtr param) { return 0; }";
    
    $HEADER2 .= "
        typedef void (*FuncPtr_New) (int a, int b);
        struct FieldTypeFormat_FuncPtr
        {
            int i;
            FuncPtr_New j;
        };
        $DECL_SPEC int fieldTypeFormat_FuncPtr(struct FieldTypeFormat_FuncPtr param);";
    $SOURCE2 .= "
        int fieldTypeFormat_FuncPtr(struct FieldTypeFormat_FuncPtr param) { return 0; }";
    
    # Removed_Virtual_Method (inline)
    $HEADER1 .= "
        class $DECL_SPEC RemovedInlineVirtualFunction {
        public:
            RemovedInlineVirtualFunction();
            virtual int removedMethod(int param) { return 0; }
            virtual int method(int param);
        };";
    $SOURCE1 .= "
        int RemovedInlineVirtualFunction::method(int param) { return param; }
        RemovedInlineVirtualFunction::RemovedInlineVirtualFunction() { }";
    
    $HEADER2 .= "
        class $DECL_SPEC RemovedInlineVirtualFunction {
        public:
            RemovedInlineVirtualFunction();
            virtual int method(int param);
        };";
    $SOURCE2 .= "
        int RemovedInlineVirtualFunction::method(int param) { return param; }
        RemovedInlineVirtualFunction::RemovedInlineVirtualFunction() { }";
    
    # MethodPtr
    $HEADER1 .= "
        class TestMethodPtr {
            public:
                typedef void (TestMethodPtr::*Method)(int*);
                Method _method;
                TestMethodPtr();
                void method();
        };";
    $SOURCE1 .= "
        TestMethodPtr::TestMethodPtr() { }
        void TestMethodPtr::method() { }";
    
    $HEADER2 .= "
        class TestMethodPtr {
            public:
                typedef void (TestMethodPtr::*Method)(int*, void*);
                Method _method;
                TestMethodPtr();
                void method();
        };";
    $SOURCE2 .= "
        TestMethodPtr::TestMethodPtr() { }
        void TestMethodPtr::method() { }";
    
    # FieldPtr
    $HEADER1 .= "
        class TestFieldPtr {
            public:
                typedef void* (TestFieldPtr::*Field);
                Field _field;
                TestFieldPtr();
                void method(void*);
        };";
    $SOURCE1 .= "
        TestFieldPtr::TestFieldPtr(){ }
        void TestFieldPtr::method(void*) { }";
    
    $HEADER2 .= "
        class TestFieldPtr {
            public:
                typedef int (TestFieldPtr::*Field);
                Field _field;
                TestFieldPtr();
                void method(void*);
        };";
    $SOURCE2 .= "
        TestFieldPtr::TestFieldPtr(){ }
        void TestFieldPtr::method(void*) { }";

    # Removed_Symbol (Template Specializations)
    $HEADER1 .= "
        template <unsigned int _TP, typename AAA>
        class Template {
            public:
                char const *field;
        };
        template <unsigned int _TP, typename AAA>
        class TestRemovedTemplate {
            public:
                char const *field;
                void method(int);
        };
        template <>
        class TestRemovedTemplate<7, char> {
            public:
                char const *field;
                void method(int);
        };";
    $SOURCE1 .= "
        void TestRemovedTemplate<7, char>::method(int){ }";

    # Removed_Symbol (Template Specializations)
    $HEADER1 .= "
        template <typename TName>
        int removedTemplateSpec(TName);

        template <> int removedTemplateSpec<char>(char);";
    $SOURCE1 .= "
        template <> int removedTemplateSpec<char>(char){return 0;}";
    
    # Removed_Field (Ref)
    $HEADER1 .= "
        struct TestRefChange {
            int a, b, c;
        };
        $DECL_SPEC int paramRefChange(const TestRefChange & p1, int p2);";
    $SOURCE1 .= "
        int paramRefChange(const TestRefChange & p1, int p2) { return p2; }";
    
    $HEADER2 .= "
        struct TestRefChange {
            int a, b;
        };
        $DECL_SPEC int paramRefChange(const TestRefChange & p1, int p2);";
    $SOURCE2 .= "
        int paramRefChange(const TestRefChange & p1, int p2) { return p2; }";
    
    # Removed_Parameter
    $HEADER1 .= "
        $DECL_SPEC int removedParameter(int param, int removed_param);";
    $SOURCE1 .= "
        int removedParameter(int param, int removed_param) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC int removedParameter(int param);";
    $SOURCE2 .= "
        int removedParameter(int param) { return 0; }";
    
    # Added_Parameter
    $HEADER1 .= "
        $DECL_SPEC int addedParameter(int param);";
    $SOURCE1 .= "
        int addedParameter(int param) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC int addedParameter(int param, int added_param);";
    $SOURCE2 .= "
        int addedParameter(int param, int added_param) { return 0; }";
    
    # Added
    $HEADER2 .= "
        typedef int (*FUNCPTR_TYPE)(int a, int b);
        $DECL_SPEC int addedFunc(FUNCPTR_TYPE*const** f);";
    $SOURCE2 .= "
        int addedFunc(FUNCPTR_TYPE*const** f) { return 0; }";
    
    # Added (3)
    $HEADER2 .= "
        struct DStruct
        {
            int i, j, k;
        };
        int addedFunc3(struct DStruct* p);";
    $SOURCE2 .= "
        int addedFunc3(struct DStruct* p) { return 0; }";
    
    # Added_Virtual_Method
    $HEADER1 .= "
        class $DECL_SPEC AddedVirtualMethod {
        public:
            virtual int method(int param);
        };";
    $SOURCE1 .= "
        int AddedVirtualMethod::method(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC AddedVirtualMethod {
        public:
            virtual int addedMethod(int param);
            virtual int method(int param);
        };";
    $SOURCE2 .= "
        int AddedVirtualMethod::addedMethod(int param) {
            return param;
        }
        int AddedVirtualMethod::method(int param) { return param; }";

    # Added_Virtual_Method (added "virtual" attribute)
    $HEADER1 .= "
        class $DECL_SPEC BecameVirtualMethod {
        public:
            int becameVirtual(int param);
            virtual int method(int param);
        };";
    $SOURCE1 .= "
        int BecameVirtualMethod::becameVirtual(int param) { return param; }
        int BecameVirtualMethod::method(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC BecameVirtualMethod {
        public:
            virtual int becameVirtual(int param);
            virtual int method(int param);
        };";
    $SOURCE2 .= "
        int BecameVirtualMethod::becameVirtual(int param) { return param; }
        int BecameVirtualMethod::method(int param) { return param; }";

    # Added_Pure_Virtual_Method
    $HEADER1 .= "
        class $DECL_SPEC AddedPureVirtualMethod {
        public:
            virtual int method(int param);
            int otherMethod(int param);
        };";
    $SOURCE1 .= "
        int AddedPureVirtualMethod::method(int param) { return param; }
        int AddedPureVirtualMethod::otherMethod(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC AddedPureVirtualMethod {
        public:
            virtual int addedMethod(int param)=0;
            virtual int method(int param);
            int otherMethod(int param);
        };";
    $SOURCE2 .= "
        int AddedPureVirtualMethod::method(int param) { return param; }
        int AddedPureVirtualMethod::otherMethod(int param) { return param; }";

    # Added_Virtual_Method_At_End (Safe)
    $HEADER1 .= "
        class $DECL_SPEC AddedVirtualMethodAtEnd {
        public:
            AddedVirtualMethodAtEnd();
            int method1(int param);
            virtual int method2(int param);
        };";
    $SOURCE1 .= "
        AddedVirtualMethodAtEnd::AddedVirtualMethodAtEnd() { }
        int AddedVirtualMethodAtEnd::method1(int param) { return param; }
        int AddedVirtualMethodAtEnd::method2(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC AddedVirtualMethodAtEnd {
        public:
            AddedVirtualMethodAtEnd();
            int method1(int param);
            virtual int method2(int param);
            virtual int addedMethod(int param);
        };";
    $SOURCE2 .= "
        AddedVirtualMethodAtEnd::AddedVirtualMethodAtEnd() { }
        int AddedVirtualMethodAtEnd::method1(int param) { return param; }
        int AddedVirtualMethodAtEnd::method2(int param) { return param; }
        int AddedVirtualMethodAtEnd::addedMethod(int param) { return param; }";

    # Added_Virtual_Method_At_End (With Default Constructor)
    $HEADER1 .= "
        class $DECL_SPEC AddedVirtualMethodAtEnd_DefaultConstructor {
        public:
            int method1(int param);
            virtual int method2(int param);
        };";
    $SOURCE1 .= "
        int AddedVirtualMethodAtEnd_DefaultConstructor::method1(int param) { return param; }
        int AddedVirtualMethodAtEnd_DefaultConstructor::method2(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC AddedVirtualMethodAtEnd_DefaultConstructor {
        public:
            int method1(int param);
            virtual int method2(int param);
            virtual int addedMethod(int param);
        };";
    $SOURCE2 .= "
        int AddedVirtualMethodAtEnd_DefaultConstructor::method1(int param) { return param; }
        int AddedVirtualMethodAtEnd_DefaultConstructor::method2(int param) { return param; }
        int AddedVirtualMethodAtEnd_DefaultConstructor::addedMethod(int param) { return param; }";
    
    # Added_First_Virtual_Method
    $HEADER1 .= "
        class $DECL_SPEC AddedFirstVirtualMethod {
        public:
            int method(int param);
        };";
    $SOURCE1 .= "
        int AddedFirstVirtualMethod::method(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC AddedFirstVirtualMethod {
        public:
            int method(int param);
            virtual int addedMethod(int param);
        };";
    $SOURCE2 .= "
        int AddedFirstVirtualMethod::method(int param) { return param; }
        int AddedFirstVirtualMethod::addedMethod(int param) { return param; }";
    
    # Removed_Virtual_Method
    $HEADER1 .= "
        class $DECL_SPEC RemovedVirtualFunction {
        public:
            int a, b, c;
            virtual int removedMethod(int param);
            virtual int vMethod(int param);
    };";
    $SOURCE1 .= "
        int RemovedVirtualFunction::removedMethod(int param) { return param; }
        int RemovedVirtualFunction::vMethod(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC RemovedVirtualFunction {
        public:
            int a, b, c;
            int removedMethod(int param);
            virtual int vMethod(int param);
    };";
    $SOURCE2 .= "
        int RemovedVirtualFunction::removedMethod(int param) { return param; }
        int RemovedVirtualFunction::vMethod(int param) { return param; }";

    # Removed_Virtual_Method (Pure, From the End)
    $HEADER1 .= "
        class $DECL_SPEC RemovedPureVirtualMethodFromEnd {
        public:
            virtual int method(int param);
            virtual int removedMethod(int param)=0;
        };";
    $SOURCE1 .= "
        int RemovedPureVirtualMethodFromEnd::method(int param) { return param; }
        int RemovedPureVirtualMethodFromEnd::removedMethod(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC RemovedPureVirtualMethodFromEnd
        {
        public:
            virtual int method(int param);
            int removedMethod(int param);
        };";
    $SOURCE2 .= "
        int RemovedPureVirtualMethodFromEnd::method(int param) { return param; }
        int RemovedPureVirtualMethodFromEnd::removedMethod(int param) { return param; }";

    # Removed_Symbol (Pure with Implementation)
    $HEADER1 .= "
        class $DECL_SPEC RemovedPureSymbol {
        public:
            virtual int method(int param);
            virtual int removedMethod(int param)=0;
        };";
    $SOURCE1 .= "
        int RemovedPureSymbol::method(int param) { return param; }
        int RemovedPureSymbol::removedMethod(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC RemovedPureSymbol
        {
        public:
            virtual int method(int param);
        };";
    $SOURCE2 .= "
        int RemovedPureSymbol::method(int param) { return param; }";

    # Removed_Virtual_Method (From the End)
    $HEADER1 .= "
        class $DECL_SPEC RemovedVirtualMethodFromEnd {
        public:
            virtual int method(int param);
            virtual int removedMethod(int param);
        };";
    $SOURCE1 .= "
        int RemovedVirtualMethodFromEnd::method(int param) { return param; }
        int RemovedVirtualMethodFromEnd::removedMethod(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC RemovedVirtualMethodFromEnd
        {
        public:
            virtual int method(int param);
            int removedMethod(int param);
        };";
    $SOURCE2 .= "
        int RemovedVirtualMethodFromEnd::method(int param) { return param; }
        int RemovedVirtualMethodFromEnd::removedMethod(int param) { return param; }";
    
    # Removed_Virtual_Method
    $HEADER1 .= "
        class $DECL_SPEC RemovedVirtualSymbol {
        public:
            virtual int method(int param);
            virtual int removedMethod(int param);
        };";
    $SOURCE1 .= "
        int RemovedVirtualSymbol::method(int param) { return param; }
        int RemovedVirtualSymbol::removedMethod(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC RemovedVirtualSymbol
        {
        public:
            virtual int method(int param);
        };";
    $SOURCE2 .= "
        int RemovedVirtualSymbol::method(int param) { return param; }";
    
    # Removed_Virtual_Method (Private)
    $HEADER1 .= "
        class $DECL_SPEC RemovedPrivateVirtualSymbol {
        public:
            virtual int method(int param);
        private:
            virtual int removedMethod(int param);
        };";
    $SOURCE1 .= "
        int RemovedPrivateVirtualSymbol::method(int param) { return param; }
        int RemovedPrivateVirtualSymbol::removedMethod(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC RemovedPrivateVirtualSymbol
        {
        public:
            virtual int method(int param);
        };";
    $SOURCE2 .= "
        int RemovedPrivateVirtualSymbol::method(int param) { return param; }";
    
    # Added_Virtual_Method (Private)
    $HEADER1 .= "
        class $DECL_SPEC AddedPrivateVirtualSymbol
        {
        public:
            AddedPrivateVirtualSymbol();
            virtual int method(int param);
        };
        
        class $DECL_SPEC AddedPrivateVirtualSymbol_Derived: public AddedPrivateVirtualSymbol
        {
        public:
            virtual int method1(int param);
        };";
    $SOURCE1 .= "
        AddedPrivateVirtualSymbol::AddedPrivateVirtualSymbol() {};
        int AddedPrivateVirtualSymbol::method(int param) { return param; }
        int AddedPrivateVirtualSymbol_Derived::method1(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC AddedPrivateVirtualSymbol {
        public:
            AddedPrivateVirtualSymbol();
            virtual int method(int param);
        private:
            virtual int addedMethod(int param);
        };
        
        class $DECL_SPEC AddedPrivateVirtualSymbol_Derived: public AddedPrivateVirtualSymbol
        {
        public:
            virtual int method1(int param);
        };";
    $SOURCE2 .= "
        AddedPrivateVirtualSymbol::AddedPrivateVirtualSymbol() {};
        int AddedPrivateVirtualSymbol::method(int param) { return param; }
        int AddedPrivateVirtualSymbol::addedMethod(int param) { return param; }
        int AddedPrivateVirtualSymbol_Derived::method1(int param) { return param; }";
    
    # Removed and added virtual method
    $HEADER1 .= "
        class $DECL_SPEC RemovedAddedVirtualSymbol {
        public:
            virtual int removedMethod(int param);
        };";
    $SOURCE1 .= "
        int RemovedAddedVirtualSymbol::removedMethod(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC RemovedAddedVirtualSymbol
        {
        public:
            virtual int addedMethod(int param);
        };";
    $SOURCE2 .= "
        int RemovedAddedVirtualSymbol::addedMethod(int param) { return param; }";
    
    # Removed_Last_Virtual_Method
    $HEADER1 .= "
        class $DECL_SPEC RemovedLastVirtualMethod
        {
        public:
            int method(int param);
            virtual int removedMethod(int param);
        };";
    $SOURCE1 .= "
        int RemovedLastVirtualMethod::method(int param) { return param; }";
    $SOURCE1 .= "
        int RemovedLastVirtualMethod::removedMethod(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC RemovedLastVirtualMethod
        {
        public:
            int method(int param);
            int removedMethod(int param);
        };";
    $SOURCE2 .= "
        int RemovedLastVirtualMethod::method(int param) { return param; }";
    $SOURCE2 .= "
        int RemovedLastVirtualMethod::removedMethod(int param) { return param; }";
    
    # Removed_Last_Virtual_Method
    $HEADER1 .= "
        class $DECL_SPEC RemovedLastVirtualSymbol
        {
        public:
            int method(int param);
            virtual int removedMethod(int param);
        };";
    $SOURCE1 .= "
        int RemovedLastVirtualSymbol::method(int param) { return param; }";
    $SOURCE1 .= "
        int RemovedLastVirtualSymbol::removedMethod(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC RemovedLastVirtualSymbol
        {
        public:
            int method(int param);
        };";
    $SOURCE2 .= "
        int RemovedLastVirtualSymbol::method(int param) { return param; }";
    
    # Virtual_Table_Size
    $HEADER1 .= "
        class $DECL_SPEC VirtualTableSize
        {
        public:
            virtual int method1(int param);
            virtual int method2(int param);
        };
        class $DECL_SPEC VirtualTableSize_SubClass: public VirtualTableSize
        {
        public:
            virtual int method3(int param);
            virtual int method4(int param);
        };";
    $SOURCE1 .= "
        int VirtualTableSize::method1(int param) { return param; }
        int VirtualTableSize::method2(int param) { return param; }
        int VirtualTableSize_SubClass::method3(int param) { return param; }
        int VirtualTableSize_SubClass::method4(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC VirtualTableSize
        {
        public:
            virtual int method1(int param);
            virtual int method2(int param);
            virtual int addedMethod(int param);
        };
        class $DECL_SPEC VirtualTableSize_SubClass: public VirtualTableSize
        {
        public:
            virtual int method3(int param);
            virtual int method4(int param);
        };";
    $SOURCE2 .= "
        int VirtualTableSize::method1(int param) { return param; }
        int VirtualTableSize::method2(int param) { return param; }
        int VirtualTableSize::addedMethod(int param) { return param; }
        int VirtualTableSize_SubClass::method3(int param) { return param; }
        int VirtualTableSize_SubClass::method4(int param) { return param; }";
    
    # Virtual_Method_Position
    $HEADER1 .= "
        class $DECL_SPEC VirtualMethodPosition
        {
        public:
            virtual int method1(int param);
            virtual int method2(int param);
        };";
    $SOURCE1 .= "
        int VirtualMethodPosition::method1(int param) { return param; }";
    $SOURCE1 .= "
        int VirtualMethodPosition::method2(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC VirtualMethodPosition
        {
        public:
            virtual int method2(int param);
            virtual int method1(int param);
        };";
    $SOURCE2 .= "
        int VirtualMethodPosition::method1(int param) { return param; }";
    $SOURCE2 .= "
        int VirtualMethodPosition::method2(int param) { return param; }";

    # Pure_Virtual_Method_Position
    $HEADER1 .= "
        class $DECL_SPEC PureVirtualFunctionPosition {
        public:
            virtual int method1(int param)=0;
            virtual int method2(int param)=0;
            int method3(int param);
        };";
    $SOURCE1 .= "
        int PureVirtualFunctionPosition::method3(int param) { return method1(7)+method2(7); }";
    
    $HEADER2 .= "
        class $DECL_SPEC PureVirtualFunctionPosition {
        public:
            virtual int method2(int param)=0;
            virtual int method1(int param)=0;
            int method3(int param);
        };";
    $SOURCE2 .= "
        int PureVirtualFunctionPosition::method3(int param) { return method1(7)+method2(7); }";

    # Virtual_Method_Position
    $HEADER1 .= "
        class $DECL_SPEC VirtualFunctionPosition {
        public:
            virtual int method1(int param);
            virtual int method2(int param);
        };";
    $SOURCE1 .= "
        int VirtualFunctionPosition::method1(int param) { return 1; }
        int VirtualFunctionPosition::method2(int param) { return 2; }";
    
    $HEADER2 .= "
        class $DECL_SPEC VirtualFunctionPosition {
        public:
            virtual int method2(int param);
            virtual int method1(int param);
        };";
    $SOURCE2 .= "
        int VirtualFunctionPosition::method1(int param) { return 1; }
        int VirtualFunctionPosition::method2(int param) { return 2; }";
    
    # Virtual_Method_Position (safe)
    $HEADER1 .= "
        class $DECL_SPEC VirtualFunctionPositionSafe_Base {
        public:
            virtual int method1(int param);
            virtual int method2(int param);
        };
        class $DECL_SPEC VirtualFunctionPositionSafe: public VirtualFunctionPositionSafe_Base {
        public:
            virtual int method1(int param);
            virtual int method2(int param);
        };";
    $SOURCE1 .= "
        int VirtualFunctionPositionSafe_Base::method1(int param) { return param; }
        int VirtualFunctionPositionSafe_Base::method2(int param) { return param; }
        int VirtualFunctionPositionSafe::method1(int param) { return param; }
        int VirtualFunctionPositionSafe::method2(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC VirtualFunctionPositionSafe_Base {
        public:
            virtual int method1(int param);
            virtual int method2(int param);
        };
        class $DECL_SPEC VirtualFunctionPositionSafe: public VirtualFunctionPositionSafe_Base {
        public:
            virtual int method2(int param);
            virtual int method1(int param);
        };";
    $SOURCE2 .= "
        int VirtualFunctionPositionSafe_Base::method1(int param) { return param; }
        int VirtualFunctionPositionSafe_Base::method2(int param) { return param; }
        int VirtualFunctionPositionSafe::method1(int param) { return param; }
        int VirtualFunctionPositionSafe::method2(int param) { return param; }";
    
    # Overridden_Virtual_Method
    $HEADER1 .= "
        class $DECL_SPEC OverriddenVirtualMethod_Base {
        public:
            virtual int method1(int param);
            virtual int method2(int param);
        };
        class $DECL_SPEC OverriddenVirtualMethod: public OverriddenVirtualMethod_Base {
        public:
            OverriddenVirtualMethod();
            virtual int method3(int param);
        };";
    $SOURCE1 .= "
        int OverriddenVirtualMethod_Base::method1(int param) { return param; }
        int OverriddenVirtualMethod_Base::method2(int param) { return param; }
        OverriddenVirtualMethod::OverriddenVirtualMethod() {}
        int OverriddenVirtualMethod::method3(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC OverriddenVirtualMethod_Base {
        public:
            virtual int method1(int param);
            virtual int method2(int param);
        };
        class $DECL_SPEC OverriddenVirtualMethod:public OverriddenVirtualMethod_Base {
            OverriddenVirtualMethod();
            virtual int method2(int param);
            virtual int method3(int param);
        };";
    $SOURCE2 .= "
        int OverriddenVirtualMethod_Base::method1(int param) { return param; }
        int OverriddenVirtualMethod_Base::method2(int param) { return param; }
        OverriddenVirtualMethod::OverriddenVirtualMethod() {}
        int OverriddenVirtualMethod::method2(int param) { return param; }
        int OverriddenVirtualMethod::method3(int param) { return param; }";

    # Overridden_Virtual_Method_B (+ removed)
    $HEADER1 .= "
        
    class $DECL_SPEC OverriddenVirtualMethodB: public OverriddenVirtualMethod_Base {
        public:
            OverriddenVirtualMethodB();
            virtual int method2(int param);
            virtual int method3(int param);
    };";
    $SOURCE1 .= "
        OverriddenVirtualMethodB::OverriddenVirtualMethodB() {}
        int OverriddenVirtualMethodB::method2(int param) { return param; }
        int OverriddenVirtualMethodB::method3(int param) { return param; }";
    
    $HEADER2 .= "
        
    class $DECL_SPEC OverriddenVirtualMethodB:public OverriddenVirtualMethod_Base {
        public:
            OverriddenVirtualMethodB();
            virtual int method3(int param);
    };";
    $SOURCE2 .= "
        OverriddenVirtualMethodB::OverriddenVirtualMethodB() {}
        int OverriddenVirtualMethodB::method3(int param) { return param; }";
    
    # Size
    $HEADER1 .= "
        struct $DECL_SPEC TypeSize
        {
        public:
            TypeSize method(TypeSize param);
            int i[5];
            long j;
            double k;
            TypeSize* p;
        };";
    $SOURCE1 .= "
        TypeSize TypeSize::method(TypeSize param) { return param; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC TypeSize
        {
        public:
            TypeSize method(TypeSize param);
            int i[15];
            long j;
            double k;
            TypeSize* p;
            int added_member;
        };";
    $SOURCE2 .= "
        TypeSize TypeSize::method(TypeSize param) { return param; }";

    # Size_Of_Allocable_Class_Increased
    $HEADER1 .= "
        class $DECL_SPEC AllocableClassSize
        {
        public:
            AllocableClassSize();
            int method();
            double p[5];
        };";
    $SOURCE1 .= "
        AllocableClassSize::AllocableClassSize() { }";
    $SOURCE1 .= "
        int AllocableClassSize::method() { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC AllocableClassSize
        {
        public:
            AllocableClassSize();
            int method();
            double p[15];
        };";
    $SOURCE2 .= "
        AllocableClassSize::AllocableClassSize() { }";
    $SOURCE2 .= "
        int AllocableClassSize::method() { return 0; }";
    
    # Size_Of_Allocable_Class_Decreased (decreased size, has derived class, has public members)
    $HEADER1 .= "
        class $DECL_SPEC DecreasedClassSize
        {
        public:
            DecreasedClassSize();
            int method();
            double p[15];
        };";
    $SOURCE1 .= "
        DecreasedClassSize::DecreasedClassSize() { }";
    $SOURCE1 .= "
        int DecreasedClassSize::method() { return 0; }";
    $HEADER1 .= "
        class $DECL_SPEC DecreasedClassSize_SubClass: public DecreasedClassSize
        {
        public:
            DecreasedClassSize_SubClass();
            int method();
            int f;
        };";
    $SOURCE1 .= "
        DecreasedClassSize_SubClass::DecreasedClassSize_SubClass() { f=7; }";
    $SOURCE1 .= "
        int DecreasedClassSize_SubClass::method() { return f; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC DecreasedClassSize
        {
        public:
            DecreasedClassSize();
            int method();
            double p[5];
        };";
    $SOURCE2 .= "
        DecreasedClassSize::DecreasedClassSize() { }";
    $SOURCE2 .= "
        int DecreasedClassSize::method() { return 0; }";
    $HEADER2 .= "
        class $DECL_SPEC DecreasedClassSize_SubClass: public DecreasedClassSize
        {
        public:
            DecreasedClassSize_SubClass();
            int method();
            int f;
        };";
    $SOURCE2 .= "
        DecreasedClassSize_SubClass::DecreasedClassSize_SubClass() { f=7; }";
    $SOURCE2 .= "
        int DecreasedClassSize_SubClass::method() { return f; }";

    # Size_Of_Copying_Class
    $HEADER1 .= "
        class $DECL_SPEC CopyingClassSize
        {
        public:
            int method();
            int p[5];
        };";
    $SOURCE1 .= "
        int CopyingClassSize::method() { return p[4]; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC CopyingClassSize
        {
        public:
            int method();
            int p[15];
        };";
    $SOURCE2 .= "
        int CopyingClassSize::method() { return p[10]; }";

    # Base_Class_Became_Virtually_Inherited
    $HEADER1 .= "
        class $DECL_SPEC BecameVirtualBase
        {
        public:
            BecameVirtualBase();
            int method();
            double p[5];
        };";
    $SOURCE1 .= "
        BecameVirtualBase::BecameVirtualBase() { }";
    $SOURCE1 .= "
        int BecameVirtualBase::method() { return 0; }";
    $HEADER1 .= "
        class $DECL_SPEC AddedVirtualBase1:public BecameVirtualBase
        {
        public:
            AddedVirtualBase1();
            int method();
        };";
    $SOURCE1 .= "
        AddedVirtualBase1::AddedVirtualBase1() { }";
    $SOURCE1 .= "
        int AddedVirtualBase1::method() { return 0; }";
    $HEADER1 .= "
        class $DECL_SPEC AddedVirtualBase2: public BecameVirtualBase
        {
        public:
            AddedVirtualBase2();
            int method();
        };";
    $SOURCE1 .= "
        AddedVirtualBase2::AddedVirtualBase2() { }";
    $SOURCE1 .= "
        int AddedVirtualBase2::method() { return 0; }";
    $HEADER1 .= "
        class $DECL_SPEC BaseClassBecameVirtuallyInherited:public AddedVirtualBase1, public AddedVirtualBase2
        {
        public:
            BaseClassBecameVirtuallyInherited();
        };";
    $SOURCE1 .= "
        BaseClassBecameVirtuallyInherited::BaseClassBecameVirtuallyInherited() { }";
    
    $HEADER2 .= "
        class $DECL_SPEC BecameVirtualBase
        {
        public:
            BecameVirtualBase();
            int method();
            double p[5];
        };";
    $SOURCE2 .= "
        BecameVirtualBase::BecameVirtualBase() { }";
    $SOURCE2 .= "
        int BecameVirtualBase::method() { return 0; }";
    $HEADER2 .= "
        class $DECL_SPEC AddedVirtualBase1:public virtual BecameVirtualBase
        {
        public:
            AddedVirtualBase1();
            int method();
        };";
    $SOURCE2 .= "
        AddedVirtualBase1::AddedVirtualBase1() { }";
    $SOURCE2 .= "
        int AddedVirtualBase1::method() { return 0; }";
    $HEADER2 .= "
        class $DECL_SPEC AddedVirtualBase2: public virtual BecameVirtualBase
        {
        public:
            AddedVirtualBase2();
            int method();
        };";
    $SOURCE2 .= "
        AddedVirtualBase2::AddedVirtualBase2() { }";
    $SOURCE2 .= "
        int AddedVirtualBase2::method() { return 0; }";
    $HEADER2 .= "
        class $DECL_SPEC BaseClassBecameVirtuallyInherited:public AddedVirtualBase1, public AddedVirtualBase2
        {
        public:
            BaseClassBecameVirtuallyInherited();
        };";
    $SOURCE2 .= "
        BaseClassBecameVirtuallyInherited::BaseClassBecameVirtuallyInherited() { }";

    # Added_Base_Class, Removed_Base_Class
    $HEADER1 .= "
        class $DECL_SPEC BaseClass
        {
        public:
            BaseClass();
            int method();
            double p[5];
        };
        class $DECL_SPEC RemovedBaseClass
        {
        public:
            RemovedBaseClass();
            int method();
        };
        class $DECL_SPEC ChangedBaseClass:public BaseClass, public RemovedBaseClass
        {
        public:
            ChangedBaseClass();
        };";
    $SOURCE1 .= "
        BaseClass::BaseClass() { }
        int BaseClass::method() { return 0; }
        RemovedBaseClass::RemovedBaseClass() { }
        int RemovedBaseClass::method() { return 0; }
        ChangedBaseClass::ChangedBaseClass() { }";
    
    $HEADER2 .= "
        class $DECL_SPEC BaseClass
        {
        public:
            BaseClass();
            int method();
            double p[5];
        };
        class $DECL_SPEC AddedBaseClass
        {
        public:
            AddedBaseClass();
            int method();
        };
        class $DECL_SPEC ChangedBaseClass:public BaseClass, public AddedBaseClass
        {
        public:
            ChangedBaseClass();
        };";
    $SOURCE2 .= "
        BaseClass::BaseClass() { }
        int BaseClass::method() { return 0; }
        AddedBaseClass::AddedBaseClass() { }
        int AddedBaseClass::method() { return 0; }
        ChangedBaseClass::ChangedBaseClass() { }";

    # Added_Base_Class_And_Shift, Removed_Base_Class_And_Shift
    $HEADER1 .= "
        struct $DECL_SPEC BaseClass2
        {
            BaseClass2();
            int method();
            double p[15];
        };
        class $DECL_SPEC ChangedBaseClassAndSize:public BaseClass
        {
        public:
            ChangedBaseClassAndSize();
        };";
    $SOURCE1 .= "
        BaseClass2::BaseClass2() { }
        int BaseClass2::method() { return 0; }
        ChangedBaseClassAndSize::ChangedBaseClassAndSize() { }";
    
    $HEADER2 .= "
        struct $DECL_SPEC BaseClass2
        {
            BaseClass2();
            int method();
            double p[15];
        };
        class $DECL_SPEC ChangedBaseClassAndSize:public BaseClass2
        {
        public:
            ChangedBaseClassAndSize();
        };";
    $SOURCE2 .= "
        BaseClass2::BaseClass2() { }
        int BaseClass2::method() { return 0; }
        ChangedBaseClassAndSize::ChangedBaseClassAndSize() { }";
    
    # Added_Field_And_Size
    $HEADER1 .= "
        struct $DECL_SPEC AddedFieldAndSize
        {
            int method(AddedFieldAndSize param);
            double i, j, k;
            AddedFieldAndSize* p;
        };";
    $SOURCE1 .= "
        int AddedFieldAndSize::method(AddedFieldAndSize param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC AddedFieldAndSize
        {
            int method(AddedFieldAndSize param);
            double i, j, k;
            AddedFieldAndSize* p;
            int added_member1;
            long long added_member2;
        };";
    $SOURCE2 .= "
        int AddedFieldAndSize::method(AddedFieldAndSize param) { return 0; }";
    
    # Added_Field
    $HEADER1 .= "
        class $DECL_SPEC ObjectAddedMember
        {
        public:
            int method(int param);
            double i, j, k;
            AddedFieldAndSize* p;
        };";
    $SOURCE1 .= "
        int ObjectAddedMember::method(int param) { return param; }";
    
    $HEADER2 .= "
        class $DECL_SPEC ObjectAddedMember
        {
        public:
            int method(int param);
            double i, j, k;
            AddedFieldAndSize* p;
            int added_member1;
            long long added_member2;
        };";
    $SOURCE2 .= "
        int ObjectAddedMember::method(int param) { return param; }";
    
    # Added_Field (safe)
    $HEADER1 .= "
        struct $DECL_SPEC AddedBitfield
        {
            int method(AddedBitfield param);
            double i, j, k;
            int b1 : 32;
            int b2 : 31;
            AddedBitfield* p;
        };";
    $SOURCE1 .= "
        int AddedBitfield::method(AddedBitfield param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC AddedBitfield
        {
            int method(AddedBitfield param);
            double i, j, k;
            int b1 : 32;
            int b2 : 31;
            int added_bitfield : 1;
            int added_bitfield2 : 1;
            AddedBitfield* p;
        };";
    $SOURCE2 .= "
        int AddedBitfield::method(AddedBitfield param) { return 0; }";
    
    # Bit_Field_Size
    $HEADER1 .= "
        struct $DECL_SPEC BitfieldSize
        {
            int method(BitfieldSize param);
            short changed_bitfield : 1;
        };";
    $SOURCE1 .= "
        int BitfieldSize::method(BitfieldSize param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC BitfieldSize
        {
            int method(BitfieldSize param);
            short changed_bitfield : 7;
        };";
    $SOURCE2 .= "
        int BitfieldSize::method(BitfieldSize param) { return 0; }";
    
    # Removed_Field
    $HEADER1 .= "
        struct $DECL_SPEC RemovedBitfield
        {
            int method(RemovedBitfield param);
            double i, j, k;
            int b1 : 32;
            int b2 : 31;
            int removed_bitfield : 1;
            RemovedBitfield* p;
        };";
    $SOURCE1 .= "
        int RemovedBitfield::method(RemovedBitfield param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC RemovedBitfield
        {
            int method(RemovedBitfield param);
            double i, j, k;
            int b1 : 32;
            int b2 : 31;
            RemovedBitfield* p;
        };";
    $SOURCE2 .= "
        int RemovedBitfield::method(RemovedBitfield param) { return 0; }";
        
    # Removed_Middle_Field
    $HEADER1 .= "
        struct $DECL_SPEC RemovedMiddleBitfield
        {
            int method(RemovedMiddleBitfield param);
            double i, j, k;
            int b1 : 32;
            int removed_middle_bitfield : 1;
            int b2 : 31;
            RemovedMiddleBitfield* p;
        };";
    $SOURCE1 .= "
        int RemovedMiddleBitfield::method(RemovedMiddleBitfield param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC RemovedMiddleBitfield
        {
            int method(RemovedMiddleBitfield param);
            double i, j, k;
            int b1 : 32;
            int b2 : 31;
            RemovedMiddleBitfield* p;
        };";
    $SOURCE2 .= "
        int RemovedMiddleBitfield::method(RemovedMiddleBitfield param) { return 0; }";
    
    # Added_Middle_Field_And_Size
    $HEADER1 .= "
        struct $DECL_SPEC AddedMiddleFieldAndSize
        {
            int method(AddedMiddleFieldAndSize param);
            int i;
            long j;
            double k;
            AddedMiddleFieldAndSize* p;
        };";
    $SOURCE1 .= "
        int AddedMiddleFieldAndSize::method(AddedMiddleFieldAndSize param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC AddedMiddleFieldAndSize
        {
            int method(AddedMiddleFieldAndSize param);
            int i;
            int added_middle_member;
            long j;
            double k;
            AddedMiddleFieldAndSize* p;
        };";
    $SOURCE2 .= "
        int AddedMiddleFieldAndSize::method(AddedMiddleFieldAndSize param) { return 0; }";
        
    # Added_Field (padding)
    $HEADER1 .= "
        struct $DECL_SPEC AddedMiddlePaddedField
        {
            int method(int param);
            short i;
            long j;
            double k;
        };";
    $SOURCE1 .= "
        int AddedMiddlePaddedField::method(int param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC AddedMiddlePaddedField
        {
            int method(int param);
            short i;
            short added_padded_field;
            long j;
            double k;
        };";
    $SOURCE2 .= "
        int AddedMiddlePaddedField::method(int param) { return 0; }";
        
    # Added_Field (tail padding)
    $HEADER1 .= "
        struct $DECL_SPEC AddedTailField
        {
            int method(int param);
            int i1, i2, i3, i4, i5, i6, i7;
            short s;
        };";
    $SOURCE1 .= "
        int AddedTailField::method(int param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC AddedTailField
        {
            int method(int param);
            int i1, i2, i3, i4, i5, i6, i7;
            short s;
            short added_tail_field;
        };";
    $SOURCE2 .= "
        int AddedTailField::method(int param) { return 0; }";
        
    # Test Alignment
    $HEADER1 .= "
        struct $DECL_SPEC TestAlignment
        {
            int method(int param);
            short s:9;
            short   j:9;
            char  c;
            short t:9;
            short u:9;
            char d;
        };";
    $SOURCE1 .= "
        int TestAlignment::method(int param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC TestAlignment
        {
            int method(int param);
            short s:9;
            short   j:9;
            char  c;
            short t:9;
            short u:9;
            char d;
        };";
    $SOURCE2 .= "
        int TestAlignment::method(int param) { return 0; }";
    
    # Renamed_Field
    $HEADER1 .= "
        struct $DECL_SPEC RenamedField
        {
            int method(RenamedField param);
            long i;
            long j;
            double k;
            RenamedField* p;
        };";
    $SOURCE1 .= "
        int RenamedField::method(RenamedField param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC RenamedField
        {
            int method(RenamedField param);
            long renamed_member;
            long j;
            double k;
            RenamedField* p;
        };";
    $SOURCE2 .= "
        int RenamedField::method(RenamedField param) { return 0; }";
    
    # Removed_Field_And_Size
    $HEADER1 .= "
        struct $DECL_SPEC RemovedFieldAndSize
        {
            int method(RemovedFieldAndSize param);
            double i, j, k;
            RemovedFieldAndSize* p;
            int removed_member1;
            long removed_member2;
        };";
    $SOURCE1 .= "
        int RemovedFieldAndSize::method(RemovedFieldAndSize param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC RemovedFieldAndSize
        {
            int method(RemovedFieldAndSize param);
            double i, j, k;
            RemovedFieldAndSize* p;
        };";
    $SOURCE2 .= "
        int RemovedFieldAndSize::method(RemovedFieldAndSize param) { return 0; }";
        
    # Field Position
    $HEADER1 .= "
        struct $DECL_SPEC MovedField
        {
            int method(int param);
            double i;
            int j;
        };";
    $SOURCE1 .= "
        int MovedField::method(int param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC MovedField
        {
            int method(int param);
            int j;
            double i;
        };";
    $SOURCE2 .= "
        int MovedField::method(int param) { return 0; }";
    
    # Removed_Middle_Field_And_Size
    $HEADER1 .= "
        struct $DECL_SPEC RemovedMiddleFieldAndSize
        {
            int method(RemovedMiddleFieldAndSize param);
            int i;
            int removed_middle_member;
            long j;
            double k;
            RemovedMiddleFieldAndSize* p;
        };";
    $SOURCE1 .= "
        int RemovedMiddleFieldAndSize::method(RemovedMiddleFieldAndSize param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC RemovedMiddleFieldAndSize
        {
            int method(RemovedMiddleFieldAndSize param);
            int i;
            long j;
            double k;
            RemovedMiddleFieldAndSize* p;
        };";
    $SOURCE2 .= "
        int RemovedMiddleFieldAndSize::method(RemovedMiddleFieldAndSize param) { return 0; }";
    
    # Enum_Member_Value
    $HEADER1 .= "
        enum EnumMemberValue
        {
            MEMBER_1=1,
            MEMBER_2=2
        };";
    $HEADER1 .= "
        $DECL_SPEC int enumMemberValueChange(enum EnumMemberValue param);";
    $SOURCE1 .= "
        int enumMemberValueChange(enum EnumMemberValue param) { return 0; }";
    
    $HEADER2 .= "
        enum EnumMemberValue
        {
            MEMBER_1=2,
            MEMBER_2=1
        };";
    $HEADER2 .= "
        $DECL_SPEC int enumMemberValueChange(enum EnumMemberValue param);";
    $SOURCE2 .= "
        int enumMemberValueChange(enum EnumMemberValue param) { return 0; }";
    
    # Enum_Member_Name
    $HEADER1 .= "
        enum EnumMemberRename
        {
            BRANCH_1=1,
            BRANCH_2=2
        };";
    $HEADER1 .= "
        $DECL_SPEC int enumMemberRename(enum EnumMemberRename param);";
    $SOURCE1 .= "
        int enumMemberRename(enum EnumMemberRename param) { return 0; }";
    
    $HEADER2 .= "
        enum EnumMemberRename
        {
            BRANCH_FIRST=1,
            BRANCH_SECOND=2
        };";
    $HEADER2 .= "
        $DECL_SPEC int enumMemberRename(enum EnumMemberRename param);";
    $SOURCE2 .= "
        int enumMemberRename(enum EnumMemberRename param) { return 0; }";
    
    # Field_Type_And_Size
    $HEADER1 .= "
        struct $DECL_SPEC FieldTypeAndSize
        {
            int method(FieldTypeAndSize param);
            int i;
            long j;
            double k;
            FieldTypeAndSize* p;
        };";
    $SOURCE1 .= "
        int FieldTypeAndSize::method(FieldTypeAndSize param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC FieldTypeAndSize
        {
            int method(FieldTypeAndSize param);
            long long i;
            long j;
            double k;
            FieldTypeAndSize* p;
        };";
    $SOURCE2 .= "
        int FieldTypeAndSize::method(FieldTypeAndSize param) { return 0; }";
    
    # Member_Type
    $HEADER1 .= "
        struct $DECL_SPEC MemberType
        {
            int method(MemberType param);
            int i;
            long j;
            double k;
            MemberType* p;
        };";
    $SOURCE1 .= "
        int MemberType::method(MemberType param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC MemberType
        {
            int method(MemberType param);
            float i;
            long j;
            double k;
            MemberType* p;
        };";
    $SOURCE2 .= "
        int MemberType::method(MemberType param) { return 0; }";
    
    # Field_BaseType
    $HEADER1 .= "
        struct $DECL_SPEC FieldBaseType
        {
            int method(FieldBaseType param);
            int *i;
            long j;
            double k;
            FieldBaseType* p;
        };";
    $SOURCE1 .= "
        int FieldBaseType::method(FieldBaseType param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC FieldBaseType
        {
            int method(FieldBaseType param);
            long long *i;
            long j;
            double k;
            FieldBaseType* p;
        };";
    $SOURCE2 .= "
        int FieldBaseType::method(FieldBaseType param) { return 0; }";
    
    # Field_PointerLevel_Increased (and size)
    $HEADER1 .= "
        struct $DECL_SPEC FieldPointerLevelAndSize
        {
            int method(FieldPointerLevelAndSize param);
            long long i;
            long j;
            double k;
            FieldPointerLevelAndSize* p;
        };";
    $SOURCE1 .= "
        int FieldPointerLevelAndSize::method(FieldPointerLevelAndSize param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC FieldPointerLevelAndSize
        {
            int method(FieldPointerLevelAndSize param);
            long long *i;
            long j;
            double k;
            FieldPointerLevelAndSize* p;
        };";
    $SOURCE2 .= "
        int FieldPointerLevelAndSize::method(FieldPointerLevelAndSize param) { return 0; }";
    
    # Field_PointerLevel
    $HEADER1 .= "
        struct $DECL_SPEC FieldPointerLevel
        {
            int method(FieldPointerLevel param);
            int **i;
            long j;
            double k;
            FieldPointerLevel* p;
        };";
    $SOURCE1 .= "
        int FieldPointerLevel::method(FieldPointerLevel param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC FieldPointerLevel
        {
            int method(FieldPointerLevel param);
            int *i;
            long j;
            double k;
            FieldPointerLevel* p;
        };";
    $SOURCE2 .= "
        int FieldPointerLevel::method(FieldPointerLevel param) { return 0; }";
    
    # Added_Interface (method)
    $HEADER1 .= "
        struct $DECL_SPEC AddedInterface
        {
            int method(AddedInterface param);
            int i;
            long j;
            double k;
            AddedInterface* p;
        };";
    $SOURCE1 .= "
        int AddedInterface::method(AddedInterface param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC AddedInterface
        {
            int method(AddedInterface param);
            int added_func(AddedInterface param);
            int i;
            long j;
            double k;
            AddedInterface* p;
        };";
    $SOURCE2 .= "
        int AddedInterface::method(AddedInterface param) { return 0; }";
    $SOURCE2 .= "
        int AddedInterface::added_func(AddedInterface param) { return 0; }";
    
    # Added_Interface (function)
    $HEADER2 .= "
        $DECL_SPEC int addedFunc2(void *** param);";
    $SOURCE2 .= "
        int addedFunc2(void *** param) { return 0; }";
    
    # Added_Interface (global variable)
    $HEADER1 .= "
        struct $DECL_SPEC AddedVariable
        {
            int method(AddedVariable param);
            int i1, i2;
            long j;
            double k;
            AddedVariable* p;
        };";
    $SOURCE1 .= "
        int AddedVariable::method(AddedVariable param) {
            return i1;
        }";
    
    $HEADER2 .= "
        struct $DECL_SPEC AddedVariable
        {
            int method(AddedVariable param);
            static int i1;
            static int i2;
            long j;
            double k;
            AddedVariable* p;
        };";
    $SOURCE2 .= "
        int AddedVariable::method(AddedVariable param) { return AddedVariable::i1; }";
    $SOURCE2 .= "
        int AddedVariable::i1=0;";
    $SOURCE2 .= "
        int AddedVariable::i2=0;";
    
    # Removed_Interface (method)
    $HEADER1 .= "
        struct $DECL_SPEC RemovedInterface
        {
            int method(RemovedInterface param);
            int removed_func(RemovedInterface param);
            int i;
            long j;
            double k;
            RemovedInterface* p;
        };";
    $SOURCE1 .= "
        int RemovedInterface::method(RemovedInterface param) { return 0; }";
    $SOURCE1 .= "
        int RemovedInterface::removed_func(RemovedInterface param) { return 0; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC RemovedInterface
        {
            int method(RemovedInterface param);
            int i;
            long j;
            double k;
            RemovedInterface* p;
        };";
    $SOURCE2 .= "
        int RemovedInterface::method(RemovedInterface param) { return 0; }";
    
    # Removed_Interface (function)
    $HEADER1 .= "
        $DECL_SPEC int removedFunc2(void *** param);";
    $SOURCE1 .= "
        int removedFunc2(void *** param) { return 0; }";
    
    # Method_Became_Static
    $HEADER1 .= "
        struct $DECL_SPEC MethodBecameStatic
        {
            MethodBecameStatic becameStatic(MethodBecameStatic param);
            int **i;
            long j;
            double k;
            MethodBecameStatic* p;
        };";
    $SOURCE1 .= "
        MethodBecameStatic MethodBecameStatic::becameStatic(MethodBecameStatic param) { return param; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC MethodBecameStatic
        {
            static MethodBecameStatic becameStatic(MethodBecameStatic param);
            int **i;
            long j;
            double k;
            MethodBecameStatic* p;
        };";
    $SOURCE2 .= "
        MethodBecameStatic MethodBecameStatic::becameStatic(MethodBecameStatic param) { return param; }";
    
    # Method_Became_Non_Static
    $HEADER1 .= "
        struct $DECL_SPEC MethodBecameNonStatic
        {
            static MethodBecameNonStatic becameNonStatic(MethodBecameNonStatic param);
            int **i;
            long j;
            double k;
            MethodBecameNonStatic* p;
        };";
    $SOURCE1 .= "
        MethodBecameNonStatic MethodBecameNonStatic::becameNonStatic(MethodBecameNonStatic param) { return param; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC MethodBecameNonStatic
        {
            MethodBecameNonStatic becameNonStatic(MethodBecameNonStatic param);
            int **i;
            long j;
            double k;
            MethodBecameNonStatic* p;
        };";
    $SOURCE2 .= "
        MethodBecameNonStatic MethodBecameNonStatic::becameNonStatic(MethodBecameNonStatic param) { return param; }";
    
    # Parameter_Type_And_Size
    $HEADER1 .= "
        $DECL_SPEC int funcParameterTypeAndSize(int param, int other_param);";
    $SOURCE1 .= "
        int funcParameterTypeAndSize(int param, int other_param) { return other_param; }";
    
    $HEADER2 .= "
        $DECL_SPEC int funcParameterTypeAndSize(long long param, int other_param);";
    $SOURCE2 .= "
        int funcParameterTypeAndSize(long long param, int other_param) { return other_param; }";
    
    # Parameter_Type
    $HEADER1 .= "
        $DECL_SPEC int funcParameterType(int param, int other_param);";
    $SOURCE1 .= "
        int funcParameterType(int param, int other_param) { return other_param; }";
    
    $HEADER2 .= "
        $DECL_SPEC int funcParameterType(float param, int other_param);";
    $SOURCE2 .= "
        int funcParameterType(float param, int other_param) { return other_param; }";
    
    # Parameter_BaseType
    $HEADER1 .= "
        $DECL_SPEC int funcParameterBaseType(int *param);";
    $SOURCE1 .= "
        int funcParameterBaseType(int *param) { return sizeof(*param); }";
    
    $HEADER2 .= "
        $DECL_SPEC int funcParameterBaseType(long long *param);";
    $SOURCE2 .= "
        int funcParameterBaseType(long long *param) { return sizeof(*param); }";
    
    # Parameter_PointerLevel
    $HEADER1 .= "
        $DECL_SPEC long long funcParameterPointerLevelAndSize(long long param);";
    $SOURCE1 .= "
        long long funcParameterPointerLevelAndSize(long long param) { return param; }";
    
    $HEADER2 .= "
        $DECL_SPEC long long funcParameterPointerLevelAndSize(long long *param);";
    $SOURCE2 .= "
        long long funcParameterPointerLevelAndSize(long long *param) { return param[5]; }";
    
    # Parameter_PointerLevel
    $HEADER1 .= "
        $DECL_SPEC int funcParameterPointerLevel(int *param);";
    $SOURCE1 .= "
        int funcParameterPointerLevel(int *param) { return param[5]; }";
    
    $HEADER2 .= "
        $DECL_SPEC int funcParameterPointerLevel(int **param);";
    $SOURCE2 .= "
        int funcParameterPointerLevel(int **param) { return param[5][5]; }";
    
    # Return_Type_And_Size
    $HEADER1 .= "
        $DECL_SPEC int funcReturnTypeAndSize(int param);";
    $SOURCE1 .= "
        int funcReturnTypeAndSize(int param) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC long long funcReturnTypeAndSize(int param);";
    $SOURCE2 .= "
        long long funcReturnTypeAndSize(int param) { return 0; }";
    
    # Return_Type
    $HEADER1 .= "
        $DECL_SPEC int funcReturnType(int param);";
    $SOURCE1 .= "
        int funcReturnType(int param) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC float funcReturnType(int param);";
    $SOURCE2 .= "
        float funcReturnType(int param) { return 0.7; }";

    # Return_Type_Became_Void ("int" to "void")
    $HEADER1 .= "
        $DECL_SPEC int funcReturnTypeBecameVoid(int param);";
    $SOURCE1 .= "
        int funcReturnTypeBecameVoid(int param) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC void funcReturnTypeBecameVoid(int param);";
    $SOURCE2 .= "
        void funcReturnTypeBecameVoid(int param) { return; }";
    
    # Return_BaseType
    $HEADER1 .= "
        $DECL_SPEC int* funcReturnBaseType(int param);";
    $SOURCE1 .= "
        int* funcReturnBaseType(int param) {
            int *x = new int[10];
            return x;
        }";
    
    $HEADER2 .= "
        $DECL_SPEC long long* funcReturnBaseType(int param);";
    $SOURCE2 .= "
        long long* funcReturnBaseType(int param) {
            long long *x = new long long[10];
            return x;
        }";
    
    # Return_PointerLevel
    $HEADER1 .= "
        $DECL_SPEC long long funcReturnPointerLevelAndSize(int param);";
    $SOURCE1 .= "
        long long funcReturnPointerLevelAndSize(int param) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC long long* funcReturnPointerLevelAndSize(int param);";
    $SOURCE2 .= "
        long long* funcReturnPointerLevelAndSize(int param) { return new long long[10]; }";
    
    # Return_PointerLevel
    $HEADER1 .= "
        $DECL_SPEC int* funcReturnPointerLevel(int param);";
    $SOURCE1 .= "
        int* funcReturnPointerLevel(int param) { return new int[10]; }";
    
    $HEADER2 .= "
        $DECL_SPEC int** funcReturnPointerLevel(int param);";
    $SOURCE2 .= "
        int** funcReturnPointerLevel(int param) { return new int*[10]; }";
    
    # Size (anon type)
    $HEADER1 .= "
        typedef struct {
            int i;
            long j;
            double k;
        } AnonTypedef;
        $DECL_SPEC int funcAnonTypedef(AnonTypedef param);";
    $SOURCE1 .= "
        int funcAnonTypedef(AnonTypedef param) { return 0; }";
    
    $HEADER2 .= "
        typedef struct {
            int i;
            long j;
            double k;
            union {
                int dummy[256];
                struct {
                    char q_skiptable[256];
                    const char *p;
                    int l;
                } p;
            };
        } AnonTypedef;
        $DECL_SPEC int funcAnonTypedef(AnonTypedef param);";
    $SOURCE2 .= "
        int funcAnonTypedef(AnonTypedef param) { return 0; }";
    
    # Added_Field (safe: opaque)
    $HEADER1 .= "
        struct $DECL_SPEC OpaqueType
        {
        public:
            OpaqueType method(OpaqueType param);
            int i;
            long j;
            double k;
            OpaqueType* p;
        };";
    $SOURCE1 .= "
        OpaqueType OpaqueType::method(OpaqueType param) { return param; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC OpaqueType
        {
        public:
            OpaqueType method(OpaqueType param);
            int i;
            long j;
            double k;
            OpaqueType* p;
            int added_member;
        };";
    $SOURCE2 .= "
        OpaqueType OpaqueType::method(OpaqueType param) { return param; }";
    
    # Added_Field (safe: internal)
    $HEADER1 .= "
        struct $DECL_SPEC InternalType {
            InternalType method(InternalType param);
            int i;
            long j;
            double k;
            InternalType* p;
        };";
    $SOURCE1 .= "
        InternalType InternalType::method(InternalType param) { return param; }";
    
    $HEADER2 .= "
        struct $DECL_SPEC InternalType {
            InternalType method(InternalType param);
            int i;
            long j;
            double k;
            InternalType* p;
            int added_member;
        };";
    $SOURCE2 .= "
        InternalType InternalType::method(InternalType param) { return param; }";
    
    # Size (unnamed struct/union fields within structs/unions)
    $HEADER1 .= "
        typedef struct {
            int a;
            struct {
                int u1;
                float u2;
            };
            int d;
        } UnnamedTypeSize;
        $DECL_SPEC int unnamedTypeSize(UnnamedTypeSize param);";
    $SOURCE1 .= "
        int unnamedTypeSize(UnnamedTypeSize param) { return 0; }";
    
    $HEADER2 .= "
        typedef struct {
            int a;
            struct {
                long double u1;
                float u2;
            };
            int d;
        } UnnamedTypeSize;
        $DECL_SPEC int unnamedTypeSize(UnnamedTypeSize param);";
    $SOURCE2 .= "
        int unnamedTypeSize(UnnamedTypeSize param) { return 0; }";
    
    # Changed_Constant
    $HEADER1 .= "
        #define PUBLIC_CONSTANT \"old_value\"";
    $HEADER2 .= "
        #define PUBLIC_CONSTANT \"new_value\"";
    
    $HEADER1 .= "
        #define PUBLIC_VERSION \"1.2 (3.4)\"";
    $HEADER2 .= "
        #define PUBLIC_VERSION \"1.2 (3.5)\"";
    
    $HEADER1 .= "
        #define PRIVATE_CONSTANT \"old_value\"
        #undef PRIVATE_CONSTANT";
    $HEADER2 .= "
        #define PRIVATE_CONSTANT \"new_value\"
        #undef PRIVATE_CONSTANT";
    
    # Added_Field (union)
    $HEADER1 .= "
        union UnionAddedField {
            int a;
            struct {
                int b;
                float c;
            };
            int d;
        };
        $DECL_SPEC int unionAddedField(UnionAddedField param);";
    $SOURCE1 .= "
        int unionAddedField(UnionAddedField param) { return 0; }";
    
    $HEADER2 .= "
        union UnionAddedField {
            int a;
            struct {
                long double x, y;
            } new_field;
            struct {
                int b;
                float c;
            };
            int d;
        };
        $DECL_SPEC int unionAddedField(UnionAddedField param);";
    $SOURCE2 .= "
        int unionAddedField(UnionAddedField param) { return 0; }";
    
    # Removed_Field (union)
    $HEADER1 .= "
        union UnionRemovedField {
            int a;
            struct {
                long double x, y;
            } removed_field;
            struct {
                int b;
                float c;
            };
            int d;
        };
        $DECL_SPEC int unionRemovedField(UnionRemovedField param);";
    $SOURCE1 .= "
        int unionRemovedField(UnionRemovedField param) { return 0; }";
    
    $HEADER2 .= "
        union UnionRemovedField {
            int a;
            struct {
                int b;
                float c;
            };
            int d;
        };
        $DECL_SPEC int unionRemovedField(UnionRemovedField param);";
    $SOURCE2 .= "
        int unionRemovedField(UnionRemovedField param) { return 0; }";

    # Added (typedef change)
    $HEADER1 .= "
        typedef float TYPEDEF_TYPE;
        $DECL_SPEC int parameterTypedefChange(TYPEDEF_TYPE param);";
    $SOURCE1 .= "
        int parameterTypedefChange(TYPEDEF_TYPE param) { return 1; }";
    
    $HEADER2 .= "
        typedef int TYPEDEF_TYPE;
        $DECL_SPEC int parameterTypedefChange(TYPEDEF_TYPE param);";
    $SOURCE2 .= "
        int parameterTypedefChange(TYPEDEF_TYPE param) { return 1; }";

    # Parameter_Default_Value_Changed (safe)
    # Converted from void* to const char*
    $HEADER1 .= "
        $DECL_SPEC int paramDefaultValue_Converted(const char* arg = 0); ";
    $SOURCE1 .= "
        int paramDefaultValue_Converted(const char* arg) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC int paramDefaultValue_Converted(const char* arg = (const char*)((void*) 0)); ";
    $SOURCE2 .= "
        int paramDefaultValue_Converted(const char* arg) { return 0; }";
    
    # Parameter_Default_Value_Changed
    # Integer
    $HEADER1 .= "
        $DECL_SPEC int paramDefaultValueChanged_Integer(int param = 0xf00f); ";
    $SOURCE1 .= "
        int paramDefaultValueChanged_Integer(int param) { return param; }";
    
    $HEADER2 .= "
        $DECL_SPEC int paramDefaultValueChanged_Integer(int param = 0xf00b); ";
    $SOURCE2 .= "
        int paramDefaultValueChanged_Integer(int param) { return param; }";

    # Parameter_Default_Value_Changed
    # String
    $HEADER1 .= "
        $DECL_SPEC int paramDefaultValueChanged_String(char const* param = \" str  1 \"); ";
    $SOURCE1 .= "
        int paramDefaultValueChanged_String(char const* param) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC int paramDefaultValueChanged_String(char const* param = \" str  2 \"); ";
    $SOURCE2 .= "
        int paramDefaultValueChanged_String(char const* param) { return 0; }";

    # Parameter_Default_Value_Changed
    # Character
    $HEADER1 .= "
        $DECL_SPEC int paramDefaultValueChanged_Char(char param = \'A\'); ";
    $SOURCE1 .= "
        int paramDefaultValueChanged_Char(char param) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC int paramDefaultValueChanged_Char(char param = \'B\'); ";
    $SOURCE2 .= "
        int paramDefaultValueChanged_Char(char param) { return 0; }";

    # Parameter_Default_Value_Changed
    # Bool
    $HEADER1 .= "
        $DECL_SPEC int paramDefaultValueChanged_Bool(bool param = true); ";
    $SOURCE1 .= "
        int paramDefaultValueChanged_Bool(bool param) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC int paramDefaultValueChanged_Bool(bool param = false); ";
    $SOURCE2 .= "
        int paramDefaultValueChanged_Bool(bool param) { return 0; }";

    # Parameter_Default_Value_Removed
    $HEADER1 .= "
        $DECL_SPEC int parameterDefaultValueRemoved(int param = 15);
    ";
    $SOURCE1 .= "
        int parameterDefaultValueRemoved(int param) { return param; }";
    
    $HEADER2 .= "
        $DECL_SPEC int parameterDefaultValueRemoved(int param);";
    $SOURCE2 .= "
        int parameterDefaultValueRemoved(int param) { return param; }";

    # Parameter_Default_Value_Added
    $HEADER1 .= "
        $DECL_SPEC int parameterDefaultValueAdded(int param);
    ";
    $SOURCE1 .= "
        int parameterDefaultValueAdded(int param) { return param; }";
    
    $HEADER2 .= "
        $DECL_SPEC int parameterDefaultValueAdded(int param = 15);";
    $SOURCE2 .= "
        int parameterDefaultValueAdded(int param) { return param; }";
    
    # Field_Type (typedefs in member type)
    $HEADER1 .= "
        typedef float TYPEDEF_TYPE_2;
        struct $DECL_SPEC FieldTypedefChange{
        public:
            TYPEDEF_TYPE_2 m;
            TYPEDEF_TYPE_2 n;
        };
        $DECL_SPEC int fieldTypedefChange(FieldTypedefChange param);";
    $SOURCE1 .= "
        int fieldTypedefChange(FieldTypedefChange param) { return 1; }";
    
    $HEADER2 .= "
        typedef int TYPEDEF_TYPE_2;
        struct $DECL_SPEC FieldTypedefChange{
        public:
            TYPEDEF_TYPE_2 m;
            TYPEDEF_TYPE_2 n;
        };
        $DECL_SPEC int fieldTypedefChange(FieldTypedefChange param);";
    $SOURCE2 .= "
        int fieldTypedefChange(FieldTypedefChange param) { return 1; }";

    # Callback (testCallback symbol should be affected
    # instead of callback1 and callback2)
    $HEADER1 .= "
        class $DECL_SPEC Callback {
        public:
            virtual int callback1(int x, int y)=0;
            virtual int callback2(int x, int y)=0;
        };
        $DECL_SPEC int testCallback(Callback* p);";
    $SOURCE1 .= "
        int testCallback(Callback* p) {
            p->callback2(1, 2);
            return 0;
        }";

    $HEADER2 .= "
        class $DECL_SPEC Callback {
        public:
            virtual int callback1(int x, int y)=0;
            virtual int added_callback(int x, int y)=0;
            virtual int callback2(int x, int y)=0;
        };
        $DECL_SPEC int testCallback(Callback* p);";
    $SOURCE2 .= "
        int testCallback(Callback* p) {
            p->callback2(1, 2);
            return 0;
        }";
    
    # End namespace
    $HEADER1 .= "\n}\n";
    $HEADER2 .= "\n}\n";
    $SOURCE1 .= "\n}\n";
    $SOURCE2 .= "\n}\n";
    
    runTests("libsample_cpp", "C++", $HEADER1, $SOURCE1, $HEADER2, $SOURCE2, "TestNS::OpaqueType", "_ZN6TestNS12InternalType6methodES0_");
}

sub testC()
{
    printMsg("INFO", "\nVerifying detectable C library changes");
    my ($HEADER1, $SOURCE1, $HEADER2, $SOURCE2) = ();
    
    my $DECL_SPEC = "";
    my $EXTERN = "";
    
    if($In::Opt{"OS"} eq "windows")
    {
        $DECL_SPEC = "__declspec( dllexport )";
        $EXTERN = "extern "; # add "extern" for CL compiler
    }
    
    # Array size
    $HEADER1 .= "
        $DECL_SPEC int arraySize(int p[10]);";
    $SOURCE1 .= "
        int arraySize(int p[10]) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC int arraySize(int p[15]);";
    $SOURCE2 .= "
        int arraySize(int p[15]) { return 0; }";
    
    # Struct to union
    $HEADER1 .= "
        typedef struct StructToUnion {
            unsigned char A[64];
        } StructToUnion;
        
        $DECL_SPEC int structToUnion(StructToUnion *p);";
    $SOURCE1 .= "
        int structToUnion(StructToUnion *p) { return 0; }";
    
    $HEADER2 .= "
        typedef union StructToUnion {
            unsigned char A[64];
            void *p;
        } StructToUnion;
        
        $DECL_SPEC int structToUnion(StructToUnion *p);";
    $SOURCE2 .= "
        int structToUnion(StructToUnion *p) { return 0; }";
    
    # Typedef to function
    $HEADER1 .= "
        typedef int(TypedefToFunction)(int pX);
        
        $DECL_SPEC int typedefToFunction(TypedefToFunction* p);";
    $SOURCE1 .= "
        int typedefToFunction(TypedefToFunction* p) { return 0; }";
    
    $HEADER2 .= "
        typedef int(TypedefToFunction)(int pX, int pY);
        
        $DECL_SPEC int typedefToFunction(TypedefToFunction* p);";
    $SOURCE2 .= "
        int typedefToFunction(TypedefToFunction* p) { return 0; }";
    
    # Used_Reserved
    $HEADER1 .= "
        typedef struct {
            int f;
            void* reserved0;
            void* reserved1;
        } UsedReserved;
        
        $DECL_SPEC int usedReserved(UsedReserved p);";
    $SOURCE1 .= "
        int usedReserved(UsedReserved p) { return 0; }";
    
    $HEADER2 .= "
        typedef struct {
            int f;
            void* f0;
            void* f1;
        } UsedReserved;
        
        $DECL_SPEC int usedReserved(UsedReserved p);";
    $SOURCE2 .= "
        int usedReserved(UsedReserved p) { return 0; }";
    
    # Parameter_Type_And_Register
    $HEADER1 .= "
        typedef struct {
            int a[4];
        } ARRAY;
        $DECL_SPEC void callConv5 (ARRAY i, int j);";
    $SOURCE1 .= "
        void callConv5 (ARRAY i, int j) { }";
    
    $HEADER2 .= "
        typedef struct {
            int a[4];
        } ARRAY;
        $DECL_SPEC void callConv5 (ARRAY i, double j);";
    $SOURCE2 .= "
        void callConv5 (ARRAY i, double j) { }";
    
    # Parameter_Type_And_Register
    $HEADER1 .= "
        typedef union {
            int a;
            double b;
        } UNION;
        $DECL_SPEC void callConv4 (UNION i, int j);";
    $SOURCE1 .= "
        void callConv4 (UNION i, int j) { }";
    
    $HEADER2 .= "
        typedef union {
            int a;
            double b;
        } UNION;
        $DECL_SPEC void callConv4 (UNION i, double j);";
    $SOURCE2 .= "
        void callConv4 (UNION i, double j) { }";
    
    # Parameter_Type_And_Register
    $HEADER1 .= "
        typedef struct {
            long a:4;
            long b:16;
        } POD2;
        $DECL_SPEC void callConv3 (POD2 i, int j);";
    $SOURCE1 .= "
        void callConv3 (POD2 i, int j) { }";
    
    $HEADER2 .= "
        typedef struct {
            long a:4;
            long b:16;
        } POD2;
        $DECL_SPEC void callConv3 (POD2 i, double j);";
    $SOURCE2 .= "
        void callConv3 (POD2 i, double j) { }";
    
    # Parameter_Type_And_Register
    $HEADER1 .= "
        typedef struct {
            short s:9;
            int j:9;
            char c;
            short t:9;
            short u:9;
            char d;
        } POD;
        $DECL_SPEC void callConv2 (POD i, int j);";
    $SOURCE1 .= "
        void callConv2 (POD i, int j) { }";
    
    $HEADER2 .= "
        typedef struct {
            short s:9;
            int j:9;
            char c;
            short t:9;
            short u:9;
            char d;
        } POD;
        $DECL_SPEC void callConv2 (POD i, double j);";
    $SOURCE2 .= "
        void callConv2 (POD i, double j) { }";
    
    # Parameter_Type_And_Register
    $HEADER1 .= "
        typedef struct {
            int a, b;
            double d;
        } POD1;
        $DECL_SPEC void callConv (int e, int f, POD1 s, int g, int h, long double ld, double m, double n, int i, int j, int k);";
    $SOURCE1 .= "
        void callConv(int e, int f, POD1 s, int g, int h, long double ld, double m, double n, int i, int j, int k) { }";
    
    $HEADER2 .= "
        typedef struct {
            int a, b;
            double d;
        } POD1;
        $DECL_SPEC void callConv (int e, int f, POD1 s, int g, int h, long double ld, double m, double n, int i, int j, double k);";
    $SOURCE2 .= "
        void callConv(int e, int f, POD1 s, int g, int h, long double ld, double m, double n, int i, int j, double k) { }";
    
    # Parameter_Type (int to "int const")
    $HEADER1 .= "
        $DECL_SPEC void parameterBecameConstInt(int arg);";
    $SOURCE1 .= "
        void parameterBecameConstInt(int arg) { }";
    
    $HEADER2 .= "
        $DECL_SPEC void parameterBecameConstInt(const int arg);";
    $SOURCE2 .= "
        void parameterBecameConstInt(const int arg) { }";

    # Parameter_Type ("int const" to int)
    $HEADER1 .= "
        $DECL_SPEC void parameterBecameNonConstInt(const int arg);";
    $SOURCE1 .= "
        void parameterBecameNonConstInt(const int arg) { }";
    
    $HEADER2 .= "
        $DECL_SPEC void parameterBecameNonConstInt(int arg);";
    $SOURCE2 .= "
        void parameterBecameNonConstInt(int arg) { }";
    
    # Parameter_Became_Register
    $HEADER1 .= "
        $DECL_SPEC void parameterBecameRegister(int arg);";
    $SOURCE1 .= "
        void parameterBecameRegister(int arg) { }";
    
    $HEADER2 .= "
        $DECL_SPEC void parameterBecameRegister(register int arg);";
    $SOURCE2 .= "
        void parameterBecameRegister(register int arg) { }";
    
    # Return_Type_Became_Const
    $HEADER1 .= "
        $DECL_SPEC char* returnTypeBecameConst(int param);";
    $SOURCE1 .= "
        char* returnTypeBecameConst(int param) { return (char*)malloc(256); }";
    
    $HEADER2 .= "
        $DECL_SPEC const char* returnTypeBecameConst(int param);";
    $SOURCE2 .= "
        const char* returnTypeBecameConst(int param) { return \"abc\"; }";
    
    # Return_Type_Became_Const (2)
    $HEADER1 .= "
        $DECL_SPEC char* returnTypeBecameConst2(int param);";
    $SOURCE1 .= "
        char* returnTypeBecameConst2(int param) { return (char*)malloc(256); }";
    
    $HEADER2 .= "
        $DECL_SPEC char*const returnTypeBecameConst2(int param);";
    $SOURCE2 .= "
        char*const returnTypeBecameConst2(int param) { return (char*const)malloc(256); }";
    
    # Return_Type_Became_Const (3)
    $HEADER1 .= "
        $DECL_SPEC char* returnTypeBecameConst3(int param);";
    $SOURCE1 .= "
        char* returnTypeBecameConst3(int param) { return (char*)malloc(256); }";
    
    $HEADER2 .= "
        $DECL_SPEC char const*const returnTypeBecameConst3(int param);";
    $SOURCE2 .= "
        char const*const returnTypeBecameConst3(int param) { return (char const*const)malloc(256); }";
    
    # Return_Type_Became_Volatile
    $HEADER1 .= "
        $DECL_SPEC char* returnTypeBecameVolatile(int param);";
    $SOURCE1 .= "
        char* returnTypeBecameVolatile(int param) { return (char*)malloc(256); }";
    
    $HEADER2 .= "
        $DECL_SPEC volatile char* returnTypeBecameVolatile(int param);";
    $SOURCE2 .= "
        volatile char* returnTypeBecameVolatile(int param) { return \"abc\"; }";
    
    # Added_Enum_Member
    $HEADER1 .= "
        enum AddedEnumMember {
            OldMember
        };
        $DECL_SPEC int addedEnumMember(enum AddedEnumMember param);";
    $SOURCE1 .= "
        int addedEnumMember(enum AddedEnumMember param) { return 0; }";
    
    $HEADER2 .= "
        enum AddedEnumMember {
            OldMember,
            NewMember
        };
        $DECL_SPEC int addedEnumMember(enum AddedEnumMember param);";
    $SOURCE2 .= "
        int addedEnumMember(enum AddedEnumMember param) { return 0; }";
    
    # Parameter_Type (Array)
    $HEADER1 .= "
        $DECL_SPEC int arrayParameterType(int param[5]);";
    $SOURCE1 .= "
        int arrayParameterType(int param[5]) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC int arrayParameterType(int param[7]);";
    $SOURCE2 .= "
        int arrayParameterType(int param[7]) { return 0; }";
    
    # Field_Type
    $HEADER1 .= "
        struct ArrayFieldType
        {
            int f;
            int i[1];
        };
        $DECL_SPEC int arrayFieldType(struct ArrayFieldType param);";
    $SOURCE1 .= "
        int arrayFieldType(struct ArrayFieldType param) { return param.i[0]; }";
    
    $HEADER2 .= "
        struct ArrayFieldType
        {
            int f;
            int i[];
        };
        $DECL_SPEC int arrayFieldType(struct ArrayFieldType param);";
    $SOURCE2 .= "
        int arrayFieldType(struct ArrayFieldType param) { return param.i[0]; }";
    
    # Field_Type_And_Size (Array)
    $HEADER1 .= "
        struct ArrayFieldSize
        {
            int i[5];
        };
        $DECL_SPEC int arrayFieldSize(struct ArrayFieldSize param);";
    $SOURCE1 .= "
        int arrayFieldSize(struct ArrayFieldSize param) { return 0; }";
    
    $HEADER2 .= "
        struct ArrayFieldSize
        {
            int i[7];
        };
        $DECL_SPEC int arrayFieldSize(struct ArrayFieldSize param);";
    $SOURCE2 .= "
        int arrayFieldSize(struct ArrayFieldSize param) { return 0; }";
    
    # Parameter_Became_Non_VaList
    $HEADER1 .= "
        $DECL_SPEC int parameterNonVaList(int param, ...);";
    $SOURCE1 .= "
        int parameterNonVaList(int param, ...) { return param; }";
    
    $HEADER2 .= "
        $DECL_SPEC int parameterNonVaList(int param1, int param2);";
    $SOURCE2 .= "
        int parameterNonVaList(int param1, int param2) { return param1; }";

    # Parameter_Became_VaList
    $HEADER1 .= "
        $DECL_SPEC int parameterVaList(int param1, int param2);";
    $SOURCE1 .= "
        int parameterVaList(int param1, int param2) { return param1; }";
    
    $HEADER2 .= "
        $DECL_SPEC int parameterVaList(int param, ...);";
    $SOURCE2 .= "
        int parameterVaList(int param, ...) { return param; }";
    
    # Field_Type_And_Size
    $HEADER1 .= "
        struct FieldSizePadded
        {
            int i;
            char changed_field;
            // padding (3 bytes)
            int j;
        };
        $DECL_SPEC int fieldSizePadded(struct FieldSizePadded param);";
    $SOURCE1 .= "
        int fieldSizePadded(struct FieldSizePadded param) { return 0; }";
    
    $HEADER2 .= "
        struct FieldSizePadded
        {
            int i;
            int changed_field;
            int j;
        };
        $DECL_SPEC int fieldSizePadded(struct FieldSizePadded param);";
    $SOURCE2 .= "
        int fieldSizePadded(struct FieldSizePadded param) { return 0; }";
    
    # Parameter_Type_Format
    $HEADER1 .= "
        struct DType1
        {
            int i;
            double j[7];
        };
        $DECL_SPEC int parameterTypeFormat(struct DType1 param);";
    $SOURCE1 .= "
        int parameterTypeFormat(struct DType1 param) { return 0; }";
    
    $HEADER2 .= "
        struct DType2
        {
            double i[7];
            int j;
        };
        $DECL_SPEC int parameterTypeFormat(struct DType2 param);";
    $SOURCE2 .= "
        int parameterTypeFormat(struct DType2 param) { return 0; }";
    
    # Field_Type_Format
    $HEADER1 .= "
        struct FieldTypeFormat
        {
            int i;
            struct DType1 j;
        };
        $DECL_SPEC int fieldTypeFormat(struct FieldTypeFormat param);";
    $SOURCE1 .= "
        int fieldTypeFormat(struct FieldTypeFormat param) { return 0; }";
    
    $HEADER2 .= "
        struct FieldTypeFormat
        {
            int i;
            struct DType2 j;
        };
        $DECL_SPEC int fieldTypeFormat(struct FieldTypeFormat param);";
    $SOURCE2 .= "
        int fieldTypeFormat(struct FieldTypeFormat param) { return 0; }";
    
    # Parameter_Type_Format (struct to union)
    $HEADER1 .= "
        struct DType
        {
            int i;
            double j;
        };
        $DECL_SPEC int parameterTypeFormat2(struct DType param);";
    $SOURCE1 .= "
        int parameterTypeFormat2(struct DType param) { return 0; }";
    
    $HEADER2 .= "
        union DType
        {
            int i;
            long double j;
        };
        $DECL_SPEC int parameterTypeFormat2(union DType param);";
    $SOURCE2 .= "
        int parameterTypeFormat2(union DType param) { return 0; }";
    
    # Global_Data_Size
    $HEADER1 .= "
        struct GlobalDataSize {
            int a;
        };
        $EXTERN $DECL_SPEC struct GlobalDataSize globalDataSize;";
    
    $HEADER2 .= "
        struct GlobalDataSize {
            int a, b;
        };
        $EXTERN $DECL_SPEC struct GlobalDataSize globalDataSize;";

    # Global_Data_Type
    $HEADER1 .= "
        $EXTERN $DECL_SPEC int globalDataType;";
    
    $HEADER2 .= "
        $EXTERN $DECL_SPEC float globalDataType;";

    # Global_Data_Type_And_Size
    $HEADER1 .= "
        $EXTERN $DECL_SPEC int globalDataTypeAndSize;";
    
    $HEADER2 .= "
        $EXTERN $DECL_SPEC short globalDataTypeAndSize;";
    
    # Global_Data_Value_Changed
    # Integer
    $HEADER1 .= "
        $EXTERN $DECL_SPEC const int globalDataValue_Integer = 10;";
    
    $HEADER2 .= "
        $EXTERN $DECL_SPEC const int globalDataValue_Integer = 15;";

    # Global_Data_Value_Changed
    # Character
    $HEADER1 .= "
        $EXTERN $DECL_SPEC const char globalDataValue_Char = \'o\';";
    
    $HEADER2 .= "
        $EXTERN $DECL_SPEC const char globalDataValue_Char = \'N\';";
    
    # Global_Data_Became_Non_Const
    $HEADER1 .= "
        $EXTERN $DECL_SPEC const int globalDataBecameNonConst = 10;";
    
    $HEADER2 .= "
        extern $DECL_SPEC int globalDataBecameNonConst;";
    $SOURCE2 .= "
        int globalDataBecameNonConst = 15;";

    # Global_Data_Became_Non_Const
    # Typedef
    $HEADER1 .= "
        typedef const int CONST_INT;
        $EXTERN $DECL_SPEC CONST_INT globalDataBecameNonConst_Typedef = 10;";
    
    $HEADER2 .= "
        extern $DECL_SPEC int globalDataBecameNonConst_Typedef;";
    $SOURCE2 .= "
        int globalDataBecameNonConst_Typedef = 15;";

    # Global_Data_Became_Const
    $HEADER1 .= "
        extern $DECL_SPEC int globalDataBecameConst;";
    $SOURCE1 .= "
        int globalDataBecameConst = 10;";
    
    $HEADER2 .= "
        $EXTERN $DECL_SPEC const int globalDataBecameConst = 15;";
    
    # Global_Data_Became_Non_Const
    $HEADER1 .= "
        struct GlobalDataType{int a;int b;struct GlobalDataType* p;};
        $EXTERN $DECL_SPEC const struct GlobalDataType globalStructDataBecameNonConst = { 1, 2, (struct GlobalDataType*)0 };";
    
    $HEADER2 .= "
        struct GlobalDataType{int a;int b;struct GlobalDataType* p;};
        $EXTERN $DECL_SPEC struct GlobalDataType globalStructDataBecameNonConst = { 1, 2, (struct GlobalDataType*)0 };";
    
    # Removed_Parameter
    $HEADER1 .= "
        $DECL_SPEC int removedParameter(int param, int removed_param);";
    $SOURCE1 .= "
        int removedParameter(int param, int removed_param) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC int removedParameter(int param);";
    $SOURCE2 .= "
        int removedParameter(int param) { return 0; }";
    
    # Added_Parameter
    $HEADER1 .= "
        $DECL_SPEC int addedParameter(int param);";
    $SOURCE1 .= "
        int addedParameter(int param) { return param; }";
    
    $HEADER2 .= "
        $DECL_SPEC int addedParameter(int param, int added_param, int added_param2);";
    $SOURCE2 .= "
        int addedParameter(int param, int added_param, int added_param2) { return added_param2; }";
    
    # Added_Interface (typedef to funcptr parameter)
    $HEADER2 .= "
        typedef int (*FUNCPTR_TYPE)(int a, int b);
        $DECL_SPEC int addedFunc(FUNCPTR_TYPE*const** f);";
    $SOURCE2 .= "
        int addedFunc(FUNCPTR_TYPE*const** f) { return 0; }";
    
    # Added_Interface (funcptr parameter)
    $HEADER2 .= "
        $DECL_SPEC int addedFunc2(int(*func)(int, int));";
    $SOURCE2 .= "
        int addedFunc2(int(*func)(int, int)) { return 0; }";
    
    # Added_Interface (no limited parameters)
    $HEADER2 .= "
        $DECL_SPEC int addedFunc3(float p1, ...);";
    $SOURCE2 .= "
        int addedFunc3(float p1, ...) { return 0; }";
    
    # Size
    $HEADER1 .= "
        struct TypeSize
        {
            long long i[5];
            long j;
            double k;
            struct TypeSize* p;
        };
        $DECL_SPEC int testSize(struct TypeSize param, int param_2);";
    $SOURCE1 .= "
        int testSize(struct TypeSize param, int param_2) { return param_2; }";
    
    $HEADER2 .= "
        struct TypeSize
        {
            long long i[15];
            long long j;
            double k;
            struct TypeSize* p;
        };
        $DECL_SPEC int testSize(struct TypeSize param, int param_2);";
    $SOURCE2 .= "
        int testSize(struct TypeSize param, int param_2) { return param_2; }";
    
    # Added_Field_And_Size
    $HEADER1 .= "
        struct AddedFieldAndSize
        {
            int i;
            long j;
            double k;
            struct AddedFieldAndSize* p;
        };
        $DECL_SPEC int addedFieldAndSize(struct AddedFieldAndSize param, int param_2);";
    $SOURCE1 .= "
        int addedFieldAndSize(struct AddedFieldAndSize param, int param_2) { return param_2; }";
    
    $HEADER2 .= "
        struct AddedFieldAndSize
        {
            int i;
            long j;
            double k;
            struct AddedFieldAndSize* p;
            int added_member1;
            int added_member2;
        };
        $DECL_SPEC int addedFieldAndSize(struct AddedFieldAndSize param, int param_2);";
    $SOURCE2 .= "
        int addedFieldAndSize(struct AddedFieldAndSize param, int param_2) { return param_2; }";
    
    # Added_Middle_Field_And_Size
    $HEADER1 .= "
        struct AddedMiddleFieldAndSize
        {
            int i;
            long j;
            double k;
            struct AddedMiddleFieldAndSize* p;
        };
        $DECL_SPEC int addedMiddleFieldAndSize(struct AddedMiddleFieldAndSize param, int param_2);";
    $SOURCE1 .= "
        int addedMiddleFieldAndSize(struct AddedMiddleFieldAndSize param, int param_2) { return param_2; }";
    
    $HEADER2 .= "
        struct AddedMiddleFieldAndSize
        {
            int i;
            int added_middle_member;
            long j;
            double k;
            struct AddedMiddleFieldAndSize* p;
        };
        $DECL_SPEC int addedMiddleFieldAndSize(struct AddedMiddleFieldAndSize param, int param_2);";
    $SOURCE2 .= "
        int addedMiddleFieldAndSize(struct AddedMiddleFieldAndSize param, int param_2) { return param_2; }";

    # Added_Middle_Field
    $HEADER1 .= "
        struct AddedMiddleField
        {
            unsigned char field1;
            unsigned short field2;
        };
        $DECL_SPEC int addedMiddleField(struct AddedMiddleField param, int param_2);";
    $SOURCE1 .= "
        int addedMiddleField(struct AddedMiddleField param, int param_2) { return param_2; }";
    
    $HEADER2 .= "
        struct AddedMiddleField
        {
            unsigned char field1;
            unsigned char added_field;
            unsigned short field2;
        };
        $DECL_SPEC int addedMiddleField(struct AddedMiddleField param, int param_2);";
    $SOURCE2 .= "
        int addedMiddleField(struct AddedMiddleField param, int param_2) { return param_2; }";
    
    # Renamed_Field
    $HEADER1 .= "
        struct RenamedField
        {
            long i;
            long j;
            double k;
            struct RenamedField* p;
        };
        $DECL_SPEC int renamedField(struct RenamedField param, int param_2);";
    $SOURCE1 .= "
        int renamedField(struct RenamedField param, int param_2) { return param_2; }";
    
    $HEADER2 .= "
        struct RenamedField
        {
            long renamed_member;
            long j;
            double k;
            struct RenamedField* p;
        };
        $DECL_SPEC int renamedField(struct RenamedField param, int param_2);";
    $SOURCE2 .= "
        int renamedField(struct RenamedField param, int param_2) { return param_2; }";
        
    # Renamed_Field
    $HEADER1 .= "
        union RenamedUnionField
        {
            int renamed_from;
            double j;
        };
        $DECL_SPEC int renamedUnionField(union RenamedUnionField param);";
    $SOURCE1 .= "
        int renamedUnionField(union RenamedUnionField param) { return 0; }";
    
    $HEADER2 .= "
        union RenamedUnionField
        {
            int renamed_to;
            double j;
        };
        $DECL_SPEC int renamedUnionField(union RenamedUnionField param);";
    $SOURCE2 .= "
        int renamedUnionField(union RenamedUnionField param) { return 0; }";
    
    # Removed_Field_And_Size
    $HEADER1 .= "
        struct RemovedFieldAndSize
        {
            int i;
            long j;
            double k;
            struct RemovedFieldAndSize* p;
            int removed_member1;
            int removed_member2;
        };
        $DECL_SPEC int removedFieldAndSize(struct RemovedFieldAndSize param, int param_2);";
    $SOURCE1 .= "
        int removedFieldAndSize(struct RemovedFieldAndSize param, int param_2) { return param_2; }";
    
    $HEADER2 .= "
        struct RemovedFieldAndSize
        {
            int i;
            long j;
            double k;
            struct RemovedFieldAndSize* p;
        };
        $DECL_SPEC int removedFieldAndSize(struct RemovedFieldAndSize param, int param_2);";
    $SOURCE2 .= "
        int removedFieldAndSize(struct RemovedFieldAndSize param, int param_2) { return param_2; }";
    
    # Removed_Middle_Field
    $HEADER1 .= "
        struct RemovedMiddleField
        {
            int i;
            int removed_middle_member;
            long j;
            double k;
            struct RemovedMiddleField* p;
        };
        $DECL_SPEC int removedMiddleField(struct RemovedMiddleField param, int param_2);";
    $SOURCE1 .= "
        int removedMiddleField(struct RemovedMiddleField param, int param_2) { return param_2; }";
    
    $HEADER2 .= "
        struct RemovedMiddleField
        {
            int i;
            long j;
            double k;
            struct RemovedMiddleField* p;
        };
        $DECL_SPEC int removedMiddleField(struct RemovedMiddleField param, int param_2);";
    $SOURCE2 .= "
        int removedMiddleField(struct RemovedMiddleField param, int param_2) { return param_2; }";
    
    # Enum_Member_Value
    $HEADER1 .= "
        enum EnumMemberValue
        {
            MEMBER1=1,
            MEMBER2=2
        };
        $DECL_SPEC int enumMemberValue(enum EnumMemberValue param);";
    $SOURCE1 .= "
        int enumMemberValue(enum EnumMemberValue param) { return 0; }";
    
    $HEADER2 .= "
        enum EnumMemberValue
        {
            MEMBER1=2,
            MEMBER2=1
        };
        $DECL_SPEC int enumMemberValue(enum EnumMemberValue param);";
    $SOURCE2 .= "
        int enumMemberValue(enum EnumMemberValue param) { return 0; }";

    # Enum_Member_Removed
    $HEADER1 .= "
        enum EnumMemberRemoved
        {
            MEMBER=1,
            MEMBER_REMOVED=2
        };
        $DECL_SPEC int enumMemberRemoved(enum EnumMemberRemoved param);";
    $SOURCE1 .= "
        int enumMemberRemoved(enum EnumMemberRemoved param) { return 0; }";
    
    $HEADER2 .= "
        enum EnumMemberRemoved
        {
            MEMBER=1
        };
        $DECL_SPEC int enumMemberRemoved(enum EnumMemberRemoved param);";
    $SOURCE2 .= "
        int enumMemberRemoved(enum EnumMemberRemoved param) { return 0; }";

    # Enum_Member_Removed (middle)
    $HEADER1 .= "
        enum EnumMiddleMemberRemoved
        {
            MEM_REMOVED,
            MEM1,
            MEM2
        };
        $DECL_SPEC int enumMiddleMemberRemoved(enum EnumMiddleMemberRemoved param);";
    $SOURCE1 .= "
        int enumMiddleMemberRemoved(enum EnumMiddleMemberRemoved param) { return 0; }";
    
    $HEADER2 .= "
        enum EnumMiddleMemberRemoved
        {
            MEM1,
            MEM2
        };
        $DECL_SPEC int enumMiddleMemberRemoved(enum EnumMiddleMemberRemoved param);";
    $SOURCE2 .= "
        int enumMiddleMemberRemoved(enum EnumMiddleMemberRemoved param) { return 0; }";
    
    # Enum_Member_Name
    $HEADER1 .= "
        enum EnumMemberName
        {
            BRANCH1=1,
            BRANCH2=2
        };
        $DECL_SPEC int enumMemberName(enum EnumMemberName param);";
    $SOURCE1 .= "
        int enumMemberName(enum EnumMemberName param) { return 0; }";
    
    $HEADER2 .= "
        enum EnumMemberName
        {
            BRANCH_FIRST=1,
            BRANCH_SECOND=2
        };
        $DECL_SPEC int enumMemberName(enum EnumMemberName param);";
    $SOURCE2 .= "
        int enumMemberName(enum EnumMemberName param) { return 0; }";
    
    # Field_Type_And_Size
    $HEADER1 .= "
        struct FieldTypeAndSize
        {
            int i;
            long j;
            double k;
            struct FieldTypeAndSize* p;
        };
        $DECL_SPEC int fieldTypeAndSize(struct FieldTypeAndSize param, int param_2);";
    $SOURCE1 .= "
        int fieldTypeAndSize(struct FieldTypeAndSize param, int param_2) { return param_2; }";
    
    $HEADER2 .= "
        struct FieldTypeAndSize
        {
            int i;
            long long j;
            double k;
            struct FieldTypeAndSize* p;
        };
        $DECL_SPEC int fieldTypeAndSize(struct FieldTypeAndSize param, int param_2);";
    $SOURCE2 .= "
        int fieldTypeAndSize(struct FieldTypeAndSize param, int param_2) { return param_2; }";
    
    # Field_Type
    $HEADER1 .= "
        struct FieldType
        {
            int i;
            long j;
            double k;
            struct FieldType* p;
        };
        $DECL_SPEC int fieldType(struct FieldType param, int param_2);";
    $SOURCE1 .= "
        int fieldType(struct FieldType param, int param_2) { return param_2; }";
    
    $HEADER2 .= "
        struct FieldType
        {
            float i;
            long j;
            double k;
            struct FieldType* p;
        };
        $DECL_SPEC int fieldType(struct FieldType param, int param_2);";
    $SOURCE2 .= "
        int fieldType(struct FieldType param, int param_2) { return param_2; }";
    
    # Field_BaseType
    $HEADER1 .= "
        struct FieldBaseType
        {
            int i;
            long *j;
            double k;
            struct FieldBaseType* p;
        };
        $DECL_SPEC int fieldBaseType(struct FieldBaseType param, int param_2);";
    $SOURCE1 .= "
        int fieldBaseType(struct FieldBaseType param, int param_2) { return param_2; }";
    
    $HEADER2 .= "
        struct FieldBaseType
        {
            int i;
            long long *j;
            double k;
            struct FieldBaseType* p;
        };
        $DECL_SPEC int fieldBaseType(struct FieldBaseType param, int param_2);";
    $SOURCE2 .= "
        int fieldBaseType(struct FieldBaseType param, int param_2) { return param_2; }";
    
    # Field_PointerLevel (and Size)
    $HEADER1 .= "
        struct FieldPointerLevelAndSize
        {
            int i;
            long long j;
            double k;
            struct FieldPointerLevelAndSize* p;
        };
        $DECL_SPEC int fieldPointerLevelAndSize(struct FieldPointerLevelAndSize param, int param_2);";
    $SOURCE1 .= "
        int fieldPointerLevelAndSize(struct FieldPointerLevelAndSize param, int param_2) { return param_2; }";
    
    $HEADER2 .= "
        struct FieldPointerLevelAndSize
        {
            int i;
            long long *j;
            double k;
            struct FieldPointerLevelAndSize* p;
        };
        $DECL_SPEC int fieldPointerLevelAndSize(struct FieldPointerLevelAndSize param, int param_2);";
    $SOURCE2 .= "
        int fieldPointerLevelAndSize(struct FieldPointerLevelAndSize param, int param_2) { return param_2; }";
    
    # Field_PointerLevel
    $HEADER1 .= "
        struct FieldPointerLevel
        {
            int i;
            long *j;
            double k;
            struct FieldPointerLevel* p;
        };
        $DECL_SPEC int fieldPointerLevel(struct FieldPointerLevel param, int param_2);";
    $SOURCE1 .= "
        int fieldPointerLevel(struct FieldPointerLevel param, int param_2) { return param_2; }";
    
    $HEADER2 .= "
        struct FieldPointerLevel
        {
            int i;
            long **j;
            double k;
            struct FieldPointerLevel* p;
        };
        $DECL_SPEC int fieldPointerLevel(struct FieldPointerLevel param, int param_2);";
    $SOURCE2 .= "
        int fieldPointerLevel(struct FieldPointerLevel param, int param_2) { return param_2; }";
    
    # Added_Interface
    $HEADER2 .= "
        $DECL_SPEC int addedFunc4(int param);";
    $SOURCE2 .= "
        int addedFunc4(int param) { return param; }";
    
    # Removed_Interface
    $HEADER1 .= "
        $DECL_SPEC int removedFunc(int param);";
    $SOURCE1 .= "
        int removedFunc(int param) { return param; }";
    
    # Parameter_Type_And_Size
    $HEADER1 .= "
        $DECL_SPEC int parameterTypeAndSize(int param, int other_param);";
    $SOURCE1 .= "
        int parameterTypeAndSize(int param, int other_param) { return other_param; }";
    
    $HEADER2 .= "
        $DECL_SPEC int parameterTypeAndSize(long long param, int other_param);";
    $SOURCE2 .= "
        int parameterTypeAndSize(long long param, int other_param) { return other_param; }";
    
    # Parameter_Type_And_Size + Parameter_Became_Non_Const
    $HEADER1 .= "
        $DECL_SPEC int parameterTypeAndSizeBecameNonConst(int* const param, int other_param);";
    $SOURCE1 .= "
        int parameterTypeAndSizeBecameNonConst(int* const param, int other_param) { return other_param; }";
    
    $HEADER2 .= "
        $DECL_SPEC int parameterTypeAndSizeBecameNonConst(long double param, int other_param);";
    $SOURCE2 .= "
        int parameterTypeAndSizeBecameNonConst(long double param, int other_param) { return other_param; }";

    # Parameter_Type_And_Size (test calling conventions)
    $HEADER1 .= "
        $DECL_SPEC int parameterCallingConvention(int p1, int p2, int p3);";
    $SOURCE1 .= "
        int parameterCallingConvention(int p1, int p2, int p3) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC float parameterCallingConvention(char p1, int p2, int p3);";
    $SOURCE2 .= "
        float parameterCallingConvention(char p1, int p2, int p3) { return 7.0f; }";
    
    # Parameter_Type
    $HEADER1 .= "
        $DECL_SPEC int parameterType(int param, int other_param);";
    $SOURCE1 .= "
        int parameterType(int param, int other_param) { return other_param; }";
    
    $HEADER2 .= "
        $DECL_SPEC int parameterType(float param, int other_param);";
    $SOURCE2 .= "
        int parameterType(float param, int other_param) { return other_param; }";
    
    # Parameter_Became_Non_Const
    $HEADER1 .= "
        $DECL_SPEC int parameterBecameNonConst(int const* param);";
    $SOURCE1 .= "
        int parameterBecameNonConst(int const* param) { return *param; }";
    
    $HEADER2 .= "
        $DECL_SPEC int parameterBecameNonConst(int* param);";
    $SOURCE2 .= "
        int parameterBecameNonConst(int* param) {
            *param=10;
            return *param;
        }";
    
    # Parameter_Became_Non_Const + Parameter_Became_Non_Volatile
    $HEADER1 .= "
        $DECL_SPEC int parameterBecameNonConstNonVolatile(int const volatile* param);";
    $SOURCE1 .= "
        int parameterBecameNonConstNonVolatile(int const volatile* param) { return *param; }";
    
    $HEADER2 .= "
        $DECL_SPEC int parameterBecameNonConstNonVolatile(int* param);";
    $SOURCE2 .= "
        int parameterBecameNonConstNonVolatile(int* param) {
            *param=10;
            return *param;
        }";
    
    # Parameter_BaseType (Typedef)
    $HEADER1 .= "
        typedef int* PARAM_TYPEDEF;
        $DECL_SPEC int parameterBaseTypedefChange(PARAM_TYPEDEF param);";
    $SOURCE1 .= "
        int parameterBaseTypedefChange(PARAM_TYPEDEF param) { return 0; }";
    
    $HEADER2 .= "
        typedef const int* PARAM_TYPEDEF;
        $DECL_SPEC int parameterBaseTypedefChange(PARAM_TYPEDEF param);";
    $SOURCE2 .= "
        int parameterBaseTypedefChange(PARAM_TYPEDEF param) { return 0; }";
    
    # Parameter_BaseType
    $HEADER1 .= "
        $DECL_SPEC int parameterBaseTypeChange(int *param);";
    $SOURCE1 .= "
        int parameterBaseTypeChange(int *param) { return sizeof(*param); }";
    
    $HEADER2 .= "
        $DECL_SPEC int parameterBaseTypeChange(long long *param);";
    $SOURCE2 .= "
        int parameterBaseTypeChange(long long *param) { return sizeof(*param); }";
    
    # Parameter_PointerLevel
    $HEADER1 .= "
        $DECL_SPEC long long parameterPointerLevelAndSize(long long param);";
    $SOURCE1 .= "
        long long parameterPointerLevelAndSize(long long param) { return param; }";
    
    $HEADER2 .= "
        $DECL_SPEC long long parameterPointerLevelAndSize(long long *param);";
    $SOURCE2 .= "
        long long parameterPointerLevelAndSize(long long *param) { return param[5]; }";
    
    # Parameter_PointerLevel
    $HEADER1 .= "
        $DECL_SPEC int parameterPointerLevel(int *param);";
    $SOURCE1 .= "
        int parameterPointerLevel(int *param) { return param[5]; }";
    
    $HEADER2 .= "
        $DECL_SPEC int parameterPointerLevel(int **param);";
    $SOURCE2 .= "
        int parameterPointerLevel(int **param) { return param[5][5]; }";
    
    # Return_Type_And_Size
    $HEADER1 .= "
        $DECL_SPEC int returnTypeAndSize(int param);";
    $SOURCE1 .= "
        int returnTypeAndSize(int param) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC long long returnTypeAndSize(int param);";
    $SOURCE2 .= "
        long long returnTypeAndSize(int param) { return 0; }";
    
    # Return_Type
    $HEADER1 .= "
        $DECL_SPEC int returnType(int param);";
    $SOURCE1 .= "
        int returnType(int param) { return 1; }";
    
    $HEADER2 .= "
        $DECL_SPEC float returnType(int param);";
    $SOURCE2 .= "
        float returnType(int param) { return 1; }";

    # Return_Type_Became_Void ("int" to "void")
    $HEADER1 .= "
        $DECL_SPEC int returnTypeChangeToVoid(int param);";
    $SOURCE1 .= "
        int returnTypeChangeToVoid(int param) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC void returnTypeChangeToVoid(int param);";
    $SOURCE2 .= "
        void returnTypeChangeToVoid(int param) { return; }";

    # Return_Type ("struct" to "void*")
    $HEADER1 .= "
        struct SomeStruct {
            int a;
            double b, c, d;
        };
        $DECL_SPEC struct SomeStruct* returnTypeChangeToVoidPtr(int param);";
    $SOURCE1 .= "
        struct SomeStruct* returnTypeChangeToVoidPtr(int param) { return (struct SomeStruct*)0; }";
    
    $HEADER2 .= "
        struct SomeStruct {
            int a;
            double b, c, d;
        };
        $DECL_SPEC void* returnTypeChangeToVoidPtr(int param);";
    $SOURCE2 .= "
        void* returnTypeChangeToVoidPtr(int param) { return (void*)0; }";
    
    # Return_Type (structure change)
    $HEADER1 .= "
        struct SomeStruct2 {
            int a;
            int b;
        };
        $DECL_SPEC struct SomeStruct2 returnType2(int param);";
    $SOURCE1 .= "
        struct SomeStruct2 returnType2(int param) { struct SomeStruct2 r = {1, 2};return r; }";
    
    $HEADER2 .= "
        struct SomeStruct2 {
            int a;
        };
        $DECL_SPEC struct SomeStruct2 returnType2(int param);";
    $SOURCE2 .= "
        struct SomeStruct2 returnType2(int param) { struct SomeStruct2 r = {1};return r; }";
        
    # Return_Type (structure change)
    $HEADER1 .= "
        struct SomeStruct3 {
            int a;
            int b;
        };
        $DECL_SPEC struct SomeStruct3 returnType3(int param);";
    $SOURCE1 .= "
        struct SomeStruct3 returnType3(int param) { struct SomeStruct3 r = {1, 2};return r; }";
    
    $HEADER2 .= "
        struct SomeStruct3 {
            int a;
            long double b;
        };
        $DECL_SPEC struct SomeStruct3 returnType3(int param);";
    $SOURCE2 .= "
        struct SomeStruct3 returnType3(int param) { struct SomeStruct3 r = {1, 2.0L};return r; }";

    # Return_Type_From_Void_And_Stack_Layout ("void" to "struct")
    $HEADER1 .= "
        $DECL_SPEC void returnTypeChangeFromVoidToStruct(int param);";
    $SOURCE1 .= "
        void returnTypeChangeFromVoidToStruct(int param) { return; }";
    
    $HEADER2 .= "
        $DECL_SPEC struct SomeStruct returnTypeChangeFromVoidToStruct(int param);";
    $SOURCE2 .= "
        struct SomeStruct returnTypeChangeFromVoidToStruct(int param) {
            struct SomeStruct obj = {1,2};
            return obj;
        }";

    # Return_Type_Became_Void_And_Stack_Layout ("struct" to "void")
    $HEADER1 .= "
        $DECL_SPEC struct SomeStruct returnTypeChangeFromStructToVoid(int param);";
    $SOURCE1 .= "
        struct SomeStruct returnTypeChangeFromStructToVoid(int param) {
            struct SomeStruct obj = {1,2};
            return obj;
        }";
    
    $HEADER2 .= "
        $DECL_SPEC void returnTypeChangeFromStructToVoid(int param);";
    $SOURCE2 .= "
        void returnTypeChangeFromStructToVoid(int param) { return; }";
    
    # Return_Type_From_Void_And_Stack_Layout (safe, "void" to "long")
    $HEADER1 .= "
        $DECL_SPEC void returnTypeChangeFromVoidToLong(int param);";
    $SOURCE1 .= "
        void returnTypeChangeFromVoidToLong(int param) { return; }";
    
    $HEADER2 .= "
        $DECL_SPEC long returnTypeChangeFromVoidToLong(int param);";
    $SOURCE2 .= "
        long returnTypeChangeFromVoidToLong(int param) { return 0; }";

    # Return_Type_From_Void_And_Stack_Layout (safe, "void" to "void*")
    $HEADER1 .= "
        $DECL_SPEC void returnTypeChangeFromVoidToVoidPtr(int param);";
    $SOURCE1 .= "
        void returnTypeChangeFromVoidToVoidPtr(int param) { return; }";
    
    $HEADER2 .= "
        $DECL_SPEC void* returnTypeChangeFromVoidToVoidPtr(int param);";
    $SOURCE2 .= "
        void* returnTypeChangeFromVoidToVoidPtr(int param) { return 0; }";
    
    # Return_Type_From_Register_To_Stack ("int" to "struct")
    $HEADER1 .= "
        $DECL_SPEC int returnTypeChangeFromIntToStruct(int param);";
    $SOURCE1 .= "
        int returnTypeChangeFromIntToStruct(int param) { return param; }";
    
    $HEADER2 .= "
        $DECL_SPEC struct SomeStruct returnTypeChangeFromIntToStruct(int param);";
    $SOURCE2 .= "
        struct SomeStruct returnTypeChangeFromIntToStruct(int param) {
            struct SomeStruct obj = {1,2};
            return obj;
        }";
    
    # Return_Type_From_Stack_To_Register (from struct to int)
    $HEADER1 .= "
        $DECL_SPEC struct SomeStruct returnTypeChangeFromStructToInt(int param);";
    $SOURCE1 .= "
        struct SomeStruct returnTypeChangeFromStructToInt(int param) {
            struct SomeStruct obj = {1,2};
            return obj;
        }";
    
    $HEADER2 .= "
        $DECL_SPEC int returnTypeChangeFromStructToInt(int param);";
    $SOURCE2 .= "
        int returnTypeChangeFromStructToInt(int param) { return param; }";

     # Return_Type_From_Stack_To_Register (from struct to int, without parameters)
    $HEADER1 .= "
        $DECL_SPEC struct SomeStruct returnTypeChangeFromStructToIntWithNoParams();";
    $SOURCE1 .= "
        struct SomeStruct returnTypeChangeFromStructToIntWithNoParams() {
            struct SomeStruct obj = {1,2};
            return obj;
        }";
    
    $HEADER2 .= "
        $DECL_SPEC int returnTypeChangeFromStructToIntWithNoParams();";
    $SOURCE2 .= "
        int returnTypeChangeFromStructToIntWithNoParams() { return 0; }";
    
    # Return_BaseType
    $HEADER1 .= "
        $DECL_SPEC int *returnBaseTypeChange(int param);";
    $SOURCE1 .= "
        int *returnBaseTypeChange(int param) { return (int*)0; }";
    
    $HEADER2 .= "
        $DECL_SPEC long long *returnBaseTypeChange(int param);";
    $SOURCE2 .= "
        long long *returnBaseTypeChange(int param) { return (long long*)0; }";
    
    # Return_PointerLevel
    $HEADER1 .= "
        $DECL_SPEC long long returnPointerLevelAndSize(int param);";
    $SOURCE1 .= "
        long long returnPointerLevelAndSize(int param) { return 100; }";
    
    $HEADER2 .= "
        $DECL_SPEC long long *returnPointerLevelAndSize(int param);";
    $SOURCE2 .= "
        long long *returnPointerLevelAndSize(int param) { return (long long *)0; }";
    
    # Return_PointerLevel
    $HEADER1 .= "
        $DECL_SPEC long long *returnPointerLevel(int param);";
    $SOURCE1 .= "
        long long *returnPointerLevel(int param) { return (long long *)0; }";
    
    $HEADER2 .= "
        $DECL_SPEC long long **returnPointerLevel(int param);";
    $SOURCE2 .= "
        long long **returnPointerLevel(int param) { return (long long **)0; }";
    
    # Size (typedef to anon structure)
    $HEADER1 .= "
        typedef struct
        {
            int i;
            long j;
            double k;
        } AnonTypedef;
        $DECL_SPEC int anonTypedef(AnonTypedef param);";
    $SOURCE1 .= "
        int anonTypedef(AnonTypedef param) { return 0; }";
    
    $HEADER2 .= "
        typedef struct
        {
            int i;
            long j;
            double k;
            union {
                int dummy[256];
                struct {
                    char q_skiptable[256];
                    const char *p;
                    int l;
                } p;
            };
        } AnonTypedef;
        $DECL_SPEC int anonTypedef(AnonTypedef param);";
    $SOURCE2 .= "
        int anonTypedef(AnonTypedef param) { return 0; }";
    
    # Size (safe: opaque)
    $HEADER1 .= "
        struct OpaqueType
        {
            long long i[5];
            long j;
            double k;
            struct OpaqueType* p;
        };
        $DECL_SPEC int opaqueTypeUse(struct OpaqueType param, int param_2);";
    $SOURCE1 .= "
        int opaqueTypeUse(struct OpaqueType param, int param_2) { return param_2; }";
    
    $HEADER2 .= "
        struct OpaqueType
        {
            long long i[5];
            long long j;
            double k;
            struct OpaqueType* p;
        };
        $DECL_SPEC int opaqueTypeUse(struct OpaqueType param, int param_2);";
    $SOURCE2 .= "
        int opaqueTypeUse(struct OpaqueType param, int param_2) { return param_2; }";
    
    # Size (safe: internal)
    $HEADER1 .= "
        struct InternalType
        {
            long long i[5];
            long j;
            double k;
            struct InternalType* p;
        };
        $DECL_SPEC int internalTypeUse(struct InternalType param, int param_2);";
    $SOURCE1 .= "
        int internalTypeUse(struct InternalType param, int param_2) { return param_2; }";
    
    $HEADER2 .= "
        struct InternalType
        {
            long long i[5];
            long long j;
            double k;
            struct InternalType* p;
        };
        $DECL_SPEC int internalTypeUse(struct InternalType param, int param_2);";
    $SOURCE2 .= "
        int internalTypeUse(struct InternalType param, int param_2) { return param_2; }";
    
    if($In::Opt{"OS"} eq "linux")
    {
        # Changed version
        $HEADER1 .= "
            $DECL_SPEC int changedVersion(int param);
            $DECL_SPEC int changedDefaultVersion(int param);";
        $SOURCE1 .= "
            int changedVersion(int param) { return 0; }
            __asm__(\".symver changedVersion,changedVersion\@VERSION_2.0\");
            int changedDefaultVersion(int param) { return 0; }";
        
        $HEADER2 .= "
            $DECL_SPEC int changedVersion(int param);
            $DECL_SPEC int changedDefaultVersion(long param);";
        $SOURCE2 .= "
            int changedVersion(int param) { return 0; }
            __asm__(\".symver changedVersion,changedVersion\@VERSION_3.0\");
            int changedDefaultVersion(long param) { return 0; }";
        
        # Unchanged version
        $HEADER1 .= "
            $DECL_SPEC int unchangedVersion(int param);
            $DECL_SPEC int unchangedDefaultVersion(int param);";
        $SOURCE1 .= "
            int unchangedVersion(int param) { return 0; }
            __asm__(\".symver unchangedVersion,unchangedVersion\@VERSION_1.0\");
            int unchangedDefaultVersion(int param) { return 0; }";
        
        $HEADER2 .= "
            $DECL_SPEC int unchangedVersion(int param);
            $DECL_SPEC int unchangedDefaultVersion(int param);";
        $SOURCE2 .= "
            int unchangedVersion(int param) { return 0; }
            __asm__(\".symver unchangedVersion,unchangedVersion\@VERSION_1.0\");
            int unchangedDefaultVersion(int param) { return 0; }";
        
        # Non-Default to Default
        $HEADER1 .= "
            $DECL_SPEC int changedVersionToDefault(int param);";
        $SOURCE1 .= "
            int changedVersionToDefault(int param) { return 0; }
            __asm__(\".symver changedVersionToDefault,changedVersionToDefault\@VERSION_1.0\");";
        
        $HEADER2 .= "
            $DECL_SPEC int changedVersionToDefault(long param);";
        $SOURCE2 .= "
            int changedVersionToDefault(long param) { return 0; }";
        
        # Default to Non-Default
        $HEADER1 .= "
            $DECL_SPEC int changedVersionToNonDefault(int param);";
        $SOURCE1 .= "
            int changedVersionToNonDefault(int param) { return 0; }";
        
        $HEADER2 .= "
            $DECL_SPEC int changedVersionToNonDefault(long param);";
        $SOURCE2 .= "
            int changedVersionToNonDefault(long param) { return 0; }
            __asm__(\".symver changedVersionToNonDefault,changedVersionToNonDefault\@VERSION_3.0\");";
        
        # Added version
        $HEADER1 .= "
            $DECL_SPEC int addedVersion(int param);
            $DECL_SPEC int addedDefaultVersion(int param);";
        $SOURCE1 .= "
            int addedVersion(int param) { return 0; }
            int addedDefaultVersion(int param) { return 0; }";
        
        $HEADER2 .= "
            $DECL_SPEC int addedVersion(int param);
            $DECL_SPEC int addedDefaultVersion(int param);";
        $SOURCE2 .= "
            int addedVersion(int param) { return 0; }
            __asm__(\".symver addedVersion,addedVersion\@VERSION_2.0\");
            int addedDefaultVersion(int param) { return 0; }";

        # Removed version
        $HEADER1 .= "
            $DECL_SPEC int removedVersion(int param);
            $DECL_SPEC int removedVersion2(int param);
            $DECL_SPEC int removedDefaultVersion(int param);";
        $SOURCE1 .= "
            int removedVersion(int param) { return 0; }
            __asm__(\".symver removedVersion,removedVersion\@VERSION_1.0\");
            int removedVersion2(int param) { return 0; }
            __asm__(\".symver removedVersion2,removedVersion\@VERSION_3.0\");
            int removedDefaultVersion(int param) { return 0; }";
        
        $HEADER2 .= "
            $DECL_SPEC int removedVersion(int param);
            $DECL_SPEC int removedVersion2(int param);
            $DECL_SPEC int removedDefaultVersion(int param);";
        $SOURCE2 .= "
            int removedVersion(int param) { return 0; }
            int removedVersion2(int param) { return 0; }
            __asm__(\".symver removedVersion2,removedVersion\@VERSION_3.0\");
            int removedDefaultVersion(int param) { return 0; }";
        
        # Return_Type (good versioning)
        $HEADER1 .= "
            $DECL_SPEC int goodVersioning(int param);";
        $SOURCE1 .= "
            int goodVersioning(int param) { return 0; }
            __asm__(\".symver goodVersioning,goodVersioning\@VERSION_1.0\");";
        
        $HEADER2 .= "
            $DECL_SPEC int goodVersioningOld(int param);";
        $SOURCE2 .= "
            int goodVersioningOld(int param) { return 0; }
            __asm__(\".symver goodVersioningOld,goodVersioning\@VERSION_1.0\");";
        
        $HEADER2 .= "
            $DECL_SPEC float goodVersioning(int param);";
        $SOURCE2 .= "
            float goodVersioning(int param) { return 0.7; }
            __asm__(\".symver goodVersioning,goodVersioning\@VERSION_2.0\");";
        
        # Return_Type (bad versioning)
        $HEADER1 .= "
            $DECL_SPEC int badVersioning(int param);";
        $SOURCE1 .= "
            int badVersioning(int param) { return 0; }
            __asm__(\".symver badVersioning,badVersioning\@VERSION_1.0\");";
        
        $HEADER2 .= "
            $DECL_SPEC float badVersioningOld(int param);";
        $SOURCE2 .= "
            float badVersioningOld(int param) { return 0.7; }
            __asm__(\".symver badVersioningOld,badVersioning\@VERSION_1.0\");";
        
        $HEADER2 .= "
            $DECL_SPEC float badVersioning(int param);";
        $SOURCE2 .= "
            float badVersioning(int param) { return 0.7; }
            __asm__(\".symver badVersioning,badVersioning\@VERSION_2.0\");";
    }
    # unnamed struct/union fields within structs/unions
    $HEADER1 .= "
        typedef struct
        {
            int a;
            union {
                int b;
                float c;
            };
            int d;
        } UnnamedTypeSize;
        $DECL_SPEC int unnamedTypeSize(UnnamedTypeSize param);";
    $SOURCE1 .= "
        int unnamedTypeSize(UnnamedTypeSize param) { return 0; }";
    
    $HEADER2 .= "
        typedef struct
        {
            int a;
            union {
                long double b;
                float c;
            };
            int d;
        } UnnamedTypeSize;
        $DECL_SPEC int unnamedTypeSize(UnnamedTypeSize param);";
    $SOURCE2 .= "
        int unnamedTypeSize(UnnamedTypeSize param) { return 0; }";
    
    # Changed_Constant (#define)
    $HEADER1 .= "
        #define PUBLIC_CONSTANT \"old_value\"";
    $HEADER2 .= "
        #define PUBLIC_CONSTANT \"new_value\"";
    
    # Changed_Constant (Safe)
    $HEADER1 .= "
        #define INTEGER_CONSTANT 0x01";
    $HEADER2 .= "
        #define INTEGER_CONSTANT 1";
    
    # Changed_Constant (Safe)
    $HEADER1 .= "
        #define PRIVATE_CONSTANT \"old_value\"
        #undef PRIVATE_CONSTANT";
    $HEADER2 .= "
        #define PRIVATE_CONSTANT \"new_value\"
        #undef PRIVATE_CONSTANT";
    
    # Changed_Constant (enum)
    $HEADER1 .= "
        enum {
            SOME_CONSTANT=0x1
        };";
    $HEADER2 .= "
        enum {
            SOME_CONSTANT=0x2
        };";
    
    # Added_Constant (#define)
    $HEADER2 .= "
        #define ADDED_CNST \"value\"";
        
    # Added_Constant (enum)
    $HEADER1 .= "
        enum {
            CONSTANT1
        };";
    $HEADER2 .= "
        enum {
            CONSTANT1,
            ADDED_CONSTANT
        };";
        
    # Removed_Constant (#define)
    $HEADER1 .= "
        #define REMOVED_CNST \"value\"";
    
    # Removed_Constant (enum)
    $HEADER1 .= "
        enum {
            CONSTANT2,
            REMOVED_CONSTANT
        };";
    $HEADER2 .= "
        enum {
            CONSTANT2
        };";
    
    # Added_Field (union)
    $HEADER1 .= "
        union UnionTypeAddedField
        {
            int a;
            struct {
                int b;
                float c;
            };
            int d;
        };
        $DECL_SPEC int unionTypeAddedField(union UnionTypeAddedField param);";
    $SOURCE1 .= "
        int unionTypeAddedField(union UnionTypeAddedField param) { return 0; }";
    
    $HEADER2 .= "
        union UnionTypeAddedField
        {
            int a;
            struct {
                long double x, y;
            } new_field;
            struct {
                int b;
                float c;
            };
            int d;
        };
        $DECL_SPEC int unionTypeAddedField(union UnionTypeAddedField param);";
    $SOURCE2 .= "
        int unionTypeAddedField(union UnionTypeAddedField param) { return 0; }";
    
    # Prameter_BaseType (typedef)
    $HEADER1 .= "
        typedef float TYPEDEF_TYPE;
        $DECL_SPEC int parameterTypedefChange(TYPEDEF_TYPE param);";
    $SOURCE1 .= "
        int parameterTypedefChange(TYPEDEF_TYPE param) { return 1.0; }";
    
    $HEADER2 .= "
        typedef int TYPEDEF_TYPE;
        $DECL_SPEC int parameterTypedefChange(TYPEDEF_TYPE param);";
    $SOURCE2 .= "
        int parameterTypedefChange(TYPEDEF_TYPE param) { return 1; }";
    
    # Field_BaseType (typedef in member type)
    $HEADER1 .= "
        typedef float TYPEDEF_TYPE_2;
        struct FieldBaseTypedefChange {
            TYPEDEF_TYPE_2 m;
        };
        $DECL_SPEC int fieldBaseTypedefChange(struct FieldBaseTypedefChange param);";
    $SOURCE1 .= "
        int fieldBaseTypedefChange(struct FieldBaseTypedefChange param) { return 1; }";
    
    $HEADER2 .= "
        typedef int TYPEDEF_TYPE_2;
        struct FieldBaseTypedefChange {
            TYPEDEF_TYPE_2 m;
        };
        $DECL_SPEC int fieldBaseTypedefChange(struct FieldBaseTypedefChange param);";
    $SOURCE2 .= "
        int fieldBaseTypedefChange(struct FieldBaseTypedefChange param) { return 1; }";
    
    # C++ keywords in C code
    $HEADER1 .= "
        $DECL_SPEC int testCppKeywords1(int class, int virtual, int (*new)(int));";
    $SOURCE1 .= "
        $DECL_SPEC int testCppKeywords1(int class, int virtual, int (*new)(int)) { return 0; }";
    
    $HEADER2 .= "
        $DECL_SPEC int testCppKeywords1(int class, int virtual);
        $DECL_SPEC int testCppKeywords2(int operator, int other);
        $DECL_SPEC int testCppKeywords3(int operator);
        $DECL_SPEC int operator(int class, int this);
        $DECL_SPEC int delete(int virtual, int* this);
        $DECL_SPEC int testCppKeywords4(int* param, int export);
        struct CppKeywords {
            int bool: 8;
            //int*this;
        };
        #ifdef __cplusplus
            class TestCppKeywords {
                void operator delete(void*);
                void operator ()(int);
                void operator,(int);
                void delete() {
                    delete this;
                };
            };
        #endif";
    $SOURCE2 .= "
        $DECL_SPEC int testCppKeywords1(int class, int virtual) { return 0; }
        $DECL_SPEC int testCppKeywords2(int operator, int other) { return 0; }
        $DECL_SPEC int testCppKeywords3(int operator) { return 0; }
        $DECL_SPEC int operator(int class, int this) { return 0; }
        $DECL_SPEC int delete(int virtual, int* this) { return 0; }
        $DECL_SPEC int testCppKeywords4(int* param, int export) { return 0; }";
    
    # Regression
    $HEADER1 .= "
        $DECL_SPEC int* testRegression(int *pointer, char const *name, ...);";
    $SOURCE1 .= "
        int* testRegression(int *pointer, char const *name, ...) { return 0; }";

    $HEADER2 .= "
        $DECL_SPEC int* testRegression(int *pointer, char const *name, ...);";
    $SOURCE2 .= "
        int* testRegression(int *pointer, char const *name, ...) { return 0; }";
    
    runTests("libsample_c", "C", $HEADER1, $SOURCE1, $HEADER2, $SOURCE2, "struct OpaqueType", "internalTypeUse");
}

sub runTests($$$$$$$$)
{
    my ($LibName, $Lang, $HEADER1, $SOURCE1, $HEADER2, $SOURCE2, $Opaque, $Private) = @_;
    
    my $LExt = $In::Opt{"Ext"};
    my $GccPath = $In::Opt{"GccPath"};
    
    my $SrcE = ($Lang eq "C++")?"cpp":"c";
    rmtree($LibName);
    
    my $ObjName = "libsample";
    
    # creating test suite
    my $Path_v1 = "$LibName/$ObjName.v1";
    my $Path_v2 = "$LibName/$ObjName.v2";
    mkpath($Path_v1);
    mkpath($Path_v2);
    writeFile("$Path_v1/$ObjName.h", $HEADER1."\n");
    writeFile("$Path_v1/$ObjName.$SrcE", "#include \"$ObjName.h\"\n".$SOURCE1."\n");
    
    writeFile("$LibName/v1.xml", "
        <version>
            1.0
        </version>
        
        <headers>
            ".getAbsPath($Path_v1)."
        </headers>
        
        <libs>
            ".getAbsPath($Path_v1)."
        </libs>
        
        <include_paths>
            ".getAbsPath($Path_v1)."
        </include_paths>
    ");
    
    writeFile("$Path_v1/test.$SrcE", "
        #include \"$ObjName.h\"
        #include <stdio.h>
        ".($Lang eq "C++"?"using namespace TestNS;":"")."
        int main()
        {
            int ret = 0;
            printf(\"\%d\\n\", ret);
            return 0;
        }
    ");
    
    writeFile("$Path_v2/$ObjName.h", $HEADER2."\n");
    writeFile("$Path_v2/$ObjName.$SrcE", "#include \"$ObjName.h\"\n".$SOURCE2."\n");
    writeFile("$LibName/v2.xml", "
        <version>
            2.0
        </version>
        
        <headers>
            ".getAbsPath($Path_v2)."
        </headers>
        
        <libs>
            ".getAbsPath($Path_v2)."
        </libs>
        
        <include_paths>
            ".getAbsPath($Path_v2)."
        </include_paths>
    ");
    
    writeFile("$Path_v2/test.$SrcE", "
        #include \"$ObjName.h\"
        #include <stdio.h>
        ".($Lang eq "C++"?"using namespace TestNS;":"")."
        int main()
        {
            int ret = 0;
            printf(\"\%d\\n\", ret);
            return 0;
        }
    ");
    
    writeFile("$LibName/filt.xml", "
        <skip_types>
            $Opaque
        </skip_types>
        
        <skip_symbols>
            $Private
        </skip_symbols>
    ");
    
    my ($BuildCmd, $BuildCmd_Test) = ("", "");
    
    if($In::Opt{"OS"} eq "linux")
    {
        if($Lang eq "C")
        { # tests for symbol versioning
            writeFile("$Path_v1/version", "
                VERSION_1.0 {
                    unchangedDefaultVersion;
                    removedDefaultVersion;
                };
                VERSION_2.0 {
                    changedDefaultVersion;
                };
                VERSION_3.0 {
                    changedVersionToNonDefault;
                };
            ");
            writeFile("$Path_v2/version", "
                VERSION_1.0 {
                    unchangedDefaultVersion;
                    changedVersionToDefault;
                };
                VERSION_2.0 {
                    addedDefaultVersion;
                };
                VERSION_3.0 {
                    changedDefaultVersion;
                };
            ");
            $BuildCmd = $GccPath." -Wl,--version-script version -shared $ObjName.$SrcE -o $ObjName.$LExt -g -Og";
            $BuildCmd_Test = $GccPath." -Wl,--version-script version test.$SrcE -Wl,$ObjName.$LExt -o test";
        }
        else
        {
            $BuildCmd = $GccPath." -shared -x c++ $ObjName.$SrcE -lstdc++ -o $ObjName.$LExt -g -Og";
            $BuildCmd_Test = $GccPath." -x c++ test.$SrcE -lstdc++ -Wl,$ObjName.$LExt -o test";
        }
        if(getArch_GCC(1)=~/\A(arm|x86_64)\Z/i)
        { # relocation R_ARM_MOVW_ABS_NC against `a local symbol' can not be used when making a shared object; recompile with -fPIC
            $BuildCmd .= " -fPIC -DPIC";
            $BuildCmd_Test .= " -fPIC -DPIC";
        }
    }
    elsif($In::Opt{"OS"} eq "macos")
    { # using GCC -dynamiclib
        if($Lang eq "C")
        {
            $BuildCmd = $GccPath." -dynamiclib $ObjName.$SrcE -o $ObjName.$LExt";
            $BuildCmd_Test = $GccPath." test.$SrcE $ObjName.$LExt -o test";
        }
        else
        { # C++
            $BuildCmd = $GccPath." -dynamiclib -x c++ $ObjName.$SrcE -lstdc++ -o $ObjName.$LExt";
            $BuildCmd_Test = $GccPath." -x c++ test.$SrcE $ObjName.$LExt -o test";
        }
    }
    elsif($In::Opt{"OS"} eq "windows")
    {
        checkWin32Env(); # to run MS VC++ compiler
        my $CL = getCmdPath("cl");
        
        if(not $CL) {
            exitStatus("Not_Found", "can't find \"cl\" compiler");
        }
        $BuildCmd = "$CL /LD $ObjName.$SrcE >build_log.txt 2>&1";
        $BuildCmd_Test = "$CL test.$SrcE $ObjName.$LExt";
    }
    else
    { # default unix-like
        if($Lang eq "C")
        {
            $BuildCmd = $GccPath." -shared $ObjName.$SrcE -o $ObjName.$LExt -g -Og";
            $BuildCmd_Test = $GccPath." test.$SrcE -Wl,$ObjName.$LExt -o test";
        }
        else
        { # C++
            $BuildCmd = $GccPath." -shared -x c++ $ObjName.$SrcE -lstdc++ -o $ObjName.$LExt -g -Og";
            $BuildCmd_Test = $GccPath." -x c++ test.$SrcE -Wl,$ObjName.$LExt -o test";
        }
        
        if(getArch_GCC(1)=~/\A(arm|x86_64)\Z/i)
        {
            $BuildCmd .= " -fPIC -DPIC";
            $BuildCmd_Test .= " -fPIC -DPIC";
        }
    }
    
    if(my $Opts = getGccOptions(1))
    { # user-defined options
        $BuildCmd .= " ".$Opts;
        $BuildCmd_Test .= " ".$Opts;
    }
    
    my $MkContent = "all:\n\t$BuildCmd\ntest:\n\t$BuildCmd_Test\n";
    if($In::Opt{"OS"} eq "windows") {
        $MkContent .= "clean:\n\tdel test $ObjName.so\n";
    }
    else {
        $MkContent .= "clean:\n\trm test $ObjName.so\n";
    }
    writeFile("$Path_v1/Makefile", $MkContent);
    writeFile("$Path_v2/Makefile", $MkContent);
    system("cd $Path_v1 && $BuildCmd >build-log.txt 2>&1");
    if($?)
    {
        my $Msg = "can't compile $LibName v.1: \'$Path_v1/build-log.txt\'";
        if(readFile("$Path_v1/build-log.txt")=~/error trying to exec \W+cc1plus\W+/) {
            $Msg .= "\nDid you install G++?";
        }
        exitStatus("Error", $Msg);
    }
    system("cd $Path_v2 && $BuildCmd >build-log.txt 2>&1");
    if($?) {
        exitStatus("Error", "can't compile $LibName v.2: \'$Path_v2/build-log.txt\'");
    }
    
    # executing the tool
    my @Cmd = ("perl", $0, "-l", $LibName);
    
    if($In::Opt{"TestABIDumper"}
    and $In::Opt{"OS"} eq "linux")
    {
        my @Cmd_d1 = ("abi-dumper", $Path_v1."/".$ObjName.".".$LExt, "-o", $LibName."/ABIv1.dump");
        @Cmd_d1 = (@Cmd_d1, "-public-headers", $Path_v1, "-lver", "1.0");
        if($In::Opt{"Debug"})
        { # debug mode
            printMsg("INFO", "Executing @Cmd_d1");
        }
        system(@Cmd_d1);
        printMsg("INFO", "");
        
        my @Cmd_d2 = ("abi-dumper", $Path_v2."/".$ObjName.".".$LExt, "-o", $LibName."/ABIv2.dump");
        @Cmd_d2 = (@Cmd_d2, "-public-headers", $Path_v2, "-lver", "2.0");
        if($In::Opt{"Debug"})
        { # debug mode
            printMsg("INFO", "Executing @Cmd_d2");
        }
        system(@Cmd_d2);
        printMsg("INFO", "");
        
        @Cmd = (@Cmd, "-old", $LibName."/ABIv1.dump", "-new", $LibName."/ABIv2.dump");
    }
    else
    {
        @Cmd = (@Cmd, "-old", "$LibName/v1.xml", "-new", "$LibName/v2.xml");
    }
    
    @Cmd = (@Cmd, "-filter", "$LibName/filt.xml");
    
    if($Lang eq "C") {
        @Cmd = (@Cmd, "-cxx-incompatible");
    }
    
    @Cmd = (@Cmd, "-lang", $Lang);
    
    if($In::Opt{"TestDump"})
    {
        @Cmd = (@Cmd, "-use-dumps");
        if($In::Opt{"SortDump"}) {
            @Cmd = (@Cmd, "-sort");
        }
    }
    if($In::Opt{"DumpFormat"} and $In::Opt{"DumpFormat"} ne "perl")
    { # Perl Data::Dumper is default format
        @Cmd = (@Cmd, "-dump-format", $In::Opt{"DumpFormat"});
    }
    if($GccPath ne "gcc") {
        @Cmd = (@Cmd, "-cross-gcc", $GccPath);
    }
    if($In::Opt{"Quiet"})
    { # quiet mode
        @Cmd = (@Cmd, "-quiet");
        @Cmd = (@Cmd, "-logging-mode", "a");
    }
    elsif($In::Opt{"LogMode"}
    and $In::Opt{"LogMode"} ne "w")
    { # "w" is default
        @Cmd = (@Cmd, "-logging-mode", $In::Opt{"LogMode"});
    }
    if($In::Opt{"ExtendedCheck"})
    { # extended mode
        @Cmd = (@Cmd, "-extended");
        if($Lang eq "C") {
            @Cmd = (@Cmd, "-lang", "C");
        }
    }
    if($In::Opt{"ReportFormat"}
    and $In::Opt{"ReportFormat"} ne "html")
    { # HTML is default format
        @Cmd = (@Cmd, "-report-format", $In::Opt{"ReportFormat"});
    }
    if($In::Opt{"CheckHeadersOnly"}) {
        @Cmd = (@Cmd, "-headers-only");
    }
    if($In::Opt{"OldStyle"}) {
        @Cmd = (@Cmd, "-old-style");
    }
    
    if($In::Opt{"DebugMangling"}) {
        @Cmd = (@Cmd, "-debug-mangling");
    }
    
    if($In::Opt{"Debug"})
    { # debug mode
        @Cmd = (@Cmd, "-debug");
        printMsg("INFO", "Executing @Cmd");
    }
    
    my $RPath = "compat_reports/$LibName/1.0_to_2.0/compat_report.".$In::Opt{"ReportFormat"};
    
    if(-f $RPath) {
        unlink($RPath);
    }
    
    system(@Cmd);
    
    my $ECode = $?>>8;
    
    if($ECode!~/\A[016]\Z/ or not -f $RPath)
    { # error
        exitStatus("Error", "analysis has failed ($ECode)");
    }
    
    my $NProblems = 0;
    if($In::Opt{"ReportFormat"} eq "xml")
    {
        my $Content = readFile($RPath);
        # binary
        if(my $PSummary = parseTag(\$Content, "problem_summary"))
        {
            $NProblems += int(parseTag(\$PSummary, "removed_symbols"));
            if(my $TProblems = parseTag(\$PSummary, "problems_with_types"))
            {
                $NProblems += int(parseTag(\$TProblems, "high"));
                $NProblems += int(parseTag(\$TProblems, "medium"));
            }
            if(my $IProblems = parseTag(\$PSummary, "problems_with_symbols"))
            {
                $NProblems += int(parseTag(\$IProblems, "high"));
                $NProblems += int(parseTag(\$IProblems, "medium"));
            }
        }
        # source
        if(my $PSummary = parseTag(\$Content, "problem_summary"))
        {
            $NProblems += int(parseTag(\$PSummary, "removed_symbols"));
            if(my $TProblems = parseTag(\$PSummary, "problems_with_types"))
            {
                $NProblems += int(parseTag(\$TProblems, "high"));
                $NProblems += int(parseTag(\$TProblems, "medium"));
            }
            
            if(my $IProblems = parseTag(\$PSummary, "problems_with_symbols"))
            {
                $NProblems += int(parseTag(\$IProblems, "high"));
                $NProblems += int(parseTag(\$IProblems, "medium"));
            }
        }
    }
    else
    {
        my $BReport = readAttributes($RPath, 0);
        $NProblems += $BReport->{"removed"};
        $NProblems += $BReport->{"type_problems_high"}+$BReport->{"type_problems_medium"};
        $NProblems += $BReport->{"interface_problems_high"}+$BReport->{"interface_problems_medium"};
        
        my $SReport = readAttributes($RPath, 1);
        $NProblems += $SReport->{"removed"};
        $NProblems += $SReport->{"type_problems_high"}+$SReport->{"type_problems_medium"};
        $NProblems += $SReport->{"interface_problems_high"}+$SReport->{"interface_problems_medium"};
    }
    
    if(($LibName eq "libsample_c" and $NProblems>70)
    or ($LibName eq "libsample_cpp" and $NProblems>150)) {
        printMsg("INFO", "Test result: SUCCESS ($NProblems problems found)\n");
    }
    else {
        printMsg("ERROR", "Test result: FAILED ($NProblems problems found)\n");
    }
}

return 1;
