snapshot for rework
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..4132f27
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,28 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES:= \
+ src/bundle.c \
+ src/debug.c \
+ src/json-format.c \
+ src/json-test.c \
+ src/text-utils.c \
+ src/uuid.c \
+ src/lava-wrapper.c
+LOCAL_MODULE := lava-wrapper
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= \
+ src/bundle.c \
+ src/debug.c \
+ src/json-format.c \
+ src/json-test.c \
+ src/text-utils.c \
+ src/uuid.c \
+ src/lava-wrapper.c
+LOCAL_MODULE := lava-wrapper
+LOCAL_MODULE_TAGS := tests
+LOCAL_CFLAGS += -g
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/bundle.h b/bundle.h
new file mode 100644
index 0000000..8f0f9f5
--- /dev/null
+++ b/bundle.h
@@ -0,0 +1,129 @@
+#ifndef BUNDLE_H
+#define BUNDLE_H
+
+/**
+ * Utility functions for printing Linaro Dashboard Bundles.
+ * See http://linaro-dashboard-bundle.readthedocs.org/en/latest/schema/examples.html
+ * for example bundles.
+ **/
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+
+/**
+ * Print the header of a bundle object.
+ *
+ * Must be called in pair with bundle_print_footer().
+ *
+ * Once called you may call bundle_print_test_run_header().
+ **/
+void
+bundle_print_header(
+ FILE *bundle_stream,
+ unsigned flags,
+ const char *format
+ );
+
+
+/**
+ * Print the footer of a bundle object.
+ *
+ * Terminates a complete bundle. You cannot call any other bundle_print_*
+ * functions on the same stream after that or the bundle will be incorrect
+ * JSON.
+ **/
+void
+bundle_print_footer(
+ FILE *bundle_stream,
+ unsigned flags
+ );
+
+
+/**
+ * Prints the header of a test run object.
+ *
+ * Must be called in pair with bundle_print_test_run_footer().
+ *
+ * Once called you may call bundle_print_test_result_header().
+ **/
+void
+bundle_print_test_run_header(
+ FILE *bundle_stream,
+ unsigned flags,
+ bool comma,
+ const char *analyzer_assigned_uuid,
+ time_t analyzer_assigned_date,
+ bool time_check_performed,
+ const char *test_id
+ );
+
+
+/**
+ * Prints the footer of a test run object.
+ *
+ * Must be called in pair with bundle_print_test_run_header().
+ *
+ * Once called you may call bundle_print_test_result_header().
+ **/
+void
+bundle_print_test_run_footer(
+ FILE *bundle_stream,
+ unsigned flags
+ );
+
+/**
+ * Prints the header of a test result object.
+ *
+ * Must be called in pair with bundle_print_test_result_footer().
+ *
+ * The initial call in the current test_run must pass comma=false, all
+ * subsequent calls must pass true there.
+ *
+ * When called you may call bundle_print_test_result_message() (any number of times)
+ **/
+void
+bundle_print_test_result_header(
+ FILE *bundle_stream,
+ unsigned flags,
+ bool comma,
+ const char *test_case_id,
+ time_t timestamp
+ );
+
+
+/**
+ * Prints a (fragment of) test result message.
+ *
+ * May be called between bundle_print_test_result_header() and
+ * bundle_print_test_result_footer().
+ *
+ * May be called multiple times. Each time the 'message' is directly
+ * concatenated to any previous messages.
+ **/
+void
+bundle_print_test_result_message(
+ FILE *bundle_stream,
+ unsigned flags,
+ const char *message
+ );
+
+
+/**
+ * Prints the footer of a test result.
+ *
+ * Must be called in pair with bundle_print_test_result_header().
+ **/
+void
+bundle_print_test_result_footer(
+ FILE *bundle_stream,
+ unsigned flags,
+ const char *result,
+ const char *log_filename,
+ int log_lineno,
+ struct timeval duration
+ );
+
+
+#endif
diff --git a/debug.h b/debug.h
new file mode 100644
index 0000000..ffa7327
--- /dev/null
+++ b/debug.h
@@ -0,0 +1,22 @@
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <stdio.h>
+
+/**
+ * Enable debuging and redirect all debug messages to the specified stream
+ **/
+void
+debug_enable(
+ FILE *stream
+ );
+
+/**
+ * Emit a printf-like message on the debug channel
+ **/
+void
+debug_log(
+ const char *format, ...
+ ) __attribute__((format(printf, 1, 2)));
+
+#endif
diff --git a/dummy-BufferQueue_test b/dummy-BufferQueue_test
new file mode 100755
index 0000000..9929e1b
--- /dev/null
+++ b/dummy-BufferQueue_test
@@ -0,0 +1,34 @@
+#!/bin/sh
+cat << DUMP
+[==========] Running 12 tests from 1 test case.
+[----------] Global test environment set-up.
+[----------] 12 tests from TestBufferQueue
+[ RUN ] TestBufferQueue.testInvalidBuffer
+[ OK ] TestBufferQueue.testInvalidBuffer
+[ RUN ] TestBufferQueue.testMuteSolo
+[ OK ] TestBufferQueue.testMuteSolo
+[ RUN ] TestBufferQueue.testSeek
+[ OK ] TestBufferQueue.testSeek
+[ RUN ] TestBufferQueue.testValidBuffer
+[ OK ] TestBufferQueue.testValidBuffer
+[ RUN ] TestBufferQueue.testEnqueueMaxBuffer
+[ OK ] TestBufferQueue.testEnqueueMaxBuffer
+[ RUN ] TestBufferQueue.testEnqueueExtraBuffer
+[ OK ] TestBufferQueue.testEnqueueExtraBuffer
+[ RUN ] TestBufferQueue.testEnqueueAtStopped
+[ OK ] TestBufferQueue.testEnqueueAtStopped
+[ RUN ] TestBufferQueue.testEnqueueAtPaused
+[ OK ] TestBufferQueue.testEnqueueAtPaused
+[ RUN ] TestBufferQueue.testClearQueue
+[ OK ] TestBufferQueue.testClearQueue
+[ RUN ] TestBufferQueue.testStateTransitionEmptyQueue
+[ OK ] TestBufferQueue.testStateTransitionEmptyQueue
+[ RUN ] TestBufferQueue.testStateTransitionNonEmptyQueue
+[ OK ] TestBufferQueue.testStateTransitionNonEmptyQueue
+[ RUN ] TestBufferQueue.testStatePlayBuffer
+[ OK ] TestBufferQueue.testStatePlayBuffer
+[----------] Global test environment tear-down
+[==========] 12 tests from 1 test case ran.
+[ PASSED ] 12 tests.
+DUMP
+
diff --git a/dummy-SurfaceTexture_test b/dummy-SurfaceTexture_test
new file mode 100755
index 0000000..b260b90
--- /dev/null
+++ b/dummy-SurfaceTexture_test
@@ -0,0 +1,98 @@
+#!/bin/sh
+cat << DUMP
+Running main() from gtest_main.cc
+[==========] Running 44 tests from 6 test cases.
+[----------] Global test environment set-up.
+[----------] 4 tests from SurfaceTest
+[ RUN ] SurfaceTest.QueuesToWindowComposerIsTrueWhenVisible
+[ OK ] SurfaceTest.QueuesToWindowComposerIsTrueWhenVisible
+[ RUN ] SurfaceTest.QueuesToWindowComposerIsTrueWhenPurgatorized
+[ OK ] SurfaceTest.QueuesToWindowComposerIsTrueWhenPurgatorized
+[ RUN ] SurfaceTest.ScreenshotsOfProtectedBuffersSucceed
+[ OK ] SurfaceTest.ScreenshotsOfProtectedBuffersSucceed
+[ RUN ] SurfaceTest.ConcreteTypeIsSurface
+[ OK ] SurfaceTest.ConcreteTypeIsSurface
+[----------] 23 tests from SurfaceTextureClientTest
+[ RUN ] SurfaceTextureClientTest.GetISurfaceTextureIsNotNull
+[ OK ] SurfaceTextureClientTest.GetISurfaceTextureIsNotNull
+[ RUN ] SurfaceTextureClientTest.QueuesToWindowCompositorIsFalse
+[ OK ] SurfaceTextureClientTest.QueuesToWindowCompositorIsFalse
+[ RUN ] SurfaceTextureClientTest.ConcreteTypeIsSurfaceTextureClient
+[ OK ] SurfaceTextureClientTest.ConcreteTypeIsSurfaceTextureClient
+[ RUN ] SurfaceTextureClientTest.EglCreateWindowSurfaceSucceeds
+[ OK ] SurfaceTextureClientTest.EglCreateWindowSurfaceSucceeds
+[ RUN ] SurfaceTextureClientTest.BufferGeometryInvalidSizesFail
+[ OK ] SurfaceTextureClientTest.BufferGeometryInvalidSizesFail
+[ RUN ] SurfaceTextureClientTest.DefaultGeometryValues
+[ OK ] SurfaceTextureClientTest.DefaultGeometryValues
+[ RUN ] SurfaceTextureClientTest.BufferGeometryCanBeSet
+[ OK ] SurfaceTextureClientTest.BufferGeometryCanBeSet
+[ RUN ] SurfaceTextureClientTest.BufferGeometryDefaultSizeSetFormat
+[ OK ] SurfaceTextureClientTest.BufferGeometryDefaultSizeSetFormat
+[ RUN ] SurfaceTextureClientTest.BufferGeometrySetSizeDefaultFormat
+[ OK ] SurfaceTextureClientTest.BufferGeometrySetSizeDefaultFormat
+[ RUN ] SurfaceTextureClientTest.BufferGeometrySizeCanBeUnset
+[ OK ] SurfaceTextureClientTest.BufferGeometrySizeCanBeUnset
+[ RUN ] SurfaceTextureClientTest.BufferGeometrySizeCanBeChangedWithoutFormat
+[ OK ] SurfaceTextureClientTest.BufferGeometrySizeCanBeChangedWithoutFormat
+[ RUN ] SurfaceTextureClientTest.SurfaceTextureSetDefaultSize
+[ OK ] SurfaceTextureClientTest.SurfaceTextureSetDefaultSize
+[ RUN ] SurfaceTextureClientTest.SurfaceTextureSetDefaultSizeAfterDequeue
+[ OK ] SurfaceTextureClientTest.SurfaceTextureSetDefaultSizeAfterDequeue
+[ RUN ] SurfaceTextureClientTest.SurfaceTextureSetDefaultSizeVsGeometry
+[ OK ] SurfaceTextureClientTest.SurfaceTextureSetDefaultSizeVsGeometry
+[ RUN ] SurfaceTextureClientTest.SurfaceTextureTooManyUpdateTexImage
+[ OK ] SurfaceTextureClientTest.SurfaceTextureTooManyUpdateTexImage
+[ RUN ] SurfaceTextureClientTest.SurfaceTextureSyncModeSlowRetire
+[ OK ] SurfaceTextureClientTest.SurfaceTextureSyncModeSlowRetire
+[ RUN ] SurfaceTextureClientTest.SurfaceTextureSyncModeFastRetire
+[ OK ] SurfaceTextureClientTest.SurfaceTextureSyncModeFastRetire
+[ RUN ] SurfaceTextureClientTest.SurfaceTextureSyncModeDQQR
+[ OK ] SurfaceTextureClientTest.SurfaceTextureSyncModeDQQR
+[ RUN ] SurfaceTextureClientTest.SurfaceTextureSyncModeMinUndequeued
+[ OK ] SurfaceTextureClientTest.SurfaceTextureSyncModeMinUndequeued
+[ RUN ] SurfaceTextureClientTest.GetTransformMatrixReturnsVerticalFlip
+[ OK ] SurfaceTextureClientTest.GetTransformMatrixReturnsVerticalFlip
+[ RUN ] SurfaceTextureClientTest.GetTransformMatrixSucceedsAfterFreeingBuffers
+[ OK ] SurfaceTextureClientTest.GetTransformMatrixSucceedsAfterFreeingBuffers
+[ RUN ] SurfaceTextureClientTest.GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop
+[ OK ] SurfaceTextureClientTest.GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop
+[ RUN ] SurfaceTextureClientTest.QueryFormatAfterSettingWorks
+[ OK ] SurfaceTextureClientTest.QueryFormatAfterSettingWorks
+[----------] 8 tests from SurfaceTextureGLTest
+[ RUN ] SurfaceTextureGLTest.TexturingFromCpuFilledYV12BufferNpot
+pixel check failure: g(184 isn't 127) b(171 isn't 255)
+frameworks/base/libs/gui/tests/SurfaceTexture_test.cpp:584: Failure
+Value of: checkPixel( 0, 0, 255, 127, 255, 255)
+ Actual: false
+Expected: true
+pixel check failure: r(4 isn't 0) g(75 isn't 133) b(87 isn't 0)
+frameworks/base/libs/gui/tests/SurfaceTexture_test.cpp:585: Failure
+Value of: checkPixel(63, 0, 0, 133, 0, 255)
+ Actual: false
+Expected: true
+pixel check failure: r(3 isn't 0) g(87 isn't 133) b(22 isn't 0)
+frameworks/base/libs/gui/tests/SurfaceTexture_test.cpp:586: Failure
+Value of: checkPixel(63, 65, 0, 133, 0, 255)
+ Actual: false
+Expected: true
+pixel check failure: g(172 isn't 127) b(236 isn't 255)
+frameworks/base/libs/gui/tests/SurfaceTexture_test.cpp:587: Failure
+Value of: checkPixel( 0, 65, 255, 127, 255, 255)
+ Actual: false
+Expected: true
+pixel check failure: b(82 isn't 118)
+frameworks/base/libs/gui/tests/SurfaceTexture_test.cpp:592: Failure
+Value of: checkPixel( 7, 31, 155, 0, 118, 255)
+ Actual: false
+Expected: true
+pixel check failure: r(103 isn't 107) g(44 isn't 24) b(0 isn't 87)
+frameworks/base/libs/gui/tests/SurfaceTexture_test.cpp:593: Failure
+Value of: checkPixel(31, 9, 107, 24, 87, 255)
+ Actual: false
+Expected: true
+*********************************************************************
+ASSERT EXIT: In file: vendor/st-ericsson/multimedia/linux/mali400/driver/./src/ump/arch_hwmem/ump_frontend_hwmem.c function: ump_mapped_pointer_release() line: 166
+Error in mapping pointer (not mapped)
+DUMP
+exit 130
diff --git a/dummy-dalvik-vm-unit-tests b/dummy-dalvik-vm-unit-tests
new file mode 100755
index 0000000..cc5fd1f
--- /dev/null
+++ b/dummy-dalvik-vm-unit-tests
@@ -0,0 +1,17 @@
+#!/bin/sh
+cat << DUMP
+[==========] Running 4 tests from 1 test case.
+[----------] Global test environment set-up.
+[----------] 4 tests from dvmHumanReadableDescriptor
+[ RUN ] dvmHumanReadableDescriptor.ArrayReferences
+[ OK ] dvmHumanReadableDescriptor.ArrayReferences
+[ RUN ] dvmHumanReadableDescriptor.ScalarReferences
+[ OK ] dvmHumanReadableDescriptor.ScalarReferences
+[ RUN ] dvmHumanReadableDescriptor.PrimitiveArrays
+[ OK ] dvmHumanReadableDescriptor.PrimitiveArrays
+[ RUN ] dvmHumanReadableDescriptor.PrimitiveScalars
+[ OK ] dvmHumanReadableDescriptor.PrimitiveScalars
+[----------] Global test environment tear-down
+[==========] 4 tests from 1 test case ran.
+[ PASSED ] 4 tests.
+DUMP
diff --git a/dummy-gtest_repeat_test b/dummy-gtest_repeat_test
new file mode 100755
index 0000000..21c49d9
--- /dev/null
+++ b/dummy-gtest_repeat_test
@@ -0,0 +1,1036 @@
+#!/bin/sh
+cat << DUMP
+[==========] Running 13 tests from 3 test cases.
+[----------] Global test environment set-up.
+[----------] 1 test from BarDeathTest
+[ RUN ] BarDeathTest.ThreadSafeAndFast
+
+[WARNING] external/gtest/src/../src/gtest-death-test.cc:789:: Death tests use fork(), which is unsafe particularly in a threaded context. For this test, Google Test couldn't detect the number of threads.
+[ OK ] BarDeathTest.ThreadSafeAndFast (229 ms)
+[----------] 1 test from BarDeathTest (229 ms total)
+
+[----------] 2 tests from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[ RUN ] FooTest.ShouldPass
+[ OK ] FooTest.ShouldPass (0 ms)
+[----------] 2 tests from FooTest (0 ms total)
+
+[----------] 10 tests from MyParamSequence/MyParamTest
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/0
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/0 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/1
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/1 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/2
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/2 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/3
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/3 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/4
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/4 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/5
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/5 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/6
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/6 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/7
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/7 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/8
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/8 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/9
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/9 (0 ms)
+[----------] 10 tests from MyParamSequence/MyParamTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 13 tests from 3 test cases ran. (231 ms total)
+[ PASSED ] 12 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+[==========] Running 13 tests from 3 test cases.
+[----------] Global test environment set-up.
+[----------] 1 test from BarDeathTest
+[ RUN ] BarDeathTest.ThreadSafeAndFast
+
+[WARNING] external/gtest/src/../src/gtest-death-test.cc:789:: Death tests use fork(), which is unsafe particularly in a threaded context. For this test, Google Test couldn't detect the number of threads.
+[ OK ] BarDeathTest.ThreadSafeAndFast (215 ms)
+[----------] 1 test from BarDeathTest (215 ms total)
+
+[----------] 2 tests from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[ RUN ] FooTest.ShouldPass
+[ OK ] FooTest.ShouldPass (0 ms)
+[----------] 2 tests from FooTest (0 ms total)
+
+[----------] 10 tests from MyParamSequence/MyParamTest
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/0
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/0 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/1
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/1 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/2
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/2 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/3
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/3 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/4
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/4 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/5
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/5 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/6
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/6 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/7
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/7 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/8
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/8 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/9
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/9 (0 ms)
+[----------] 10 tests from MyParamSequence/MyParamTest (1 ms total)
+
+[----------] Global test environment tear-down
+[==========] 13 tests from 3 test cases ran. (216 ms total)
+[ PASSED ] 12 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 1) . . .
+
+[==========] Running 13 tests from 3 test cases.
+[----------] Global test environment set-up.
+[----------] 1 test from BarDeathTest
+[ RUN ] BarDeathTest.ThreadSafeAndFast
+
+[WARNING] external/gtest/src/../src/gtest-death-test.cc:789:: Death tests use fork(), which is unsafe particularly in a threaded context. For this test, Google Test couldn't detect the number of threads.
+[ OK ] BarDeathTest.ThreadSafeAndFast (219 ms)
+[----------] 1 test from BarDeathTest (219 ms total)
+
+[----------] 2 tests from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[ RUN ] FooTest.ShouldPass
+[ OK ] FooTest.ShouldPass (0 ms)
+[----------] 2 tests from FooTest (0 ms total)
+
+[----------] 10 tests from MyParamSequence/MyParamTest
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/0
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/0 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/1
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/1 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/2
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/2 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/3
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/3 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/4
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/4 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/5
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/5 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/6
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/6 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/7
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/7 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/8
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/8 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/9
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/9 (0 ms)
+[----------] 10 tests from MyParamSequence/MyParamTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 13 tests from 3 test cases ran. (220 ms total)
+[ PASSED ] 12 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 2) . . .
+
+[==========] Running 13 tests from 3 test cases.
+[----------] Global test environment set-up.
+[----------] 1 test from BarDeathTest
+[ RUN ] BarDeathTest.ThreadSafeAndFast
+
+[WARNING] external/gtest/src/../src/gtest-death-test.cc:789:: Death tests use fork(), which is unsafe particularly in a threaded context. For this test, Google Test couldn't detect the number of threads.
+[ OK ] BarDeathTest.ThreadSafeAndFast (205 ms)
+[----------] 1 test from BarDeathTest (205 ms total)
+
+[----------] 2 tests from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[ RUN ] FooTest.ShouldPass
+[ OK ] FooTest.ShouldPass (0 ms)
+[----------] 2 tests from FooTest (0 ms total)
+
+[----------] 10 tests from MyParamSequence/MyParamTest
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/0
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/0 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/1
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/1 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/2
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/2 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/3
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/3 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/4
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/4 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/5
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/5 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/6
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/6 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/7
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/7 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/8
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/8 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/9
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/9 (0 ms)
+[----------] 10 tests from MyParamSequence/MyParamTest (1 ms total)
+
+[----------] Global test environment tear-down
+[==========] 13 tests from 3 test cases ran. (206 ms total)
+[ PASSED ] 12 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 3) . . .
+
+[==========] Running 13 tests from 3 test cases.
+[----------] Global test environment set-up.
+[----------] 1 test from BarDeathTest
+[ RUN ] BarDeathTest.ThreadSafeAndFast
+
+[WARNING] external/gtest/src/../src/gtest-death-test.cc:789:: Death tests use fork(), which is unsafe particularly in a threaded context. For this test, Google Test couldn't detect the number of threads.
+[ OK ] BarDeathTest.ThreadSafeAndFast (215 ms)
+[----------] 1 test from BarDeathTest (215 ms total)
+
+[----------] 2 tests from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[ RUN ] FooTest.ShouldPass
+[ OK ] FooTest.ShouldPass (0 ms)
+[----------] 2 tests from FooTest (0 ms total)
+
+[----------] 10 tests from MyParamSequence/MyParamTest
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/0
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/0 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/1
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/1 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/2
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/2 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/3
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/3 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/4
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/4 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/5
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/5 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/6
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/6 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/7
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/7 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/8
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/8 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/9
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/9 (0 ms)
+[----------] 10 tests from MyParamSequence/MyParamTest (1 ms total)
+
+[----------] Global test environment tear-down
+[==========] 13 tests from 3 test cases ran. (216 ms total)
+[ PASSED ] 12 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 4) . . .
+
+[==========] Running 13 tests from 3 test cases.
+[----------] Global test environment set-up.
+[----------] 1 test from BarDeathTest
+[ RUN ] BarDeathTest.ThreadSafeAndFast
+
+[WARNING] external/gtest/src/../src/gtest-death-test.cc:789:: Death tests use fork(), which is unsafe particularly in a threaded context. For this test, Google Test couldn't detect the number of threads.
+[ OK ] BarDeathTest.ThreadSafeAndFast (227 ms)
+[----------] 1 test from BarDeathTest (227 ms total)
+
+[----------] 2 tests from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[ RUN ] FooTest.ShouldPass
+[ OK ] FooTest.ShouldPass (0 ms)
+[----------] 2 tests from FooTest (0 ms total)
+
+[----------] 10 tests from MyParamSequence/MyParamTest
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/0
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/0 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/1
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/1 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/2
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/2 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/3
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/3 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/4
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/4 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/5
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/5 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/6
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/6 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/7
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/7 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/8
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/8 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/9
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/9 (0 ms)
+[----------] 10 tests from MyParamSequence/MyParamTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 13 tests from 3 test cases ran. (227 ms total)
+[ PASSED ] 12 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 5) . . .
+
+[==========] Running 13 tests from 3 test cases.
+[----------] Global test environment set-up.
+[----------] 1 test from BarDeathTest
+[ RUN ] BarDeathTest.ThreadSafeAndFast
+
+[WARNING] external/gtest/src/../src/gtest-death-test.cc:789:: Death tests use fork(), which is unsafe particularly in a threaded context. For this test, Google Test couldn't detect the number of threads.
+[ OK ] BarDeathTest.ThreadSafeAndFast (225 ms)
+[----------] 1 test from BarDeathTest (225 ms total)
+
+[----------] 2 tests from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[ RUN ] FooTest.ShouldPass
+[ OK ] FooTest.ShouldPass (0 ms)
+[----------] 2 tests from FooTest (0 ms total)
+
+[----------] 10 tests from MyParamSequence/MyParamTest
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/0
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/0 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/1
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/1 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/2
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/2 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/3
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/3 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/4
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/4 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/5
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/5 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/6
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/6 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/7
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/7 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/8
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/8 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/9
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/9 (0 ms)
+[----------] 10 tests from MyParamSequence/MyParamTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 13 tests from 3 test cases ran. (225 ms total)
+[ PASSED ] 12 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 1) . . .
+
+Note: Google Test filter = None
+[==========] Running 0 tests from 0 test cases.
+[==========] 0 tests from 0 test cases ran. (0 ms total)
+[ PASSED ] 0 tests.
+
+Repeating all tests (iteration 2) . . .
+
+Note: Google Test filter = None
+[==========] Running 0 tests from 0 test cases.
+[==========] 0 tests from 0 test cases ran. (0 ms total)
+[ PASSED ] 0 tests.
+
+Repeating all tests (iteration 1) . . .
+
+Note: Google Test filter = None
+[==========] Running 0 tests from 0 test cases.
+[==========] 0 tests from 0 test cases ran. (0 ms total)
+[ PASSED ] 0 tests.
+
+Repeating all tests (iteration 2) . . .
+
+Note: Google Test filter = None
+[==========] Running 0 tests from 0 test cases.
+[==========] 0 tests from 0 test cases ran. (0 ms total)
+[ PASSED ] 0 tests.
+
+Repeating all tests (iteration 3) . . .
+
+Note: Google Test filter = None
+[==========] Running 0 tests from 0 test cases.
+[==========] 0 tests from 0 test cases ran. (0 ms total)
+[ PASSED ] 0 tests.
+
+Repeating all tests (iteration 1) . . .
+
+Note: Google Test filter = *-*ShouldFail
+[==========] Running 12 tests from 3 test cases.
+[----------] Global test environment set-up.
+[----------] 1 test from BarDeathTest
+[ RUN ] BarDeathTest.ThreadSafeAndFast
+
+[WARNING] external/gtest/src/../src/gtest-death-test.cc:789:: Death tests use fork(), which is unsafe particularly in a threaded context. For this test, Google Test couldn't detect the number of threads.
+[ OK ] BarDeathTest.ThreadSafeAndFast (215 ms)
+[----------] 1 test from BarDeathTest (215 ms total)
+
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldPass
+[ OK ] FooTest.ShouldPass (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] 10 tests from MyParamSequence/MyParamTest
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/0
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/0 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/1
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/1 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/2
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/2 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/3
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/3 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/4
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/4 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/5
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/5 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/6
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/6 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/7
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/7 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/8
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/8 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/9
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/9 (0 ms)
+[----------] 10 tests from MyParamSequence/MyParamTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 12 tests from 3 test cases ran. (215 ms total)
+[ PASSED ] 12 tests.
+
+Repeating all tests (iteration 2) . . .
+
+Note: Google Test filter = *-*ShouldFail
+[==========] Running 12 tests from 3 test cases.
+[----------] Global test environment set-up.
+[----------] 1 test from BarDeathTest
+[ RUN ] BarDeathTest.ThreadSafeAndFast
+
+[WARNING] external/gtest/src/../src/gtest-death-test.cc:789:: Death tests use fork(), which is unsafe particularly in a threaded context. For this test, Google Test couldn't detect the number of threads.
+[ OK ] BarDeathTest.ThreadSafeAndFast (233 ms)
+[----------] 1 test from BarDeathTest (233 ms total)
+
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldPass
+[ OK ] FooTest.ShouldPass (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] 10 tests from MyParamSequence/MyParamTest
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/0
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/0 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/1
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/1 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/2
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/2 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/3
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/3 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/4
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/4 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/5
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/5 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/6
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/6 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/7
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/7 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/8
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/8 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/9
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/9 (0 ms)
+[----------] 10 tests from MyParamSequence/MyParamTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 12 tests from 3 test cases ran. (233 ms total)
+[ PASSED ] 12 tests.
+
+Repeating all tests (iteration 3) . . .
+
+Note: Google Test filter = *-*ShouldFail
+[==========] Running 12 tests from 3 test cases.
+[----------] Global test environment set-up.
+[----------] 1 test from BarDeathTest
+[ RUN ] BarDeathTest.ThreadSafeAndFast
+
+[WARNING] external/gtest/src/../src/gtest-death-test.cc:789:: Death tests use fork(), which is unsafe particularly in a threaded context. For this test, Google Test couldn't detect the number of threads.
+[ OK ] BarDeathTest.ThreadSafeAndFast (238 ms)
+[----------] 1 test from BarDeathTest (238 ms total)
+
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldPass
+[ OK ] FooTest.ShouldPass (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] 10 tests from MyParamSequence/MyParamTest
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/0
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/0 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/1
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/1 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/2
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/2 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/3
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/3 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/4
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/4 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/5
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/5 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/6
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/6 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/7
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/7 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/8
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/8 (0 ms)
+[ RUN ] MyParamSequence/MyParamTest.ShouldPass/9
+[ OK ] MyParamSequence/MyParamTest.ShouldPass/9 (0 ms)
+[----------] 10 tests from MyParamSequence/MyParamTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 12 tests from 3 test cases ran. (239 ms total)
+[ PASSED ] 12 tests.
+
+Repeating all tests (iteration 1) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (1 ms)
+[----------] 1 test from FooTest (1 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (1 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 2) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (0 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 3) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (1 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (1 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 4) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (0 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+PASS
+root@android:/data/nativetest #
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (0 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 3) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (1 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (1 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 4) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (0 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+PASS
+root@android:/data/nativetest #
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 2) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (0 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 3) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (1 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (1 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 4) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (0 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+PASS
+root@android:/data/nativetest #
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (0 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 3) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (1 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (1 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 4) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (0 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+PASS
+root@android:/data/nativetest #
+
+
+
+
+
+
+
+
+
+
+
+
+
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 2) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (0 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 3) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (1 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (1 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 4) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (0 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+PASS
+root@android:/data/nativetest #
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (0 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 3) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (1 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (1 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 4) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (0 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+PASS
+root@android:/data/nativetest #
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 2) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (0 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 3) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (1 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (1 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+
+Repeating all tests (iteration 4) . . .
+
+Note: Google Test filter = *ShouldFail
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from FooTest
+[ RUN ] FooTest.ShouldFail
+external/gtest/test/gtest_repeat_test.cc:96: Failure
+Value of: 1
+Expected: 0
+Expected failure.
+[ FAILED ] FooTest.ShouldFail (0 ms)
+[----------] 1 test from FooTest (0 ms total)
+
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran. (0 ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 1 test, listed below:
+[ FAILED ] FooTest.ShouldFail
+
+ 1 FAILED TEST
+PASS
+DUMP
diff --git a/dummy-libopenslestest b/dummy-libopenslestest
new file mode 100755
index 0000000..e3940c0
--- /dev/null
+++ b/dummy-libopenslestest
@@ -0,0 +1,41 @@
+#!/bin/sh
+cat << DUMP
+[==========] Running 2 tests from 1 test case.
+[----------] Global test environment set-up.
+[----------] 2 tests from MimeUri
+[ RUN ] MimeUri.testPlayAbsPath
+ PrefetchEventCallback: received event 3
+ PrefetchEventCallback: Error while prefetching data, exiting
+system/media/wilhelm/tests/mimeUri_test.cpp:84: Failure
+Value of: false
+ Actual: false
+Expected: true
+Error: Failed to prefetch data in time, exiting
+system/media/wilhelm/tests/mimeUri_test.cpp:211: Failure
+Value of: false
+ Actual: false
+Expected: true
+[ FAILED ] MimeUri.testPlayAbsPath
+[ RUN ] MimeUri.testPlayfilePath
+ PrefetchEventCallback: received event 3
+ PrefetchEventCallback: Error while prefetching data, exiting
+system/media/wilhelm/tests/mimeUri_test.cpp:84: Failure
+Value of: false
+ Actual: false
+Expected: true
+Error: Failed to prefetch data in time, exiting
+system/media/wilhelm/tests/mimeUri_test.cpp:211: Failure
+Value of: false
+ Actual: false
+Expected: true
+[ FAILED ] MimeUri.testPlayfilePath
+[----------] Global test environment tear-down
+[==========] 2 tests from 1 test case ran.
+[ PASSED ] 0 tests.
+[ FAILED ] 2 tests, listed below:
+[ FAILED ] MimeUri.testPlayAbsPath
+[ FAILED ] MimeUri.testPlayfilePath
+
+ 2 FAILED TESTS
+DUMP
+exit 1
diff --git a/json-format.h b/json-format.h
new file mode 100644
index 0000000..ded38a6
--- /dev/null
+++ b/json-format.h
@@ -0,0 +1,83 @@
+#ifndef JSON_FORMAT_H
+#define JSON_FORMAT_H
+
+#include <stdio.h>
+
+/* Token for JSON pieces.
+ *
+ * Used as simple command language to write JSON documents */
+enum json_token {
+ /* End of commands marker */
+ JSON_END,
+ /* Prints '{' */
+ JSON_DICT_START,
+ /* Prints '}' */
+ JSON_DICT_END,
+ /* Prints '[' */
+ JSON_ARRAY_START,
+ /* Prints ']' */
+ JSON_ARRAY_END,
+ /* Prints ',' */
+ JSON_COMMA,
+ /* Prints ':' */
+ JSON_COLON,
+ /* Prints '\n' but only in human readable mode */
+ JSON_NEWLINE,
+ /* Prints ' ' but only in human readable mode */
+ JSON_SPACE,
+ /* Consumes (int) and prints some indent but only in human readable mode */
+ JSON_INDENT,
+ /* Prints 'null' */
+ JSON_NULL,
+ /* Consumes (bool) and prints either 'true' or 'false' */
+ JSON_BOOLEAN,
+ /* Consumes (int) and prints it as a number */
+ JSON_NUMBER_INT,
+ /* Consumes (const char *) and prints it as a number */
+ JSON_NUMBER_STRING,
+ /* Consumes (const char *) and prints it as UTF-8 string */
+ JSON_STRING,
+ /* Just as JSON_STRING but without the final double quotes */
+ JSON_STRING_START,
+ /* Just as JSON_STRING but without both initial and final double qoutes */
+ JSON_STRING_NEXT,
+ /* Consumes (time_t) and formats that as JSON string with strftime() format
+ * of "%FT%TZ". This gives nice international timestmaps such as
+ * "2012-08-13T21:15:45Z" where 'T' separates date (YYYY-MM-DD) from time
+ * (HH:MM:SS) and 'Z' indicates the UTC timezone */
+ JSON_TIME_STAMP,
+ /* Consumes (struct timeval) and formats that as JSON string with printf()
+ * "%ds %dus" where the first part contains the number of seconds and the
+ * second part, number of microseconds. This format is used by LAVA to
+ * express duration */
+ JSON_TIME_DURATION,
+ /* Just as JSON_STRING but without the initial double quotes */
+ JSON_STRING_END,
+};
+
+
+/**
+ * Flag suitable for json_format(), causes the output to be generally human readable
+ **/
+#define JSON_READABLE 1
+
+/**
+ * Flag suitable for json_format(), causes a newline to be printed on JSON_END
+ **/
+#define JSON_EOL 2
+
+
+/**
+ * Render a sequence of JSON tokens on to the specified json_stream.
+ * The list must be terminated by JSON_END (zero).
+ *
+ * There are no checks for semantically valid output.
+ **/
+void
+__attribute__((sentinel))
+json_format(
+ FILE *stream,
+ unsigned flags, ...
+ );
+
+#endif
diff --git a/json-test.h b/json-test.h
new file mode 100644
index 0000000..eebcd03
--- /dev/null
+++ b/json-test.h
@@ -0,0 +1,6 @@
+#ifndef JSON_TEST_H
+#define JSON_TEST_H
+
+void json_test_all();
+
+#endif
diff --git a/src/bundle.c b/src/bundle.c
new file mode 100644
index 0000000..a89ea6a
--- /dev/null
+++ b/src/bundle.c
@@ -0,0 +1,203 @@
+#include "bundle.h"
+
+#include "json-format.h"
+
+
+void
+bundle_print_header(
+ FILE *bundle_stream,
+ unsigned flags,
+ const char *format
+ )
+{
+ /* This should print something like:
+ *
+ * <indent 0>{
+ * <indent 1>"format": $format,
+ * <indent 1>"test_runs": [
+ */
+ json_format(bundle_stream, flags,
+ /* Open the bundle */
+ JSON_DICT_START,
+ /* Add the format field */
+ JSON_NEWLINE, JSON_INDENT, 1,
+ JSON_STRING, "format", JSON_COLON, JSON_SPACE,
+ JSON_STRING, format, JSON_COMMA,
+ /* Add the test run field */
+ JSON_NEWLINE, JSON_INDENT, 1,
+ JSON_STRING, "test_runs", JSON_COLON, JSON_SPACE,
+ JSON_ARRAY_START,
+ NULL);
+}
+
+
+void
+bundle_print_footer(
+ FILE *bundle_stream,
+ unsigned flags
+ )
+{
+ /* This should print something like:
+ *
+ * <indent 1>]<newline>
+ * <indent 0>}<newline>
+ */
+ json_format(bundle_stream, flags | JSON_EOL,
+ JSON_NEWLINE, JSON_INDENT, 1, JSON_ARRAY_END,
+ JSON_NEWLINE, JSON_DICT_END,
+ NULL);
+}
+
+
+void
+bundle_print_test_run_header(
+ FILE *bundle_stream,
+ unsigned flags,
+ bool comma,
+ const char *analyzer_assigned_uuid,
+ time_t analyzer_assigned_date,
+ bool time_check_performed,
+ const char *test_id
+ )
+{
+ /* This should print something like:
+ *
+ * ,
+ */
+ if (comma)
+ json_format(bundle_stream, flags, JSON_COMMA, JSON_SPACE, NULL);
+ /* This should print something like:
+ *
+ * <indent 2>{
+ * <indent 3>"analyzer_assigned_uuid": $analyzer_assigned_uuid,
+ * <indent 3>"analyzer_assigned_date": $analyzer_assigned_date,
+ * <indent 3>"time_check_performed": false,
+ * <indent 3>"test_id": $test_id,
+ * <indent 3>"test_results": [
+ */
+ json_format(bundle_stream, flags,
+ JSON_NEWLINE, JSON_INDENT, 2, JSON_DICT_START,
+ JSON_NEWLINE, JSON_INDENT, 3,
+ JSON_STRING, "analyzer_assigned_uuid", JSON_COLON, JSON_SPACE,
+ JSON_STRING, analyzer_assigned_uuid, JSON_COMMA,
+ JSON_NEWLINE, JSON_INDENT, 3,
+ JSON_STRING, "analyzer_assigned_date", JSON_COLON, JSON_SPACE,
+ JSON_TIME_STAMP, analyzer_assigned_date, JSON_COMMA,
+ JSON_NEWLINE, JSON_INDENT, 3,
+ JSON_STRING, "time_check_performed", JSON_COLON, JSON_SPACE,
+ JSON_BOOLEAN, time_check_performed, JSON_COMMA, JSON_SPACE,
+ JSON_NEWLINE, JSON_INDENT, 3,
+ JSON_STRING, "test_id", JSON_COLON, JSON_SPACE,
+ JSON_STRING, test_id, JSON_COMMA,
+ JSON_NEWLINE, JSON_INDENT, 3,
+ JSON_STRING, "test_results", JSON_COLON, JSON_SPACE,
+ JSON_ARRAY_START,
+ NULL);
+}
+
+
+void
+bundle_print_test_run_footer(
+ FILE *bundle_stream,
+ unsigned flags
+ )
+{
+ /* This should print something like:
+ *
+ * <indent 3>]
+ * <indent 2>}
+ */
+ json_format(bundle_stream, flags,
+ JSON_NEWLINE, JSON_INDENT, 3, JSON_ARRAY_END,
+ JSON_NEWLINE, JSON_INDENT, 2, JSON_DICT_END,
+ NULL);
+}
+
+
+void
+bundle_print_test_result_header(
+ FILE *bundle_stream,
+ unsigned flags,
+ bool comma,
+ const char *test_case_id,
+ time_t timestamp
+ )
+{
+ if (comma)
+ json_format(bundle_stream, flags, JSON_COMMA, JSON_SPACE, NULL);
+ /* This should print something like:
+ *
+ * <indent 4>{
+ * <indent 5>"test_case_id": $test_case_id,
+ * <indent 5>"timestamp": $timestamp,
+ * <indent 5>"message": "
+ *
+ * note: the message value (string) is _not_ terminated
+ */
+ json_format(bundle_stream, flags,
+ JSON_NEWLINE, JSON_INDENT, 4, JSON_DICT_START,
+ JSON_NEWLINE, JSON_INDENT, 5,
+ JSON_STRING, "test_case_id", JSON_COLON, JSON_SPACE,
+ JSON_STRING, test_case_id, JSON_COMMA,
+ JSON_NEWLINE, JSON_INDENT, 5,
+ JSON_STRING, "timestamp", JSON_COLON, JSON_SPACE,
+ JSON_TIME_STAMP, timestamp, JSON_COMMA,
+ JSON_NEWLINE, JSON_INDENT, 5,
+ JSON_STRING, "message", JSON_COLON, JSON_SPACE,
+ JSON_STRING_START, "",
+ NULL);
+}
+
+
+
+void
+bundle_print_test_result_message(
+ FILE *bundle_stream,
+ unsigned flags,
+ const char *message
+ )
+{
+ json_format(bundle_stream, flags,
+ JSON_STRING_NEXT, message,
+ JSON_STRING_NEXT, "\n", NULL);
+}
+
+
+void
+bundle_print_test_result_footer(
+ FILE *bundle_stream,
+ unsigned flags,
+ const char *result,
+ const char *log_filename,
+ int log_lineno,
+ struct timeval duration
+ )
+{
+ /* This should print something like:
+ *
+ * ",
+ * <indent 5>"result": $result,
+ * <indent 5>"duration": $duration,
+ * <indent 5>"log_filename": $log_filename,
+ * <indent 5>"log_lineno": $log_lineno,
+ * <indent 4>}
+ *
+ * note: the first part terminates the quote left open by bundle_print_test_result_header()
+ */
+ json_format(bundle_stream, flags,
+ JSON_STRING_END, "", JSON_COMMA,
+ JSON_NEWLINE, JSON_INDENT, 5,
+ JSON_STRING, "result", JSON_COLON, JSON_SPACE,
+ JSON_STRING, result, JSON_COMMA,
+ JSON_NEWLINE, JSON_INDENT, 5,
+ JSON_STRING, "duration", JSON_COLON, JSON_SPACE,
+ JSON_TIME_DURATION, duration, JSON_COMMA,
+ JSON_NEWLINE, JSON_INDENT, 5,
+ JSON_STRING, "log_filename", JSON_COLON, JSON_SPACE,
+ JSON_STRING, log_filename, JSON_COMMA,
+ JSON_NEWLINE, JSON_INDENT, 5,
+ JSON_STRING, "log_lineno", JSON_COLON, JSON_SPACE,
+ JSON_NUMBER_INT, log_lineno,
+ JSON_NEWLINE, JSON_INDENT, 4, JSON_DICT_END,
+ NULL);
+}
diff --git a/src/debug.c b/src/debug.c
new file mode 100644
index 0000000..9ba4ec4
--- /dev/null
+++ b/src/debug.c
@@ -0,0 +1,35 @@
+#include "debug.h"
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+
+static bool debug_enabled = false;
+static FILE *debug_stream = NULL;
+
+
+void
+debug_enable(
+ FILE *stream
+ )
+{
+ debug_stream = stream;
+ debug_enabled = true;
+}
+
+
+void
+__attribute__((format(printf, 1, 2)))
+debug_log(
+ const char *format, ...
+ )
+{
+ va_list ap;
+ va_start(ap, format);
+ if (debug_enabled) {
+ fprintf(debug_stream, "LAVA> ");
+ vfprintf(debug_stream, format, ap);
+ }
+ va_end(ap);
+}
diff --git a/src/json-format.c b/src/json-format.c
new file mode 100644
index 0000000..1661a13
--- /dev/null
+++ b/src/json-format.c
@@ -0,0 +1,200 @@
+#include "json-format.h"
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <time.h>
+
+
+static
+void
+json_string(FILE *stream, const char *value) {
+ char c;
+ /* TODO: verify the string is valid UTF-8 */
+ while ((c = *value++)) {
+ switch (c) {
+ case '"':
+ fputc('\\', stream);
+ fputc('"', stream);
+ break;
+ case '\\':
+ fputc('\\', stream);
+ fputc('\\', stream);
+ break;
+#if 0
+ case '/':
+ fputc('\\', stream);
+ fputc('/', stream);
+ break;
+#endif
+ case '\b':
+ fputc('\\', stream);
+ fputc('b', stream);
+ break;
+ case '\f':
+ fputc('\\', stream);
+ fputc('f', stream);
+ break;
+ case '\n':
+ fputc('\\', stream);
+ fputc('n', stream);
+ break;
+ case '\r':
+ fputc('\\', stream);
+ fputc('r', stream);
+ break;
+ case '\t':
+ fputc('\\', stream);
+ fputc('t', stream);
+ break;
+ default:
+ fputc(c, stream);
+ break;
+ }
+ }
+}
+
+
+void
+__attribute__((sentinel))
+json_format(FILE *stream, unsigned flags, ...)
+{
+ va_list ap;
+ enum json_token token;
+ va_start(ap, flags);
+ do {
+ token = va_arg(ap, enum json_token);
+ switch (token) {
+ case JSON_END:
+ if (JSON_EOL & flags)
+ fputc('\n', stream);
+ break;
+ case JSON_DICT_START:
+ fputc('{', stream);
+ break;
+ case JSON_DICT_END:
+ fputc('}', stream);
+ break;
+ case JSON_ARRAY_START:
+ fputc('[', stream);
+ break;
+ case JSON_ARRAY_END:
+ fputc(']', stream);
+ break;
+ case JSON_COMMA:
+ fputc(',', stream);
+ break;
+ case JSON_COLON:
+ fputc(':', stream);
+ break;
+ case JSON_NEWLINE:
+ if (JSON_READABLE & flags)
+ fputc('\n', stream);
+ break;
+ case JSON_SPACE:
+ if (JSON_READABLE & flags)
+ fputc(' ', stream);
+ break;
+ case JSON_INDENT:
+ {
+ int depth;
+ depth = va_arg(ap, int);
+ if (JSON_READABLE & flags)
+ while (depth-- > 0)
+ fputs(" ", stream);
+ }
+ break;
+ case JSON_NULL:
+ fputs("null", stream);
+ break;
+ case JSON_BOOLEAN:
+ {
+ bool value;
+ value = va_arg(ap, int); /* _Bool is promoted to int when passed to ... */
+ fputs(value ? "true" : "false", stream);
+ }
+ break;
+ case JSON_NUMBER_INT:
+ {
+ int value;
+ value = va_arg(ap, int);
+ fprintf(stream, "%d", value);
+ }
+ break;
+ case JSON_NUMBER_STRING:
+ {
+ const char *value;
+ value = va_arg(ap, const char *);
+ /* TODO: verify the string is a valid number */
+ fputs(value, stream);
+ }
+ break;
+ case JSON_STRING:
+ {
+ const char *value;
+ value = va_arg(ap, const char *);
+ fputc('"', stream);
+ json_string(stream, value);
+ fputc('"', stream);
+ }
+ break;
+ case JSON_STRING_START:
+ {
+ const char *value;
+ value = va_arg(ap, const char *);
+ fputc('"', stream);
+ json_string(stream, value);
+ }
+ break;
+ case JSON_STRING_NEXT:
+ {
+ const char *value;
+ value = va_arg(ap, const char *);
+ json_string(stream, value);
+ }
+ break;
+ case JSON_STRING_END:
+ {
+ const char *value;
+ value = va_arg(ap, const char *);
+ json_string(stream, value);
+ fputc('"', stream);
+ }
+ break;
+ case JSON_TIME_STAMP:
+ {
+ time_t value;
+ struct tm tm;
+ char buf[128];
+ value = va_arg(ap, time_t);
+ gmtime_r(&value, &tm);
+ strftime(buf, sizeof buf, "%FT%TZ", &tm);
+ fputc('"', stream);
+ json_string(stream, buf);
+ fputc('"', stream);
+ }
+ break;
+ case JSON_TIME_DURATION:
+ {
+ struct timeval value;
+ const int SECONDS_IN_DAY = 60 * 60 * 24;
+ char buf[128];
+ value = va_arg(ap, struct timeval);
+ snprintf(buf, sizeof buf, "%0ldd %0lds %0ldus",
+ (long)(value.tv_sec) / SECONDS_IN_DAY,
+ (long)(value.tv_sec) % SECONDS_IN_DAY,
+ (long)value.tv_usec);
+ fputc('"', stream);
+ json_string(stream, buf);
+ fputc('"', stream);
+ }
+ break;
+ default:
+ abort();
+ break;
+ }
+ } while (token != JSON_END);
+ va_end(ap);
+}
diff --git a/src/json-test.c b/src/json-test.c
new file mode 100644
index 0000000..014e549
--- /dev/null
+++ b/src/json-test.c
@@ -0,0 +1,111 @@
+#include "json-test.h"
+
+#include "json-format.h"
+
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#define MSG_INFO "[==========] "
+#define MSG_DEBUG "[----------] "
+
+
+#define TEST_HEADER() printf(MSG_INFO "Output of: %s\n", __FUNCTION__)
+#define TEST_NEXT() printf("\n" MSG_DEBUG "Additional line of output\n")
+#define TEST_FOOTER() printf("\n" MSG_DEBUG "(end of test case)\n")
+
+
+static void test_nothing() {
+ TEST_HEADER();
+ json_format(stdout, 0, NULL);
+ TEST_FOOTER();
+}
+
+
+static void test_dict() {
+ TEST_HEADER();
+ json_format(stdout, 0, JSON_DICT_START, JSON_COLON, JSON_DICT_END, NULL);
+ TEST_FOOTER();
+}
+
+
+static void test_array() {
+ TEST_HEADER();
+ json_format(stdout, 0, JSON_ARRAY_START, JSON_COMMA, JSON_ARRAY_END, NULL);
+ TEST_FOOTER();
+}
+
+
+static void test_null() {
+ TEST_HEADER();
+ json_format(stdout, 0, JSON_NULL, NULL);
+ TEST_FOOTER();
+}
+
+
+static void test_bool() {
+ TEST_HEADER();
+ json_format(stdout, 0, JSON_BOOLEAN, true, NULL);
+ TEST_NEXT();
+ json_format(stdout, 0, JSON_BOOLEAN, false, NULL);
+ TEST_FOOTER();
+}
+
+
+static void test_int() {
+ TEST_HEADER();
+ json_format(stdout, 0, JSON_NUMBER_INT, 0, NULL);
+ TEST_NEXT();
+ json_format(stdout, 0, JSON_NUMBER_INT, INT_MAX, NULL);
+ TEST_NEXT();
+ json_format(stdout, 0, JSON_NUMBER_INT, INT_MIN, NULL);
+ TEST_FOOTER();
+}
+
+
+static void test_int_str() {
+ TEST_HEADER();
+ json_format(stdout, 0, JSON_NUMBER_STRING, "0", NULL);
+ TEST_NEXT();
+ json_format(stdout, 0, JSON_NUMBER_STRING, "15.2", NULL);
+ TEST_FOOTER();
+}
+
+
+static void test_str() {
+ TEST_HEADER();
+ json_format(stdout, 0, JSON_STRING, "hello world", NULL);
+ TEST_NEXT();
+ json_format(stdout, 0, JSON_STRING, "double quote: \"", NULL);
+ TEST_NEXT();
+ json_format(stdout, 0, JSON_STRING, "forward slash: \\", NULL);
+ TEST_NEXT();
+ json_format(stdout, 0, JSON_STRING, "backspace: \b", NULL);
+ TEST_NEXT();
+ json_format(stdout, 0, JSON_STRING, "form feed: \f", NULL);
+ TEST_NEXT();
+ json_format(stdout, 0, JSON_STRING, "new line: \n", NULL);
+ TEST_NEXT();
+ json_format(stdout, 0, JSON_STRING, "carriage return:\r", NULL);
+ TEST_NEXT();
+ json_format(stdout, 0, JSON_STRING, "tab: \t", NULL);
+ TEST_NEXT();
+ json_format(stdout, 0, JSON_STRING, "single quote: ' (should be UNQUOTED)", NULL);
+ TEST_NEXT();
+ json_format(stdout, 0, JSON_STRING, "", NULL);
+ TEST_NEXT();
+ json_format(stdout, 0, JSON_STRING, "0", NULL);
+ TEST_FOOTER();
+}
+
+
+void json_test_all() {
+ test_nothing();
+ test_dict();
+ test_array();
+ test_null();
+ test_bool();
+ test_int();
+ test_int_str();
+ test_str();
+}
diff --git a/src/lava-wrapper.c b/src/lava-wrapper.c
new file mode 100644
index 0000000..cbb8ab9
--- /dev/null
+++ b/src/lava-wrapper.c
@@ -0,0 +1,354 @@
+/**
+ * Copyright (c) Zygmunt Krynicki <zygmunt.krynicki@linaro.org> 2012
+ **/
+
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "bundle.h"
+#include "debug.h"
+#include "json-format.h"
+#include "json-test.h"
+#include "text-utils.h"
+#include "uuid.h"
+
+/** Patterns used to discover gtest-like output */
+#define GTEST_LOG1_PATTERN "[==========] "
+#define GTEST_LOG2_PATTERN "[----------] "
+#define GTEST_RUN_PATTERN "[ RUN ] "
+#define GTEST_OK_PATTERN "[ OK ] "
+#define GTEST_PASSED_PATTERN "[ PASSED ] "
+#define GTEST_FAILED_PATTERN "[ FAILED ] "
+
+enum gtest_line_type {
+ GTEST_LINE_LOG1,
+ GTEST_LINE_LOG2,
+ GTEST_LINE_RUN,
+ GTEST_LINE_OK,
+ GTEST_LINE_PASSED,
+ GTEST_LINE_FAILED,
+ GTEST_LINE_OTHER
+};
+
+
+static
+void
+process_output(
+ FILE *bundle_stream,
+ FILE *child_stream,
+ unsigned flags
+ )
+{
+ char *line = NULL;
+ size_t line_capacity = 0;
+ char *line_sans_pattern = NULL;
+ int lineno = 0;
+ enum gtest_line_type line_type;
+
+ int test_run_cnt = 0;
+ char *previous_test_id = NULL;
+ size_t previous_test_id_capacity = 0;
+
+ int test_result_cnt = 0;
+ bool test_result_open = false;
+ const char *test_result_result = "unknown";
+ bool test_result_ready = false;
+ struct timeval test_result_start = { .tv_sec = 0, .tv_usec = 0};
+
+ struct timeval line_timestamp;
+ do {
+ /* Read a line from the child stream */
+ if (text_readline(&line, &line_capacity, child_stream) != 0) {
+ perror("text_readline()");
+ abort();
+ }
+ lineno += 1;
+ /* Measure the time, we may need it in several spots below */
+ gettimeofday(&line_timestamp, NULL);
+ /* We need to classify each line, there are a number of options:
+ * 0) status lines (either '=' or '-')
+ * 1) a 'RUN' line is where we start to run a test case
+ * 2) a 'OK' line is when the test passes
+ * 3) a 'FAILED' line is when the test has failed (but it must be
+ * paired with 'RUN' line just directly before.
+ * 4) other lines, arbitrary messages generated by the the case
+ * 5) a summary line like 'PASSED' or FAILED (we ignore those) */
+ if (strstr(line, GTEST_LOG1_PATTERN)) {
+ line_type = GTEST_LINE_LOG1;
+ line_sans_pattern = line + strlen(GTEST_LOG1_PATTERN);
+ } else if (strstr(line, GTEST_LOG2_PATTERN)) {
+ line_type = GTEST_LINE_LOG2;
+ line_sans_pattern = line + strlen(GTEST_LOG2_PATTERN);
+ } else if (strstr(line, GTEST_RUN_PATTERN)) {
+ line_type = GTEST_LINE_RUN;
+ line_sans_pattern = line + strlen(GTEST_RUN_PATTERN);
+ } else if (strstr(line, GTEST_OK_PATTERN)) {
+ line_type = GTEST_LINE_OK;
+ line_sans_pattern = line + strlen(GTEST_OK_PATTERN);
+ } else if (strstr(line, GTEST_PASSED_PATTERN)) {
+ line_type = GTEST_LINE_PASSED;
+ line_sans_pattern = line + strlen(GTEST_PASSED_PATTERN);
+ } else if (strstr(line, GTEST_FAILED_PATTERN)) {
+ line_type = GTEST_LINE_FAILED;
+ line_sans_pattern = line + strlen(GTEST_FAILED_PATTERN);
+ } else {
+ line_type = GTEST_LINE_OTHER;
+ line_sans_pattern = line;
+ }
+ /* Now that we know what kind of line we have we can run our simple state
+ * machine to react to the data */
+ switch (line_type) {
+ case GTEST_LINE_LOG1:
+ case GTEST_LINE_LOG2:
+ case GTEST_LINE_PASSED:
+ debug_log("message from gtest: %s\n", line_sans_pattern);
+ break;
+ case GTEST_LINE_FAILED:
+ /* FAILED line is printed when a test case fails
+ * and we need to keep track of that. Sadly, it is
+ * also printed as a 'summary' line at the end of a test run.
+ *
+ * To differentiate them we will treat any FAILED line that was
+ * printed after a RUN line was seen (which opens a test case)
+ * as the terminator */
+ if (test_result_open) {
+ debug_log("test case finished unsuccessfully\n");
+ /* This test case has failed */
+ test_result_result = "fail";
+ /* And we have enough data to print the test case footer */
+ test_result_ready = true;
+ } else
+ debug_log("message from gtest: %s\n", line_sans_pattern);
+ break;
+ case GTEST_LINE_RUN:
+ {
+ char *dot;
+ char *test_case_id;
+ char *test_id;
+ /* We need to terminate previous test case that has probably
+ * crashed bad enough not to print the failure record */
+ if (test_result_open) {
+ struct timeval duration;
+ duration.tv_sec = line_timestamp.tv_sec - test_result_start.tv_sec;
+ duration.tv_usec = line_timestamp.tv_usec - test_result_start.tv_usec;
+ debug_log("closing previous test result\n");
+ bundle_print_test_result_footer(
+ bundle_stream, flags,
+ test_result_result, "<stdout>", lineno, duration);
+ test_result_ready = false;
+ test_result_open = false;
+ }
+ /* Parse the RUN line. Try to find the test case id (it
+ * should be right after the dot component that separates
+ * test id from test case id */
+ dot = strchr(line_sans_pattern, '.');
+ if (dot != NULL) {
+ /* The test case has a dot component. We can use that to
+ * discover the test id and test case id. Let's just split
+ * it there by modifying the dot to a nul character */
+ *dot = 0;
+ test_id = line_sans_pattern;
+ test_case_id = dot + 1;
+ } else {
+ /* For some reason the test case did not have the dot that
+ * otherwise separates test id from test case id. */
+ test_id = "unknown-gtest-based-test";
+ test_case_id = line_sans_pattern;
+ }
+ /* We may need to print the test run header.
+ *
+ * This can happen when we see a change in test_id or when
+ * we need the initial header for the very first test case. */
+ if (previous_test_id == NULL || strcmp(previous_test_id, test_id) != 0) {
+ char analyzer_assigned_uuid[UUID_ASCII_LEN + 1];
+ const bool time_check_performed = false;
+ /* Close the previous test run if it is open */
+ if (test_run_cnt > 0) {
+ debug_log("closing previous test run\n");
+ bundle_print_test_run_footer(bundle_stream, flags);
+ }
+ /* Copy the old test_id so that we can keep comparing it */
+ if (text_copy(&previous_test_id,
+ &previous_test_id_capacity, test_id) != 0) {
+ perror("text_copy()");
+ abort();
+ }
+ /* Generate an UUID */
+ if (uuid_gen(analyzer_assigned_uuid) != 0) {
+ perror("uuid_gen()");
+ abort();
+ }
+ debug_log("generated analyzer_assigned_uuid: %s\n", analyzer_assigned_uuid);
+ /* Open another test run */
+ debug_log("starting new test run for test_id: %s\n", test_id);
+ bundle_print_test_run_header(
+ bundle_stream, flags, test_run_cnt > 0,
+ analyzer_assigned_uuid, line_timestamp.tv_sec,
+ time_check_performed, test_id);
+ /* Keep track of the number of test runs we have printed */
+ test_run_cnt += 1;
+ /* Reset the number of test cases we've printed in this test run */
+ test_result_cnt = 0;
+ }
+ debug_log("starting new test result for test_case_id: %s\n", test_case_id);
+ test_result_start = line_timestamp;
+ /* Print the header of the test result */
+ bundle_print_test_result_header(
+ bundle_stream, flags, test_result_cnt > 0, test_case_id,
+ test_result_start.tv_sec);
+ /* Keep track of subsequent test cases in one test run */
+ test_result_cnt += 1;
+ /* Keep track of output state */
+ test_result_open = true;
+ /* Reset result to unknown */
+ test_result_result = "unknown";
+ }
+ break;
+ case GTEST_LINE_OK:
+ debug_log("test case finished successfully\n");
+ /* This test case has passed */
+ test_result_result = "pass";
+ /* And we have enough data to print the test case footer */
+ test_result_ready = true;
+ break;
+ case GTEST_LINE_OTHER:
+ /* Once we've seen a RUN line that opens a test case
+ * we want to capture any output as test case message. */
+ if (test_result_open) {
+ debug_log("message from test: %s\n", line_sans_pattern);
+ bundle_print_test_result_message(
+ bundle_stream, flags,
+ line_sans_pattern);
+ } else
+ debug_log("message from gtest: %s\n", line_sans_pattern);
+ break;
+ default:
+ abort();
+ }
+ /* Write out the test result once we have everything */
+ if (test_result_ready) {
+ struct timeval duration;
+ duration.tv_sec = line_timestamp.tv_sec - test_result_start.tv_sec;
+ duration.tv_usec = line_timestamp.tv_usec - test_result_start.tv_usec;
+ debug_log("closing previous test result\n");
+ bundle_print_test_result_footer(
+ bundle_stream, flags,
+ test_result_result, "<stdout>", lineno, duration);
+ test_result_ready = false;
+ test_result_open = false;
+ }
+ } while (!feof(child_stream));
+ /* We may need to terminate the final test result */
+ if (test_result_open) {
+ struct timeval duration;
+ duration.tv_sec = line_timestamp.tv_sec - test_result_start.tv_sec;
+ duration.tv_usec = line_timestamp.tv_usec - test_result_start.tv_usec;
+ debug_log("closing previous (final) test result\n");
+ bundle_print_test_result_footer(
+ bundle_stream, flags,
+ test_result_result, "<stdout>", lineno, duration);
+ }
+ /* We may need to terminate the final test run */
+ if (test_run_cnt > 0) {
+ debug_log("closing previous (final) test run\n");
+ bundle_print_test_run_footer(bundle_stream, flags);
+ }
+ /* Reclaim line cache */
+ if (line)
+ free(line);
+ /* Reclaim memory used to keep the previous test_id */
+ if (previous_test_id)
+ free(previous_test_id);
+}
+
+
+static void
+run_test_prog(
+ const char *test_prog,
+ const char *bundle_name,
+ unsigned flags
+ )
+{
+ FILE *child_stream;
+ FILE *bundle_stream;
+ /* Open the bundle file */
+ bundle_stream = fopen(bundle_name, "wt");
+ if (bundle_stream == NULL) {
+ perror("fopen()");
+ abort();
+ }
+ /* Open the child process */
+ child_stream = popen(test_prog, "r");
+ if (child_stream == NULL) {
+ perror("popen()");
+ abort();
+ }
+ /* Write the bundle header */
+ debug_log("Saving bundle to %s\n", bundle_name);
+ bundle_print_header(bundle_stream, flags, "Dashboard Bundle Format 1.3");
+ /* Process the output data */
+ process_output(bundle_stream, child_stream, flags);
+ /* Terminate the test process */
+ pclose(child_stream);
+ /* Write the bundle footer */
+ bundle_print_footer(bundle_stream, flags);
+}
+
+
+static void show_usage() {
+ printf("Usage: android-lava-wrapper [-o BUNDLE] [-r] [-d] <executable>\n"
+ " android-lava-wrapper -t\n"
+ "\n"
+ "The first form runs the specified executable and parses\n"
+ "the output as a gtest-based test.\n"
+ "-r creates a human-readable bundle\n"
+ "-o sets the name of the bundle, by default it is bundle.json\n"
+ "-d enables debugging\n"
+ "\n"
+ "The second form runs the internal self-test\n");
+}
+
+
+int main(int argc, char *argv[]) {
+ int opt;
+ unsigned flags = 0;
+ const char *bundle_pathname = "bundle.json";
+ while ((opt = getopt(argc, argv, "drto:")) != -1) {
+ switch (opt) {
+ case 'd':
+ debug_enable(stderr);
+ break;
+ case 'r':
+ flags |= JSON_READABLE;
+ break;
+ case 't':
+ json_test_all();
+ return 0;
+ case 'o':
+ bundle_pathname = optarg;
+ break;
+ default:
+ show_usage();
+ printf("\nUnsupported option: %c\n", optopt);
+ return 1;
+ }
+ }
+ if (optind >= argc) {
+ show_usage();
+ printf("\nYou have to pass the pathname of the executable to run\n");
+ return 1;
+ } else {
+ run_test_prog(argv[optind], bundle_pathname, flags);
+ return 0;
+ }
+}
diff --git a/src/text-utils.c b/src/text-utils.c
new file mode 100644
index 0000000..a832f3f
--- /dev/null
+++ b/src/text-utils.c
@@ -0,0 +1,122 @@
+#include "text-utils.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "debug.h"
+
+
+int
+text_readline(
+ char **buffer_ptr,
+ size_t *capacity_ptr,
+ FILE *stream
+ )
+{
+ int c;
+ size_t size = 0;
+ char *buffer;
+ size_t capacity;
+ int error;
+ /* Ensure the caller passed line and capacity pointers */
+ if (buffer_ptr == NULL || capacity_ptr == NULL)
+ return EINVAL;
+ buffer = *buffer_ptr;
+ capacity = *capacity_ptr;
+ do {
+ text_grow_buffer(&buffer, &capacity, size + 1);
+ /* Do the IO, read one byte at a time */
+ c = fgetc(stream);
+ if (c != EOF && c != '\n') {
+ buffer[size++] = (char)c;
+ } else {
+ buffer[size++] = 0;
+ break;
+ }
+ } while (1);
+ error = 0;
+out:
+ /* Copy back the line and capacity */
+ *buffer_ptr = buffer;
+ *capacity_ptr = capacity;
+ return error;
+}
+
+
+int
+text_copy(
+ char **buffer_ptr,
+ size_t *capacity_ptr,
+ const char *text
+ )
+{
+ size_t text_len;
+ int error;
+ /* Ensure the caller passed line and capacity pointers */
+ if (buffer_ptr == NULL || capacity_ptr == NULL)
+ return EINVAL;
+ if (text == NULL)
+ return EINVAL;
+ text_len = strlen(text);
+ error = text_grow_buffer(buffer_ptr, capacity_ptr, text_len + 1);
+ if (error != 0)
+ return error;
+ strncpy(*buffer_ptr, text, *capacity_ptr);
+ return 0;
+}
+
+
+/**
+ * Find a good reallocation size for the current size
+ **/
+static
+size_t
+next_best_capacity(size_t size) {
+ const size_t good_sizes[] = {128, 512, 4 * 1024, 16 * 1024};
+ size_t i;
+ /* Try to use one of the good sizes */
+ for (i=0; i<sizeof(good_sizes) / sizeof(*good_sizes); ++i)
+ if (size < good_sizes[i])
+ return good_sizes[i];
+ /* Or just double the current size */
+ return size * 2;
+}
+
+
+int
+text_grow_buffer(
+ char **buffer_ptr,
+ size_t *capacity_ptr,
+ size_t min_capacity
+ )
+{
+ char *buffer, *new_buffer;
+ size_t capacity, new_capacity;
+ /* Ensure the caller passed line and capacity pointers */
+ if (buffer_ptr == NULL || capacity_ptr == NULL)
+ return EINVAL;
+ /* Load current buffer pointer and size */
+ buffer = *buffer_ptr;
+ capacity = *capacity_ptr;
+ /* Keep growing the buffer as required */
+ while (capacity <= min_capacity) {
+ new_capacity = next_best_capacity(min_capacity);
+ debug_log("Resizing text buffer from %zd to %zd bytes\n",
+ capacity, new_capacity);
+ new_buffer = realloc(buffer, new_capacity);
+ if (new_buffer != NULL) {
+ debug_log("Resize complete, old buffer %p, new buffer %p\n",
+ buffer, new_buffer);
+ buffer = new_buffer;
+ capacity = new_capacity;
+ } else {
+ debug_log("Unable to resize line buffer!\n");
+ return ENOMEM;
+ }
+ }
+ /* Copy back the new buffer pointer and new capacity */
+ *buffer_ptr = buffer;
+ *capacity_ptr = capacity;
+ return 0;
+}
diff --git a/src/uuid.c b/src/uuid.c
new file mode 100644
index 0000000..cae0ee5
--- /dev/null
+++ b/src/uuid.c
@@ -0,0 +1,29 @@
+#include "uuid.h"
+
+#include <errno.h>
+#include <stdio.h>
+
+int
+uuid_gen(char *buf) {
+ FILE *stream = NULL;
+ int retval;
+ size_t num_read;
+
+ stream = fopen(UUID_PATHNAME, "rt");
+ if (!stream) {
+ retval = errno;
+ goto out;
+ }
+ num_read = fread(buf, 1, UUID_ASCII_LEN, stream);
+ if (num_read != UUID_ASCII_LEN) {
+ retval = errno ? errno : EIO;
+ goto out;
+ } else {
+ buf[UUID_ASCII_LEN] = 0;
+ retval = 0;
+ }
+out:
+ if (stream != NULL)
+ fclose(stream);
+ return retval;
+}
diff --git a/text-utils.h b/text-utils.h
new file mode 100644
index 0000000..cf20b8d
--- /dev/null
+++ b/text-utils.h
@@ -0,0 +1,51 @@
+#ifndef TEXT_UTILS_H
+#define TEXT_UTILS_H
+
+#include <stdio.h>
+
+/**
+ * Read one line from stream.
+ *
+ * This function allocates the memory on demand, reusing any previous
+ * buffers if possible. The buffer data is kept in two variables that must
+ * be provided by the caller.
+ *
+ * Uses text_grow_buffer() and can fail the same way.
+ **/
+int
+text_readline(
+ char **buffer_ptr,
+ size_t *capacity_ptr,
+ FILE *stream
+ );
+
+
+/**
+ * Copy specified text into the specified buffer.
+ *
+ * Uses text_grow_buffer() and can fail the same way.
+ **/
+int
+text_copy(
+ char **buffer_ptr,
+ size_t *capacity_ptr,
+ const char *text
+ );
+
+
+/**
+ * Grow the text buffer so that it can hold at lest the specified required
+ * capacity of bytes.
+ *
+ * Returns 0 on success. On out-of-memory error the old line buffer and
+ * capacity are left intact and it is expected that the caller will free
+ * that buffer.
+ **/
+int
+text_grow_buffer(
+ char **buffer_ptr,
+ size_t *capacity_ptr,
+ size_t min_capacity
+ );
+
+#endif
diff --git a/uuid.h b/uuid.h
new file mode 100644
index 0000000..8ca4d3d
--- /dev/null
+++ b/uuid.h
@@ -0,0 +1,24 @@
+#ifndef UUID_H
+#define UUID_H
+
+/**
+ * Pathname of a special file that generates UUID on read
+ **/
+#define UUID_PATHNAME "/proc/sys/kernel/random/uuid"
+
+/**
+ * Number of bytes, not including the final nul byte, required to store an UUID in text form
+ **/
+#define UUID_ASCII_LEN 36
+
+/**
+ * Generate a random UUID by reading from UUID_PATHNAME
+ *
+ * The buffer must have at least UUID_ASCII_LEN + 1 bytes.
+ * Returns 0 on success.
+ **/
+
+int
+uuid_gen(char *buf);
+
+#endif