summaryrefslogtreecommitdiffstats
path: root/tinyusb/test/vendor/ceedling/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'tinyusb/test/vendor/ceedling/plugins')
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/beep/README.md22
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/beep/lib/beep.rb40
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/bullseye/assets/template.erb15
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/bullseye/bullseye.rake169
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/bullseye/config/defaults.yml57
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/bullseye/lib/bullseye.rb194
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/bullseye/readme.txt0
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/colour_report/lib/colour_report.rb16
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/command_hooks/README.md53
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/command_hooks/lib/command_hooks.rb92
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/README.md250
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/Rakefile19
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/project.yml71
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/rakefile.rb7
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.c1
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.h14
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/custom_types.h6
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.c7
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.h16
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.c93
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.h11
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.c16
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.h8
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.c1
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.h6
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_event_processor.c155
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_foo.c47
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/lib/fake_function_framework.rb87
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/lib/fff_mock_generator.rb163
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_header_generator_spec.rb304
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_source_generator_spec.rb149
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/spec/header_generator.rb51
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/spec/spec_helper.rb96
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/fake_function_framework/src/fff_unity_helper.h33
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/gcov/README.md101
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/gcov/assets/template.erb15
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/gcov/config/defaults.yml73
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/gcov/gcov.rake220
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/gcov/lib/gcov.rb113
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/gcov/lib/gcov_constants.rb19
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/junit_tests_report/README.md36
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/junit_tests_report/lib/junit_tests_report.rb129
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/module_generator/config/module_generator.yml4
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/module_generator/lib/module_generator.rb70
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/module_generator/module_generator.rake47
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/raw_output_report/lib/raw_output_report.rb41
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb84
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb copy59
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/stdout_gtestlike_tests_report/config/stdout_gtestlike_tests_report.yml4
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/stdout_gtestlike_tests_report/lib/stdout_gtestlike_tests_report.rb43
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/stdout_ide_tests_report/config/stdout_ide_tests_report.yml4
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/stdout_ide_tests_report/lib/stdout_ide_tests_report.rb44
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/stdout_pretty_tests_report/assets/template.erb59
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/stdout_pretty_tests_report/config/stdout_pretty_tests_report.yml4
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/stdout_pretty_tests_report/lib/stdout_pretty_tests_report.rb47
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/subprojects/README.md63
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/subprojects/config/defaults.yml33
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/subprojects/lib/subprojects.rb92
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/subprojects/subprojects.rake78
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/teamcity_tests_report/config/teamcity_tests_report.yml4
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/teamcity_tests_report/lib/teamcity_tests_report.rb57
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/warnings_report/lib/warnings_report.rb69
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/xml_tests_report/README.md36
-rwxr-xr-xtinyusb/test/vendor/ceedling/plugins/xml_tests_report/lib/xml_tests_report.rb110
64 files changed, 4027 insertions, 0 deletions
diff --git a/tinyusb/test/vendor/ceedling/plugins/beep/README.md b/tinyusb/test/vendor/ceedling/plugins/beep/README.md
new file mode 100755
index 00000000..e59d881b
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/beep/README.md
@@ -0,0 +1,22 @@
+ceedling-beep
+=============
+
+This is a simple plugin that just beeps at the end of a build and/or test sequence. Are you getting too distracted surfing
+the internet, chatting with coworkers, or swordfighting while it's building or testing? The friendly beep will let you know
+it's time to pay attention again.
+
+This plugin has very few configuration options. At this time it can beep on completion of a task and/or on an error condition.
+For each of these, you can configure the method that it should beep.
+
+```
+:tools:
+ :beep_on_done: :bell
+ :beep_on_error: :bell
+```
+
+Each of these have the following options:
+
+ - :bell - this option uses the ASCII bell character out stdout
+ - :speaker_test - this uses the linux speaker-test command if installed
+
+Very likely, we'll be adding to this list if people find this to be useful.
diff --git a/tinyusb/test/vendor/ceedling/plugins/beep/lib/beep.rb b/tinyusb/test/vendor/ceedling/plugins/beep/lib/beep.rb
new file mode 100755
index 00000000..6a6d01ab
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/beep/lib/beep.rb
@@ -0,0 +1,40 @@
+require 'ceedling/plugin'
+require 'ceedling/constants'
+
+class Beep < Plugin
+
+ attr_reader :config
+
+ def setup
+ @config = {
+ :on_done => ((defined? TOOLS_BEEP_ON_DONE) ? TOOLS_BEEP_ON_DONE : :bell ),
+ :on_error => ((defined? TOOLS_BEEP_ON_ERROR) ? TOOLS_BEEP_ON_ERROR : :bell ),
+ }
+ end
+
+ def post_build
+ beep @config[:on_done]
+ end
+
+ def post_error
+ beep @config[:on_error]
+ end
+
+ private
+
+ def beep(method = :none)
+ case method
+ when :bell
+ if (SystemWrapper.windows?)
+ puts "echo '\007'"
+ else
+ puts "echo -ne '\007'"
+ end
+ when :speaker_test
+ `speaker-test -t sine -f 1000 -l 1`
+ else
+ #do nothing with illegal or :none
+ end
+ end
+end
+
diff --git a/tinyusb/test/vendor/ceedling/plugins/bullseye/assets/template.erb b/tinyusb/test/vendor/ceedling/plugins/bullseye/assets/template.erb
new file mode 100755
index 00000000..504f8558
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/bullseye/assets/template.erb
@@ -0,0 +1,15 @@
+% function_string = hash[:coverage][:functions].to_s
+% branch_string = hash[:coverage][:branches].to_s
+% format_string = "%#{[function_string.length, branch_string.length].max}i"
+<%=@ceedling[:plugin_reportinator].generate_banner("#{hash[:header]}: CODE COVERAGE SUMMARY")%>
+% if (!hash[:coverage][:functions].nil?)
+FUNCTIONS: <%=sprintf(format_string, hash[:coverage][:functions])%>%
+% else
+FUNCTIONS: none
+% end
+% if (!hash[:coverage][:branches].nil?)
+BRANCHES: <%=sprintf(format_string, hash[:coverage][:branches])%>%
+% else
+BRANCHES: none
+% end
+
diff --git a/tinyusb/test/vendor/ceedling/plugins/bullseye/bullseye.rake b/tinyusb/test/vendor/ceedling/plugins/bullseye/bullseye.rake
new file mode 100755
index 00000000..a7bbebe3
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/bullseye/bullseye.rake
@@ -0,0 +1,169 @@
+directory(BULLSEYE_BUILD_OUTPUT_PATH)
+directory(BULLSEYE_RESULTS_PATH)
+directory(BULLSEYE_ARTIFACTS_PATH)
+directory(BULLSEYE_DEPENDENCIES_PATH)
+
+CLEAN.include(File.join(BULLSEYE_BUILD_OUTPUT_PATH, '*'))
+CLEAN.include(File.join(BULLSEYE_RESULTS_PATH, '*'))
+CLEAN.include(File.join(BULLSEYE_DEPENDENCIES_PATH, '*'))
+
+CLOBBER.include(File.join(BULLSEYE_BUILD_PATH, '**/*'))
+PLUGINS_BULLSEYE_LIB_PATH = 'C:\\tools\\BullseyeCoverage\\lib' if not defined?(PLUGINS_BULLSEYE_LIB_PATH)
+
+rule(/#{BULLSEYE_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_OBJECT}$/ => [
+ proc do |task_name|
+ @ceedling[:file_finder].find_compilation_input_file(task_name)
+ end
+ ]) do |object|
+
+ if File.basename(object.source) =~ /^(#{PROJECT_TEST_FILE_PREFIX}|#{CMOCK_MOCK_PREFIX}|#{BULLSEYE_IGNORE_SOURCES.join('|')})/i
+ @ceedling[:generator].generate_object_file(
+ TOOLS_BULLSEYE_COMPILER,
+ OPERATION_COMPILE_SYM,
+ BULLSEYE_SYM,
+ object.source,
+ object.name,
+ @ceedling[:file_path_utils].form_test_build_list_filepath(object.name)
+ )
+ else
+ @ceedling[BULLSEYE_SYM].generate_coverage_object_file(object.source, object.name)
+ end
+
+end
+
+rule(/#{BULLSEYE_BUILD_OUTPUT_PATH}\/#{'.+\\'+EXTENSION_EXECUTABLE}$/) do |bin_file|
+ @ceedling[:generator].generate_executable_file(
+ TOOLS_BULLSEYE_LINKER,
+ BULLSEYE_SYM,
+ bin_file.prerequisites,
+ bin_file.name,
+ @ceedling[:file_path_utils].form_test_build_map_filepath(bin_file.name)
+ )
+end
+
+rule(/#{BULLSEYE_RESULTS_PATH}\/#{'.+\\'+EXTENSION_TESTPASS}$/ => [
+ proc do |task_name|
+ @ceedling[:file_path_utils].form_test_executable_filepath(task_name)
+ end
+ ]) do |test_result|
+ @ceedling[:generator].generate_test_results(TOOLS_BULLSEYE_FIXTURE, BULLSEYE_SYM, test_result.source, test_result.name)
+end
+
+rule(/#{BULLSEYE_DEPENDENCIES_PATH}\/#{'.+\\'+EXTENSION_DEPENDENCIES}$/ => [
+ proc do |task_name|
+ @ceedling[:file_finder].find_compilation_input_file(task_name)
+ end
+ ]) do |dep|
+ @ceedling[:generator].generate_dependencies_file(
+ TOOLS_TEST_DEPENDENCIES_GENERATOR,
+ BULLSEYE_SYM,
+ dep.source,
+ File.join(BULLSEYE_BUILD_OUTPUT_PATH, File.basename(dep.source).ext(EXTENSION_OBJECT) ),
+ dep.name
+ )
+end
+
+task :directories => [BULLSEYE_BUILD_OUTPUT_PATH, BULLSEYE_RESULTS_PATH, BULLSEYE_DEPENDENCIES_PATH, BULLSEYE_ARTIFACTS_PATH]
+
+namespace BULLSEYE_SYM do
+ task source_coverage: COLLECTION_ALL_SOURCE.pathmap("#{BULLSEYE_BUILD_OUTPUT_PATH}/%n#{@ceedling[:configurator].extension_object}")
+
+ desc 'Run code coverage for all tests'
+ task all: [:directories] do
+ @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config)
+ @ceedling[BULLSEYE_SYM].enableBullseye(true)
+ @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, BULLSEYE_SYM)
+ @ceedling[:configurator].restore_config
+ end
+
+ desc "Run single test w/ coverage ([*] real test or source file name, no path)."
+ task :* do
+ message = "\nOops! '#{BULLSEYE_ROOT_NAME}:*' isn't a real task. " +
+ "Use a real test or source file name (no path) in place of the wildcard.\n" +
+ "Example: rake #{BULLSEYE_ROOT_NAME}:foo.c\n\n"
+
+ @ceedling[:streaminator].stdout_puts( message )
+ end
+
+ desc 'Run tests by matching regular expression pattern.'
+ task :pattern, [:regex] => [:directories] do |_t, args|
+ matches = []
+
+ COLLECTION_ALL_TESTS.each do |test|
+ matches << test if test =~ /#{args.regex}/
+ end
+
+ if !matches.empty?
+ @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config)
+ @ceedling[BULLSEYE_SYM].enableBullseye(true)
+ @ceedling[:test_invoker].setup_and_invoke(matches, BULLSEYE_SYM, force_run: false)
+ @ceedling[:configurator].restore_config
+ else
+ @ceedling[:streaminator].stdout_puts("\nFound no tests matching pattern /#{args.regex}/.")
+ end
+ end
+
+ desc 'Run tests whose test path contains [dir] or [dir] substring.'
+ task :path, [:dir] => [:directories] do |_t, args|
+ matches = []
+
+ COLLECTION_ALL_TESTS.each do |test|
+ matches << test if File.dirname(test).include?(args.dir.tr('\\', '/'))
+ end
+
+ if !matches.empty?
+ @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config)
+ @ceedling[BULLSEYE_SYM].enableBullseye(true)
+ @ceedling[:test_invoker].setup_and_invoke(matches, BULLSEYE_SYM, force_run: false)
+ @ceedling[:configurator].restore_config
+ else
+ @ceedling[:streaminator].stdout_puts("\nFound no tests including the given path or path component.")
+ end
+ end
+
+ desc 'Run code coverage for changed files'
+ task delta: [:directories] do
+ @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config)
+ @ceedling[BULLSEYE_SYM].enableBullseye(true)
+ @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, BULLSEYE_SYM, {:force_run => false})
+ @ceedling[:configurator].restore_config
+ end
+
+ # use a rule to increase efficiency for large projects
+ # bullseye test tasks by regex
+ rule(/^#{BULLSEYE_TASK_ROOT}\S+$/ => [
+ proc do |task_name|
+ test = task_name.sub(/#{BULLSEYE_TASK_ROOT}/, '')
+ test = "#{PROJECT_TEST_FILE_PREFIX}#{test}" unless test.start_with?(PROJECT_TEST_FILE_PREFIX)
+ @ceedling[:file_finder].find_test_from_file_path(test)
+ end
+ ]) do |test|
+ @ceedling[:rake_wrapper][:directories].invoke
+ @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config)
+ @ceedling[BULLSEYE_SYM].enableBullseye(true)
+ @ceedling[:test_invoker].setup_and_invoke([test.source], BULLSEYE_SYM)
+ @ceedling[:configurator].restore_config
+ end
+
+end
+
+if PROJECT_USE_DEEP_DEPENDENCIES
+namespace REFRESH_SYM do
+ task BULLSEYE_SYM do
+ @ceedling[:configurator].replace_flattened_config(@ceedling[BULLSEYE_SYM].config)
+ @ceedling[BULLSEYE_SYM].enableBullseye(true)
+ @ceedling[:test_invoker].refresh_deep_dependencies
+ @ceedling[:configurator].restore_config
+ end
+end
+end
+
+namespace UTILS_SYM do
+
+ desc "Open Bullseye code coverage browser"
+ task BULLSEYE_SYM do
+ command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_BROWSER, [])
+ @ceedling[:tool_executor].exec(command[:line], command[:options])
+ end
+
+end
diff --git a/tinyusb/test/vendor/ceedling/plugins/bullseye/config/defaults.yml b/tinyusb/test/vendor/ceedling/plugins/bullseye/config/defaults.yml
new file mode 100755
index 00000000..ed261d8e
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/bullseye/config/defaults.yml
@@ -0,0 +1,57 @@
+---
+
+:bullseye:
+ :auto_license: TRUE
+:plugins:
+ :bullseye_lib_path: []
+:paths:
+ :bullseye_toolchain_include: []
+
+:tools:
+ :bullseye_instrumentation:
+ :executable: covc
+ :arguments:
+ - '--file $': ENVIRONMENT_COVFILE
+ - -q
+ - ${1}
+ :bullseye_compiler:
+ :executable: gcc
+ :arguments:
+ - -g
+ - -I"$": COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR
+ - -I"$": COLLECTION_PATHS_BULLSEYE_TOOLCHAIN_INCLUDE
+ - -D$: COLLECTION_DEFINES_TEST_AND_VENDOR
+ - -DBULLSEYE_COMPILER
+ - -c "${1}"
+ - -o "${2}"
+ :bullseye_linker:
+ :executable: gcc
+ :arguments:
+ - ${1}
+ - -o ${2}
+ - -L$: PLUGINS_BULLSEYE_LIB_PATH
+ - -lcov
+ :bullseye_fixture:
+ :executable: ${1}
+ :bullseye_report_covsrc:
+ :executable: covsrc
+ :arguments:
+ - '--file $': ENVIRONMENT_COVFILE
+ - -q
+ - -w140
+ :bullseye_report_covfn:
+ :executable: covfn
+ :stderr_redirect: :auto
+ :arguments:
+ - '--file $': ENVIRONMENT_COVFILE
+ - --width 120
+ - --no-source
+ - '"${1}"'
+ :bullseye_browser:
+ :executable: CoverageBrowser
+ :background_exec: :auto
+ :optional: TRUE
+ :arguments:
+ - '"$"': ENVIRONMENT_COVFILE
+
+...
diff --git a/tinyusb/test/vendor/ceedling/plugins/bullseye/lib/bullseye.rb b/tinyusb/test/vendor/ceedling/plugins/bullseye/lib/bullseye.rb
new file mode 100755
index 00000000..ffa444ac
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/bullseye/lib/bullseye.rb
@@ -0,0 +1,194 @@
+require 'ceedling/plugin'
+require 'ceedling/constants'
+
+BULLSEYE_ROOT_NAME = 'bullseye'
+BULLSEYE_TASK_ROOT = BULLSEYE_ROOT_NAME + ':'
+BULLSEYE_SYM = BULLSEYE_ROOT_NAME.to_sym
+
+BULLSEYE_BUILD_PATH = "#{PROJECT_BUILD_ROOT}/#{BULLSEYE_ROOT_NAME}"
+BULLSEYE_BUILD_OUTPUT_PATH = "#{BULLSEYE_BUILD_PATH}/out"
+BULLSEYE_RESULTS_PATH = "#{BULLSEYE_BUILD_PATH}/results"
+BULLSEYE_DEPENDENCIES_PATH = "#{BULLSEYE_BUILD_PATH}/dependencies"
+BULLSEYE_ARTIFACTS_PATH = "#{PROJECT_BUILD_ARTIFACTS_ROOT}/#{BULLSEYE_ROOT_NAME}"
+
+BULLSEYE_IGNORE_SOURCES = ['unity', 'cmock', 'cexception']
+
+
+class Bullseye < Plugin
+
+ def setup
+ @result_list = []
+ @environment = [ {:covfile => File.join( BULLSEYE_ARTIFACTS_PATH, 'test.cov' )} ]
+ @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+ @coverage_template_all = @ceedling[:file_wrapper].read(File.join(@plugin_root, 'assets/template.erb'))
+ end
+
+ def config
+ {
+ :project_test_build_output_path => BULLSEYE_BUILD_OUTPUT_PATH,
+ :project_test_results_path => BULLSEYE_RESULTS_PATH,
+ :project_test_dependencies_path => BULLSEYE_DEPENDENCIES_PATH,
+ :defines_test => DEFINES_TEST + ['CODE_COVERAGE'],
+ :collection_defines_test_and_vendor => COLLECTION_DEFINES_TEST_AND_VENDOR + ['CODE_COVERAGE']
+ }
+ end
+
+ def generate_coverage_object_file(source, object)
+ arg_hash = {:tool => TOOLS_BULLSEYE_INSTRUMENTATION, :context => BULLSEYE_SYM, :source => source, :object => object}
+ @ceedling[:plugin_manager].pre_compile_execute(arg_hash)
+
+ @ceedling[:streaminator].stdout_puts("Compiling #{File.basename(source)} with coverage...")
+ compile_command =
+ @ceedling[:tool_executor].build_command_line(
+ TOOLS_BULLSEYE_COMPILER,
+ @ceedling[:flaginator].flag_down( OPERATION_COMPILE_SYM, BULLSEYE_SYM, source ),
+ source,
+ object,
+ @ceedling[:file_path_utils].form_test_build_list_filepath( object ) )
+ coverage_command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_INSTRUMENTATION, [], compile_command[:line] )
+
+ shell_result = @ceedling[:tool_executor].exec( coverage_command[:line], coverage_command[:options] )
+
+ arg_hash[:shell_result] = shell_result
+ @ceedling[:plugin_manager].post_compile_execute(arg_hash)
+ end
+
+ def post_test_fixture_execute(arg_hash)
+ result_file = arg_hash[:result_file]
+
+ if ((result_file =~ /#{BULLSEYE_RESULTS_PATH}/) and (not @result_list.include?(result_file)))
+ @result_list << arg_hash[:result_file]
+ end
+ end
+
+ def post_build
+ return if (not @ceedling[:task_invoker].invoked?(/^#{BULLSEYE_TASK_ROOT}/))
+
+ # test results
+ results = @ceedling[:plugin_reportinator].assemble_test_results(@result_list)
+ hash = {
+ :header => BULLSEYE_ROOT_NAME.upcase,
+ :results => results
+ }
+
+ @ceedling[:plugin_reportinator].run_test_results_report(hash) do
+ message = ''
+ message = 'Unit test failures.' if (results[:counts][:failed] > 0)
+ message
+ end
+
+ # coverage results
+ return if (verify_coverage_file() == false)
+ if (@ceedling[:task_invoker].invoked?(/^#{BULLSEYE_TASK_ROOT}(all|delta)/))
+ command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_REPORT_COVSRC, [])
+ shell_result = @ceedling[:tool_executor].exec(command[:line], command[:options])
+ report_coverage_results_all(shell_result[:output])
+ else
+ report_per_function_coverage_results(@ceedling[:test_invoker].sources)
+ end
+ end
+
+ def summary
+ return if (verify_coverage_file() == false)
+ result_list = @ceedling[:file_path_utils].form_pass_results_filelist( BULLSEYE_RESULTS_PATH, COLLECTION_ALL_TESTS )
+
+ # test results
+ # get test results for only those tests in our configuration and of those only tests with results on disk
+ hash = {
+ :header => BULLSEYE_ROOT_NAME.upcase,
+ :results => @ceedling[:plugin_reportinator].assemble_test_results(result_list, {:boom => false})
+ }
+
+ @ceedling[:plugin_reportinator].run_test_results_report(hash)
+
+ # coverage results
+ command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_REPORT_COVSRC)
+ shell_result = @ceedling[:tool_executor].exec(command[:line], command[:options])
+ report_coverage_results_all(shell_result[:output])
+ end
+
+ def enableBullseye(enable)
+ if BULLSEYE_AUTO_LICENSE
+ if (enable)
+ args = ['push', 'on']
+ @ceedling[:streaminator].stdout_puts("Enabling Bullseye")
+ else
+ args = ['pop']
+ @ceedling[:streaminator].stdout_puts("Reverting Bullseye to previous state")
+ end
+
+ args.each do |arg|
+ command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_BUILD_ENABLE_DISABLE, [], arg)
+ shell_result = @ceedling[:tool_executor].exec(command[:line], command[:options])
+ end
+
+ end
+ end
+
+ private ###################################
+
+ def report_coverage_results_all(coverage)
+ results = {
+ :header => BULLSEYE_ROOT_NAME.upcase,
+ :coverage => {
+ :functions => nil,
+ :branches => nil
+ }
+ }
+
+ if (coverage =~ /^Total.*?=\s+([0-9]+)\%/)
+ results[:coverage][:functions] = $1.to_i
+ end
+
+ if (coverage =~ /^Total.*=\s+([0-9]+)\%\s*$/)
+ results[:coverage][:branches] = $1.to_i
+ end
+
+ @ceedling[:plugin_reportinator].run_report($stdout, @coverage_template_all, results)
+ end
+
+ def report_per_function_coverage_results(sources)
+ banner = @ceedling[:plugin_reportinator].generate_banner( "#{BULLSEYE_ROOT_NAME.upcase}: CODE COVERAGE SUMMARY" )
+ @ceedling[:streaminator].stdout_puts "\n" + banner
+
+ coverage_sources = sources.clone
+ coverage_sources.delete_if {|item| item =~ /#{CMOCK_MOCK_PREFIX}.+#{EXTENSION_SOURCE}$/}
+ coverage_sources.delete_if {|item| item =~ /#{BULLSEYE_IGNORE_SOURCES.join('|')}#{EXTENSION_SOURCE}$/}
+
+ coverage_sources.each do |source|
+ command = @ceedling[:tool_executor].build_command_line(TOOLS_BULLSEYE_REPORT_COVFN, [], source)
+ shell_results = @ceedling[:tool_executor].exec(command[:line], command[:options])
+ coverage_results = shell_results[:output].deep_clone
+ coverage_results.sub!(/.*\n.*\n/,'') # Remove the Bullseye tool banner
+ if (coverage_results =~ /warning cov814: report is empty/)
+ coverage_results = "WARNING: #{source} contains no coverage data!\n\n"
+ @ceedling[:streaminator].stdout_puts(coverage_results, Verbosity::COMPLAIN)
+ else
+ coverage_results += "\n"
+ @ceedling[:streaminator].stdout_puts(coverage_results)
+ end
+ end
+ end
+
+ def verify_coverage_file
+ exist = @ceedling[:file_wrapper].exist?( ENVIRONMENT_COVFILE )
+
+ if (!exist)
+ banner = @ceedling[:plugin_reportinator].generate_banner( "#{BULLSEYE_ROOT_NAME.upcase}: CODE COVERAGE SUMMARY" )
+ @ceedling[:streaminator].stdout_puts "\n" + banner + "\nNo coverage file.\n\n"
+ end
+
+ return exist
+ end
+
+end
+
+
+# end blocks always executed following rake run
+END {
+ # cache our input configurations to use in comparison upon next execution
+ if (@ceedling[:task_invoker].invoked?(/^#{BULLSEYE_TASK_ROOT}/))
+ @ceedling[:cacheinator].cache_test_config( @ceedling[:setupinator].config_hash )
+ @ceedling[BULLSEYE_SYM].enableBullseye(false)
+ end
+}
diff --git a/tinyusb/test/vendor/ceedling/plugins/bullseye/readme.txt b/tinyusb/test/vendor/ceedling/plugins/bullseye/readme.txt
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/bullseye/readme.txt
diff --git a/tinyusb/test/vendor/ceedling/plugins/colour_report/lib/colour_report.rb b/tinyusb/test/vendor/ceedling/plugins/colour_report/lib/colour_report.rb
new file mode 100755
index 00000000..1211eab4
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/colour_report/lib/colour_report.rb
@@ -0,0 +1,16 @@
+require 'ceedling/plugin'
+require 'ceedling/streaminator'
+require 'ceedling/constants'
+
+class ColourReport < Plugin
+
+ def setup
+ @ceedling[:stream_wrapper].stdout_override(&ColourReport.method(:colour_stdout))
+ end
+
+ def self.colour_stdout(string)
+ require 'colour_reporter.rb'
+ report string
+ end
+
+end
diff --git a/tinyusb/test/vendor/ceedling/plugins/command_hooks/README.md b/tinyusb/test/vendor/ceedling/plugins/command_hooks/README.md
new file mode 100755
index 00000000..8ac64afc
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/command_hooks/README.md
@@ -0,0 +1,53 @@
+ceedling-command-hooks
+======================
+
+Plugin for easily calling command line tools at various points in the build process
+
+Define any of these sections in :tools: to provide additional hooks to be called on demand:
+
+```
+ :pre_mock_generate
+ :post_mock_generate
+ :pre_runner_generate
+ :post_runner_generate
+ :pre_compile_execute
+ :post_compile_execute
+ :pre_link_execute
+ :post_link_execute
+ :pre_test_fixture_execute
+ :pre_test
+ :post_test
+ :pre_release
+ :post_release
+ :pre_build
+ :post_build
+```
+
+Each of these tools can support an :executable string and an :arguments list, like so:
+
+```
+:tools:
+ :post_link_execute:
+ :executable: objcopy.exe
+ :arguments:
+ - ${1} #This is replaced with the executable name
+ - output.srec
+ - --strip-all
+```
+
+You may also specify an array of executables to be called in a particular place, like so:
+
+```
+:tools:
+ :post_test:
+ - :executable: echo
+ :arguments: "${1} was glorious!"
+ - :executable: echo
+ :arguments:
+ - it kinda made me cry a little.
+ - you?
+```
+
+Please note that it varies which arguments are being parsed down to the
+hooks. For now see `command_hooks.rb` to figure out which suits you best.
+Happy Tweaking!
diff --git a/tinyusb/test/vendor/ceedling/plugins/command_hooks/lib/command_hooks.rb b/tinyusb/test/vendor/ceedling/plugins/command_hooks/lib/command_hooks.rb
new file mode 100755
index 00000000..4bf8b531
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/command_hooks/lib/command_hooks.rb
@@ -0,0 +1,92 @@
+require 'ceedling/plugin'
+require 'ceedling/constants'
+class CommandHooks < Plugin
+
+ attr_reader :config
+
+ def setup
+ @config = {
+ :pre_mock_generate => ((defined? TOOLS_PRE_MOCK_GENERATE) ? TOOLS_PRE_MOCK_GENERATE : nil ),
+ :post_mock_generate => ((defined? TOOLS_POST_MOCK_GENERATE) ? TOOLS_POST_MOCK_GENERATE : nil ),
+ :pre_runner_generate => ((defined? TOOLS_PRE_RUNNER_GENERATE) ? TOOLS_PRE_RUNNER_GENERATE : nil ),
+ :post_runner_generate => ((defined? TOOLS_POST_RUNNER_GENERATE) ? TOOLS_POST_RUNNER_GENERATE : nil ),
+ :pre_compile_execute => ((defined? TOOLS_PRE_COMPILE_EXECUTE) ? TOOLS_PRE_COMPILE_EXECUTE : nil ),
+ :post_compile_execute => ((defined? TOOLS_POST_COMPILE_EXECUTE) ? TOOLS_POST_COMPILE_EXECUTE : nil ),
+ :pre_link_execute => ((defined? TOOLS_PRE_LINK_EXECUTE) ? TOOLS_PRE_LINK_EXECUTE : nil ),
+ :post_link_execute => ((defined? TOOLS_POST_LINK_EXECUTE) ? TOOLS_POST_LINK_EXECUTE : nil ),
+ :pre_test_fixture_execute => ((defined? TOOLS_PRE_TEST_FIXTURE_EXECUTE) ? TOOLS_PRE_TEST_FIXTURE_EXECUTE : nil ),
+ :post_test_fixture_execute => ((defined? TOOLS_POST_TEST_FIXTURE_EXECUTE) ? TOOLS_POST_TEST_FIXTURE_EXECUTE : nil ),
+ :pre_test => ((defined? TOOLS_PRE_TEST) ? TOOLS_PRE_TEST : nil ),
+ :post_test => ((defined? TOOLS_POST_TEST) ? TOOLS_POST_TEST : nil ),
+ :pre_release => ((defined? TOOLS_PRE_RELEASE) ? TOOLS_PRE_RELEASE : nil ),
+ :post_release => ((defined? TOOLS_POST_RELEASE) ? TOOLS_POST_RELEASE : nil ),
+ :pre_build => ((defined? TOOLS_PRE_BUILD) ? TOOLS_PRE_BUILD : nil ),
+ :post_build => ((defined? TOOLS_POST_BUILD) ? TOOLS_POST_BUILD : nil ),
+ :post_error => ((defined? TOOLS_POST_ERROR) ? TOOLS_POST_ERROR : nil ),
+ }
+ @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+ end
+
+ def pre_mock_generate(arg_hash); run_hook(:pre_mock_generate, arg_hash[:header_file] ); end
+ def post_mock_generate(arg_hash); run_hook(:post_mock_generate, arg_hash[:header_file] ); end
+ def pre_runner_generate(arg_hash); run_hook(:pre_runner_generate, arg_hash[:source ] ); end
+ def post_runner_generate(arg_hash); run_hook(:post_runner_generate, arg_hash[:runner_file] ); end
+ def pre_compile_execute(arg_hash); run_hook(:pre_compile_execute, arg_hash[:source_file] ); end
+ def post_compile_execute(arg_hash); run_hook(:post_compile_execute, arg_hash[:object_file] ); end
+ def pre_link_execute(arg_hash); run_hook(:pre_link_execute, arg_hash[:executable] ); end
+ def post_link_execute(arg_hash); run_hook(:post_link_execute, arg_hash[:executable] ); end
+ def pre_test_fixture_execute(arg_hash); run_hook(:pre_test_fixture_execute, arg_hash[:executable] ); end
+ def post_test_fixture_execute(arg_hash); run_hook(:post_test_fixture_execute, arg_hash[:executable] ); end
+ def pre_test(test); run_hook(:pre_test, test ); end
+ def post_test(test); run_hook(:post_test, test ); end
+ def pre_release; run_hook(:pre_release ); end
+ def post_release; run_hook(:post_release ); end
+ def pre_build; run_hook(:pre_build ); end
+ def post_build; run_hook(:post_build ); end
+ def post_error; run_hook(:post_error ); end
+
+ private
+
+ ##
+ # Run a hook if its available.
+ #
+ # :args:
+ # - hook: Name of the hook to run
+ # - name: Name of file (default: "")
+ #
+ # :return:
+ # shell_result.
+ #
+ def run_hook_step(hook, name="")
+ if (hook[:executable])
+ # Handle argument replacemant ({$1}), and get commandline
+ cmd = @ceedling[:tool_executor].build_command_line( hook, [], name )
+ shell_result = @ceedling[:tool_executor].exec(cmd[:line], cmd[:options])
+ end
+ end
+
+ ##
+ # Run a hook if its available.
+ #
+ # If __which_hook__ is an array, run each of them sequentially.
+ #
+ # :args:
+ # - which_hook: Name of the hook to run
+ # - name: Name of file
+ #
+ def run_hook(which_hook, name="")
+ if (@config[which_hook])
+ @ceedling[:streaminator].stdout_puts("Running Hook #{which_hook}...", Verbosity::NORMAL)
+ if (@config[which_hook].is_a? Array)
+ @config[which_hook].each do |hook|
+ run_hook_step(hook, name)
+ end
+ elsif (@config[which_hook].is_a? Hash)
+ run_hook_step( @config[which_hook], name )
+ else
+ @ceedling[:streaminator].stdout_puts("Hook #{which_hook} was poorly formed", Verbosity::COMPLAINT)
+ end
+ end
+ end
+end
+
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/README.md b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/README.md
new file mode 100755
index 00000000..8042775e
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/README.md
@@ -0,0 +1,250 @@
+# A Fake Function Framework Plug-in for Ceedling
+
+This is a plug-in for [Ceedling](https://github.com/ThrowTheSwitch/Ceedling) to use the [Fake Function Framework](https://github.com/meekrosoft/fff) for mocking instead of CMock.
+
+Using fff provides less strict mocking than CMock, and allows for more loosely-coupled tests.
+And, when tests fail -- since you get the actual line number of the failure -- it's a lot easier to figure out what went wrong.
+
+## Installing the plug-in
+
+To use the plugin you need to 1) get the contents of this repo and 2) configure your project to use it.
+
+### Get the source
+
+The easiest way to get the source is to just clone this repo into the Ceedling plugin folder for your existing Ceedling project.
+(Don't have a Ceedling project already? [Here are instructions to create one.](http://www.electronvector.com/blog/try-embedded-test-driven-development-right-now-with-ceedling))
+From within `<your-project>/vendor/ceedling/plugins`, run:
+
+`git clone https://github.com/ElectronVector/fake_function_framework.git`
+
+This will create a new folder named `fake_function_framework` in the plugins folder.
+
+### Enable the plug-in.
+
+The plug-in is enabled from within your project.yml file.
+
+In the `:plugins` configuration, add `fake_function_framework` to the list of enabled plugins:
+
+```yaml
+:plugins:
+ :load_paths:
+ - vendor/ceedling/plugins
+ :enabled:
+ - stdout_pretty_tests_report
+ - module_generator
+ - fake_function_framework
+```
+*Note that you could put the plugin source in some other loaction.
+In that case you'd need to add a new path the `:load_paths`.*
+
+## How to use it
+
+You use fff with Ceedling the same way you used to use CMock.
+Modules can still be generated with the default module generator: `rake module:create[my_module]`.
+If you want to "mock" `some_module.h` in your tests, just `#include "mock_some_module.h"`.
+This creates a fake function for each of the functions defined in `some_module.h`.
+
+The name of each fake is the original function name with an appended `_fake`.
+For example, if we're generating fakes for a stack module with `push` and `pop` functions, we would have the fakes `push_fake` and `pop_fake`.
+These fakes are linked into our test executable so that any time our unit under test calls `push` or `pop` our fakes are called instead.
+
+Each of these fakes is actually a structure containing information about how the function was called, and what it might return.
+We can use Unity to inspect these fakes in our tests, and verify the interactions of our units.
+There is also a global structure named `fff` which we can use to check the sequence of calls.
+
+The fakes can also be configured to return particular values, so you can exercise the unit under test however you want.
+
+The examples below explain how to use fff to test a variety of module interactions.
+Each example uses fakes for a "display" module, created from a display.h file with `#include "mock_display.h"`. The `display.h` file must exist and must contain the prototypes for the functions to be faked.
+
+### Test that a function was called once
+
+```c
+void
+test_whenTheDeviceIsReset_thenTheStatusLedIsTurnedOff()
+{
+ // When
+ event_deviceReset();
+
+ // Then
+ TEST_ASSERT_EQUAL(1, display_turnOffStatusLed_fake.call_count);
+}
+```
+
+### Test that a function was NOT called
+
+```c
+void
+test_whenThePowerReadingIsLessThan5_thenTheStatusLedIsNotTurnedOn(void)
+{
+ // When
+ event_powerReadingUpdate(4);
+
+ // Then
+ TEST_ASSERT_EQUAL(0, display_turnOnStatusLed_fake.call_count);
+}
+```
+
+## Test that a single function was called with the correct argument
+
+```c
+void
+test_whenTheVolumeKnobIsMaxed_thenVolumeDisplayIsSetTo11(void)
+{
+ // When
+ event_volumeKnobMaxed();
+
+ // Then
+ TEST_ASSERT_EQUAL(1, display_setVolume_fake.call_count);
+ TEST_ASSERT_EQUAL(11, display_setVolume_fake.arg0_val);
+}
+```
+
+## Test that calls are made in a particular sequence
+
+```c
+void
+test_whenTheModeSelectButtonIsPressed_thenTheDisplayModeIsCycled(void)
+{
+ // When
+ event_modeSelectButtonPressed();
+ event_modeSelectButtonPressed();
+ event_modeSelectButtonPressed();
+
+ // Then
+ TEST_ASSERT_EQUAL_PTR((void*)display_setModeToMinimum, fff.call_history[0]);
+ TEST_ASSERT_EQUAL_PTR((void*)display_setModeToMaximum, fff.call_history[1]);
+ TEST_ASSERT_EQUAL_PTR((void*)display_setModeToAverage, fff.call_history[2]);
+}
+```
+
+## Fake a return value from a function
+
+```c
+void
+test_givenTheDisplayHasAnError_whenTheDeviceIsPoweredOn_thenTheDisplayIsPoweredDown(void)
+{
+ // Given
+ display_isError_fake.return_val = true;
+
+ // When
+ event_devicePoweredOn();
+
+ // Then
+ TEST_ASSERT_EQUAL(1, display_powerDown_fake.call_count);
+}
+```
+
+## Fake a function with a value returned by reference
+
+```c
+void
+test_givenTheUserHasTypedSleep_whenItIsTimeToCheckTheKeyboard_theDisplayIsPoweredDown(void)
+{
+ // Given
+ char mockedEntry[] = "sleep";
+ void return_mock_value(char * entry, int length)
+ {
+ if (length > strlen(mockedEntry))
+ {
+ strncpy(entry, mockedEntry, length);
+ }
+ }
+ display_getKeyboardEntry_fake.custom_fake = return_mock_value;
+
+ // When
+ event_keyboardCheckTimerExpired();
+
+ // Then
+ TEST_ASSERT_EQUAL(1, display_powerDown_fake.call_count);
+}
+```
+
+## Fake a function with a function pointer parameter
+
+```
+void
+test_givenNewDataIsAvailable_whenTheDisplayHasUpdated_thenTheEventIsComplete(void)
+{
+ // A mock function for capturing the callback handler function pointer.
+ void(*registeredCallback)(void) = 0;
+ void mock_display_updateData(int data, void(*callback)(void))
+ {
+ //Save the callback function.
+ registeredCallback = callback;
+ }
+ display_updateData_fake.custom_fake = mock_display_updateData;
+
+ // Given
+ event_newDataAvailable(10);
+
+ // When
+ if (registeredCallback != 0)
+ {
+ registeredCallback();
+ }
+
+ // Then
+ TEST_ASSERT_EQUAL(true, eventProcessor_isLastEventComplete());
+}
+```
+
+## Helper macros
+
+For convenience, there are also some helper macros that create new Unity-style asserts:
+
+- `TEST_ASSERT_CALLED(function)`: Asserts that a function was called once.
+- `TEST_ASSERT_NOT_CALLED(function)`: Asserts that a function was never called.
+- `TEST_ASSERT_CALLED_TIMES(times, function)`: Asserts that a function was called a particular number of times.
+- `TEST_ASSERT_CALLED_IN_ORDER(order, function)`: Asserts that a function was called in a particular order.
+
+Here's how you might use one of these instead of simply checking the call_count value:
+
+```c
+void
+test_whenTheDeviceIsReset_thenTheStatusLedIsTurnedOff()
+{
+ // When
+ event_deviceReset();
+
+ // Then
+ // This how to directly use fff...
+ TEST_ASSERT_EQUAL(1, display_turnOffStatusLed_fake.call_count);
+ // ...and this is how to use the helper macro.
+ TEST_ASSERT_CALLED(display_turnOffStatusLed);
+}
+```
+
+## Test setup
+
+All of the fake functions, and any fff global state are all reset automatically between each test.
+
+## CMock configuration
+
+Use still use some of the CMock configuration options for setting things like the mock prefix, and for including additional header files in the mock files.
+
+```yaml
+:cmock:
+ :mock_prefix: mock_
+ :includes:
+ -
+ :includes_h_pre_orig_header:
+ -
+ :includes_h_post_orig_header:
+ -
+ :includes_c_pre_header:
+ -
+ :includes_c_post_header:
+```
+
+## Running the tests
+
+There are unit and integration tests for the plug-in itself.
+These are run with the default `rake` task.
+The integration test runs the tests for the example project in examples/fff_example.
+For the integration tests to succeed, this repository must be placed in a Ceedling tree in the plugins folder.
+
+## More examples
+
+There is an example project in examples/fff_example.
+It shows how to use the plug-in with some full-size examples.
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/Rakefile b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/Rakefile
new file mode 100755
index 00000000..bc559411
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/Rakefile
@@ -0,0 +1,19 @@
+require 'rake'
+require 'rspec/core/rake_task'
+
+desc "Run all rspecs"
+RSpec::Core::RakeTask.new(:spec) do |t|
+ t.pattern = Dir.glob('spec/**/*_spec.rb')
+ t.rspec_opts = '--format documentation'
+ # t.rspec_opts << ' more options'
+end
+
+desc "Run integration test on example"
+task :integration_test do
+ chdir("./examples/fff_example") do
+ sh "rake clobber"
+ sh "rake test:all"
+ end
+end
+
+task :default => [:spec, :integration_test] \ No newline at end of file
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/project.yml b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/project.yml
new file mode 100755
index 00000000..6bda2229
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/project.yml
@@ -0,0 +1,71 @@
+---
+
+# Notes:
+# Sample project C code is not presently written to produce a release artifact.
+# As such, release build options are disabled.
+# This sample, therefore, only demonstrates running a collection of unit tests.
+
+:project:
+ :use_exceptions: FALSE
+ :use_test_preprocessor: TRUE
+ :use_auxiliary_dependencies: TRUE
+ :build_root: build
+# :release_build: TRUE
+ :test_file_prefix: test_
+
+#:release_build:
+# :output: MyApp.out
+# :use_assembly: FALSE
+
+:environment:
+
+:extension:
+ :executable: .out
+
+:paths:
+ :test:
+ - +:test/**
+ :source:
+ - src/**
+ :support:
+
+:defines:
+ # in order to add common defines:
+ # 1) remove the trailing [] from the :common: section
+ # 2) add entries to the :common: section (e.g. :test: has TEST defined)
+ :commmon: &common_defines []
+ :test:
+ - *common_defines
+ - TEST
+ :test_preprocess:
+ - *common_defines
+ - TEST
+
+:cmock:
+ :mock_prefix: mock_
+ :when_no_prototypes: :warn
+ :enforce_strict_ordering: TRUE
+ :plugins:
+ - :ignore
+ - :callback
+ :treat_as:
+ uint8: HEX8
+ uint16: HEX16
+ uint32: UINT32
+ int8: INT8
+ bool: UINT8
+
+#:tools:
+# Ceedling defaults to using gcc for compiling, linking, etc.
+# As [:tools] is blank, gcc will be used (so long as it's in your system path)
+# See documentation to configure a given toolchain for use
+
+:plugins:
+ :load_paths:
+ # This change from the default is for running Ceedling out of another folder.
+ - ../../../../plugins
+ :enabled:
+ - stdout_pretty_tests_report
+ - module_generator
+ - fake_function_framework
+...
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/rakefile.rb b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/rakefile.rb
new file mode 100755
index 00000000..e484d5fb
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/rakefile.rb
@@ -0,0 +1,7 @@
+# This change from the default is for running Ceedling out of another folder.
+PROJECT_CEEDLING_ROOT = "../../../.."
+load "#{PROJECT_CEEDLING_ROOT}/lib/ceedling.rb"
+
+Ceedling.load_project
+
+task :default => %w[ test:all release ]
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.c b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.c
new file mode 100755
index 00000000..6a403234
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.c
@@ -0,0 +1 @@
+#include "bar.h"
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.h b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.h
new file mode 100755
index 00000000..febc5865
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/bar.h
@@ -0,0 +1,14 @@
+#ifndef bar_H
+#define bar_H
+
+#include "custom_types.h"
+
+void bar_turn_on(void);
+void bar_print_message(const char * message);
+void bar_print_message_formatted(const char * format, ...);
+void bar_numbers(int one, int two, char three);
+void bar_const_test(const char * a, char * const b, const int c);
+custom_t bar_needs_custom_type(void);
+const char * bar_return_const_ptr(int one);
+
+#endif // bar_H
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/custom_types.h b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/custom_types.h
new file mode 100755
index 00000000..b426b32c
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/custom_types.h
@@ -0,0 +1,6 @@
+#ifndef custom_types_H
+#define custom_types_H
+
+typedef int custom_t;
+
+#endif
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.c b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.c
new file mode 100755
index 00000000..2f03449b
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "display.h"
+
+void display_turnOffStatusLed(void)
+{
+ printf("Display: Status LED off");
+} \ No newline at end of file
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.h b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.h
new file mode 100755
index 00000000..def29960
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/display.h
@@ -0,0 +1,16 @@
+#include <stdbool.h>
+
+void display_turnOffStatusLed(void);
+void display_turnOnStatusLed(void);
+void display_setVolume(int level);
+void display_setModeToMinimum(void);
+void display_setModeToMaximum(void);
+void display_setModeToAverage(void);
+bool display_isError(void);
+void display_powerDown(void);
+void display_updateData(int data, void(*updateCompleteCallback)(void));
+
+/*
+ The entry is returned (up to `length` bytes) in the provided `entry` buffer.
+*/
+void display_getKeyboardEntry(char * entry, int length);
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.c b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.c
new file mode 100755
index 00000000..916a9236
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.c
@@ -0,0 +1,93 @@
+/*
+ This module implements some business logic to test.
+
+ Signal events by calling the functions on the module.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include "event_processor.h"
+#include "display.h"
+
+void event_deviceReset(void)
+{
+ //printf ("Device reset\n");
+ display_turnOffStatusLed();
+}
+
+void event_volumeKnobMaxed(void)
+{
+ display_setVolume(11);
+}
+
+void event_powerReadingUpdate(int powerReading)
+{
+ if (powerReading >= 5)
+ {
+ display_turnOnStatusLed();
+ }
+}
+
+void event_modeSelectButtonPressed(void)
+{
+ static int mode = 0;
+
+ if (mode == 0)
+ {
+ display_setModeToMinimum();
+ mode++;
+ }
+ else if (mode == 1)
+ {
+ display_setModeToMaximum();
+ mode++;
+ }
+ else if (mode == 2)
+ {
+ display_setModeToAverage();
+ mode++;
+ }
+ else
+ {
+ mode = 0;
+ }
+}
+
+void event_devicePoweredOn(void)
+{
+ if (display_isError())
+ {
+ display_powerDown();
+ }
+}
+
+void event_keyboardCheckTimerExpired(void)
+{
+ char userEntry[100];
+
+ display_getKeyboardEntry(userEntry, 100);
+
+ if (strcmp(userEntry, "sleep") == 0)
+ {
+ display_powerDown();
+ }
+}
+
+static bool event_lastComplete = false;
+
+/* Function called when the display update is complete. */
+static void displayUpdateComplete(void)
+{
+ event_lastComplete = true;
+}
+
+void event_newDataAvailable(int data)
+{
+ event_lastComplete = false;
+ display_updateData(data, displayUpdateComplete);
+}
+
+bool eventProcessor_isLastEventComplete(void)
+{
+ return event_lastComplete;
+}
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.h b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.h
new file mode 100755
index 00000000..a79e68c5
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/event_processor.h
@@ -0,0 +1,11 @@
+#include <stdbool.h>
+
+void event_deviceReset(void);
+void event_volumeKnobMaxed(void);
+void event_powerReadingUpdate(int powerReading);
+void event_modeSelectButtonPressed(void);
+void event_devicePoweredOn(void);
+void event_keyboardCheckTimerExpired(void);
+void event_newDataAvailable(int data);
+
+bool eventProcessor_isLastEventComplete(void);
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.c b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.c
new file mode 100755
index 00000000..c05b1154
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.c
@@ -0,0 +1,16 @@
+#include "foo.h"
+#include "bar.h"
+#include "subfolder/zzz.h"
+
+void foo_turn_on(void) {
+ bar_turn_on();
+ zzz_sleep(1, "sleepy");
+}
+
+void foo_print_message(const char * message) {
+ bar_print_message(message);
+}
+
+void foo_print_special_message(void) {
+ bar_print_message_formatted("The numbers are %d, %d and %d", 1, 2, 3);
+}
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.h b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.h
new file mode 100755
index 00000000..3fea6994
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/foo.h
@@ -0,0 +1,8 @@
+#ifndef foo_H
+#define foo_H
+
+void foo_turn_on(void);
+void foo_print_message(const char * message);
+void foo_print_special_message(void);
+
+#endif // foo_H
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.c b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.c
new file mode 100755
index 00000000..85f370e1
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.c
@@ -0,0 +1 @@
+#include "zzz.h"
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.h b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.h
new file mode 100755
index 00000000..32c52940
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/src/subfolder/zzz.h
@@ -0,0 +1,6 @@
+#ifndef zzz_H
+#define zzz_H
+
+int zzz_sleep(int time, char * name);
+
+#endif // zzz_H
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_event_processor.c b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_event_processor.c
new file mode 100755
index 00000000..9f999443
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_event_processor.c
@@ -0,0 +1,155 @@
+#include "unity.h"
+#include "event_processor.h"
+#include "mock_display.h"
+#include <string.h>
+
+void setUp (void)
+{
+}
+
+void tearDown (void)
+{
+}
+/*
+ Test that a single function was called.
+*/
+void
+test_whenTheDeviceIsReset_thenTheStatusLedIsTurnedOff()
+{
+ // When
+ event_deviceReset();
+
+ // Then
+ TEST_ASSERT_EQUAL(1, display_turnOffStatusLed_fake.call_count);
+ // or use the helper macro...
+ TEST_ASSERT_CALLED(display_turnOffStatusLed);
+}
+
+/*
+ Test that a single function is NOT called.
+*/
+void
+test_whenThePowerReadingIsLessThan5_thenTheStatusLedIsNotTurnedOn(void)
+{
+ // When
+ event_powerReadingUpdate(4);
+
+ // Then
+ TEST_ASSERT_EQUAL(0, display_turnOnStatusLed_fake.call_count);
+ // or use the helper macro...
+ TEST_ASSERT_NOT_CALLED(display_turnOffStatusLed);
+}
+
+/*
+ Test that a single function was called with the correct arugment.
+*/
+void
+test_whenTheVolumeKnobIsMaxed_thenVolumeDisplayIsSetTo11(void)
+{
+ // When
+ event_volumeKnobMaxed();
+
+ // Then
+ TEST_ASSERT_EQUAL(1, display_setVolume_fake.call_count);
+ // or use the helper macro...
+ TEST_ASSERT_CALLED(display_setVolume);
+ TEST_ASSERT_EQUAL(11, display_setVolume_fake.arg0_val);
+}
+
+/*
+ Test a sequence of calls.
+*/
+
+void
+test_whenTheModeSelectButtonIsPressed_thenTheDisplayModeIsCycled(void)
+{
+ // When
+ event_modeSelectButtonPressed();
+ event_modeSelectButtonPressed();
+ event_modeSelectButtonPressed();
+
+ // Then
+ TEST_ASSERT_EQUAL_PTR((void *)display_setModeToMinimum, fff.call_history[0]);
+ TEST_ASSERT_EQUAL_PTR((void *)display_setModeToMaximum, fff.call_history[1]);
+ TEST_ASSERT_EQUAL_PTR((void *)display_setModeToAverage, fff.call_history[2]);
+ // or use the helper macros...
+ TEST_ASSERT_CALLED_IN_ORDER(0, display_setModeToMinimum);
+ TEST_ASSERT_CALLED_IN_ORDER(1, display_setModeToMaximum);
+ TEST_ASSERT_CALLED_IN_ORDER(2, display_setModeToAverage);
+}
+
+/*
+ Mock a return value from a function.
+*/
+void
+test_givenTheDisplayHasAnError_whenTheDeviceIsPoweredOn_thenTheDisplayIsPoweredDown(void)
+{
+ // Given
+ display_isError_fake.return_val = true;
+
+ // When
+ event_devicePoweredOn();
+
+ // Then
+ TEST_ASSERT_EQUAL(1, display_powerDown_fake.call_count);
+ // or use the helper macro...
+ TEST_ASSERT_CALLED(display_powerDown);
+}
+
+/*
+ Mock a sequence of calls with return values.
+*/
+
+/*
+ Mocking a function with a value returned by reference.
+*/
+void
+test_givenTheUserHasTypedSleep_whenItIsTimeToCheckTheKeyboard_theDisplayIsPoweredDown(void)
+{
+ // Given
+ char mockedEntry[] = "sleep";
+ void return_mock_value(char * entry, int length)
+ {
+ if (length > strlen(mockedEntry))
+ {
+ strncpy(entry, mockedEntry, length);
+ }
+ }
+ display_getKeyboardEntry_fake.custom_fake = return_mock_value;
+
+ // When
+ event_keyboardCheckTimerExpired();
+
+ // Then
+ TEST_ASSERT_EQUAL(1, display_powerDown_fake.call_count);
+ // or use the helper macro...
+ TEST_ASSERT_CALLED(display_powerDown);
+}
+
+/*
+ Mock a function with a function pointer parameter.
+*/
+void
+test_givenNewDataIsAvailable_whenTheDisplayHasUpdated_thenTheEventIsComplete(void)
+{
+ // A mock function for capturing the callback handler function pointer.
+ void(*registeredCallback)(void) = 0;
+ void mock_display_updateData(int data, void(*callback)(void))
+ {
+ //Save the callback function.
+ registeredCallback = callback;
+ }
+ display_updateData_fake.custom_fake = mock_display_updateData;
+
+ // Given
+ event_newDataAvailable(10);
+
+ // When
+ if (registeredCallback != 0)
+ {
+ registeredCallback();
+ }
+
+ // Then
+ TEST_ASSERT_EQUAL(true, eventProcessor_isLastEventComplete());
+}
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_foo.c b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_foo.c
new file mode 100755
index 00000000..12dd61a1
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/examples/fff_example/test/test_foo.c
@@ -0,0 +1,47 @@
+#include "unity.h"
+#include "foo.h"
+#include "mock_bar.h"
+#include "mock_zzz.h"
+
+void setUp(void)
+{
+}
+
+void tearDown(void)
+{
+}
+
+void test_foo(void)
+{
+ //When
+ foo_turn_on();
+
+ //Then
+ TEST_ASSERT_EQUAL(1, bar_turn_on_fake.call_count);
+ TEST_ASSERT_EQUAL(1, zzz_sleep_fake.call_count);
+ TEST_ASSERT_EQUAL_STRING("sleepy", zzz_sleep_fake.arg1_val);
+}
+
+void test_foo_again(void)
+{
+ //When
+ foo_turn_on();
+
+ //Then
+ TEST_ASSERT_EQUAL(1, bar_turn_on_fake.call_count);
+}
+
+void test_foo_mock_with_const(void)
+{
+ foo_print_message("123");
+
+ TEST_ASSERT_EQUAL(1, bar_print_message_fake.call_count);
+ TEST_ASSERT_EQUAL_STRING("123", bar_print_message_fake.arg0_val);
+}
+
+void test_foo_mock_with_variable_args(void)
+{
+ foo_print_special_message();
+ TEST_ASSERT_EQUAL(1, bar_print_message_formatted_fake.call_count);
+ TEST_ASSERT_EQUAL_STRING("The numbers are %d, %d and %d", bar_print_message_formatted_fake.arg0_val);
+}
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/lib/fake_function_framework.rb b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/lib/fake_function_framework.rb
new file mode 100755
index 00000000..51a90b3a
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/lib/fake_function_framework.rb
@@ -0,0 +1,87 @@
+require 'ceedling/plugin'
+require 'fff_mock_generator'
+
+class FakeFunctionFramework < Plugin
+
+ # Set up Ceedling to use this plugin.
+ def setup
+ # Get the location of this plugin.
+ @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+ puts "Using fake function framework (fff)..."
+
+ # Switch out the cmock_builder with our own.
+ @ceedling[:cmock_builder].cmock = FffMockGeneratorForCMock.new(@ceedling[:setupinator].config_hash[:cmock])
+
+ # Add the path to fff.h to the include paths.
+ COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR << "#{@plugin_root}/vendor/fff"
+ COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR << "#{@plugin_root}/src"
+ end
+
+ def post_runner_generate(arg_hash)
+ # After the test runner file has been created, append the FFF globals
+ # definition to the end of the test runner. These globals will be shared by
+ # all mocks linked into the test.
+ File.open(arg_hash[:runner_file], 'a') do |f|
+ f.puts
+ f.puts "//=======Defintions of FFF variables====="
+ f.puts %{#include "fff.h"}
+ f.puts "DEFINE_FFF_GLOBALS;"
+ end
+ end
+
+end # class FakeFunctionFramework
+
+class FffMockGeneratorForCMock
+
+ def initialize(options=nil)
+ @cm_config = CMockConfig.new(options)
+ @cm_parser = CMockHeaderParser.new(@cm_config)
+ @silent = (@cm_config.verbosity < 2)
+
+ # These are the additional files to include in the mock files.
+ @includes_h_pre_orig_header = (@cm_config.includes || @cm_config.includes_h_pre_orig_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
+ @includes_h_post_orig_header = (@cm_config.includes_h_post_orig_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
+ @includes_c_pre_header = (@cm_config.includes_c_pre_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
+ @includes_c_post_header = (@cm_config.includes_c_post_header || []).map{|h| h =~ /</ ? h : "\"#{h}\""}
+ end
+
+ def setup_mocks(files)
+ [files].flatten.each do |src|
+ generate_mock (src)
+ end
+ end
+
+ def generate_mock (header_file_to_mock)
+ module_name = File.basename(header_file_to_mock, '.h')
+ puts "Creating mock for #{module_name}..." unless @silent
+ mock_name = @cm_config.mock_prefix + module_name + @cm_config.mock_suffix
+ mock_path = @cm_config.mock_path
+ if @cm_config.subdir
+ # If a subdirectory has been configured, append it to the mock path.
+ mock_path = "#{mock_path}/#{@cm_config.subdir}"
+ end
+ full_path_for_mock = "#{mock_path}/#{mock_name}"
+
+ # Parse the header file so we know what to mock.
+ parsed_header = @cm_parser.parse(module_name, File.read(header_file_to_mock))
+
+ # Create the directory if it doesn't exist.
+ mkdir_p full_path_for_mock.pathmap("%d")
+
+ # Generate the mock header file.
+ puts "Creating mock: #{full_path_for_mock}.h"
+
+ # Create the mock header.
+ File.open("#{full_path_for_mock}.h", 'w') do |f|
+ f.write(FffMockGenerator.create_mock_header(module_name, mock_name, parsed_header,
+ @includes_h_pre_orig_header, @includes_h_post_orig_header))
+ end
+
+ # Create the mock source file.
+ File.open("#{full_path_for_mock}.c", 'w') do |f|
+ f.write(FffMockGenerator.create_mock_source(mock_name, parsed_header,
+ @includes_c_pre_orig_header, @includes_c_post_orig_header))
+ end
+ end
+
+end
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/lib/fff_mock_generator.rb b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/lib/fff_mock_generator.rb
new file mode 100755
index 00000000..9dc03a65
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/lib/fff_mock_generator.rb
@@ -0,0 +1,163 @@
+# Creates mock files from parsed header files that can be linked into applications.
+# The mocks created are compatible with CMock for use with Ceedling.
+
+class FffMockGenerator
+
+ def self.create_mock_header(module_name, mock_name, parsed_header, pre_includes=nil,
+ post_includes=nil)
+ output = StringIO.new
+ write_opening_include_guard(mock_name, output)
+ output.puts
+ write_extra_includes(pre_includes, output)
+ write_header_includes(module_name, output)
+ write_extra_includes(post_includes, output)
+ output.puts
+ write_typedefs(parsed_header, output)
+ output.puts
+ write_function_declarations(parsed_header, output)
+ output.puts
+ write_control_function_prototypes(mock_name, output)
+ output.puts
+ write_closing_include_guard(mock_name, output)
+ output.string
+ end
+
+ def self.create_mock_source (mock_name, parsed_header, pre_includes=nil,
+ post_includes=nil)
+ output = StringIO.new
+ write_extra_includes(pre_includes, output)
+ write_source_includes(mock_name, output)
+ write_extra_includes(post_includes, output)
+ output.puts
+ write_function_definitions(parsed_header, output)
+ output.puts
+ write_control_function_definitions(mock_name, parsed_header, output)
+ output.string
+ end
+
+ private
+
+# Header file generation functions.
+
+ def self.write_opening_include_guard(mock_name, output)
+ output.puts "#ifndef #{mock_name}_H"
+ output.puts "#define #{mock_name}_H"
+ end
+
+ def self.write_header_includes(module_name, output)
+ output.puts %{#include "fff.h"}
+ output.puts %{#include "fff_unity_helper.h"}
+ output.puts %{#include "#{module_name}.h"}
+ end
+
+ def self.write_typedefs(parsed_header, output)
+ return unless parsed_header.key?(:typedefs)
+ parsed_header[:typedefs].each do |typedef|
+ output.puts typedef
+ end
+ end
+
+ def self.write_function_declarations(parsed_header, output)
+ write_function_macros("DECLARE", parsed_header, output)
+ end
+
+
+ def self.write_control_function_prototypes(mock_name, output)
+ output.puts "void #{mock_name}_Init(void);"
+ output.puts "void #{mock_name}_Verify(void);"
+ output.puts "void #{mock_name}_Destroy(void);"
+ end
+
+ def self.write_closing_include_guard(mock_name, output)
+ output.puts "#endif // #{mock_name}_H"
+ end
+
+# Source file generation functions.
+
+ def self.write_source_includes (mock_name, output)
+ output.puts "#include <string.h>"
+ output.puts %{#include "fff.h"}
+ output.puts %{#include "#{mock_name}.h"}
+ end
+
+ def self.write_function_definitions(parsed_header, output)
+ write_function_macros("DEFINE", parsed_header, output)
+ end
+
+ def self.write_control_function_definitions(mock_name, parsed_header, output)
+ output.puts "void #{mock_name}_Init(void)"
+ output.puts "{"
+ # In the init function, reset the FFF globals. These are used for things
+ # like the call history.
+ output.puts " FFF_RESET_HISTORY();"
+
+ # Also, reset all of the fakes.
+ if parsed_header[:functions]
+ parsed_header[:functions].each do |function|
+ output.puts " RESET_FAKE(#{function[:name]})"
+ end
+ end
+ output.puts "}"
+ output.puts "void #{mock_name}_Verify(void)"
+ output.puts "{"
+ output.puts "}"
+ output.puts "void #{mock_name}_Destroy(void)"
+ output.puts "{"
+ output.puts "}"
+ end
+
+# Shared functions.
+
+ def self.write_extra_includes(includes, output)
+ if includes
+ includes.each {|inc| output.puts "#include #{inc}\n"}
+ end
+ end
+
+ def self.write_function_macros(macro_type, parsed_header, output)
+ return unless parsed_header.key?(:functions)
+ parsed_header[:functions].each do |function|
+ name = function[:name]
+ return_type = function[:return][:type]
+ if function.has_key? :modifier
+ # Prepend any modifier. If there isn't one, trim any leading whitespace.
+ return_type = "#{function[:modifier]} #{return_type}".lstrip
+ end
+ arg_count = function[:args].size
+
+ # Check for variable arguments.
+ var_arg_suffix = ""
+ if function[:var_arg]
+ # If there are are variable arguments, then we need to add this argument
+ # to the count, update the suffix that will get added to the macro.
+ arg_count += 1
+ var_arg_suffix = "_VARARG"
+ end
+
+ # Generate the correct macro.
+ if return_type == 'void'
+ output.print "#{macro_type}_FAKE_VOID_FUNC#{arg_count}#{var_arg_suffix}(#{name}"
+ else
+ output.print "#{macro_type}_FAKE_VALUE_FUNC#{arg_count}#{var_arg_suffix}(#{return_type}, #{name}"
+ end
+
+ # Append each argument type.
+ function[:args].each do |arg|
+ output.print ", "
+ if arg[:const?]
+ output.print "const "
+ end
+ output.print "#{arg[:type]}"
+ end
+
+ # If this argument list ends with a variable argument, add it here at the end.
+ if function[:var_arg]
+ output.print ", ..."
+ end
+
+ # Close the declaration.
+ output.puts ");"
+ end
+ end
+
+end
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_header_generator_spec.rb b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_header_generator_spec.rb
new file mode 100755
index 00000000..e6ac11dd
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_header_generator_spec.rb
@@ -0,0 +1,304 @@
+require 'stringio'
+require 'fff_mock_generator.rb'
+require 'header_generator.rb'
+
+# Test the contents of the .h file created for the mock.
+describe "FffMockGenerator.create_mock_header" do
+
+ context "when there is nothing to mock," do
+ let(:mock_header) {
+ parsed_header = {}
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
+ }
+ it "then the generated header file starts with an opening include guard" do
+ expect(mock_header).to start_with(
+ "#ifndef mock_display_H\n" +
+ "#define mock_display_H")
+ end
+ it "then the generated file ends with a closing include guard" do
+ expect(mock_header).to end_with(
+ "#endif // mock_display_H\n")
+ end
+ it "then the generated file includes the fff header" do
+ expect(mock_header).to include(
+ %{#include "fff.h"\n})
+ end
+ it "then the generated file has a prototype for the init function" do
+ expect(mock_header).to include(
+ "void mock_display_Init(void);")
+ end
+ it "then the generated file has a prototype for the verify function" do
+ expect(mock_header).to include(
+ "void mock_display_Verify(void);")
+ end
+ it "then the generated file has a prototype for the destroy function" do
+ expect(mock_header).to include(
+ "void mock_display_Destroy(void);")
+ end
+ end
+
+ context "when there is a function with no args and a void return," do
+ let(:mock_header) {
+ parsed_header = create_cmock_style_parsed_header(
+ [{:name => 'display_turnOffStatusLed', :return_type => 'void'}])
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
+ }
+ it "then the generated header file starts with an opening include guard" do
+ expect(mock_header).to start_with(
+ "#ifndef mock_display_H\n" +
+ "#define mock_display_H")
+ end
+ it "then the generated header file contains a fake function declaration" do
+ expect(mock_header).to include(
+ "DECLARE_FAKE_VOID_FUNC0(display_turnOffStatusLed);"
+ )
+ end
+ it "then the generated file ends with a closing include guard" do
+ expect(mock_header).to end_with(
+ "#endif // mock_display_H\n")
+ end
+ end
+
+ context "when there is a function with no args and a bool return," do
+ let(:mock_header) {
+ parsed_header = create_cmock_style_parsed_header(
+ [{:name => 'display_isError', :return_type => 'bool'}])
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
+ }
+ it "then the generated file contains the fake function declaration" do
+ expect(mock_header).to include(
+ "DECLARE_FAKE_VALUE_FUNC0(bool, display_isError);"
+ )
+ end
+ end
+
+ context "when there is a function with no args and an int return," do
+ let(:mock_header) {
+ parsed_header = create_cmock_style_parsed_header(
+ [{:name => 'display_isError', :return_type => 'int'}])
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
+ }
+ it "then the generated file contains the fake function declaration" do
+ expect(mock_header).to include(
+ "DECLARE_FAKE_VALUE_FUNC0(int, display_isError);"
+ )
+ end
+ end
+
+ context "when there is a function with args and a void return," do
+ let(:mock_header) {
+ parsed_header = create_cmock_style_parsed_header(
+ [{:name => 'display_setVolume', :return_type => 'void', :args => ['int']}])
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
+ }
+ it "then the generated file contains the fake function declaration" do
+ expect(mock_header).to include(
+ "DECLARE_FAKE_VOID_FUNC1(display_setVolume, int);"
+ )
+ end
+ end
+
+ context "when there is a function with args and a value return," do
+ let(:mock_header) {
+ parsed_header = create_cmock_style_parsed_header(
+ [{:name => 'a_function', :return_type => 'int', :args => ['char *']}])
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
+ }
+ it "then the generated file contains the fake function declaration" do
+ expect(mock_header).to include(
+ "FAKE_VALUE_FUNC1(int, a_function, char *);"
+ )
+ end
+ end
+
+ context "when there is a function with many args and a void return," do
+ let(:mock_header) {
+ parsed_header = create_cmock_style_parsed_header(
+ [{:name => 'a_function', :return_type => 'void',
+ :args => ['int', 'char *', 'int', 'int', 'bool', 'applesauce']}])
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
+ }
+ it "then the generated file contains the fake function declaration" do
+ expect(mock_header).to include(
+ "DECLARE_FAKE_VOID_FUNC6(a_function, int, char *, int, int, bool, applesauce);"
+ )
+ end
+ end
+
+ context "when there are multiple functions," do
+ let(:mock_header) {
+ parsed_header = create_cmock_style_parsed_header(
+ [ {:name => 'a_function', :return_type => 'int', :args => ['char *']},
+ {:name => 'another_function', :return_type => 'void'},
+ {:name => 'three', :return_type => 'bool', :args => ['float', 'int']}
+ ])
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
+ }
+ it "then the generated file contains the first fake function declaration" do
+ expect(mock_header).to include(
+ "DECLARE_FAKE_VALUE_FUNC1(int, a_function, char *);"
+ )
+ end
+ it "then the generated file contains the second fake function declaration" do
+ expect(mock_header).to include(
+ "DECLARE_FAKE_VOID_FUNC0(another_function);"
+ )
+ end
+ it "then the generated file contains the third fake function declaration" do
+ expect(mock_header).to include(
+ "DECLARE_FAKE_VALUE_FUNC2(bool, three, float, int);"
+ )
+ end
+ end
+
+ context "when there is a typedef," do
+ let(:mock_header) {
+ parsed_header = create_cmock_style_parsed_header(
+ nil, ["typedef void (*displayCompleteCallback) (void);"])
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
+ }
+ it "then the generated file contains the typedef" do
+ expect(mock_header).to include(
+ "typedef void (*displayCompleteCallback) (void);"
+ )
+ end
+ end
+
+ context "when there is a void function with variable arguments" do
+ let(:mock_header){
+ parsed_header = {}
+ parsed_header[:functions] = [{
+ :name => "function_with_var_args",
+ :return => {:type => "void"},
+ :var_arg => "...",
+ :args => [{:type => 'char *'}]
+ }]
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
+ }
+ it "then the generated file contains the vararg declaration" do
+ expect(mock_header).to include(
+ "DECLARE_FAKE_VOID_FUNC2_VARARG(function_with_var_args, char *, ...)"
+ )
+ end
+ end
+
+ context "when there is a function with a return value and variable arguments" do
+ let(:mock_header){
+ parsed_header = {}
+ parsed_header[:functions] = [{
+ :name => "function_with_var_args",
+ :return => {:type => "int"},
+ :var_arg => "...",
+ :args => [{:type => 'char *'}]
+ }]
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
+ }
+ it "then the generated file contains the vararg declaration" do
+ expect(mock_header).to include(
+ "DECLARE_FAKE_VALUE_FUNC2_VARARG(int, function_with_var_args, char *, ...)"
+ )
+ end
+ end
+
+ context "when there is a void function with variable arguments and " +
+ "additional arguments" do
+ let(:mock_header){
+ parsed_header = {}
+ parsed_header[:functions] = [{
+ :name => "function_with_var_args",
+ :return => {:type => "void"},
+ :var_arg => "...",
+ :args => [{:type => 'char *'}, {:type => 'int'}]
+ }]
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
+ }
+ it "then the generated file contains the vararg declaration" do
+ expect(mock_header).to include(
+ "DECLARE_FAKE_VOID_FUNC3_VARARG(function_with_var_args, char *, int, ...)"
+ )
+ end
+ end
+
+ context "when there is a function with a pointer to a const value" do
+ let(:mock_header){
+ parsed_header = {}
+ parsed_header[:functions] = [{
+ :name => "const_test_function",
+ :return => {:type => "void"},
+ :args => [{:type => "char *", :name => "a", :ptr? => false, :const? => true},
+ {:type => "char *", :name => "b", :ptr? => false, :const? => false}]
+ }]
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
+ }
+ it "then the generated file contains the correct const argument in the declaration" do
+ expect(mock_header).to include(
+ "DECLARE_FAKE_VOID_FUNC2(const_test_function, const char *, char *)"
+ )
+ end
+ end
+
+ context "when there is a function that returns a const pointer" do
+ let(:mock_header){
+ parsed_header = {}
+ parsed_header[:functions] = [{
+ :name => "return_const_pointer_test_function",
+ :modifier => "const",
+ :return => {:type => "char *" },
+ :args => [{:type => "int", :name => "a"}]
+ }]
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
+ }
+ it "then the generated file contains the correct const return value in the declaration" do
+ expect(mock_header).to include(
+ "DECLARE_FAKE_VALUE_FUNC1(const char *, return_const_pointer_test_function, int)"
+ )
+ end
+ end
+
+ context "when there is a function that returns a const int" do
+ let(:mock_header){
+ parsed_header = {}
+ parsed_header[:functions] = [{
+ :name => "return_const_int_test_function",
+ :modifier => "const",
+ :return => {:type => "int" },
+ :args => []
+ }]
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header)
+ }
+ it "then the generated file contains the correct const return value in the declaration" do
+ expect(mock_header).to include(
+ "DECLARE_FAKE_VALUE_FUNC0(const int, return_const_int_test_function)"
+ )
+ end
+ end
+
+ context "when there are pre-includes" do
+ let(:mock_header) {
+ parsed_header = {}
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header,
+ [%{"another_header.h"}])
+ }
+ it "then they are included before the other files" do
+ expect(mock_header).to include(
+ %{#include "another_header.h"\n} +
+ %{#include "fff.h"}
+ )
+ end
+ end
+
+ context "when there are post-includes" do
+ let(:mock_header) {
+ parsed_header = {}
+ FffMockGenerator.create_mock_header("display", "mock_display", parsed_header,
+ nil, [%{"another_header.h"}])
+ }
+ it "then they are included after the other files" do
+ expect(mock_header).to include(
+ %{#include "display.h"\n} +
+ %{#include "another_header.h"\n}
+ )
+ end
+ end
+
+end
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_source_generator_spec.rb b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_source_generator_spec.rb
new file mode 100755
index 00000000..364f8521
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/spec/fff_mock_source_generator_spec.rb
@@ -0,0 +1,149 @@
+require 'stringio'
+require 'fff_mock_generator.rb'
+
+# Test the contents of the .c file created for the mock.
+describe "FffMockGenerator.create_mock_source" do
+
+ context "when there is nothing to mock," do
+ let(:mock_source) {
+ parsed_header = {}
+ FffMockGenerator.create_mock_source("mock_my_module", parsed_header)
+ }
+ it "then the generated file includes the fff header" do
+ expect(mock_source).to include(
+ # fff.h also requires including string.h
+ %{#include <string.h>\n} +
+ %{#include "fff.h"}
+ )
+ end
+ it "then the generated file includes the mock header" do
+ expect(mock_source).to include(
+ %{#include "mock_my_module.h"\n}
+ )
+ end
+ it "then the generated file defines the init function" do
+ expect(mock_source).to include(
+ "void mock_my_module_Init(void)\n" +
+ "{\n" +
+ " FFF_RESET_HISTORY();\n" +
+ "}"
+ )
+ end
+ it "then the generated file defines the verify function" do
+ expect(mock_source).to include(
+ "void mock_my_module_Verify(void)\n" +
+ "{\n" +
+ "}"
+ )
+ end
+ it "then the generated file defines the destroy function" do
+ expect(mock_source).to include(
+ "void mock_my_module_Destroy(void)\n" +
+ "{\n" +
+ "}"
+ )
+ end
+ end
+
+ context "when there are multiple functions," do
+ let(:mock_source) {
+ parsed_header = create_cmock_style_parsed_header(
+ [ {:name => 'a_function', :return_type => 'int', :args => ['char *']},
+ {:name => 'another_function', :return_type => 'void'},
+ {:name => 'three', :return_type => 'bool', :args => ['float', 'int']}
+ ])
+ FffMockGenerator.create_mock_source("mock_display", parsed_header)
+ }
+ it "then the generated file contains the first fake function definition" do
+ expect(mock_source).to include(
+ "DEFINE_FAKE_VALUE_FUNC1(int, a_function, char *);"
+ )
+ end
+ it "then the generated file contains the second fake function definition" do
+ expect(mock_source).to include(
+ "DEFINE_FAKE_VOID_FUNC0(another_function);"
+ )
+ end
+ it "then the generated file contains the third fake function definition" do
+ expect(mock_source).to include(
+ "DEFINE_FAKE_VALUE_FUNC2(bool, three, float, int);"
+ )
+ end
+ it "then the init function resets all of the fakes" do
+ expect(mock_source).to include(
+ "void mock_display_Init(void)\n" +
+ "{\n" +
+ " FFF_RESET_HISTORY();\n" +
+ " RESET_FAKE(a_function)\n" +
+ " RESET_FAKE(another_function)\n" +
+ " RESET_FAKE(three)\n" +
+ "}"
+ )
+ end
+ end
+
+ context "when there is a void function with variable arguments and " +
+ "additional arguments" do
+ let(:mock_source){
+ parsed_header = {}
+ parsed_header[:functions] = [{
+ :name => "function_with_var_args",
+ :return => {:type => "void"},
+ :var_arg => "...",
+ :args => [{:type => 'char *'}, {:type => 'int'}]
+ }]
+ FffMockGenerator.create_mock_source("mock_display", parsed_header)
+ }
+ it "then the generated file contains the vararg definition" do
+ expect(mock_source).to include(
+ "DEFINE_FAKE_VOID_FUNC3_VARARG(function_with_var_args, char *, int, ...)"
+ )
+ end
+ end
+
+ context "when there is a function with a pointer to a const value" do
+ let(:mock_source){
+ parsed_header = {}
+ parsed_header[:functions] = [{
+ :name => "const_test_function",
+ :return => {:type => "void"},
+ :args => [{:type => "char *", :name => "a", :ptr? => false, :const? => true},
+ {:type => "char *", :name => "b", :ptr? => false, :const? => false}]
+ }]
+ FffMockGenerator.create_mock_source("mock_display", parsed_header)
+ }
+ it "then the generated file contains the correct const argument in the declaration" do
+ expect(mock_source).to include(
+ "DEFINE_FAKE_VOID_FUNC2(const_test_function, const char *, char *)"
+ )
+ end
+ end
+
+ context "when there are pre-includes" do
+ let(:mock_source) {
+ parsed_source = {}
+ FffMockGenerator.create_mock_source("mock_display", parsed_source,
+ [%{"another_header.h"}])
+ }
+ it "then they are included before the other files" do
+ expect(mock_source).to include(
+ %{#include "another_header.h"\n} +
+ %{#include <string.h>}
+ )
+ end
+ end
+
+ context "when there are post-includes" do
+ let(:mock_source) {
+ parsed_source = {}
+ FffMockGenerator.create_mock_source("mock_display", parsed_source,
+ nil, [%{"another_header.h"}])
+ }
+ it "then they are included before the other files" do
+ expect(mock_source).to include(
+ %{#include "mock_display.h"\n} +
+ %{#include "another_header.h"\n}
+ )
+ end
+ end
+end \ No newline at end of file
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/spec/header_generator.rb b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/spec/header_generator.rb
new file mode 100755
index 00000000..cda27844
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/spec/header_generator.rb
@@ -0,0 +1,51 @@
+# Create a CMock-style parsed header hash. This the type of hash created by
+# CMock when parsing header files for automock generation. It contains all of
+# includes, typedefs and functions (with return types and arguments) parsed from
+# the header file.
+def create_cmock_style_parsed_header(functions, typedefs = nil)
+ parsed_header = {
+ :includes => nil,
+ :functions => [],
+ :typedefs => []
+ }
+
+ # Add the typedefs.
+ if typedefs
+ typedefs.each do |typedef|
+ parsed_header[:typedefs] << typedef
+ end
+ end
+
+ # Add the functions.
+ if functions
+ functions.each do |function|
+ # Build the array of arguments.
+ args = []
+ if function.key?(:args)
+ function[:args].each do |arg|
+ args << {
+ :type => arg
+ }
+ end
+ end
+ parsed_header[:functions] << {
+ :name => function[:name],
+ :modifier => "",
+ :return => {
+ :type => function[:return_type],
+ :name => "cmock_to_return",
+ :ptr? => false,
+ :const? => false,
+ :str => "void cmock_to_return",
+ :void? => true
+ },
+ :var_arg => nil,
+ :args_string => "void",
+ :args => args,
+ :args_call => "",
+ :contains_ptr? => false
+ }
+ end
+ end
+ parsed_header
+end \ No newline at end of file
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/spec/spec_helper.rb b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/spec/spec_helper.rb
new file mode 100755
index 00000000..25dc80ac
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/spec/spec_helper.rb
@@ -0,0 +1,96 @@
+# This file was generated by the `rspec --init` command. Conventionally, all
+# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
+# The generated `.rspec` file contains `--require spec_helper` which will cause
+# this file to always be loaded, without a need to explicitly require it in any
+# files.
+#
+# Given that it is always loaded, you are encouraged to keep this file as
+# light-weight as possible. Requiring heavyweight dependencies from this file
+# will add to the boot time of your test suite on EVERY test run, even for an
+# individual file that may not need all of that loaded. Instead, consider making
+# a separate helper file that requires the additional dependencies and performs
+# the additional setup, and require it from the spec files that actually need
+# it.
+#
+# The `.rspec` file also contains a few flags that are not defaults but that
+# users commonly want.
+#
+# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
+RSpec.configure do |config|
+ # rspec-expectations config goes here. You can use an alternate
+ # assertion/expectation library such as wrong or the stdlib/minitest
+ # assertions if you prefer.
+ config.expect_with :rspec do |expectations|
+ # This option will default to `true` in RSpec 4. It makes the `description`
+ # and `failure_message` of custom matchers include text for helper methods
+ # defined using `chain`, e.g.:
+ # be_bigger_than(2).and_smaller_than(4).description
+ # # => "be bigger than 2 and smaller than 4"
+ # ...rather than:
+ # # => "be bigger than 2"
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
+ end
+
+ # rspec-mocks config goes here. You can use an alternate test double
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
+ config.mock_with :rspec do |mocks|
+ # Prevents you from mocking or stubbing a method that does not exist on
+ # a real object. This is generally recommended, and will default to
+ # `true` in RSpec 4.
+ mocks.verify_partial_doubles = true
+ end
+
+# The settings below are suggested to provide a good initial experience
+# with RSpec, but feel free to customize to your heart's content.
+=begin
+ # These two settings work together to allow you to limit a spec run
+ # to individual examples or groups you care about by tagging them with
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
+ # get run.
+ config.filter_run :focus
+ config.run_all_when_everything_filtered = true
+
+ # Allows RSpec to persist some state between runs in order to support
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
+ # you configure your source control system to ignore this file.
+ config.example_status_persistence_file_path = "spec/examples.txt"
+
+ # Limits the available syntax to the non-monkey patched syntax that is
+ # recommended. For more details, see:
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
+ config.disable_monkey_patching!
+
+ # This setting enables warnings. It's recommended, but in some cases may
+ # be too noisy due to issues in dependencies.
+ config.warnings = true
+
+ # Many RSpec users commonly either run the entire suite or an individual
+ # file, and it's useful to allow more verbose output when running an
+ # individual spec file.
+ if config.files_to_run.one?
+ # Use the documentation formatter for detailed output,
+ # unless a formatter has already been configured
+ # (e.g. via a command-line flag).
+ config.default_formatter = 'doc'
+ end
+
+ # Print the 10 slowest examples and example groups at the
+ # end of the spec run, to help surface which specs are running
+ # particularly slow.
+ config.profile_examples = 10
+
+ # Run specs in random order to surface order dependencies. If you find an
+ # order dependency and want to debug it, you can fix the order by providing
+ # the seed, which is printed after each run.
+ # --seed 1234
+ config.order = :random
+
+ # Seed global randomization in this process using the `--seed` CLI option.
+ # Setting this allows you to use `--seed` to deterministically reproduce
+ # test failures related to randomization by passing the same `--seed` value
+ # as the one that triggered the failure.
+ Kernel.srand config.seed
+=end
+end
diff --git a/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/src/fff_unity_helper.h b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/src/fff_unity_helper.h
new file mode 100755
index 00000000..de3db44a
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/fake_function_framework/src/fff_unity_helper.h
@@ -0,0 +1,33 @@
+#ifndef fff_unity_helper_H
+#define fff_unity_helper_H
+
+/*
+ FFF helper macros for Unity.
+*/
+
+/*
+ Fail if the function was not called the expected number of times.
+*/
+#define TEST_ASSERT_CALLED_TIMES(times_, function_) \
+ TEST_ASSERT_EQUAL_MESSAGE(times_, \
+ function_ ## _fake.call_count, \
+ "Function " #function_ " called the incorrect number of times.")
+/*
+ Fail if the function was not called exactly once.
+*/
+#define TEST_ASSERT_CALLED(function_) TEST_ASSERT_CALLED_TIMES(1, function_)
+
+/*
+ Fail if the function was called 1 or more times.
+*/
+#define TEST_ASSERT_NOT_CALLED(function_) TEST_ASSERT_CALLED_TIMES(0, function_)
+
+/*
+ Fail if the function was not called in this particular order.
+*/
+#define TEST_ASSERT_CALLED_IN_ORDER(order_, function_) \
+ TEST_ASSERT_EQUAL_PTR_MESSAGE((void *) function_, \
+ fff.call_history[order_], \
+ "Function " #function_ " not called in order " #order_ )
+
+#endif \ No newline at end of file
diff --git a/tinyusb/test/vendor/ceedling/plugins/gcov/README.md b/tinyusb/test/vendor/ceedling/plugins/gcov/README.md
new file mode 100755
index 00000000..096ffa10
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/gcov/README.md
@@ -0,0 +1,101 @@
+ceedling-gcov
+=============
+
+# Plugin Overview
+
+Plugin for integrating GNU GCov code coverage tool into Ceedling projects.
+Currently only designed for the gcov command (like LCOV for example). In the
+future we could configure this to work with other code coverage tools.
+
+This plugin currently uses `gcovr` to generate HTML and/or XML reports as a
+utility. The normal gcov plugin _must_ be run first for this report to generate.
+
+## Installation
+
+Gcovr can be installed via pip like so:
+
+```
+pip install gcovr
+```
+
+## Configuration
+
+The gcov plugin supports configuration options via your `project.yml` provided
+by Ceedling.
+
+Generation of HTML reports may be enabled or disabled with the following
+config. Set to `true` to enable or set to `false` to disable.
+
+```
+:gcov:
+ :html_report: true
+```
+
+Generation of XML reports may be enabled or disabled with the following
+config. Set to `true` to enable or set to `false` to disable.
+
+```
+:gcov:
+ :xml_report: true
+```
+
+There are two types of gcovr HTML reports that can be configured in your
+`project.yml`. To create a basic HTML report, with only the overall file
+information, use the following config.
+
+```
+:gcov:
+ :html_report_type: basic
+```
+
+To create a detailed HTML report, with line by line breakdown of the
+coverage, use the following config.
+
+```
+:gcov:
+ :html_report_type: detailed
+```
+
+There are a number of options to control which files are considered part of
+the coverage report. Most often, we only care about coverage on our source code, and not
+on tests or automatically generated mocks, runners, etc. However, there are times
+where this isn't true... or there are times where we've moved ceedling's directory
+structure so that the project file isn't at the root of the project anymore. In these
+cases, you may need to tweak the following:
+
+```
+:gcov:
+ :report_root: "."
+ :report_exclude: "^build|^vendor|^test|^support"
+ :report_include: "^src"
+```
+
+One important note about html_report_root: gcovr will only take a single root folder, unlike
+Ceedling's ability to take as many as you like. So you will need to choose a folder which is
+a superset of ALL the folders you want, and then use the include or exclude options to set up
+patterns of files to pay attention to or ignore. It's not ideal, but it works.
+
+Finally, there are a number of settings which can be specified in order to adjust the
+default behaviors of gcov:
+
+```
+:gcov:
+ :html_medium_threshold: 75
+ :html_high_threshold: 90
+ :fail_under_line: 30
+ :fail_under_branch: 30
+```
+
+These HTML and XML reports will be found in `build/artifacts/gcov`.
+
+## Example Usage
+
+```
+ceedling gcov:all utils:gcov
+```
+
+## To-Do list
+
+- Generate overall report (combined statistics from all files with coverage)
+- Generate coverage output files
+- Easier option override for better customisation
diff --git a/tinyusb/test/vendor/ceedling/plugins/gcov/assets/template.erb b/tinyusb/test/vendor/ceedling/plugins/gcov/assets/template.erb
new file mode 100755
index 00000000..5e5a1742
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/gcov/assets/template.erb
@@ -0,0 +1,15 @@
+% function_string = hash[:coverage][:functions].to_s
+% branch_string = hash[:coverage][:branches].to_s
+% format_string = "%#{[function_string.length, branch_string.length].max}i"
+<%=@ceedling[:plugin_reportinator].generate_banner("#{GCOV_ROOT_NAME.upcase}: CODE COVERAGE SUMMARY")%>
+% if (!hash[:coverage][:functions].nil?)
+FUNCTIONS: <%=sprintf(format_string, hash[:coverage][:functions])%>%
+% else
+FUNCTIONS: none
+% end
+% if (!hash[:coverage][:branches].nil?)
+BRANCHES: <%=sprintf(format_string, hash[:coverage][:branches])%>%
+% else
+BRANCHES: none
+% end
+
diff --git a/tinyusb/test/vendor/ceedling/plugins/gcov/config/defaults.yml b/tinyusb/test/vendor/ceedling/plugins/gcov/config/defaults.yml
new file mode 100755
index 00000000..13bac556
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/gcov/config/defaults.yml
@@ -0,0 +1,73 @@
+---
+
+:tools:
+ :gcov_compiler:
+ :executable: gcc
+ :arguments:
+ - -g
+ - -fprofile-arcs
+ - -ftest-coverage
+ - -I"$": COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR
+ - -I"$": COLLECTION_PATHS_TEST_TOOLCHAIN_INCLUDE
+ - -D$: COLLECTION_DEFINES_TEST_AND_VENDOR
+ - -DGCOV_COMPILER
+ - -DCODE_COVERAGE
+ - -c "${1}"
+ - -o "${2}"
+ :gcov_linker:
+ :executable: gcc
+ :arguments:
+ - -fprofile-arcs
+ - -ftest-coverage
+ - ${1}
+ - -o ${2}
+ - ${3}
+ :gcov_fixture:
+ :executable: ${1}
+ :gcov_report:
+ :executable: gcov
+ :arguments:
+ - -n
+ - -p
+ - -b
+ - -o "$": GCOV_BUILD_OUTPUT_PATH
+ - "\"${1}\""
+ :gcov_post_report:
+ :executable: gcovr
+ :optional: TRUE
+ :arguments:
+ - -p
+ - -b
+ - ${1}
+ - --html
+ - -o GcovCoverageResults.html
+ :gcov_post_report_basic:
+ :executable: gcovr
+ :optional: TRUE
+ :arguments:
+ - -p
+ - -b
+ - ${1}
+ - --html
+ - -o "$": GCOV_ARTIFACTS_FILE
+ :gcov_post_report_advanced:
+ :executable: gcovr
+ :optional: TRUE
+ :arguments:
+ - -p
+ - -b
+ - ${1}
+ - --html
+ - --html-details
+ - -o "$": GCOV_ARTIFACTS_FILE
+ :gcov_post_report_xml:
+ :executable: gcovr
+ :optional: TRUE
+ :arguments:
+ - -p
+ - -b
+ - ${1}
+ - --xml
+ - -o "$": GCOV_ARTIFACTS_FILE_XML
+
+...
diff --git a/tinyusb/test/vendor/ceedling/plugins/gcov/gcov.rake b/tinyusb/test/vendor/ceedling/plugins/gcov/gcov.rake
new file mode 100755
index 00000000..3acab856
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/gcov/gcov.rake
@@ -0,0 +1,220 @@
+directory(GCOV_BUILD_OUTPUT_PATH)
+directory(GCOV_RESULTS_PATH)
+directory(GCOV_ARTIFACTS_PATH)
+directory(GCOV_DEPENDENCIES_PATH)
+
+CLEAN.include(File.join(GCOV_BUILD_OUTPUT_PATH, '*'))
+CLEAN.include(File.join(GCOV_RESULTS_PATH, '*'))
+CLEAN.include(File.join(GCOV_ARTIFACTS_PATH, '*'))
+CLEAN.include(File.join(GCOV_DEPENDENCIES_PATH, '*'))
+
+CLOBBER.include(File.join(GCOV_BUILD_PATH, '**/*'))
+
+rule(/#{GCOV_BUILD_OUTPUT_PATH}\/#{'.+\\' + EXTENSION_OBJECT}$/ => [
+ proc do |task_name|
+ @ceedling[:file_finder].find_compilation_input_file(task_name)
+ end
+ ]) do |object|
+
+ if File.basename(object.source) =~ /^(#{PROJECT_TEST_FILE_PREFIX}|#{CMOCK_MOCK_PREFIX}|#{GCOV_IGNORE_SOURCES.join('|')})/i
+ @ceedling[:generator].generate_object_file(
+ TOOLS_GCOV_COMPILER,
+ OPERATION_COMPILE_SYM,
+ GCOV_SYM,
+ object.source,
+ object.name,
+ @ceedling[:file_path_utils].form_test_build_list_filepath(object.name)
+ )
+ else
+ @ceedling[GCOV_SYM].generate_coverage_object_file(object.source, object.name)
+ end
+end
+
+rule(/#{GCOV_BUILD_OUTPUT_PATH}\/#{'.+\\' + EXTENSION_EXECUTABLE}$/) do |bin_file|
+ lib_args = @ceedling[:test_invoker].convert_libraries_to_arguments()
+
+ @ceedling[:generator].generate_executable_file(
+ TOOLS_GCOV_LINKER,
+ GCOV_SYM,
+ bin_file.prerequisites,
+ bin_file.name,
+ lib_args,
+ @ceedling[:file_path_utils].form_test_build_map_filepath(bin_file.name)
+ )
+end
+
+rule(/#{GCOV_RESULTS_PATH}\/#{'.+\\' + EXTENSION_TESTPASS}$/ => [
+ proc do |task_name|
+ @ceedling[:file_path_utils].form_test_executable_filepath(task_name)
+ end
+ ]) do |test_result|
+ @ceedling[:generator].generate_test_results(TOOLS_GCOV_FIXTURE, GCOV_SYM, test_result.source, test_result.name)
+end
+
+rule(/#{GCOV_DEPENDENCIES_PATH}\/#{'.+\\' + EXTENSION_DEPENDENCIES}$/ => [
+ proc do |task_name|
+ @ceedling[:file_finder].find_compilation_input_file(task_name)
+ end
+ ]) do |dep|
+ @ceedling[:generator].generate_dependencies_file(
+ TOOLS_TEST_DEPENDENCIES_GENERATOR,
+ GCOV_SYM,
+ dep.source,
+ File.join(GCOV_BUILD_OUTPUT_PATH, File.basename(dep.source).ext(EXTENSION_OBJECT)),
+ dep.name
+ )
+end
+
+task directories: [GCOV_BUILD_OUTPUT_PATH, GCOV_RESULTS_PATH, GCOV_DEPENDENCIES_PATH, GCOV_ARTIFACTS_PATH]
+
+namespace GCOV_SYM do
+ task source_coverage: COLLECTION_ALL_SOURCE.pathmap("#{GCOV_BUILD_OUTPUT_PATH}/%n#{@ceedling[:configurator].extension_object}")
+
+ desc 'Run code coverage for all tests'
+ task all: [:directories] do
+ @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config)
+ @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, GCOV_SYM)
+ @ceedling[:configurator].restore_config
+ end
+
+ desc 'Run single test w/ coverage ([*] real test or source file name, no path).'
+ task :* do
+ message = "\nOops! '#{GCOV_ROOT_NAME}:*' isn't a real task. " \
+ "Use a real test or source file name (no path) in place of the wildcard.\n" \
+ "Example: rake #{GCOV_ROOT_NAME}:foo.c\n\n"
+
+ @ceedling[:streaminator].stdout_puts(message)
+ end
+
+ desc 'Run tests by matching regular expression pattern.'
+ task :pattern, [:regex] => [:directories] do |_t, args|
+ matches = []
+
+ COLLECTION_ALL_TESTS.each do |test|
+ matches << test if test =~ /#{args.regex}/
+ end
+
+ if !matches.empty?
+ @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config)
+ @ceedling[:test_invoker].setup_and_invoke(matches, GCOV_SYM, force_run: false)
+ @ceedling[:configurator].restore_config
+ else
+ @ceedling[:streaminator].stdout_puts("\nFound no tests matching pattern /#{args.regex}/.")
+ end
+ end
+
+ desc 'Run tests whose test path contains [dir] or [dir] substring.'
+ task :path, [:dir] => [:directories] do |_t, args|
+ matches = []
+
+ COLLECTION_ALL_TESTS.each do |test|
+ matches << test if File.dirname(test).include?(args.dir.tr('\\', '/'))
+ end
+
+ if !matches.empty?
+ @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config)
+ @ceedling[:test_invoker].setup_and_invoke(matches, GCOV_SYM, force_run: false)
+ @ceedling[:configurator].restore_config
+ else
+ @ceedling[:streaminator].stdout_puts("\nFound no tests including the given path or path component.")
+ end
+ end
+
+ desc 'Run code coverage for changed files'
+ task delta: [:directories] do
+ @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config)
+ @ceedling[:test_invoker].setup_and_invoke(COLLECTION_ALL_TESTS, GCOV_SYM, force_run: false)
+ @ceedling[:configurator].restore_config
+ end
+
+ # use a rule to increase efficiency for large projects
+ # gcov test tasks by regex
+ rule(/^#{GCOV_TASK_ROOT}\S+$/ => [
+ proc do |task_name|
+ test = task_name.sub(/#{GCOV_TASK_ROOT}/, '')
+ test = "#{PROJECT_TEST_FILE_PREFIX}#{test}" unless test.start_with?(PROJECT_TEST_FILE_PREFIX)
+ @ceedling[:file_finder].find_test_from_file_path(test)
+ end
+ ]) do |test|
+ @ceedling[:rake_wrapper][:directories].invoke
+ @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config)
+ @ceedling[:test_invoker].setup_and_invoke([test.source], GCOV_SYM)
+ @ceedling[:configurator].restore_config
+ end
+end
+
+if PROJECT_USE_DEEP_DEPENDENCIES
+ namespace REFRESH_SYM do
+ task GCOV_SYM do
+ @ceedling[:configurator].replace_flattened_config(@ceedling[GCOV_SYM].config)
+ @ceedling[:test_invoker].refresh_deep_dependencies
+ @ceedling[:configurator].restore_config
+ end
+ end
+end
+
+namespace UTILS_SYM do
+ def gcov_args_builder(opts)
+ args = ""
+ args += "-r \"#{opts[:gcov_report_root] || '.'}\" "
+ args += "-f \"#{opts[:gcov_report_include]}\" " unless opts[:gcov_report_include].nil?
+ args += "-e \"#{opts[:gcov_report_exclude] || GCOV_FILTER_EXCLUDE}\" "
+ [ :gcov_fail_under_line, :gcov_fail_under_branch, :gcov_html_medium_threshold, :gcov_html_high_threshold].each do |opt|
+ args += "--#{opt.to_s.gsub('_','-').sub(/:?gcov-/,'')} #{opts[opt]} " unless opts[opt].nil?
+ end
+ return args
+ end
+
+ desc 'Create gcov code coverage html report (must run ceedling gcov first)'
+ task GCOV_SYM do
+
+ if !File.directory? GCOV_ARTIFACTS_PATH
+ FileUtils.mkdir_p GCOV_ARTIFACTS_PATH
+ end
+
+ args = gcov_args_builder(@ceedling[:configurator].project_config_hash)
+
+ if @ceedling[:configurator].project_config_hash[:gcov_html_report].nil?
+ puts "In your project.yml, define: \n\n:gcov:\n :html_report:\n\n to true or false to refine this feature."
+ puts "For now, assumimg you want an html report generated."
+ html_enabled = true
+ else
+ html_enabled = @ceedling[:configurator].project_config_hash[:gcov_html_report]
+ end
+
+ if @ceedling[:configurator].project_config_hash[:gcov_xml_report].nil?
+ puts "In your project.yml, define: \n\n:gcov:\n :xml_report:\n\n to true or false to refine this feature."
+ puts "For now, assumimg you do not want an xml report generated."
+ xml_enabled = false
+ else
+ xml_enabled = @ceedling[:configurator].project_config_hash[:gcov_xml_report]
+ end
+
+ if html_enabled
+ if @ceedling[:configurator].project_config_hash[:gcov_html_report_type] == 'basic'
+ puts "Creating a basic html report of gcov results in #{GCOV_ARTIFACTS_FILE}..."
+ command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_POST_REPORT_BASIC, [], args)
+ @ceedling[:tool_executor].exec(command[:line], command[:options])
+ elsif @ceedling[:configurator].project_config_hash[:gcov_html_report_type] == 'detailed'
+ puts "Creating a detailed html report of gcov results in #{GCOV_ARTIFACTS_FILE}..."
+ command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_POST_REPORT_ADVANCED, [], args)
+ @ceedling[:tool_executor].exec(command[:line], command[:options])
+
+ else
+ puts "In your project.yml, define: \n\n:gcov:\n :html_report_type:\n\n to basic or detailed to refine this feature."
+ puts "For now, just creating basic."
+ puts "Creating a basic html report of gcov results in #{GCOV_ARTIFACTS_FILE}..."
+ command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_POST_REPORT_BASIC, [], args)
+ @ceedling[:tool_executor].exec(command[:line], command[:options])
+ end
+ end
+
+ if xml_enabled
+ puts "Creating an xml report of gcov results in #{GCOV_ARTIFACTS_FILE_XML}..."
+ command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_POST_REPORT_XML, [], filter)
+ @ceedling[:tool_executor].exec(command[:line], command[:options])
+ end
+
+ puts "Done."
+ end
+end
diff --git a/tinyusb/test/vendor/ceedling/plugins/gcov/lib/gcov.rb b/tinyusb/test/vendor/ceedling/plugins/gcov/lib/gcov.rb
new file mode 100755
index 00000000..15a1b4cf
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/gcov/lib/gcov.rb
@@ -0,0 +1,113 @@
+require 'ceedling/plugin'
+require 'ceedling/constants'
+require 'gcov_constants'
+
+class Gcov < Plugin
+ attr_reader :config
+
+ def setup
+ @result_list = []
+
+ @config = {
+ project_test_build_output_path: GCOV_BUILD_OUTPUT_PATH,
+ project_test_build_output_c_path: GCOV_BUILD_OUTPUT_PATH,
+ project_test_results_path: GCOV_RESULTS_PATH,
+ project_test_dependencies_path: GCOV_DEPENDENCIES_PATH,
+ defines_test: DEFINES_TEST + ['CODE_COVERAGE'],
+ gcov_html_report_filter: GCOV_FILTER_EXCLUDE
+ }
+
+ @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+ @coverage_template_all = @ceedling[:file_wrapper].read(File.join(@plugin_root, 'assets/template.erb'))
+ end
+
+ def generate_coverage_object_file(source, object)
+ lib_args = @ceedling[:test_invoker].convert_libraries_to_arguments()
+ compile_command =
+ @ceedling[:tool_executor].build_command_line(
+ TOOLS_GCOV_COMPILER,
+ @ceedling[:flaginator].flag_down(OPERATION_COMPILE_SYM, GCOV_SYM, source),
+ source,
+ object,
+ @ceedling[:file_path_utils].form_test_build_list_filepath(object),
+ lib_args
+ )
+ @ceedling[:streaminator].stdout_puts("Compiling #{File.basename(source)} with coverage...")
+ @ceedling[:tool_executor].exec(compile_command[:line], compile_command[:options])
+ end
+
+ def post_test_fixture_execute(arg_hash)
+ result_file = arg_hash[:result_file]
+
+ if (result_file =~ /#{GCOV_RESULTS_PATH}/) && !@result_list.include?(result_file)
+ @result_list << arg_hash[:result_file]
+ end
+ end
+
+ def post_build
+ return unless @ceedling[:task_invoker].invoked?(/^#{GCOV_TASK_ROOT}/)
+
+ # test results
+ results = @ceedling[:plugin_reportinator].assemble_test_results(@result_list)
+ hash = {
+ header: GCOV_ROOT_NAME.upcase,
+ results: results
+ }
+
+ @ceedling[:plugin_reportinator].run_test_results_report(hash) do
+ message = ''
+ message = 'Unit test failures.' if results[:counts][:failed] > 0
+ message
+ end
+
+ report_per_file_coverage_results(@ceedling[:test_invoker].sources)
+ end
+
+ def summary
+ result_list = @ceedling[:file_path_utils].form_pass_results_filelist(GCOV_RESULTS_PATH, COLLECTION_ALL_TESTS)
+
+ # test results
+ # get test results for only those tests in our configuration and of those only tests with results on disk
+ hash = {
+ header: GCOV_ROOT_NAME.upcase,
+ results: @ceedling[:plugin_reportinator].assemble_test_results(result_list, boom: false)
+ }
+
+ @ceedling[:plugin_reportinator].run_test_results_report(hash)
+ end
+
+ private ###################################
+
+ def report_per_file_coverage_results(sources)
+ banner = @ceedling[:plugin_reportinator].generate_banner "#{GCOV_ROOT_NAME.upcase}: CODE COVERAGE SUMMARY"
+ @ceedling[:streaminator].stdout_puts "\n" + banner
+
+ coverage_sources = sources.clone
+ coverage_sources.delete_if { |item| item =~ /#{CMOCK_MOCK_PREFIX}.+#{EXTENSION_SOURCE}$/ }
+ coverage_sources.delete_if { |item| item =~ /#{GCOV_IGNORE_SOURCES.join('|')}#{EXTENSION_SOURCE}$/ }
+
+ coverage_sources.each do |source|
+ basename = File.basename(source)
+ command = @ceedling[:tool_executor].build_command_line(TOOLS_GCOV_REPORT, [], [basename])
+ shell_results = @ceedling[:tool_executor].exec(command[:line], command[:options])
+ coverage_results = shell_results[:output]
+
+ if coverage_results.strip =~ /(File\s+'#{Regexp.escape(source)}'.+$)/m
+ report = Regexp.last_match(1).lines.to_a[1..-1].map { |line| basename + ' ' + line }.join('')
+ @ceedling[:streaminator].stdout_puts(report + "\n\n")
+ end
+ end
+
+ COLLECTION_ALL_SOURCE.each do |source|
+ unless coverage_sources.include?(source)
+ @ceedling[:streaminator].stdout_puts("Could not find coverage results for " + source + "\n")
+ end
+ end
+ end
+end
+
+# end blocks always executed following rake run
+END {
+ # cache our input configurations to use in comparison upon next execution
+ @ceedling[:cacheinator].cache_test_config(@ceedling[:setupinator].config_hash) if @ceedling[:task_invoker].invoked?(/^#{GCOV_TASK_ROOT}/)
+}
diff --git a/tinyusb/test/vendor/ceedling/plugins/gcov/lib/gcov_constants.rb b/tinyusb/test/vendor/ceedling/plugins/gcov/lib/gcov_constants.rb
new file mode 100755
index 00000000..539d46f7
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/gcov/lib/gcov_constants.rb
@@ -0,0 +1,19 @@
+
+GCOV_ROOT_NAME = 'gcov'.freeze
+GCOV_TASK_ROOT = GCOV_ROOT_NAME + ':'
+GCOV_SYM = GCOV_ROOT_NAME.to_sym
+
+GCOV_BUILD_PATH = File.join(PROJECT_BUILD_ROOT, GCOV_ROOT_NAME)
+GCOV_BUILD_OUTPUT_PATH = File.join(GCOV_BUILD_PATH, "out")
+GCOV_RESULTS_PATH = File.join(GCOV_BUILD_PATH, "results")
+GCOV_DEPENDENCIES_PATH = File.join(GCOV_BUILD_PATH, "dependencies")
+GCOV_ARTIFACTS_PATH = File.join(PROJECT_BUILD_ARTIFACTS_ROOT, GCOV_ROOT_NAME)
+
+GCOV_ARTIFACTS_FILE = File.join(GCOV_ARTIFACTS_PATH, "GcovCoverageResults.html")
+GCOV_ARTIFACTS_FILE_XML = File.join(GCOV_ARTIFACTS_PATH, "GcovCoverageResults.xml")
+
+GCOV_IGNORE_SOURCES = %w(unity cmock cexception).freeze
+
+GCOV_FILTER_EXCLUDE = '^vendor.*|^build.*|^test.*|^lib.*'
+
+
diff --git a/tinyusb/test/vendor/ceedling/plugins/junit_tests_report/README.md b/tinyusb/test/vendor/ceedling/plugins/junit_tests_report/README.md
new file mode 100755
index 00000000..1259fd66
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/junit_tests_report/README.md
@@ -0,0 +1,36 @@
+junit_tests_report
+====================
+
+## Overview
+
+The junit_tests_report plugin creates an XML file of test results in JUnit
+format, which is handy for Continuous Integration build servers or as input
+into other reporting tools. The XML file is output to the appropriate
+`<build_root>/artifacts/` directory (e.g. `artifacts/test/` for test tasks,
+`artifacts/gcov/` for gcov, or `artifacts/bullseye/` for bullseye runs).
+
+## Setup
+
+Enable the plugin in your project.yml by adding `junit_tests_report`
+to the list of enabled plugins.
+
+``` YAML
+:plugins:
+ :enabled:
+ - junit_tests_report
+```
+
+## Configuration
+
+Optionally configure the output / artifact filename in your project.yml with
+the `artifact_filename` configuration option. The default filename is
+`report.xml`.
+
+You can also configure the path that this artifact is stored. This can be done
+by setting `path`. The default is that it will be placed in a subfolder under
+the `build` directory.
+
+``` YAML
+:junit_tests_report:
+ :artifact_filename: report_junit.xml
+```
diff --git a/tinyusb/test/vendor/ceedling/plugins/junit_tests_report/lib/junit_tests_report.rb b/tinyusb/test/vendor/ceedling/plugins/junit_tests_report/lib/junit_tests_report.rb
new file mode 100755
index 00000000..a777d07d
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/junit_tests_report/lib/junit_tests_report.rb
@@ -0,0 +1,129 @@
+require 'ceedling/plugin'
+require 'ceedling/constants'
+
+class JunitTestsReport < Plugin
+
+ def setup
+ @results_list = {}
+ @test_counter = 0
+ @time_result = []
+ end
+
+ def post_test_fixture_execute(arg_hash)
+ context = arg_hash[:context]
+
+ @results_list[context] = [] if (@results_list[context].nil?)
+
+ @results_list[context] << arg_hash[:result_file]
+ @time_result << arg_hash[:shell_result][:time]
+
+ end
+
+ def post_build
+ @results_list.each_key do |context|
+ results = @ceedling[:plugin_reportinator].assemble_test_results(@results_list[context])
+
+ artifact_filename = @ceedling[:configurator].project_config_hash[:junit_tests_report_artifact_filename] || 'report.xml'
+ artifact_fullpath = @ceedling[:configurator].project_config_hash[:junit_tests_report_path] || File.join(PROJECT_BUILD_ARTIFACTS_ROOT, context.to_s)
+ file_path = File.join(artifact_fullpath, artifact_filename)
+
+ @ceedling[:file_wrapper].open( file_path, 'w' ) do |f|
+ @testsuite_counter = 0
+ @testcase_counter = 0
+ suites = reorganise_results( results )
+
+ write_header( results, f )
+ suites.each{|suite| write_suite( suite, f ) }
+ write_footer( f )
+ end
+ end
+ end
+
+ private
+
+ def write_header( results, stream )
+ results[:counts][:time] = @time_result.reduce(0, :+)
+ stream.puts '<?xml version="1.0" encoding="utf-8" ?>'
+ stream.puts('<testsuites tests="%<total>d" failures="%<failed>d" skipped="%<ignored>d" time="%<time>f">' % results[:counts])
+ end
+
+ def write_footer( stream )
+ stream.puts '</testsuites>'
+ end
+
+ def reorganise_results( results )
+ # Reorganise the output by test suite instead of by result
+ suites = Hash.new{ |h,k| h[k] = {collection: [], total: 0, success: 0, failed: 0, ignored: 0, stdout: []} }
+ results[:successes].each do |result|
+ source = result[:source]
+ name = source[:file].sub(/\..{1,4}$/, "")
+ suites[name][:collection] += result[:collection].map{|test| test.merge(result: :success)}
+ suites[name][:total] += result[:collection].length
+ suites[name][:success] += result[:collection].length
+ end
+ results[:failures].each do |result|
+ source = result[:source]
+ name = source[:file].sub(/\..{1,4}$/, "")
+ suites[name][:collection] += result[:collection].map{|test| test.merge(result: :failed)}
+ suites[name][:total] += result[:collection].length
+ suites[name][:failed] += result[:collection].length
+ end
+ results[:ignores].each do |result|
+ source = result[:source]
+ name = source[:file].sub(/\..{1,4}$/, "")
+ suites[name][:collection] += result[:collection].map{|test| test.merge(result: :ignored)}
+ suites[name][:total] += result[:collection].length
+ suites[name][:ignored] += result[:collection].length
+ end
+ results[:stdout].each do |result|
+ source = result[:source]
+ name = source[:file].sub(/\..{1,4}$/, "")
+ suites[name][:stdout] += result[:collection]
+ end
+ suites.map{|name, data| data.merge(name: name) }
+ end
+
+ def write_suite( suite, stream )
+ suite[:time] = @time_result.shift
+ stream.puts(' <testsuite name="%<name>s" tests="%<total>d" failures="%<failed>d" skipped="%<ignored>d" time="%<time>f">' % suite)
+
+ suite[:collection].each do |test|
+ write_test( test, stream )
+ end
+
+ unless suite[:stdout].empty?
+ stream.puts(' <system-out>')
+ suite[:stdout].each do |line|
+ line.gsub!(/&/, '&amp;')
+ line.gsub!(/</, '&lt;')
+ line.gsub!(/>/, '&gt;')
+ line.gsub!(/"/, '&quot;')
+ line.gsub!(/'/, '&apos;')
+ stream.puts(line)
+ end
+ stream.puts(' </system-out>')
+ end
+
+ stream.puts(' </testsuite>')
+ end
+
+ def write_test( test, stream )
+ test[:test].gsub!('"', '&quot;')
+ case test[:result]
+ when :success
+ stream.puts(' <testcase name="%<test>s" />' % test)
+ when :failed
+ stream.puts(' <testcase name="%<test>s">' % test)
+ if test[:message].empty?
+ stream.puts(' <failure />')
+ else
+ stream.puts(' <failure message="%s" />' % test[:message])
+ end
+ stream.puts(' </testcase>')
+ when :ignored
+ stream.puts(' <testcase name="%<test>s">' % test)
+ stream.puts(' <skipped />')
+ stream.puts(' </testcase>')
+ end
+ end
+end
diff --git a/tinyusb/test/vendor/ceedling/plugins/module_generator/config/module_generator.yml b/tinyusb/test/vendor/ceedling/plugins/module_generator/config/module_generator.yml
new file mode 100755
index 00000000..cdb2da2e
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/module_generator/config/module_generator.yml
@@ -0,0 +1,4 @@
+:module_generator:
+ :project_root: ./
+ :source_root: src/
+ :test_root: test/ \ No newline at end of file
diff --git a/tinyusb/test/vendor/ceedling/plugins/module_generator/lib/module_generator.rb b/tinyusb/test/vendor/ceedling/plugins/module_generator/lib/module_generator.rb
new file mode 100755
index 00000000..b2fac006
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/module_generator/lib/module_generator.rb
@@ -0,0 +1,70 @@
+require 'ceedling/plugin'
+require 'ceedling/constants'
+require 'erb'
+require 'fileutils'
+
+class ModuleGenerator < Plugin
+
+ attr_reader :config
+
+ def create(module_name, optz={})
+
+ require "generate_module.rb" #From Unity Scripts
+
+ if ((!optz.nil?) && (optz[:destroy]))
+ UnityModuleGenerator.new( divine_options(optz) ).destroy(module_name)
+ else
+ UnityModuleGenerator.new( divine_options(optz) ).generate(module_name)
+ end
+ end
+
+ private
+
+ def divine_options(optz={})
+ unity_generator_options =
+ {
+ :path_src => ((defined? MODULE_GENERATOR_SOURCE_ROOT ) ? MODULE_GENERATOR_SOURCE_ROOT.gsub('\\', '/').sub(/^\//, '').sub(/\/$/, '') : "src" ),
+ :path_inc => ((defined? MODULE_GENERATOR_INC_ROOT ) ?
+ MODULE_GENERATOR_INC_ROOT.gsub('\\', '/').sub(/^\//, '').sub(/\/$/, '')
+ : (defined? MODULE_GENERATOR_SOURCE_ROOT ) ?
+ MODULE_GENERATOR_SOURCE_ROOT.gsub('\\', '/').sub(/^\//, '').sub(/\/$/, '')
+ : "src" ),
+ :path_tst => ((defined? MODULE_GENERATOR_TEST_ROOT ) ? MODULE_GENERATOR_TEST_ROOT.gsub( '\\', '/').sub(/^\//, '').sub(/\/$/, '') : "test" ),
+ :pattern => optz[:pattern],
+ :test_prefix => ((defined? PROJECT_TEST_FILE_PREFIX ) ? PROJECT_TEST_FILE_PREFIX : "Test" ),
+ :mock_prefix => ((defined? CMOCK_MOCK_PREFIX ) ? CMOCK_MOCK_PREFIX : "Mock" ),
+ :includes => ((defined? MODULE_GENERATOR_INCLUDES ) ? MODULE_GENERATOR_INCLUDES : {} ),
+ :boilerplates => ((defined? MODULE_GENERATOR_BOILERPLATES) ? MODULE_GENERATOR_BOILERPLATES : {} ),
+ :naming => ((defined? MODULE_GENERATOR_NAMING ) ? MODULE_GENERATOR_NAMING : nil ),
+ :update_svn => ((defined? MODULE_GENERATOR_UPDATE_SVN ) ? MODULE_GENERATOR_UPDATE_SVN : false ),
+ }
+
+ # Read Boilerplate template file.
+ if (defined? MODULE_GENERATOR_BOILERPLATE_FILES)
+
+ bf = MODULE_GENERATOR_BOILERPLATE_FILES
+
+ if !bf[:src].nil? && File.exists?(bf[:src])
+ unity_generator_options[:boilerplates][:src] = File.read(bf[:src])
+ end
+
+ if !bf[:inc].nil? && File.exists?(bf[:inc])
+ unity_generator_options[:boilerplates][:inc] = File.read(bf[:inc])
+ end
+
+ if !bf[:tst].nil? && File.exists?(bf[:tst])
+ unity_generator_options[:boilerplates][:tst] = File.read(bf[:tst])
+ end
+ end
+
+ # If using "create[<module_root>:<module_name>]" option from command line.
+ unless optz[:module_root_path].to_s.empty?
+ unity_generator_options[:path_src] = File.join(optz[:module_root_path], unity_generator_options[:path_src])
+ unity_generator_options[:path_inc] = File.join(optz[:module_root_path], unity_generator_options[:path_inc])
+ unity_generator_options[:path_tst] = File.join(optz[:module_root_path], unity_generator_options[:path_tst])
+ end
+
+ return unity_generator_options
+ end
+
+end
diff --git a/tinyusb/test/vendor/ceedling/plugins/module_generator/module_generator.rake b/tinyusb/test/vendor/ceedling/plugins/module_generator/module_generator.rake
new file mode 100755
index 00000000..e88e346a
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/module_generator/module_generator.rake
@@ -0,0 +1,47 @@
+
+namespace :module do
+ module_root_separator = ":"
+
+ desc "Generate module (source, header and test files)"
+ task :create, :module_path do |t, args|
+ files = [args[:module_path]] + (args.extras || [])
+ optz = { :module_root_path => "" }
+ ["dh", "dih", "mch", "mvp", "src", "test"].each do |pat|
+ p = files.delete(pat)
+ optz[:pattern] = p unless p.nil?
+ end
+ files.each do |v|
+ module_root_path, module_name = v.split(module_root_separator, 2)
+ if module_name
+ optz[:module_root_path] = module_root_path
+ v = module_name
+ end
+ if (v =~ /^test_?/i)
+ # If the name of the file starts with test, automatically treat it as one
+ @ceedling[:module_generator].create(v.sub(/^test_?/i,''), optz.merge({:pattern => 'test'}))
+ else
+ # Otherwise, go through the normal procedure
+ @ceedling[:module_generator].create(v, optz)
+ end
+ end
+ end
+
+ desc "Destroy module (source, header and test files)"
+ task :destroy, :module_path do |t, args|
+ files = [args[:module_path]] + (args.extras || [])
+ optz = { :destroy => true, :module_root_path => "" }
+ ["dh", "dih", "mch", "mvp", "src", "test"].each do |pat|
+ p = files.delete(pat)
+ optz[:pattern] = p unless p.nil?
+ end
+ files.each do |v|
+ module_root_path, module_name = v.split(module_root_separator, 2)
+ if module_name
+ optz[:module_root_path] = module_root_path
+ v = module_name
+ end
+ @ceedling[:module_generator].create(v, optz)
+ end
+ end
+
+end
diff --git a/tinyusb/test/vendor/ceedling/plugins/raw_output_report/lib/raw_output_report.rb b/tinyusb/test/vendor/ceedling/plugins/raw_output_report/lib/raw_output_report.rb
new file mode 100755
index 00000000..014e6771
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/raw_output_report/lib/raw_output_report.rb
@@ -0,0 +1,41 @@
+require 'ceedling/plugin'
+require 'ceedling/constants'
+
+class RawOutputReport < Plugin
+ def setup
+ @log_paths = {}
+ end
+
+ def post_test_fixture_execute(arg_hash)
+ output = strip_output(arg_hash[:shell_result][:output])
+ write_raw_output_log(arg_hash, output)
+ end
+
+ private
+
+ def strip_output(raw_output)
+ output = ""
+ raw_output.each_line do |line|
+ next if line =~ /^\n$/
+ next if line =~ /^.*:\d+:.*:(IGNORE|PASS|FAIL)/
+ return output if line =~/^-----------------------\n$/
+ output << line
+ end
+ end
+ def write_raw_output_log(arg_hash, output)
+ logging = generate_log_path(arg_hash)
+ @ceedling[:file_wrapper].write(logging[:path], output , logging[:flags]) unless logging.nil?
+ end
+
+ def generate_log_path(arg_hash)
+ f_name = File.basename(arg_hash[:result_file], '.pass')
+ base_path = File.join(PROJECT_BUILD_ARTIFACTS_ROOT, arg_hash[:context].to_s)
+ file_path = File.join(base_path, f_name + '.log')
+
+ if @ceedling[:file_wrapper].exist?(base_path)
+ return { path: file_path, flags: 'w' }
+ end
+
+ nil
+ end
+end
diff --git a/tinyusb/test/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb b/tinyusb/test/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb
new file mode 100755
index 00000000..fb8e3b13
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb
@@ -0,0 +1,84 @@
+% ignored = hash[:results][:counts][:ignored]
+% failed = hash[:results][:counts][:failed]
+% stdout_count = hash[:results][:counts][:stdout]
+% header_prepend = ((hash[:header].length > 0) ? "#{hash[:header]}: " : '')
+% banner_width = 25 + header_prepend.length # widest message
+% results = {}
+% hash[:results][:successes].each do |testresult|
+% results[ testresult[:source][:file] ] = testresult[:collection]
+% results[ testresult[:source][:file] ].length.times do |i|
+% results[ testresult[:source][:file] ][i][:pass] = true
+% end
+% end
+% hash[:results][:ignores].each do |testresult|
+% if (results[ testresult[:source][:file] ].nil?)
+% results[ testresult[:source][:file] ] = testresult[:collection]
+% else
+% results[ testresult[:source][:file] ] += testresult[:collection]
+% end
+% results[ testresult[:source][:file] ].length.times do |i|
+% results[ testresult[:source][:file] ][i][:pass] = true
+% end
+% end
+% hash[:results][:failures].each do |testresult|
+% if (results[ testresult[:source][:file] ].nil?)
+% results[ testresult[:source][:file] ] = testresult[:collection]
+% else
+% results[ testresult[:source][:file] ] += testresult[:collection]
+% end
+% end
+
+
+[==========] Running <%=hash[:results][:counts][:total].to_s%> tests from <%=results.length.to_s%> test cases.
+[----------] Global test environment set-up.
+% results.each_pair do |modulename, moduledetails|
+[----------] <%=moduledetails.length.to_s%> tests from <%=modulename%>
+% moduledetails.each do |item|
+[ RUN ] <%=modulename%>.<%=item[:test]%>
+% if (not item[:pass])
+% if (not item[:message].empty?)
+<%=modulename%>(<%=item[:line]%>): error: <%=item[:message]%>
+
+% m = item[:message].match(/Expected\s+(.*)\s+Was\s+([^\.]*)\./)
+% if m.nil?
+ Actual: FALSE
+ Expected: TRUE
+% else
+ Actual: <%=m[2]%>
+ Expected: <%=m[1]%>
+% end
+% else
+<%=modulename%>(<%=item[:line]%>): fail: <%=item[:message]%>
+ Actual: FALSE
+ Expected: TRUE
+% end
+[ FAILED ] <%=modulename%>.<%=item[:test]%> (0 ms)
+% else
+[ OK ] <%=modulename%>.<%=item[:test]%> (0 ms)
+% end
+% end
+[----------] <%=moduledetails.length.to_s%> tests from <%=modulename%> (0 ms total)
+% end
+
+% if (hash[:results][:counts][:total] > 0)
+[----------] Global test environment tear-down.
+[==========] <%=hash[:results][:counts][:total].to_s%> tests from <%=hash[:results][:stdout].length.to_s%> test cases ran.
+[ PASSED ] <%=hash[:results][:counts][:passed].to_s%> tests.
+% if (failed == 0)
+[ FAILED ] 0 tests.
+
+ 0 FAILED TESTS
+% else
+[ FAILED ] <%=failed.to_s%> tests, listed below:
+% hash[:results][:failures].each do |failure|
+% failure[:collection].each do |item|
+[ FAILED ] <%=failure[:source][:file]%>.<%=item[:test]%>
+% end
+% end
+% end
+
+ <%=failed.to_s%> FAILED TESTS
+% else
+
+No tests executed.
+% end
diff --git a/tinyusb/test/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb copy b/tinyusb/test/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb copy
new file mode 100755
index 00000000..a90f495e
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/stdout_gtestlike_tests_report/assets/template.erb copy
@@ -0,0 +1,59 @@
+% ignored = hash[:results][:counts][:ignored]
+% failed = hash[:results][:counts][:failed]
+% stdout_count = hash[:results][:counts][:stdout]
+% header_prepend = ((hash[:header].length > 0) ? "#{hash[:header]}: " : '')
+% banner_width = 25 + header_prepend.length # widest message
+
+
+% if (stdout_count > 0)
+[==========] Running <%=hash[:results][:counts][:total].to_s%> tests from <%=hash[:results][:stdout].length.to_s%> test cases.
+[----------] Global test environment set-up.
+% end
+% if (failed > 0)
+% hash[:results][:failures].each do |failure|
+[----------] <%=failure[:collection].length.to_s%> tests from <%=failure[:source][:file]%>
+% failure[:collection].each do |item|
+[ RUN ] <%=failure[:source][:file]%>.<%=item[:test]%>
+% if (not item[:message].empty?)
+<%=failure[:source][:file]%>(<%=item[:line]%>): error: <%=item[:message]%>
+
+% m = item[:message].match(/Expected\s+(.*)\s+Was\s+([^\.]*)\./)
+% if m.nil?
+ Actual: FALSE
+ Expected: TRUE
+% else
+ Actual: <%=m[2]%>
+ Expected: <%=m[1]%>
+% end
+% else
+<%=failure[:source][:file]%>(<%=item[:line]%>): fail: <%=item[:message]%>
+ Actual: FALSE
+ Expected: TRUE
+% end
+[ FAILED ] <%=failure[:source][:file]%>.<%=item[:test]%> (0 ms)
+% end
+[----------] <%=failure[:collection].length.to_s%> tests from <%=failure[:source][:file]%> (0 ms total)
+% end
+% end
+% if (hash[:results][:counts][:total] > 0)
+[----------] Global test environment tear-down.
+[==========] <%=hash[:results][:counts][:total].to_s%> tests from <%=hash[:results][:stdout].length.to_s%> test cases ran.
+[ PASSED ] <%=hash[:results][:counts][:passed].to_s%> tests.
+% if (failed == 0)
+[ FAILED ] 0 tests.
+
+ 0 FAILED TESTS
+% else
+[ FAILED ] <%=failed.to_s%> tests, listed below:
+% hash[:results][:failures].each do |failure|
+% failure[:collection].each do |item|
+[ FAILED ] <%=failure[:source][:file]%>.<%=item[:test]%>
+% end
+% end
+
+ <%=failed.to_s%> FAILED TESTS
+% end
+% else
+
+No tests executed.
+% end
diff --git a/tinyusb/test/vendor/ceedling/plugins/stdout_gtestlike_tests_report/config/stdout_gtestlike_tests_report.yml b/tinyusb/test/vendor/ceedling/plugins/stdout_gtestlike_tests_report/config/stdout_gtestlike_tests_report.yml
new file mode 100755
index 00000000..c25acf51
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/stdout_gtestlike_tests_report/config/stdout_gtestlike_tests_report.yml
@@ -0,0 +1,4 @@
+---
+:plugins:
+ # tell Ceedling we got results display taken care of
+ :display_raw_test_results: FALSE
diff --git a/tinyusb/test/vendor/ceedling/plugins/stdout_gtestlike_tests_report/lib/stdout_gtestlike_tests_report.rb b/tinyusb/test/vendor/ceedling/plugins/stdout_gtestlike_tests_report/lib/stdout_gtestlike_tests_report.rb
new file mode 100755
index 00000000..a51438a3
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/stdout_gtestlike_tests_report/lib/stdout_gtestlike_tests_report.rb
@@ -0,0 +1,43 @@
+require 'ceedling/plugin'
+require 'ceedling/defaults'
+
+class StdoutGtestlikeTestsReport < Plugin
+
+ def setup
+ @result_list = []
+ @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+ template = @ceedling[:file_wrapper].read(File.join(@plugin_root, 'assets/template.erb'))
+ @ceedling[:plugin_reportinator].register_test_results_template( template )
+ end
+
+ def post_test_fixture_execute(arg_hash)
+ return if not (arg_hash[:context] == TEST_SYM)
+
+ @result_list << arg_hash[:result_file]
+ end
+
+ def post_build
+ return if not (@ceedling[:task_invoker].test_invoked?)
+
+ results = @ceedling[:plugin_reportinator].assemble_test_results(@result_list)
+ hash = {
+ :header => '',
+ :results => results
+ }
+
+ @ceedling[:plugin_reportinator].run_test_results_report(hash)
+ end
+
+ def summary
+ result_list = @ceedling[:file_path_utils].form_pass_results_filelist( PROJECT_TEST_RESULTS_PATH, COLLECTION_ALL_TESTS )
+
+ # get test results for only those tests in our configuration and of those only tests with results on disk
+ hash = {
+ :header => '',
+ :results => @ceedling[:plugin_reportinator].assemble_test_results(result_list, {:boom => false})
+ }
+
+ @ceedling[:plugin_reportinator].run_test_results_report(hash)
+ end
+
+end
diff --git a/tinyusb/test/vendor/ceedling/plugins/stdout_ide_tests_report/config/stdout_ide_tests_report.yml b/tinyusb/test/vendor/ceedling/plugins/stdout_ide_tests_report/config/stdout_ide_tests_report.yml
new file mode 100755
index 00000000..c25acf51
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/stdout_ide_tests_report/config/stdout_ide_tests_report.yml
@@ -0,0 +1,4 @@
+---
+:plugins:
+ # tell Ceedling we got results display taken care of
+ :display_raw_test_results: FALSE
diff --git a/tinyusb/test/vendor/ceedling/plugins/stdout_ide_tests_report/lib/stdout_ide_tests_report.rb b/tinyusb/test/vendor/ceedling/plugins/stdout_ide_tests_report/lib/stdout_ide_tests_report.rb
new file mode 100755
index 00000000..48b3e819
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/stdout_ide_tests_report/lib/stdout_ide_tests_report.rb
@@ -0,0 +1,44 @@
+require 'ceedling/plugin'
+require 'ceedling/defaults'
+
+class StdoutIdeTestsReport < Plugin
+
+ def setup
+ @result_list = []
+ end
+
+ def post_test_fixture_execute(arg_hash)
+ return if not (arg_hash[:context] == TEST_SYM)
+
+ @result_list << arg_hash[:result_file]
+ end
+
+ def post_build
+ return if (not @ceedling[:task_invoker].test_invoked?)
+
+ results = @ceedling[:plugin_reportinator].assemble_test_results(@result_list)
+ hash = {
+ :header => '',
+ :results => results
+ }
+
+ @ceedling[:plugin_reportinator].run_test_results_report(hash) do
+ message = ''
+ message = 'Unit test failures.' if (hash[:results][:counts][:failed] > 0)
+ message
+ end
+ end
+
+ def summary
+ result_list = @ceedling[:file_path_utils].form_pass_results_filelist( PROJECT_TEST_RESULTS_PATH, COLLECTION_ALL_TESTS )
+
+ # get test results for only those tests in our configuration and of those only tests with results on disk
+ hash = {
+ :header => '',
+ :results => @ceedling[:plugin_reportinator].assemble_test_results(result_list, {:boom => false})
+ }
+
+ @ceedling[:plugin_reportinator].run_test_results_report(hash)
+ end
+
+end
diff --git a/tinyusb/test/vendor/ceedling/plugins/stdout_pretty_tests_report/assets/template.erb b/tinyusb/test/vendor/ceedling/plugins/stdout_pretty_tests_report/assets/template.erb
new file mode 100755
index 00000000..52b29f7f
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/stdout_pretty_tests_report/assets/template.erb
@@ -0,0 +1,59 @@
+% ignored = hash[:results][:counts][:ignored]
+% failed = hash[:results][:counts][:failed]
+% stdout_count = hash[:results][:counts][:stdout]
+% header_prepend = ((hash[:header].length > 0) ? "#{hash[:header]}: " : '')
+% banner_width = 25 + header_prepend.length # widest message
+
+% if (stdout_count > 0)
+<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'TEST OUTPUT')%>
+% hash[:results][:stdout].each do |string|
+[<%=string[:source][:file]%>]
+% string[:collection].each do |item|
+ - "<%=item%>"
+% end
+
+% end
+% end
+% if (ignored > 0)
+<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'IGNORED TEST SUMMARY')%>
+% hash[:results][:ignores].each do |ignore|
+[<%=ignore[:source][:file]%>]
+% ignore[:collection].each do |item|
+ Test: <%=item[:test]%>
+% if (not item[:message].empty?)
+ At line (<%=item[:line]%>): "<%=item[:message]%>"
+% else
+ At line (<%=item[:line]%>)
+% end
+
+% end
+% end
+% end
+% if (failed > 0)
+<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'FAILED TEST SUMMARY')%>
+% hash[:results][:failures].each do |failure|
+[<%=failure[:source][:file]%>]
+% failure[:collection].each do |item|
+ Test: <%=item[:test]%>
+% if (not item[:message].empty?)
+ At line (<%=item[:line]%>): "<%=item[:message]%>"
+% else
+ At line (<%=item[:line]%>)
+% end
+
+% end
+% end
+% end
+% total_string = hash[:results][:counts][:total].to_s
+% format_string = "%#{total_string.length}i"
+<%=@ceedling[:plugin_reportinator].generate_banner(header_prepend + 'OVERALL TEST SUMMARY')%>
+% if (hash[:results][:counts][:total] > 0)
+TESTED: <%=hash[:results][:counts][:total].to_s%>
+PASSED: <%=sprintf(format_string, hash[:results][:counts][:passed])%>
+FAILED: <%=sprintf(format_string, failed)%>
+IGNORED: <%=sprintf(format_string, ignored)%>
+% else
+
+No tests executed.
+% end
+
diff --git a/tinyusb/test/vendor/ceedling/plugins/stdout_pretty_tests_report/config/stdout_pretty_tests_report.yml b/tinyusb/test/vendor/ceedling/plugins/stdout_pretty_tests_report/config/stdout_pretty_tests_report.yml
new file mode 100755
index 00000000..c25acf51
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/stdout_pretty_tests_report/config/stdout_pretty_tests_report.yml
@@ -0,0 +1,4 @@
+---
+:plugins:
+ # tell Ceedling we got results display taken care of
+ :display_raw_test_results: FALSE
diff --git a/tinyusb/test/vendor/ceedling/plugins/stdout_pretty_tests_report/lib/stdout_pretty_tests_report.rb b/tinyusb/test/vendor/ceedling/plugins/stdout_pretty_tests_report/lib/stdout_pretty_tests_report.rb
new file mode 100755
index 00000000..018388fc
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/stdout_pretty_tests_report/lib/stdout_pretty_tests_report.rb
@@ -0,0 +1,47 @@
+require 'ceedling/plugin'
+require 'ceedling/defaults'
+
+class StdoutPrettyTestsReport < Plugin
+
+ def setup
+ @result_list = []
+ @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+ template = @ceedling[:file_wrapper].read(File.join(@plugin_root, 'assets/template.erb'))
+ @ceedling[:plugin_reportinator].register_test_results_template( template )
+ end
+
+ def post_test_fixture_execute(arg_hash)
+ return if not (arg_hash[:context] == TEST_SYM)
+
+ @result_list << arg_hash[:result_file]
+ end
+
+ def post_build
+ return if not (@ceedling[:task_invoker].test_invoked?)
+
+ results = @ceedling[:plugin_reportinator].assemble_test_results(@result_list)
+ hash = {
+ :header => '',
+ :results => results
+ }
+
+ @ceedling[:plugin_reportinator].run_test_results_report(hash) do
+ message = ''
+ message = 'Unit test failures.' if (results[:counts][:failed] > 0)
+ message
+ end
+ end
+
+ def summary
+ result_list = @ceedling[:file_path_utils].form_pass_results_filelist( PROJECT_TEST_RESULTS_PATH, COLLECTION_ALL_TESTS )
+
+ # get test results for only those tests in our configuration and of those only tests with results on disk
+ hash = {
+ :header => '',
+ :results => @ceedling[:plugin_reportinator].assemble_test_results(result_list, {:boom => false})
+ }
+
+ @ceedling[:plugin_reportinator].run_test_results_report(hash)
+ end
+
+end
diff --git a/tinyusb/test/vendor/ceedling/plugins/subprojects/README.md b/tinyusb/test/vendor/ceedling/plugins/subprojects/README.md
new file mode 100755
index 00000000..e51a4e60
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/subprojects/README.md
@@ -0,0 +1,63 @@
+ceedling-subprojects
+====================
+
+Plugin for supporting subprojects that are built as static libraries. It continues to support
+dependency tracking, without getting confused between your main project files and your
+subproject files. It accepts different compiler flags and linker flags, allowing you to
+optimize for your situation.
+
+First, you're going to want to add the extension to your list of known extensions:
+
+```
+:extension:
+ :subprojects: '.a'
+```
+
+Define a new section called :subprojects. There, you can list as many subprojects
+as you may need under the :paths key. For each, you specify a unique place to build
+and a unique name.
+
+```
+:subprojects:
+ :paths:
+ - :name: libprojectA
+ :source:
+ - ./subprojectA/first/dir
+ - ./subprojectA/second/dir
+ :include:
+ - ./subprojectA/include/dir
+ :build_root: ./subprojectA/build/dir
+ :defines:
+ - DEFINE_JUST_FOR_THIS_FILE
+ - AND_ANOTHER
+ - :name: libprojectB
+ :source:
+ - ./subprojectB/only/dir
+ :include:
+ - ./subprojectB/first/include/dir
+ - ./subprojectB/second/include/dir
+ :build_root: ./subprojectB/build/dir
+ :defines: [] #none for this one
+```
+
+You can specify the compiler and linker, just as you would a release build:
+
+```
+:tools:
+ :subprojects_compiler:
+ :executable: gcc
+ :arguments:
+ - -g
+ - -I"$": COLLECTION_PATHS_SUBPROJECTS
+ - -D$: COLLECTION_DEFINES_SUBPROJECTS
+ - -c "${1}"
+ - -o "${2}"
+ :subprojects_linker:
+ :executable: ar
+ :arguments:
+ - rcs
+ - ${2}
+ - ${1}
+```
+
+That's all there is to it! Happy Hacking!
diff --git a/tinyusb/test/vendor/ceedling/plugins/subprojects/config/defaults.yml b/tinyusb/test/vendor/ceedling/plugins/subprojects/config/defaults.yml
new file mode 100755
index 00000000..1045a595
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/subprojects/config/defaults.yml
@@ -0,0 +1,33 @@
+---
+#:extension:
+# :subprojects: '.a'
+
+:subprojects:
+ :paths: []
+# - :name: subprojectA
+# :source:
+# - ./first/subproject/dir
+# - ./second/subproject/dir
+# :include:
+# - ./first/include/dir
+# :build_root: ./subproject/build/dir
+# :defines:
+# - FIRST_DEFINE
+
+:tools:
+ :subprojects_compiler:
+ :executable: gcc
+ :arguments:
+ - -g
+ - -I"$": COLLECTION_PATHS_SUBPROJECTS
+ - -D$: COLLECTION_DEFINES_SUBPROJECTS
+ - -c "${1}"
+ - -o "${2}"
+ :subprojects_linker:
+ :executable: ar
+ :arguments:
+ - rcs
+ - ${2}
+ - ${1}
+
+...
diff --git a/tinyusb/test/vendor/ceedling/plugins/subprojects/lib/subprojects.rb b/tinyusb/test/vendor/ceedling/plugins/subprojects/lib/subprojects.rb
new file mode 100755
index 00000000..1f5d4c2f
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/subprojects/lib/subprojects.rb
@@ -0,0 +1,92 @@
+require 'ceedling/plugin'
+require 'ceedling/constants'
+
+SUBPROJECTS_ROOT_NAME = 'subprojects'
+SUBPROJECTS_TASK_ROOT = SUBPROJECTS_ROOT_NAME + ':'
+SUBPROJECTS_SYM = SUBPROJECTS_ROOT_NAME.to_sym
+
+class Subprojects < Plugin
+
+ def setup
+ @plugin_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+
+ # Add to the test paths
+ SUBPROJECTS_PATHS.each do |subproj|
+ subproj[:source].each do |path|
+ COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR << path
+ end
+ subproj[:include].each do |path|
+ COLLECTION_PATHS_TEST_SUPPORT_SOURCE_INCLUDE_VENDOR << path
+ end
+ end
+
+ #gather information about the subprojects
+ @subprojects = {}
+ @subproject_lookup_by_path = {}
+ SUBPROJECTS_PATHS.each do |subproj|
+ @subprojects[ subproj[:name] ] = subproj.clone
+ @subprojects[ subproj[:name] ][:c] = []
+ @subprojects[ subproj[:name] ][:asm] = []
+ subproj[:source].each do |path|
+ search_path = "#{path[-1].match(/\\|\//) ? path : "#{path}/"}*#{EXTENSION_SOURCE}"
+ @subprojects[ subproj[:name] ][:c] += Dir[search_path]
+ if (EXTENSION_ASSEMBLY && !EXTENSION_ASSEMBLY.empty?)
+ search_path = "#{path[-1].match(/\\|\//) ? path : "#{path}/"}*#{EXTENSION_ASSEMBLY}"
+ @subprojects[ subproj[:name] ][:asm] += Dir[search_path]
+ end
+ end
+ @subproject_lookup_by_path[ subproj[:build_root] ] = subproj[:name]
+ end
+ end
+
+ def find_my_project( c_file, file_type = :c )
+ @subprojects.each_pair do |subprojname, subproj|
+ return subprojname if (subproj[file_type].include?(c_file))
+ end
+ end
+
+ def find_my_paths( c_file, file_type = :c )
+ @subprojects.each_pair do |subprojname, subproj|
+ return (subproj[:source] + (subproj[:include] || [])) if (subproj[file_type].include?(c_file))
+ end
+ return []
+ end
+
+ def find_my_defines( c_file, file_type = :c )
+ @subprojects.each_pair do |subprojname, subproj|
+ return (subproj[:defines] || []) if (subproj[file_type].include?(c_file))
+ end
+ return []
+ end
+
+ def list_all_object_files_for_subproject( lib_name )
+ subproj = File.basename(lib_name, EXTENSION_SUBPROJECTS)
+ objpath = "#{@subprojects[subproj][:build_root]}/out/c"
+ bbb = @subprojects[subproj][:c].map{|f| "#{objpath}/#{File.basename(f,EXTENSION_SOURCE)}#{EXTENSION_OBJECT}" }
+ bbb
+ end
+
+ def find_library_source_file_for_object( obj_name )
+ cname = "#{File.basename(obj_name, EXTENSION_OBJECT)}#{EXTENSION_SOURCE}"
+ dname = File.dirname(obj_name)[0..-7]
+ pname = @subproject_lookup_by_path[dname]
+ return @ceedling[:file_finder].find_file_from_list(cname, @subprojects[pname][:c], :error)
+ end
+
+ def find_library_assembly_file_for_object( obj_name )
+ cname = "#{File.basename(obj_name, EXTENSION_OBJECT)}#{EXTENSION_ASEMBLY}"
+ dname = File.dirname(obj_name)[0..-7]
+ pname = @subproject_lookup_by_path[dname]
+ return @ceedling[:file_finder].find_file_from_list(cname, @subprojects[pname][:asm], :error)
+ end
+
+ def replace_constant(constant, new_value)
+ Object.send(:remove_const, constant.to_sym) if (Object.const_defined? constant)
+ Object.const_set(constant, new_value)
+ end
+
+end
+
+# end blocks always executed following rake run
+END {
+}
diff --git a/tinyusb/test/vendor/ceedling/plugins/subprojects/subprojects.rake b/tinyusb/test/vendor/ceedling/plugins/subprojects/subprojects.rake
new file mode 100755
index 00000000..0025c3ec
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/subprojects/subprojects.rake
@@ -0,0 +1,78 @@
+
+
+SUBPROJECTS_PATHS.each do |subproj|
+
+ subproj_source = subproj[:source]
+ subproj_include = subproj[:include]
+ subproj_name = subproj[:name]
+ subproj_build_root = subproj[:build_root]
+ subproj_build_out = "#{subproj[:build_root]}/out"
+ subproj_build_c = "#{subproj[:build_root]}/out/c"
+ subproj_build_asm = "#{subproj[:build_root]}/out/asm"
+ subproj_directories = [ subproj_build_root, subproj_build_out, subproj_build_c, subproj_build_asm ]
+
+ subproj_directories.each do |subdir|
+ directory(subdir)
+ end
+
+ CLEAN.include(File.join(subproj_build_root, '*'))
+ CLEAN.include(File.join(subproj_build_out, '*'))
+
+ CLOBBER.include(File.join(subproj_build_root, '**/*'))
+
+ # Add a rule for building the actual static library from our object files
+ rule(/#{subproj_build_root}#{'.+\\'+EXTENSION_SUBPROJECTS}$/ => [
+ proc do |task_name|
+ @ceedling[SUBPROJECTS_SYM].list_all_object_files_for_subproject(task_name)
+ end
+ ]) do |bin_file|
+ @ceedling[:generator].generate_executable_file(
+ TOOLS_SUBPROJECTS_LINKER,
+ SUBPROJECTS_SYM,
+ bin_file.prerequisites,
+ bin_file.name,
+ @ceedling[:file_path_utils].form_test_build_map_filepath(bin_file.name))
+ end
+
+ # Add a rule for building object files from assembly files to link into a library
+ if (RELEASE_BUILD_USE_ASSEMBLY)
+ rule(/#{subproj_build_asm}#{'.+\\'+EXTENSION_OBJECT}$/ => [
+ proc do |task_name|
+ @ceedling[SUBPROJECTS_SYM].find_library_assembly_file_for_object(task_name)
+ end
+ ]) do |object|
+ @ceedling[SUBPROJECTS_SYM].replace_constant(:COLLECTION_PATHS_SUBPROJECTS, @ceedling[SUBPROJECTS_SYM].find_my_paths(object.source, :asm))
+ @ceedling[SUBPROJECTS_SYM].replace_constant(:COLLECTION_DEFINES_SUBPROJECTS, @ceedling[SUBPROJECTS_SYM].find_my_defines(object.source, :asm))
+ @ceedling[:generator].generate_object_file(
+ TOOLS_SUBPROJECTS_ASSEMBLER,
+ OPERATION_ASSEMBLE_SYM,
+ SUBPROJECTS_SYM,
+ object.source,
+ object.name )
+ end
+ end
+
+ # Add a rule for building object files from C files to link into a library
+ rule(/#{subproj_build_c}#{'.+\\'+EXTENSION_OBJECT}$/ => [
+ proc do |task_name|
+ @ceedling[SUBPROJECTS_SYM].find_library_source_file_for_object(task_name)
+ end
+ ]) do |object|
+ @ceedling[SUBPROJECTS_SYM].replace_constant(:COLLECTION_PATHS_SUBPROJECTS, @ceedling[SUBPROJECTS_SYM].find_my_paths(object.source, :c))
+ @ceedling[SUBPROJECTS_SYM].replace_constant(:COLLECTION_DEFINES_SUBPROJECTS, @ceedling[SUBPROJECTS_SYM].find_my_defines(object.source, :c))
+ @ceedling[:generator].generate_object_file(
+ TOOLS_SUBPROJECTS_COMPILER,
+ OPERATION_COMPILE_SYM,
+ SUBPROJECTS_SYM,
+ object.source,
+ object.name,
+ @ceedling[:file_path_utils].form_release_build_c_list_filepath( object.name ) )
+ end
+
+ # Add the subdirectories involved to our list of those that should be autogenerated
+ task :directories => subproj_directories.clone
+
+ # Finally, add the static library to our RELEASE build dependency list
+ task RELEASE_SYM => ["#{subproj_build_root}/#{subproj_name}#{EXTENSION_SUBPROJECTS}"]
+end
+
diff --git a/tinyusb/test/vendor/ceedling/plugins/teamcity_tests_report/config/teamcity_tests_report.yml b/tinyusb/test/vendor/ceedling/plugins/teamcity_tests_report/config/teamcity_tests_report.yml
new file mode 100755
index 00000000..c25acf51
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/teamcity_tests_report/config/teamcity_tests_report.yml
@@ -0,0 +1,4 @@
+---
+:plugins:
+ # tell Ceedling we got results display taken care of
+ :display_raw_test_results: FALSE
diff --git a/tinyusb/test/vendor/ceedling/plugins/teamcity_tests_report/lib/teamcity_tests_report.rb b/tinyusb/test/vendor/ceedling/plugins/teamcity_tests_report/lib/teamcity_tests_report.rb
new file mode 100755
index 00000000..33d8548f
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/teamcity_tests_report/lib/teamcity_tests_report.rb
@@ -0,0 +1,57 @@
+require 'ceedling/plugin'
+require 'ceedling/defaults'
+
+class TeamcityTestsReport < Plugin
+
+ def setup
+ @suite_started = nil
+ @output_enabled = !defined?(TEAMCITY_BUILD) || TEAMCITY_BUILD
+ end
+
+ def escape(string)
+ string.gsub(/['|\[\]]/, '|\0').gsub('\r', '|r').gsub('\n', '|n')
+ end
+
+ def pre_test(test)
+ teamcity_message "testSuiteStarted name='#{File.basename(test, '.c')}'"
+ @suite_started = Time.now
+ end
+
+ def post_test(test)
+ teamcity_message "testSuiteFinished name='#{File.basename(test, '.c')}'"
+ end
+
+ def post_test_fixture_execute(arg_hash)
+ duration = (Time.now - @suite_started) * 1000
+ results = @ceedling[:plugin_reportinator].assemble_test_results([arg_hash[:result_file]])
+ avg_duration = (duration / [1, results[:counts][:passed] + results[:counts][:failed]].max).round
+
+ results[:successes].each do |success|
+ success[:collection].each do |test|
+ teamcity_message "testStarted name='#{test[:test]}'"
+ teamcity_message "testFinished name='#{test[:test]}' duration='#{avg_duration}'"
+ end
+ end
+
+ results[:failures].each do |failure|
+ failure[:collection].each do |test|
+ teamcity_message "testStarted name='#{test[:test]}'"
+ teamcity_message "testFailed name='#{test[:test]}' message='#{escape(test[:message])}' details='File: #{failure[:source][:path]}/#{failure[:source][:file]} Line: #{test[:line]}'"
+ teamcity_message "testFinished name='#{test[:test]}' duration='#{avg_duration}'"
+ end
+ end
+
+ results[:ignores].each do |failure|
+ failure[:collection].each do |test|
+ teamcity_message "testIgnored name='#{test[:test]}' message='#{escape(test[:message])}'"
+ end
+ end
+
+ # We ignore stdout
+ end
+
+ def teamcity_message(content)
+ puts "##teamcity[#{content}]" unless !@output_enabled
+ end
+
+end
diff --git a/tinyusb/test/vendor/ceedling/plugins/warnings_report/lib/warnings_report.rb b/tinyusb/test/vendor/ceedling/plugins/warnings_report/lib/warnings_report.rb
new file mode 100755
index 00000000..d4f43fb5
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/warnings_report/lib/warnings_report.rb
@@ -0,0 +1,69 @@
+require 'ceedling/plugin'
+require 'ceedling/constants'
+
+class WarningsReport < Plugin
+ def setup
+ @stderr_redirect = nil
+ @log_paths = {}
+ end
+
+ def pre_compile_execute(arg_hash)
+ # at beginning of compile, override tool's stderr_redirect so we can parse $stderr + $stdout
+ set_stderr_redirect(arg_hash)
+ end
+
+ def post_compile_execute(arg_hash)
+ # after compilation, grab output for parsing/logging, restore stderr_redirect, log warning if it exists
+ output = arg_hash[:shell_result][:output]
+ restore_stderr_redirect(arg_hash)
+ write_warning_log(arg_hash[:context], output)
+ end
+
+ def pre_link_execute(arg_hash)
+ # at beginning of link, override tool's stderr_redirect so we can parse $stderr + $stdout
+ set_stderr_redirect(arg_hash)
+ end
+
+ def post_link_execute(arg_hash)
+ # after linking, grab output for parsing/logging, restore stderr_redirect, log warning if it exists
+ output = arg_hash[:shell_result][:output]
+ restore_stderr_redirect(arg_hash)
+ write_warning_log(arg_hash[:context], output)
+ end
+
+ private
+
+ def set_stderr_redirect(hash)
+ @stderr_redirect = hash[:tool][:stderr_redirect]
+ hash[:tool][:stderr_redirect] = StdErrRedirect::AUTO
+ end
+
+ def restore_stderr_redirect(hash)
+ hash[:tool][:stderr_redirect] = @stderr_redirect
+ end
+
+ def write_warning_log(context, output)
+ # if $stderr/$stdout contain "warning", log it
+ if output =~ /warning/i
+ # generate a log path & file io write flags
+ logging = generate_log_path(context)
+ @ceedling[:file_wrapper].write(logging[:path], output + "\n", logging[:flags]) unless logging.nil?
+ end
+ end
+
+ def generate_log_path(context)
+ # if path has already been generated, return it & 'append' file io flags (append to log)
+ return { path: @log_paths[context], flags: 'a' } unless @log_paths[context].nil?
+
+ # first time through, generate path & 'write' file io flags (create new log)
+ base_path = File.join(PROJECT_BUILD_ARTIFACTS_ROOT, context.to_s)
+ file_path = File.join(base_path, 'warnings.log')
+
+ if @ceedling[:file_wrapper].exist?(base_path)
+ @log_paths[context] = file_path
+ return { path: file_path, flags: 'w' }
+ end
+
+ nil
+ end
+end
diff --git a/tinyusb/test/vendor/ceedling/plugins/xml_tests_report/README.md b/tinyusb/test/vendor/ceedling/plugins/xml_tests_report/README.md
new file mode 100755
index 00000000..ce81eadf
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/xml_tests_report/README.md
@@ -0,0 +1,36 @@
+xml_tests_report
+====================
+
+## Overview
+
+The xml_tests_report plugin creates an XML file of test results in xUnit
+format, which is handy for Continuous Integration build servers or as input
+into other reporting tools. The XML file is output to the appropriate
+`<build_root>/artifacts/` directory (e.g. `artifacts/test/` for test tasks,
+`artifacts/gcov/` for gcov, or `artifacts/bullseye/` for bullseye runs).
+
+## Setup
+
+Enable the plugin in your project.yml by adding `xml_tests_report` to the list
+of enabled plugins.
+
+``` YAML
+:plugins:
+ :enabled:
+ - xml_tests_report
+```
+
+## Configuration
+
+Optionally configure the output / artifact filename in your project.yml with
+the `artifact_filename` configuration option. The default filename is
+`report.xml`.
+
+You can also configure the path that this artifact is stored. This can be done
+by setting `path`. The default is that it will be placed in a subfolder under
+the `build` directory.
+
+``` YAML
+:xml_tests_report:
+ :artifact_filename: report_xunit.xml
+```
diff --git a/tinyusb/test/vendor/ceedling/plugins/xml_tests_report/lib/xml_tests_report.rb b/tinyusb/test/vendor/ceedling/plugins/xml_tests_report/lib/xml_tests_report.rb
new file mode 100755
index 00000000..ed4e9960
--- /dev/null
+++ b/tinyusb/test/vendor/ceedling/plugins/xml_tests_report/lib/xml_tests_report.rb
@@ -0,0 +1,110 @@
+require 'ceedling/plugin'
+require 'ceedling/constants'
+
+class XmlTestsReport < Plugin
+ def setup
+ @results_list = {}
+ @test_counter = 0
+ end
+
+ def post_test_fixture_execute(arg_hash)
+ context = arg_hash[:context]
+
+ @results_list[context] = [] if @results_list[context].nil?
+
+ @results_list[context] << arg_hash[:result_file]
+ end
+
+ def post_build
+ @results_list.each_key do |context|
+ results = @ceedling[:plugin_reportinator].assemble_test_results(@results_list[context])
+
+ artifact_filename = @ceedling[:configurator].project_config_hash[:xml_tests_report_artifact_filename] || 'report.xml'
+ artifact_fullpath = @ceedling[:configurator].project_config_hash[:xml_tests_report_path] || File.join(PROJECT_BUILD_ARTIFACTS_ROOT, context.to_s)
+ file_path = File.join(artifact_fullpath, artifact_filename)
+
+ @ceedling[:file_wrapper].open(file_path, 'w') do |f|
+ @test_counter = 1
+ write_results(results, f)
+ end
+ end
+ end
+
+ private
+
+ def write_results(results, stream)
+ write_header(stream)
+ write_failures(results[:failures], stream)
+ write_tests(results[:successes], stream, 'SuccessfulTests')
+ write_tests(results[:ignores], stream, 'IgnoredTests')
+ write_statistics(results[:counts], stream)
+ write_footer(stream)
+ end
+
+ def write_header(stream)
+ stream.puts "<?xml version='1.0' encoding='utf-8' ?>"
+ stream.puts '<TestRun>'
+ end
+
+ def write_failures(results, stream)
+ if results.size.zero?
+ stream.puts "\t<FailedTests/>"
+ return
+ end
+
+ stream.puts "\t<FailedTests>"
+
+ results.each do |result|
+ result[:collection].each do |item|
+ filename = File.join(result[:source][:path], result[:source][:file])
+
+ stream.puts "\t\t<Test id=\"#{@test_counter}\">"
+ stream.puts "\t\t\t<Name>#{filename}::#{item[:test]}</Name>"
+ stream.puts "\t\t\t<FailureType>Assertion</FailureType>"
+ stream.puts "\t\t\t<Location>"
+ stream.puts "\t\t\t\t<File>#{filename}</File>"
+ stream.puts "\t\t\t\t<Line>#{item[:line]}</Line>"
+ stream.puts "\t\t\t</Location>"
+ stream.puts "\t\t\t<Message>#{item[:message]}</Message>"
+ stream.puts "\t\t</Test>"
+ @test_counter += 1
+ end
+ end
+
+ stream.puts "\t</FailedTests>"
+ end
+
+ def write_tests(results, stream, tag)
+ if results.size.zero?
+ stream.puts "\t<#{tag}/>"
+ return
+ end
+
+ stream.puts "\t<#{tag}>"
+
+ results.each do |result|
+ result[:collection].each do |item|
+ stream.puts "\t\t<Test id=\"#{@test_counter}\">"
+ stream.puts "\t\t\t<Name>#{File.join(result[:source][:path], result[:source][:file])}::#{item[:test]}</Name>"
+ stream.puts "\t\t</Test>"
+ @test_counter += 1
+ end
+ end
+
+ stream.puts "\t</#{tag}>"
+ end
+
+ def write_statistics(counts, stream)
+ stream.puts "\t<Statistics>"
+ stream.puts "\t\t<Tests>#{counts[:total]}</Tests>"
+ stream.puts "\t\t<Ignores>#{counts[:ignored]}</Ignores>"
+ stream.puts "\t\t<FailuresTotal>#{counts[:failed]}</FailuresTotal>"
+ stream.puts "\t\t<Errors>0</Errors>"
+ stream.puts "\t\t<Failures>#{counts[:failed]}</Failures>"
+ stream.puts "\t</Statistics>"
+ end
+
+ def write_footer(stream)
+ stream.puts '</TestRun>'
+ end
+end