diff --git a/AutomatedTests/CMakeLists.txt b/AutomatedTests/CMakeLists.txt index 2bddc976ed..3cfb851fca 100644 --- a/AutomatedTests/CMakeLists.txt +++ b/AutomatedTests/CMakeLists.txt @@ -1,26 +1,36 @@ enable_testing() -set(RETRO68_TEST_CONFIG "-eminivmac" "-t4" "--minivmac-dir=/home/wolfgang/Emulators" +set(RETRO68_LAUNCH_METHOD classic CACHE String "How to launch Mac applications (for automated testing)") + +set(RETRO68_TEST_CONFIG "-t4" "--minivmac-dir=/home/wolfgang/Emulators" "--system-image=/home/wolfgang/Emulators/baresystem.dsk" "--autoquit-image=/home/wolfgang/Emulators/vmac extras/autoquit-1.1.1.dsk") find_program(LAUNCH_APPL LaunchAPPL PATH "${CMAKE_INSTALL_PREFIX}/../bin/") -function(test name) - add_application(${name} ${name}.c Test.h Test.c) - add_test(NAME ${name} COMMAND ${LAUNCH_APPL} ${RETRO68_TEST_CONFIG} ${name}.bin) +function(test FILE) + get_filename_component(NAME ${FILE} NAME_WE) + add_application(${NAME} ${FILE} Test.h Test.c) + add_test(NAME ${NAME} COMMAND ${LAUNCH_APPL} + -e ${RETRO68_LAUNCH_METHOD} ${RETRO68_TEST_CONFIG} ${ARGN} ${NAME}.bin) endfunction() - -test(ReallyEmpty) if(CMAKE_SYSTEM_NAME MATCHES Retro68) + test(ReallyEmpty.c) set_target_properties(ReallyEmpty PROPERTIES LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-single") endif() -test(Empty) +test(Empty.c) -test(File) +test(File.c) set_tests_properties(File PROPERTIES PASS_REGULAR_EXPRESSION "OK") -test(Log) +test(Timeout.c) +set_tests_properties(Timeout PROPERTIES PASS_REGULAR_EXPRESSION "One\nTwo") + +test(Log.c) set_tests_properties(Log PROPERTIES PASS_REGULAR_EXPRESSION "One\nTwo\nThree") + +test(Init.cc) +set_tests_properties(Init PROPERTIES PASS_REGULAR_EXPRESSION "constructor\nmain\ndestructor") + diff --git a/AutomatedTests/Init.cc b/AutomatedTests/Init.cc new file mode 100644 index 0000000000..1ec84912f7 --- /dev/null +++ b/AutomatedTests/Init.cc @@ -0,0 +1,22 @@ +#include "Test.h" + +class Constructed +{ +public: + Constructed() + { + TestLog("constructor"); + } + ~Constructed() + { + TestLog("destructor"); + } +}; + +Constructed thing; + +int main() +{ + TestLog("main"); + return 0; +} diff --git a/AutomatedTests/Test.h b/AutomatedTests/Test.h index 46c3b66940..b43e622931 100644 --- a/AutomatedTests/Test.h +++ b/AutomatedTests/Test.h @@ -26,7 +26,7 @@ _ref = _hpb.ioParam.ioRefNum; \ \ memset(&_hpb,0,sizeof(_hpb)); \ - _hpb.ioParam.ioBuffer = str; \ + _hpb.ioParam.ioBuffer = (Ptr)str; \ _hpb.ioParam.ioReqCount = size; \ _hpb.ioParam.ioPosMode = fsFromLEOF; \ _hpb.ioParam.ioPosOffset = 0; \ @@ -46,6 +46,9 @@ FlushVol(NULL,0); \ } while(0); +#ifdef __cplusplus +extern "C" +#endif void TestLog(const char *str); #endif // TEST_H diff --git a/LaunchAPPL/CMakeLists.txt b/LaunchAPPL/CMakeLists.txt index 4dfa3d1e50..c5be453b42 100644 --- a/LaunchAPPL/CMakeLists.txt +++ b/LaunchAPPL/CMakeLists.txt @@ -1,14 +1,32 @@ find_package(Boost COMPONENTS filesystem program_options) +set(LAUNCHMETHODS + Executor.h Executor.cc + MiniVMac.h MiniVMac.cc +) + +if(APPLE) +LIST(APPEND LAUNCHMETHODS + Classic.h Classic.cc + Carbon.h Carbon.cc + ) +endif() + add_executable(LaunchAPPL LaunchAPPL.cc bootblock.c LaunchMethod.h LaunchMethod.cc Launcher.h Launcher.cc - Executor.h Executor.cc - MiniVMac.h MiniVMac.cc) + ${LAUNCHMETHODS}) + + target_include_directories(LaunchAPPL PRIVATE ${CMAKE_INSTALL_PREFIX}/include ${Boost_INCLUDE_DIR}) target_link_libraries(LaunchAPPL ResourceFiles ${Boost_LIBRARIES}) +if(APPLE) + find_library(APPLICATIONSERVICES_FW ApplicationServices) + target_link_libraries(LaunchAPPL ${APPLICATIONSERVICES_FW}) +endif() + install(TARGETS LaunchAPPL RUNTIME DESTINATION bin) diff --git a/LaunchAPPL/Carbon.cc b/LaunchAPPL/Carbon.cc new file mode 100644 index 0000000000..22ef6e92e6 --- /dev/null +++ b/LaunchAPPL/Carbon.cc @@ -0,0 +1,35 @@ +#include "Carbon.h" +#include "Launcher.h" + +namespace po = boost::program_options; + +class CarbonLauncher : public Launcher +{ +public: + CarbonLauncher(po::variables_map& options); + virtual ~CarbonLauncher(); + + virtual bool Go(int timeout = 0); + +}; + +CarbonLauncher::CarbonLauncher(po::variables_map &options) + : Launcher(options, ResourceFile::Format::real) +{ + +} + +CarbonLauncher::~CarbonLauncher() +{ + +} + +bool CarbonLauncher::Go(int timeout) +{ + return ChildProcess("LaunchCarbon", { appPath.string() }, timeout) == 0; +} + +std::unique_ptr Carbon::MakeLauncher(variables_map &options) +{ + return std::unique_ptr(new CarbonLauncher(options)); +} diff --git a/LaunchAPPL/Carbon.h b/LaunchAPPL/Carbon.h new file mode 100644 index 0000000000..f9c2ce219e --- /dev/null +++ b/LaunchAPPL/Carbon.h @@ -0,0 +1,14 @@ +#ifndef CARBON_METHOD_H +#define CARBON_METHOD_H + +#include "LaunchMethod.h" + +class Carbon : public LaunchMethod +{ +public: + virtual std::string GetName() { return "carbon"; } + + virtual std::unique_ptr MakeLauncher(variables_map& options); +}; + +#endif // CARBON_METHOD_H diff --git a/LaunchAPPL/Classic.cc b/LaunchAPPL/Classic.cc new file mode 100644 index 0000000000..45fdceb630 --- /dev/null +++ b/LaunchAPPL/Classic.cc @@ -0,0 +1,68 @@ +#include "Classic.h" +#include "Launcher.h" + +#define ResType MacResType +#include + +namespace po = boost::program_options; + +class ClassicLauncher : public Launcher +{ +public: + ClassicLauncher(po::variables_map& options); + virtual ~ClassicLauncher(); + + virtual bool Go(int timeout = 0); + +}; + +ClassicLauncher::ClassicLauncher(po::variables_map &options) + : Launcher(options, ResourceFile::Format::real) +{ + +} + +ClassicLauncher::~ClassicLauncher() +{ + +} + +bool ClassicLauncher::Go(int timeout) +{ + FSRef ref; + FSPathMakeRef((const UInt8*) appPath.string().c_str(), &ref, NULL); + LSApplicationParameters params; + memset(¶ms, 0, sizeof(params)); + params.flags = kLSLaunchStartClassic + | kLSLaunchInClassic + | kLSLaunchDontAddToRecents + | kLSLaunchNewInstance; + params.application = &ref; + + ProcessSerialNumber psn; + LSOpenApplication(¶ms, &psn); + + // Classic startup takes place before LSOpenApplication returns, + // so no extra timeout is needed + + for(int i = 0; i < timeout || timeout == 0; i++) + { + sleep(1); + + ProcessInfoRec pi; + pi.processInfoLength = sizeof(pi); + pi.processName = NULL; + pi.processAppSpec = 0; + if(GetProcessInformation(&psn, &pi) == procNotFound) + return true; + } + + KillProcess(&psn); + + return false; +} + +std::unique_ptr Classic::MakeLauncher(variables_map &options) +{ + return std::unique_ptr(new ClassicLauncher(options)); +} diff --git a/LaunchAPPL/Classic.h b/LaunchAPPL/Classic.h new file mode 100644 index 0000000000..17b5627603 --- /dev/null +++ b/LaunchAPPL/Classic.h @@ -0,0 +1,14 @@ +#ifndef CLASSIC_H +#define CLASSIC_H + +#include "LaunchMethod.h" + +class Classic : public LaunchMethod +{ +public: + virtual std::string GetName() { return "classic"; } + + virtual std::unique_ptr MakeLauncher(variables_map& options); +}; + +#endif // CLASSIC_H diff --git a/LaunchAPPL/LaunchAPPL.cc b/LaunchAPPL/LaunchAPPL.cc index 4befeda29d..89b4b5935a 100644 --- a/LaunchAPPL/LaunchAPPL.cc +++ b/LaunchAPPL/LaunchAPPL.cc @@ -8,6 +8,10 @@ #include "LaunchMethod.h" #include "Launcher.h" +#ifdef __APPLE__ +#include "Classic.h" +#include "Carbon.h" +#endif #include "Executor.h" #include "MiniVMac.h" @@ -31,6 +35,9 @@ static void usage() int main(int argc, char *argv[]) { std::vector methods = { +#ifdef __APPLE__ + new Classic(), new Carbon(), +#endif new Executor(), new MiniVMac() }; desc.add_options() diff --git a/LaunchAPPL/MiniVMac.cc b/LaunchAPPL/MiniVMac.cc index 4f8f686b67..5b78bef100 100644 --- a/LaunchAPPL/MiniVMac.cc +++ b/LaunchAPPL/MiniVMac.cc @@ -6,6 +6,8 @@ extern "C" { } #include +#include +#include namespace fs = boost::filesystem; using std::string;