| // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #include <fcntl.h> |
| #include <magenta/syscalls.h> |
| #include <mxio/util.h> |
| #include <stdbool.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| // This program runs Dart VM unit tests. The Dart VM unit tests are contained |
| // in a separate binary whose location is defined in kRunVmTestsPath below. |
| // That program accepts a command line argument --list to list all the available |
| // tests, or the name of a single test to run. This program accepts a single |
| // command line argument which is the path to a file containing a list of tests |
| // to run, one per line. |
| |
| const char* kRunVmTestsPath = "/boot/bin/dart_vm_tests"; |
| |
| // Tests that are invalid, wedge, or cause panics. |
| const char* kSkip[] = { |
| // These expect a file to exist that we aren't putting in the image. |
| "Read", |
| "FileLength", |
| "FilePosition", |
| // Hangs. |
| "ArrayLengthMaxElements", |
| "Int8ListLengthMaxElements", |
| "ThreadPool_WorkerShutdown", |
| "LargeMap", |
| "CompileFunctionOnHelperThread", |
| // Kernel panic. |
| "ThreadBarrier", |
| // The profiler is turned off. |
| "Profiler_AllocationSampleTest", |
| "Profiler_ArrayAllocation", |
| "Profiler_BasicSourcePosition", |
| "Profiler_BasicSourcePositionOptimized", |
| "Profiler_BinaryOperatorSourcePosition", |
| "Profiler_BinaryOperatorSourcePositionOptimized", |
| "Profiler_ChainedSamples", |
| "Profiler_ClosureAllocation", |
| "Profiler_CodeTicks", |
| "Profiler_ContextAllocation", |
| "Profiler_FunctionInline", |
| "Profiler_FunctionTicks", |
| "Profiler_InliningIntervalBoundry", |
| "Profiler_IntrinsicAllocation", |
| "Profiler_SampleBufferIterateTest", |
| "Profiler_SampleBufferWrapTest", |
| "Profiler_SourcePosition", |
| "Profiler_SourcePositionOptimized", |
| "Profiler_StringAllocation", |
| "Profiler_StringInterpolation", |
| "Profiler_ToggleRecordAllocation", |
| "Profiler_TrivialRecordAllocation", |
| "Profiler_TypedArrayAllocation", |
| "Profiler_GetSourceReport", |
| "Service_Profile", |
| // No realpath. |
| "Dart2JSCompilerStats", |
| "Dart2JSCompileAll", |
| }; |
| |
| // Expected to fail/crash. |
| const char* kExpectFail[] = { |
| "Fail0", |
| "Fail1", |
| "Fail2", |
| "IsolateReload_PendingUnqualifiedCall_InstanceToStatic", |
| "IsolateReload_PendingUnqualifiedCall_StaticToInstance", |
| "IsolateReload_PendingConstructorCall_AbstractToConcrete", |
| "IsolateReload_PendingConstructorCall_ConcreteToAbstract", |
| "IsolateReload_PendingStaticCall_DefinedToNSM", |
| "IsolateReload_PendingStaticCall_NSMToDefined", |
| "ArrayNew_Overflow_Crash", |
| "AllocGeneric_Overflow", |
| "CodeImmutability", |
| "SNPrint_BadArgs", |
| }; |
| |
| // Bugs to fix, or things that are not yet impelemnted. |
| const char* kBugs[] = { |
| // pthreads not using specified stack size. |
| "StackOverflowStacktraceInfo", |
| // Needs OS::GetCurrentThreadCPUMicros. |
| "Timeline_Dart_TimelineDuration", |
| "Timeline_Dart_TimelineInstant" |
| "Timeline_Dart_TimelineAsyncDisabled", |
| "Timeline_Dart_TimelineAsync", |
| "Timeline_Dart_TimelineGetTrace", |
| "Timeline_Dart_TimelineGetTraceOnlyDartEvents", |
| "Timeline_Dart_TimelineGetTraceWithDartEvents", |
| "Timeline_Dart_TimelineGetTraceGlobalOverride", |
| "Timeline_Dart_GlobalTimelineGetTrace", |
| "Timeline_Dart_GlobalTimelineGetTrace_Threaded", |
| "TimelineEventDuration", |
| "TimelineEventDurationPrintJSON", |
| "TimelineEventArguments", |
| "TimelineEventArgumentsPrintJSON", |
| "TimelineEventBufferPrintJSON", |
| "TimelineEventCallbackRecorderBasic", |
| "TimelineAnalysis_ThreadBlockCount", |
| "TimelineRingRecorderJSONOrder", |
| "TimelinePauses_BeginEnd", |
| // Crash. |
| "FindCodeObject", |
| // Needs OS::Sleep. |
| "MessageHandler_Run", |
| "Sleep", |
| // Calls VirtualMemory::FreeSubSegment. |
| "GrowableObjectArray", |
| "PrintJSON", |
| "GenerateSource", |
| "FreeVirtualMemory", |
| // Several missing calls. |
| "OsFuncs", |
| // OS::AlignedAllocate. |
| "OSAlignedAllocate", |
| // Needs NativeSymbolResolver |
| "Service_PersistentHandles", |
| // Need to investigate: |
| "ThreadPool_RunOne", |
| "ThreadPool_WorkerTimeout", |
| "Monitor", |
| "ThreadIterator_AddFindRemove", |
| // Needs Utils::HostToBigEndian16 |
| "Endianity", |
| }; |
| |
| |
| static bool contains(const char** list, intptr_t len, const char* str) { |
| for (intptr_t i = 0; i < len; i++) { |
| if (strcmp(list[i], str) == 0) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| static bool isSkip(const char* test) { |
| return contains( |
| kSkip, sizeof(kSkip) / sizeof(kSkip[0]), test); |
| } |
| |
| |
| static bool isExpectFail(const char* test) { |
| return contains( |
| kExpectFail, sizeof(kExpectFail) / sizeof(kExpectFail[0]), test); |
| } |
| |
| |
| static bool isBug(const char* test) { |
| return contains(kBugs, sizeof(kBugs) / sizeof(kBugs[0]), test); |
| } |
| |
| |
| static int run_test(const char* test_name) { |
| const intptr_t kArgc = 2; |
| const char* argv[3]; |
| argv[0] = kRunVmTestsPath; |
| argv[1] = test_name; |
| |
| mx_handle_t p = mxio_start_process(argv[0], kArgc, argv); |
| if (p < 0) { |
| printf("process failed to start\n"); |
| return -1; |
| } |
| |
| mx_signals_state_t state; |
| mx_status_t r = mx_handle_wait_one( |
| p, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, &state); |
| if (r != NO_ERROR) { |
| printf("[process(%x): wait failed? %d]\n", p, r); |
| return -1; |
| } |
| |
| mx_process_info_t proc_info; |
| mx_ssize_t ret = mx_handle_get_info( |
| p, MX_INFO_PROCESS, &proc_info, sizeof(proc_info)); |
| if (ret != sizeof(proc_info)) { |
| printf("[process(%x): handle_get_info failed? %ld]\n", p, ret); |
| return -1; |
| } |
| |
| mx_handle_close(p); |
| return proc_info.return_code; |
| } |
| |
| |
| static void trim(char* line) { |
| const intptr_t line_len = strlen(line); |
| if (line[line_len - 1] == '\n') { |
| line[line_len - 1] = '\0'; |
| } |
| } |
| |
| |
| static bool should_run(const char* test) { |
| return !(test[0] == '#') && !isSkip(test); |
| } |
| |
| |
| static void handle_result(intptr_t result, const char* test) { |
| if (result != 0) { |
| if (!isExpectFail(test) && !isBug(test)) { |
| printf("******** Test %s FAILED\n", test); |
| } |
| } else { |
| if (isExpectFail(test)) { |
| printf("******** Test %s is expected to fail, but PASSED\n", test); |
| } |
| if (isBug(test)) { |
| printf("******** Test %s is marked as a bug, but PASSED\n", test); |
| } |
| } |
| } |
| |
| |
| int main(int argc, char** argv) { |
| if (argc <= 1) { |
| fprintf(stderr, "Pass the path to a file containing the list of tests\n"); |
| return -1; |
| } |
| const char* tests_path = argv[1]; |
| |
| FILE* fp = fopen(tests_path, "r"); |
| if (fp == NULL) { |
| fprintf(stderr, "Failed to read the file: %s\n", tests_path); |
| return -1; |
| } |
| |
| char* test = NULL; |
| size_t len = 0; |
| ssize_t read; |
| while ((read = getline(&test, &len, fp)) != -1) { |
| trim(test); |
| if (!should_run(test)) { |
| continue; |
| } |
| intptr_t result = run_test(test); |
| handle_result(result, test); |
| } |
| |
| fclose(fp); |
| if (test != NULL) { |
| free(test); |
| } |
| return 0; |
| } |
| |