This commit is contained in:
Dominocs 2025-07-01 00:15:37 +08:00
parent 0f33bd251c
commit 4e27abd78e
151 changed files with 16997 additions and 113734 deletions

View File

@ -1,3 +0,0 @@
软件可直接使用VSCODE编译并上传依赖于PlatformIO
硬件适配Esp32Cam也可直接将制版文件上传JLC, 使用摄像头为OV2640红外版本。
硬件开源连接:https://oshwhub.com/padawan/cympleface_v0-1

Binary file not shown.

Binary file not shown.

View File

@ -1,32 +0,0 @@
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
11e88001988e29c5da89674d2796e367a1ffa1e6

View File

@ -1 +0,0 @@
me-no-dev/AsyncTCP@^1.1.1

View File

@ -1,27 +0,0 @@
###############################################################################
# Unity Project - A Test Framework for C
# .editorconfig - F. Zahn 2019
###############################################################################
# This is the topmost .editorconfig file
root = true
# Settings that apply to all languages / files
[*]
charset = utf-8
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.txt]
trim_trailing_whitespace = false
[*.rb]
indent_size = 2
[*.yml]
indent_size = 2

View File

@ -1,31 +0,0 @@
* text=auto
# These files are text and should be normalized (convert crlf to lf)
*.rb text
*.test text
*.c text
*.cpp text
*.h text
*.txt text
*.yml text
*.s79 text
*.bat text
*.xcl text
*.inc text
*.info text
*.md text
makefile text
rakefile text
meson.build text
#These files are binary and should not be normalized
*.doc binary
*.odt binary
*.pdf binary
*.ewd binary
*.eww binary
*.dni binary
*.wsdt binary
*.dbgdt binary
*.mac binary

View File

@ -1,32 +0,0 @@
---
# Continuous Integration Workflow: Test case suite run + validation build check
name: CI
# Controls when the action will run.
# Triggers the workflow on push or pull request events but only for the master branch
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
# Job: Unit test suite
unit-tests:
name: "Unit Tests"
runs-on: ubuntu-latest
steps:
# Install Ruby Testing Tools
- name: Setup Ruby Testing Tools
run: |
sudo gem install rspec
sudo gem install rubocop -v 0.57.2
# Checks out repository under $GITHUB_WORKSPACE
- name: Checkout Latest Repo
uses: actions/checkout@v2
# Run Tests
- name: Run All Unit Tests
run: |
cd test && rake ci

View File

@ -1,13 +0,0 @@
build/
builddir/
test/sandbox
.DS_Store
examples/example_1/test1.exe
examples/example_1/test2.exe
examples/example_2/all_tests.exe
examples/example_1/test1.out
examples/example_1/test2.out
examples/example_2/all_tests.out
examples/example_4/builddir
*.sublime-project
*.sublime-workspace

View File

@ -1 +0,0 @@
{"type": "library", "name": "Unity", "version": "2.5.2", "spec": {"owner": "throwtheswitch", "id": 13894, "name": "Unity", "requirements": null, "uri": null}}

View File

@ -1,159 +0,0 @@
###################################################################################
# #
# NAME: CMakeLists.txt #
# #
# AUTHOR: Mike Karlesky, Mark VanderVoord, Greg Williams. #
# WRITTEN BY: Michael Brockus. #
# #
# License: MIT #
# #
###################################################################################
cmake_minimum_required(VERSION 3.12)
# Read src/unity.h file and get project version from it
set(UNITY_HEADER "src/unity.h")
file(STRINGS "${UNITY_HEADER}" UNITY_HEADER_CONTENT
REGEX "^#define UNITY_VERSION_(MAJOR|MINOR|BUILD) +[0-9]+$"
)
set(UNITY_HEADER_VERSION_MAJOR 0)
set(UNITY_HEADER_VERSION_MINOR 0)
set(UNITY_HEADER_VERSION_BUILD 0)
foreach(VERSION_LINE IN LISTS UNITY_HEADER_CONTENT)
foreach(VERSION_PART MAJOR MINOR BUILD)
string(CONCAT REGEX_STRING "#define UNITY_VERSION_"
"${VERSION_PART}"
" +([0-9]+)"
)
if(VERSION_LINE MATCHES "${REGEX_STRING}")
set(UNITY_HEADER_VERSION_${VERSION_PART} "${CMAKE_MATCH_1}")
endif()
endforeach()
endforeach()
project(unity
VERSION ${UNITY_HEADER_VERSION_MAJOR}.${UNITY_HEADER_VERSION_MINOR}.${UNITY_HEADER_VERSION_BUILD}
LANGUAGES C
DESCRIPTION "C Unit testing framework."
)
# Options to Build With Extras -------------------------------------------------
option(UNITY_EXTENSION_FIXTURE "Compiles Unity with the \"fixture\" extension." OFF)
option(UNITY_EXTENSION_MEMORY "Compiles Unity with the \"memory\" extension." OFF)
set(UNITY_EXTENSION_FIXTURE_ENABLED $<BOOL:${UNITY_EXTENSION_FIXTURE}>)
set(UNITY_EXTENSION_MEMORY_ENABLED $<OR:${UNITY_EXTENSION_FIXTURE_ENABLED},$<BOOL:${UNITY_EXTENSION_MEMORY}>>)
if(${UNITY_EXTENSION_FIXTURE})
message(STATUS "Unity: Bulding with the fixture extension.")
endif()
if(${UNITY_EXTENSION_MEMORY})
message(STATUS "Unity: Bulding with the memory extension.")
endif()
# Main target ------------------------------------------------------------------
add_library(${PROJECT_NAME} STATIC)
add_library(${PROJECT_NAME}::framework ALIAS ${PROJECT_NAME})
# Includes ---------------------------------------------------------------------
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
target_sources(${PROJECT_NAME}
PRIVATE
src/unity.c
$<$<BOOL:${UNITY_EXTENSION_FIXTURE_ENABLED}>:extras/fixture/src/unity_fixture.c>
$<$<BOOL:${UNITY_EXTENSION_MEMORY_ENABLED}>:extras/memory/src/unity_memory.c>
)
target_include_directories(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}>
$<BUILD_INTERFACE:$<$<BOOL:${UNITY_EXTENSION_MEMORY_ENABLED}>:${CMAKE_CURRENT_SOURCE_DIR}/extras/memory/src>>
$<BUILD_INTERFACE:$<$<BOOL:${UNITY_EXTENSION_FIXTURE_ENABLED}>:${CMAKE_CURRENT_SOURCE_DIR}/extras/fixture/src>>
)
set(${PROJECT_NAME}_PUBLIC_HEADERS
src/unity.h
src/unity_internals.h
$<$<BOOL:${UNITY_EXTENSION_FIXTURE_ENABLED}>:${CMAKE_CURRENT_SOURCE_DIR}/extras/fixture/src/unity_fixture.h>
$<$<BOOL:${UNITY_EXTENSION_FIXTURE_ENABLED}>:${CMAKE_CURRENT_SOURCE_DIR}/extras/fixture/src/unity_fixture_internals.h>
$<$<BOOL:${UNITY_EXTENSION_MEMORY_ENABLED}>:${CMAKE_CURRENT_SOURCE_DIR}/extras/memory/src/unity_memory.h>
)
set_target_properties(${PROJECT_NAME}
PROPERTIES
C_STANDARD 11
C_STANDARD_REQUIRED ON
C_EXTENSIONS OFF
PUBLIC_HEADER "${${PROJECT_NAME}_PUBLIC_HEADERS}"
EXPORT_NAME framework
)
target_compile_options(${PROJECT_NAME}
PRIVATE
$<$<C_COMPILER_ID:Clang>:-Wcast-align
-Wcast-qual
-Wconversion
-Wexit-time-destructors
-Wglobal-constructors
-Wmissing-noreturn
-Wmissing-prototypes
-Wno-missing-braces
-Wold-style-cast
-Wshadow
-Wweak-vtables
-Werror
-Wall>
$<$<C_COMPILER_ID:GNU>:-Waddress
-Waggregate-return
-Wformat-nonliteral
-Wformat-security
-Wformat
-Winit-self
-Wmissing-declarations
-Wmissing-include-dirs
-Wno-multichar
-Wno-parentheses
-Wno-type-limits
-Wno-unused-parameter
-Wunreachable-code
-Wwrite-strings
-Wpointer-arith
-Werror
-Wall>
$<$<C_COMPILER_ID:MSVC>:/Wall>
)
write_basic_package_version_file(${PROJECT_NAME}ConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
)
## Target installation
install(TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}Targets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}
COMPONENT library
)
## Target's cmake files: targets export
install(EXPORT ${PROJECT_NAME}Targets
NAMESPACE ${PROJECT_NAME}::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)
## Target's cmake files: config and version config for find_package()
install(FILES ${PROJECT_NAME}Config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)

View File

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) <year> 2007-21 Mike Karlesky, Mark VanderVoord, Greg Williams
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,200 +0,0 @@
Unity Test ![CI](https://github.com/ThrowTheSwitch/Unity/workflows/CI/badge.svg)
==========
__Copyright (c) 2007 - 2021 Unity Project by Mike Karlesky, Mark VanderVoord, and Greg Williams__
Welcome to the Unity Test Project, one of the main projects of ThrowTheSwitch.org. Unity Test is a
unit testing framework built for C, with a focus on working with embedded toolchains.
This project is made to test code targetting microcontrollers big and small. The core project is a
single C file and a pair of headers, allowing it to the added to your existing build setup without
too much headache. You may use any compiler you wish, and may use most existing build systems
including make, cmake, etc. If you'd like to leave the hard work to us, you might be interested
in Ceedling, a build tool also by ThrowTheSwitch.org.
If you're new to Unity, we encourage you to tour the [getting started guide](docs/UnityGettingStartedGuide.md)
Getting Started
===============
The [docs](docs/) folder contains a [getting started guide](docs/UnityGettingStartedGuide.md)
and much more tips about using Unity.
Unity Assertion Summary
=======================
For the full list, see [UnityAssertionsReference.md](docs/UnityAssertionsReference.md).
Basic Validity Tests
--------------------
TEST_ASSERT_TRUE(condition)
Evaluates whatever code is in condition and fails if it evaluates to false
TEST_ASSERT_FALSE(condition)
Evaluates whatever code is in condition and fails if it evaluates to true
TEST_ASSERT(condition)
Another way of calling `TEST_ASSERT_TRUE`
TEST_ASSERT_UNLESS(condition)
Another way of calling `TEST_ASSERT_FALSE`
TEST_FAIL()
TEST_FAIL_MESSAGE(message)
This test is automatically marked as a failure. The message is output stating why.
Numerical Assertions: Integers
------------------------------
TEST_ASSERT_EQUAL_INT(expected, actual)
TEST_ASSERT_EQUAL_INT8(expected, actual)
TEST_ASSERT_EQUAL_INT16(expected, actual)
TEST_ASSERT_EQUAL_INT32(expected, actual)
TEST_ASSERT_EQUAL_INT64(expected, actual)
Compare two integers for equality and display errors as signed integers. A cast will be performed
to your natural integer size so often this can just be used. When you need to specify the exact size,
like when comparing arrays, you can use a specific version:
TEST_ASSERT_EQUAL_UINT(expected, actual)
TEST_ASSERT_EQUAL_UINT8(expected, actual)
TEST_ASSERT_EQUAL_UINT16(expected, actual)
TEST_ASSERT_EQUAL_UINT32(expected, actual)
TEST_ASSERT_EQUAL_UINT64(expected, actual)
Compare two integers for equality and display errors as unsigned integers. Like INT, there are
variants for different sizes also.
TEST_ASSERT_EQUAL_HEX(expected, actual)
TEST_ASSERT_EQUAL_HEX8(expected, actual)
TEST_ASSERT_EQUAL_HEX16(expected, actual)
TEST_ASSERT_EQUAL_HEX32(expected, actual)
TEST_ASSERT_EQUAL_HEX64(expected, actual)
Compares two integers for equality and display errors as hexadecimal. Like the other integer comparisons,
you can specify the size... here the size will also effect how many nibbles are shown (for example, `HEX16`
will show 4 nibbles).
TEST_ASSERT_EQUAL(expected, actual)
Another way of calling TEST_ASSERT_EQUAL_INT
TEST_ASSERT_INT_WITHIN(delta, expected, actual)
Asserts that the actual value is within plus or minus delta of the expected value. This also comes in
size specific variants.
TEST_ASSERT_GREATER_THAN(threshold, actual)
Asserts that the actual value is greater than the threshold. This also comes in size specific variants.
TEST_ASSERT_LESS_THAN(threshold, actual)
Asserts that the actual value is less than the threshold. This also comes in size specific variants.
Arrays
------
_ARRAY
You can append `_ARRAY` to any of these macros to make an array comparison of that type. Here you will
need to care a bit more about the actual size of the value being checked. You will also specify an
additional argument which is the number of elements to compare. For example:
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, elements)
_EACH_EQUAL
Another array comparison option is to check that EVERY element of an array is equal to a single expected
value. You do this by specifying the EACH_EQUAL macro. For example:
TEST_ASSERT_EACH_EQUAL_INT32(expected, actual, elements)
Numerical Assertions: Bitwise
-----------------------------
TEST_ASSERT_BITS(mask, expected, actual)
Use an integer mask to specify which bits should be compared between two other integers. High bits in the mask are compared, low bits ignored.
TEST_ASSERT_BITS_HIGH(mask, actual)
Use an integer mask to specify which bits should be inspected to determine if they are all set high. High bits in the mask are compared, low bits ignored.
TEST_ASSERT_BITS_LOW(mask, actual)
Use an integer mask to specify which bits should be inspected to determine if they are all set low. High bits in the mask are compared, low bits ignored.
TEST_ASSERT_BIT_HIGH(bit, actual)
Test a single bit and verify that it is high. The bit is specified 0-31 for a 32-bit integer.
TEST_ASSERT_BIT_LOW(bit, actual)
Test a single bit and verify that it is low. The bit is specified 0-31 for a 32-bit integer.
Numerical Assertions: Floats
----------------------------
TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual)
Asserts that the actual value is within plus or minus delta of the expected value.
TEST_ASSERT_EQUAL_FLOAT(expected, actual)
TEST_ASSERT_EQUAL_DOUBLE(expected, actual)
Asserts that two floating point values are "equal" within a small % delta of the expected value.
String Assertions
-----------------
TEST_ASSERT_EQUAL_STRING(expected, actual)
Compare two null-terminate strings. Fail if any character is different or if the lengths are different.
TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len)
Compare two strings. Fail if any character is different, stop comparing after len characters.
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, actual, message)
Compare two null-terminate strings. Fail if any character is different or if the lengths are different. Output a custom message on failure.
TEST_ASSERT_EQUAL_STRING_LEN_MESSAGE(expected, actual, len, message)
Compare two strings. Fail if any character is different, stop comparing after len characters. Output a custom message on failure.
Pointer Assertions
------------------
Most pointer operations can be performed by simply using the integer comparisons above. However, a couple of special cases are added for clarity.
TEST_ASSERT_NULL(pointer)
Fails if the pointer is not equal to NULL
TEST_ASSERT_NOT_NULL(pointer)
Fails if the pointer is equal to NULL
Memory Assertions
-----------------
TEST_ASSERT_EQUAL_MEMORY(expected, actual, len)
Compare two blocks of memory. This is a good generic assertion for types that can't be coerced into acting like
standard types... but since it's a memory compare, you have to be careful that your data types are packed.
\_MESSAGE
---------
you can append \_MESSAGE to any of the macros to make them take an additional argument. This argument
is a string that will be printed at the end of the failure strings. This is useful for specifying more
information about the problem.

View File

@ -1,119 +0,0 @@
# ==========================================
# Unity Project - A Test Framework for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
if RUBY_PLATFORM =~ /(win|w)32$/
begin
require 'Win32API'
rescue LoadError
puts 'ERROR! "Win32API" library not found'
puts '"Win32API" is required for colour on a windows machine'
puts ' try => "gem install Win32API" on the command line'
puts
end
# puts
# puts 'Windows Environment Detected...'
# puts 'Win32API Library Found.'
# puts
end
class ColourCommandLine
def initialize
return unless RUBY_PLATFORM =~ /(win|w)32$/
get_std_handle = Win32API.new('kernel32', 'GetStdHandle', ['L'], 'L')
@set_console_txt_attrb =
Win32API.new('kernel32', 'SetConsoleTextAttribute', %w[L N], 'I')
@hout = get_std_handle.call(-11)
end
def change_to(new_colour)
if RUBY_PLATFORM =~ /(win|w)32$/
@set_console_txt_attrb.call(@hout, win32_colour(new_colour))
else
"\033[30;#{posix_colour(new_colour)};22m"
end
end
def win32_colour(colour)
case colour
when :black then 0
when :dark_blue then 1
when :dark_green then 2
when :dark_cyan then 3
when :dark_red then 4
when :dark_purple then 5
when :dark_yellow, :narrative then 6
when :default_white, :default, :dark_white then 7
when :silver then 8
when :blue then 9
when :green, :success then 10
when :cyan, :output then 11
when :red, :failure then 12
when :purple then 13
when :yellow then 14
when :white then 15
else
0
end
end
def posix_colour(colour)
# ANSI Escape Codes - Foreground colors
# | Code | Color |
# | 39 | Default foreground color |
# | 30 | Black |
# | 31 | Red |
# | 32 | Green |
# | 33 | Yellow |
# | 34 | Blue |
# | 35 | Magenta |
# | 36 | Cyan |
# | 37 | Light gray |
# | 90 | Dark gray |
# | 91 | Light red |
# | 92 | Light green |
# | 93 | Light yellow |
# | 94 | Light blue |
# | 95 | Light magenta |
# | 96 | Light cyan |
# | 97 | White |
case colour
when :black then 30
when :red, :failure then 31
when :green, :success then 32
when :yellow then 33
when :blue, :narrative then 34
when :purple, :magenta then 35
when :cyan, :output then 36
when :white, :default_white then 37
when :default then 39
else
39
end
end
def out_c(mode, colour, str)
case RUBY_PLATFORM
when /(win|w)32$/
change_to(colour)
$stdout.puts str if mode == :puts
$stdout.print str if mode == :print
change_to(:default_white)
else
$stdout.puts("#{change_to(colour)}#{str}\033[0m") if mode == :puts
$stdout.print("#{change_to(colour)}#{str}\033[0m") if mode == :print
end
end
end
def colour_puts(role, str)
ColourCommandLine.new.out_c(:puts, role, str)
end
def colour_print(role, str)
ColourCommandLine.new.out_c(:print, role, str)
end

View File

@ -1,39 +0,0 @@
# ==========================================
# Unity Project - A Test Framework for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
require_relative 'colour_prompt'
$colour_output = true
def report(message)
if !$colour_output
$stdout.puts(message)
else
message = message.join('\n') if message.class == Array
message.each_line do |line|
line.chomp!
colour = case line
when /(?:total\s+)?tests:?\s+(\d+)\s+(?:total\s+)?failures:?\s+\d+\s+Ignored:?/i
Regexp.last_match(1).to_i.zero? ? :green : :red
when /PASS/
:green
when /^OK$/
:green
when /(?:FAIL|ERROR)/
:red
when /IGNORE/
:yellow
when /^(?:Creating|Compiling|Linking)/
:white
else
:silver
end
colour_puts(colour, line)
end
end
$stdout.flush
$stderr.flush
end

View File

@ -1,36 +0,0 @@
#this is a sample configuration file for generate_module
#you would use it by calling generate_module with the -ygenerate_config.yml option
#files like this are useful for customizing generate_module to your environment
:generate_module:
:defaults:
#these defaults are used in place of any missing options at the command line
:path_src: ../src/
:path_inc: ../src/
:path_tst: ../test/
:update_svn: true
:includes:
#use [] for no additional includes, otherwise list the includes on separate lines
:src:
- Defs.h
- Board.h
:inc: []
:tst:
- Defs.h
- Board.h
- Exception.h
:boilerplates:
#these are inserted at the top of generated files.
#just comment out or remove if not desired.
#use %1$s where you would like the file name to appear (path/extension not included)
:src: |
//-------------------------------------------
// %1$s.c
//-------------------------------------------
:inc: |
//-------------------------------------------
// %1$s.h
//-------------------------------------------
:tst: |
//-------------------------------------------
// Test%1$s.c : Units tests for %1$s.c
//-------------------------------------------

View File

@ -1,313 +0,0 @@
# ==========================================
# Unity Project - A Test Framework for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
# This script creates all the files with start code necessary for a new module.
# A simple module only requires a source file, header file, and test file.
# Triad modules require a source, header, and test file for each triad type (like model, conductor, and hardware).
require 'rubygems'
require 'fileutils'
require 'pathname'
# TEMPLATE_TST
TEMPLATE_TST ||= '#ifdef TEST
#include "unity.h"
%2$s#include "%1$s.h"
void setUp(void)
{
}
void tearDown(void)
{
}
void test_%4$s_NeedToImplement(void)
{
TEST_IGNORE_MESSAGE("Need to Implement %1$s");
}
#endif // TEST
'.freeze
# TEMPLATE_SRC
TEMPLATE_SRC ||= '%2$s#include "%1$s.h"
'.freeze
# TEMPLATE_INC
TEMPLATE_INC ||= '#ifndef %3$s_H
#define %3$s_H
%2$s
#endif // %3$s_H
'.freeze
class UnityModuleGenerator
############################
def initialize(options = nil)
@options = UnityModuleGenerator.default_options
case options
when NilClass then @options
when String then @options.merge!(UnityModuleGenerator.grab_config(options))
when Hash then @options.merge!(options)
else raise 'If you specify arguments, it should be a filename or a hash of options'
end
# Create default file paths if none were provided
@options[:path_src] = "#{__dir__}/../src/" if @options[:path_src].nil?
@options[:path_inc] = @options[:path_src] if @options[:path_inc].nil?
@options[:path_tst] = "#{__dir__}/../test/" if @options[:path_tst].nil?
@options[:path_src] += '/' unless @options[:path_src][-1] == 47
@options[:path_inc] += '/' unless @options[:path_inc][-1] == 47
@options[:path_tst] += '/' unless @options[:path_tst][-1] == 47
# Built in patterns
@patterns = {
'src' => {
'' => { inc: [] }
},
'test' => {
'' => { inc: [] }
},
'dh' => {
'Driver' => { inc: [create_filename('%1$s', 'Hardware.h')] },
'Hardware' => { inc: [] }
},
'dih' => {
'Driver' => { inc: [create_filename('%1$s', 'Hardware.h'), create_filename('%1$s', 'Interrupt.h')] },
'Interrupt' => { inc: [create_filename('%1$s', 'Hardware.h')] },
'Hardware' => { inc: [] }
},
'mch' => {
'Model' => { inc: [] },
'Conductor' => { inc: [create_filename('%1$s', 'Model.h'), create_filename('%1$s', 'Hardware.h')] },
'Hardware' => { inc: [] }
},
'mvp' => {
'Model' => { inc: [] },
'Presenter' => { inc: [create_filename('%1$s', 'Model.h'), create_filename('%1$s', 'View.h')] },
'View' => { inc: [] }
}
}
end
############################
def self.default_options
{
pattern: 'src',
includes: {
src: [],
inc: [],
tst: []
},
update_svn: false,
boilerplates: {},
test_prefix: 'Test',
mock_prefix: 'Mock'
}
end
############################
def self.grab_config(config_file)
options = default_options
unless config_file.nil? || config_file.empty?
require 'yaml'
yaml_guts = YAML.load_file(config_file)
options.merge!(yaml_guts[:unity] || yaml_guts[:cmock])
raise "No :unity or :cmock section found in #{config_file}" unless options
end
options
end
############################
def files_to_operate_on(module_name, pattern = nil)
# strip any leading path information from the module name and save for later
subfolder = File.dirname(module_name)
module_name = File.basename(module_name)
# create triad definition
prefix = @options[:test_prefix] || 'Test'
triad = [{ ext: '.c', path: @options[:path_src], prefix: '', template: TEMPLATE_SRC, inc: :src, boilerplate: @options[:boilerplates][:src] },
{ ext: '.h', path: @options[:path_inc], prefix: '', template: TEMPLATE_INC, inc: :inc, boilerplate: @options[:boilerplates][:inc] },
{ ext: '.c', path: @options[:path_tst], prefix: prefix, template: TEMPLATE_TST, inc: :tst, boilerplate: @options[:boilerplates][:tst] }]
# prepare the pattern for use
pattern = (pattern || @options[:pattern] || 'src').downcase
patterns = @patterns[pattern]
raise "ERROR: The design pattern '#{pattern}' specified isn't one that I recognize!" if patterns.nil?
# single file patterns (currently just 'test') can reject the other parts of the triad
triad.select! { |v| v[:inc] == :tst } if pattern == 'test'
# Assemble the path/names of the files we need to work with.
files = []
triad.each do |cfg|
patterns.each_pair do |pattern_file, pattern_traits|
submodule_name = create_filename(module_name, pattern_file)
filename = cfg[:prefix] + submodule_name + cfg[:ext]
files << {
path: (Pathname.new("#{cfg[:path]}#{subfolder}") + filename).cleanpath,
name: submodule_name,
template: cfg[:template],
boilerplate: cfg[:boilerplate],
includes: case (cfg[:inc])
when :src then (@options[:includes][:src] || []) | (pattern_traits[:inc].map { |f| format(f, module_name) })
when :inc then (@options[:includes][:inc] || [])
when :tst then (@options[:includes][:tst] || []) | (pattern_traits[:inc].map { |f| format("#{@options[:mock_prefix]}#{f}", module_name) })
end
}
end
end
files
end
############################
def neutralize_filename(name, start_cap = true)
return name if name.empty?
name = name.split(/(?:\s+|_|(?=[A-Z][a-z]))|(?<=[a-z])(?=[A-Z])/).map { |v| v.capitalize }.join('_')
name = name[0].downcase + name[1..-1] unless start_cap
return name
end
############################
def create_filename(part1, part2 = '')
name = part2.empty? ? part1 : part1 + '_' + part2
case (@options[:naming])
when 'bumpy' then neutralize_filename(name,false).delete('_')
when 'camel' then neutralize_filename(name).delete('_')
when 'snake' then neutralize_filename(name).downcase
when 'caps' then neutralize_filename(name).upcase
else name
end
end
############################
def generate(module_name, pattern = nil)
files = files_to_operate_on(module_name, pattern)
# Abort if all of the module files already exist
all_files_exist = true
files.each do |file|
all_files_exist = false unless File.exist?(file[:path])
end
raise "ERROR: File #{files[0][:name]} already exists. Exiting." if all_files_exist
# Create Source Modules
files.each_with_index do |file, _i|
# If this file already exists, don't overwrite it.
if File.exist?(file[:path])
puts "File #{file[:path]} already exists!"
next
end
# Create the path first if necessary.
FileUtils.mkdir_p(File.dirname(file[:path]), verbose: false)
File.open(file[:path], 'w') do |f|
f.write("#{file[:boilerplate]}\n" % [file[:name]]) unless file[:boilerplate].nil?
f.write(file[:template] % [file[:name],
file[:includes].map { |ff| "#include \"#{ff}\"\n" }.join,
file[:name].upcase.gsub(/-/, '_'),
file[:name].gsub(/-/, '_')])
end
if @options[:update_svn]
`svn add \"#{file[:path]}\"`
if $!.exitstatus.zero?
puts "File #{file[:path]} created and added to source control"
else
puts "File #{file[:path]} created but FAILED adding to source control!"
end
else
puts "File #{file[:path]} created"
end
end
puts 'Generate Complete'
end
############################
def destroy(module_name, pattern = nil)
files_to_operate_on(module_name, pattern).each do |filespec|
file = filespec[:path]
if File.exist?(file)
if @options[:update_svn]
`svn delete \"#{file}\" --force`
puts "File #{file} deleted and removed from source control"
else
FileUtils.remove(file)
puts "File #{file} deleted"
end
else
puts "File #{file} does not exist so cannot be removed."
end
end
puts 'Destroy Complete'
end
end
############################
# Handle As Command Line If Called That Way
if $0 == __FILE__
destroy = false
options = {}
module_name = nil
# Parse the command line parameters.
ARGV.each do |arg|
case arg
when /^-d/ then destroy = true
when /^-u/ then options[:update_svn] = true
when /^-p\"?(\w+)\"?/ then options[:pattern] = Regexp.last_match(1)
when /^-s\"?(.+)\"?/ then options[:path_src] = Regexp.last_match(1)
when /^-i\"?(.+)\"?/ then options[:path_inc] = Regexp.last_match(1)
when /^-t\"?(.+)\"?/ then options[:path_tst] = Regexp.last_match(1)
when /^-n\"?(.+)\"?/ then options[:naming] = Regexp.last_match(1)
when /^-y\"?(.+)\"?/ then options = UnityModuleGenerator.grab_config(Regexp.last_match(1))
when /^(\w+)/
raise "ERROR: You can't have more than one Module name specified!" unless module_name.nil?
module_name = arg
when /^-(h|-help)/
ARGV = [].freeze
else
raise "ERROR: Unknown option specified '#{arg}'"
end
end
unless ARGV[0]
puts ["\nGENERATE MODULE\n-------- ------",
"\nUsage: ruby generate_module [options] module_name",
" -i\"include\" sets the path to output headers to 'include' (DEFAULT ../src)",
" -s\"../src\" sets the path to output source to '../src' (DEFAULT ../src)",
" -t\"C:/test\" sets the path to output source to 'C:/test' (DEFAULT ../test)",
' -p"MCH" sets the output pattern to MCH.',
' dh - driver hardware.',
' dih - driver interrupt hardware.',
' mch - model conductor hardware.',
' mvp - model view presenter.',
' src - just a source module, header and test. (DEFAULT)',
' test - just a test file.',
' -d destroy module instead of creating it.',
' -n"camel" sets the file naming convention.',
' bumpy - BumpyCaseFilenames.',
' camel - camelCaseFilenames.',
' snake - snake_case_filenames.',
' caps - CAPS_CASE_FILENAMES.',
' -u update subversion too (requires subversion command line)',
' -y"my.yml" selects a different yaml config file for module generation',
''].join("\n")
exit
end
raise 'ERROR: You must have a Module name specified! (use option -h for help)' if module_name.nil?
if destroy
UnityModuleGenerator.new(options).destroy(module_name)
else
UnityModuleGenerator.new(options).generate(module_name)
end
end

View File

@ -1,511 +0,0 @@
# ==========================================
# Unity Project - A Test Framework for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
class UnityTestRunnerGenerator
def initialize(options = nil)
@options = UnityTestRunnerGenerator.default_options
case options
when NilClass
@options
when String
@options.merge!(UnityTestRunnerGenerator.grab_config(options))
when Hash
# Check if some of these have been specified
@options[:has_setup] = !options[:setup_name].nil?
@options[:has_teardown] = !options[:teardown_name].nil?
@options[:has_suite_setup] = !options[:suite_setup].nil?
@options[:has_suite_teardown] = !options[:suite_teardown].nil?
@options.merge!(options)
else
raise 'If you specify arguments, it should be a filename or a hash of options'
end
require_relative 'type_sanitizer'
end
def self.default_options
{
includes: [],
defines: [],
plugins: [],
framework: :unity,
test_prefix: 'test|spec|should',
mock_prefix: 'Mock',
mock_suffix: '',
setup_name: 'setUp',
teardown_name: 'tearDown',
test_reset_name: 'resetTest',
test_verify_name: 'verifyTest',
main_name: 'main', # set to :auto to automatically generate each time
main_export_decl: '',
cmdline_args: false,
omit_begin_end: false,
use_param_tests: false,
include_extensions: '(?:hpp|hh|H|h)',
source_extensions: '(?:cpp|cc|ino|C|c)'
}
end
def self.grab_config(config_file)
options = default_options
unless config_file.nil? || config_file.empty?
require 'yaml'
yaml_guts = YAML.load_file(config_file)
options.merge!(yaml_guts[:unity] || yaml_guts[:cmock])
raise "No :unity or :cmock section found in #{config_file}" unless options
end
options
end
def run(input_file, output_file, options = nil)
@options.merge!(options) unless options.nil?
# pull required data from source file
source = File.read(input_file)
source = source.force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
tests = find_tests(source)
headers = find_includes(source)
testfile_includes = (headers[:local] + headers[:system])
used_mocks = find_mocks(testfile_includes)
testfile_includes = (testfile_includes - used_mocks)
testfile_includes.delete_if { |inc| inc =~ /(unity|cmock)/ }
find_setup_and_teardown(source)
# build runner file
generate(input_file, output_file, tests, used_mocks, testfile_includes)
# determine which files were used to return them
all_files_used = [input_file, output_file]
all_files_used += testfile_includes.map { |filename| filename + '.c' } unless testfile_includes.empty?
all_files_used += @options[:includes] unless @options[:includes].empty?
all_files_used += headers[:linkonly] unless headers[:linkonly].empty?
all_files_used.uniq
end
def generate(input_file, output_file, tests, used_mocks, testfile_includes)
File.open(output_file, 'w') do |output|
create_header(output, used_mocks, testfile_includes)
create_externs(output, tests, used_mocks)
create_mock_management(output, used_mocks)
create_setup(output)
create_teardown(output)
create_suite_setup(output)
create_suite_teardown(output)
create_reset(output)
create_run_test(output) unless tests.empty?
create_args_wrappers(output, tests)
create_main(output, input_file, tests, used_mocks)
end
return unless @options[:header_file] && !@options[:header_file].empty?
File.open(@options[:header_file], 'w') do |output|
create_h_file(output, @options[:header_file], tests, testfile_includes, used_mocks)
end
end
def find_tests(source)
tests_and_line_numbers = []
# contains characters which will be substituted from within strings, doing
# this prevents these characters from interfering with scrubbers
# @ is not a valid C character, so there should be no clashes with files genuinely containing these markers
substring_subs = { '{' => '@co@', '}' => '@cc@', ';' => '@ss@', '/' => '@fs@' }
substring_re = Regexp.union(substring_subs.keys)
substring_unsubs = substring_subs.invert # the inverse map will be used to fix the strings afterwords
substring_unsubs['@quote@'] = '\\"'
substring_unsubs['@apos@'] = '\\\''
substring_unre = Regexp.union(substring_unsubs.keys)
source_scrubbed = source.clone
source_scrubbed = source_scrubbed.gsub(/\\"/, '@quote@') # hide escaped quotes to allow capture of the full string/char
source_scrubbed = source_scrubbed.gsub(/\\'/, '@apos@') # hide escaped apostrophes to allow capture of the full string/char
source_scrubbed = source_scrubbed.gsub(/("[^"\n]*")|('[^'\n]*')/) { |s| s.gsub(substring_re, substring_subs) } # temporarily hide problematic characters within strings
source_scrubbed = source_scrubbed.gsub(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks
source_scrubbed = source_scrubbed.gsub(/\/\*.*?\*\//m, '') # remove block comments
source_scrubbed = source_scrubbed.gsub(/\/\/.*$/, '') # remove line comments (all that remain)
lines = source_scrubbed.split(/(^\s*\#.*$) | (;|\{|\}) /x) # Treat preprocessor directives as a logical line. Match ;, {, and } as end of lines
.map { |line| line.gsub(substring_unre, substring_unsubs) } # unhide the problematic characters previously removed
lines.each_with_index do |line, _index|
# find tests
next unless line =~ /^((?:\s*(?:TEST_CASE|TEST_RANGE)\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/m
arguments = Regexp.last_match(1)
name = Regexp.last_match(2)
call = Regexp.last_match(3)
params = Regexp.last_match(4)
args = nil
if @options[:use_param_tests] && !arguments.empty?
args = []
arguments.scan(/\s*TEST_CASE\s*\((.*)\)\s*$/) { |a| args << a[0] }
arguments.scan(/\s*TEST_RANGE\s*\((.*)\)\s*$/).flatten.each do |range_str|
args += range_str.scan(/\[(-?\d+.?\d*), *(-?\d+.?\d*), *(-?\d+.?\d*)\]/).map do |arg_values_str|
arg_values_str.map do |arg_value_str|
arg_value_str.include?('.') ? arg_value_str.to_f : arg_value_str.to_i
end
end.map do |arg_values|
(arg_values[0]..arg_values[1]).step(arg_values[2]).to_a
end.reduce do |result, arg_range_expanded|
result.product(arg_range_expanded)
end.map do |arg_combinations|
arg_combinations.flatten.join(', ')
end
end
end
tests_and_line_numbers << { test: name, args: args, call: call, params: params, line_number: 0 }
end
tests_and_line_numbers.uniq! { |v| v[:test] }
# determine line numbers and create tests to run
source_lines = source.split("\n")
source_index = 0
tests_and_line_numbers.size.times do |i|
source_lines[source_index..-1].each_with_index do |line, index|
next unless line =~ /\s+#{tests_and_line_numbers[i][:test]}(?:\s|\()/
source_index += index
tests_and_line_numbers[i][:line_number] = source_index + 1
break
end
end
tests_and_line_numbers
end
def find_includes(source)
# remove comments (block and line, in three steps to ensure correct precedence)
source.gsub!(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks
source.gsub!(/\/\*.*?\*\//m, '') # remove block comments
source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain)
# parse out includes
includes = {
local: source.scan(/^\s*#include\s+\"\s*(.+\.#{@options[:include_extensions]})\s*\"/).flatten,
system: source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten.map { |inc| "<#{inc}>" },
linkonly: source.scan(/^TEST_FILE\(\s*\"\s*(.+\.#{@options[:source_extensions]})\s*\"/).flatten
}
includes
end
def find_mocks(includes)
mock_headers = []
includes.each do |include_path|
include_file = File.basename(include_path)
mock_headers << include_path if include_file =~ /^#{@options[:mock_prefix]}.*#{@options[:mock_suffix]}\.h$/i
end
mock_headers
end
def find_setup_and_teardown(source)
@options[:has_setup] = source =~ /void\s+#{@options[:setup_name]}\s*\(/
@options[:has_teardown] = source =~ /void\s+#{@options[:teardown_name]}\s*\(/
@options[:has_suite_setup] ||= (source =~ /void\s+suiteSetUp\s*\(/)
@options[:has_suite_teardown] ||= (source =~ /int\s+suiteTearDown\s*\(int\s+([a-zA-Z0-9_])+\s*\)/)
end
def create_header(output, mocks, testfile_includes = [])
output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */')
output.puts("\n/*=======Automagically Detected Files To Include=====*/")
output.puts("#include \"#{@options[:framework]}.h\"")
output.puts('#include "cmock.h"') unless mocks.empty?
if @options[:defines] && !@options[:defines].empty?
@options[:defines].each { |d| output.puts("#ifndef #{d}\n#define #{d}\n#endif /* #{d} */") }
end
if @options[:header_file] && !@options[:header_file].empty?
output.puts("#include \"#{File.basename(@options[:header_file])}\"")
else
@options[:includes].flatten.uniq.compact.each do |inc|
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}")
end
testfile_includes.each do |inc|
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}")
end
end
mocks.each do |mock|
output.puts("#include \"#{mock}\"")
end
output.puts('#include "CException.h"') if @options[:plugins].include?(:cexception)
return unless @options[:enforce_strict_ordering]
output.puts('')
output.puts('int GlobalExpectCount;')
output.puts('int GlobalVerifyOrder;')
output.puts('char* GlobalOrderError;')
end
def create_externs(output, tests, _mocks)
output.puts("\n/*=======External Functions This Runner Calls=====*/")
output.puts("extern void #{@options[:setup_name]}(void);")
output.puts("extern void #{@options[:teardown_name]}(void);")
output.puts("\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif") if @options[:externc]
tests.each do |test|
output.puts("extern void #{test[:test]}(#{test[:call] || 'void'});")
end
output.puts("#ifdef __cplusplus\n}\n#endif") if @options[:externc]
output.puts('')
end
def create_mock_management(output, mock_headers)
output.puts("\n/*=======Mock Management=====*/")
output.puts('static void CMock_Init(void)')
output.puts('{')
if @options[:enforce_strict_ordering]
output.puts(' GlobalExpectCount = 0;')
output.puts(' GlobalVerifyOrder = 0;')
output.puts(' GlobalOrderError = NULL;')
end
mocks = mock_headers.map { |mock| File.basename(mock, '.*') }
mocks.each do |mock|
mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
output.puts(" #{mock_clean}_Init();")
end
output.puts("}\n")
output.puts('static void CMock_Verify(void)')
output.puts('{')
mocks.each do |mock|
mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
output.puts(" #{mock_clean}_Verify();")
end
output.puts("}\n")
output.puts('static void CMock_Destroy(void)')
output.puts('{')
mocks.each do |mock|
mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
output.puts(" #{mock_clean}_Destroy();")
end
output.puts("}\n")
end
def create_setup(output)
return if @options[:has_setup]
output.puts("\n/*=======Setup (stub)=====*/")
output.puts("void #{@options[:setup_name]}(void) {}")
end
def create_teardown(output)
return if @options[:has_teardown]
output.puts("\n/*=======Teardown (stub)=====*/")
output.puts("void #{@options[:teardown_name]}(void) {}")
end
def create_suite_setup(output)
return if @options[:suite_setup].nil?
output.puts("\n/*=======Suite Setup=====*/")
output.puts('void suiteSetUp(void)')
output.puts('{')
output.puts(@options[:suite_setup])
output.puts('}')
end
def create_suite_teardown(output)
return if @options[:suite_teardown].nil?
output.puts("\n/*=======Suite Teardown=====*/")
output.puts('int suiteTearDown(int num_failures)')
output.puts('{')
output.puts(@options[:suite_teardown])
output.puts('}')
end
def create_reset(output)
output.puts("\n/*=======Test Reset Options=====*/")
output.puts("void #{@options[:test_reset_name]}(void);")
output.puts("void #{@options[:test_reset_name]}(void)")
output.puts('{')
output.puts(" #{@options[:teardown_name]}();")
output.puts(' CMock_Verify();')
output.puts(' CMock_Destroy();')
output.puts(' CMock_Init();')
output.puts(" #{@options[:setup_name]}();")
output.puts('}')
output.puts("void #{@options[:test_verify_name]}(void);")
output.puts("void #{@options[:test_verify_name]}(void)")
output.puts('{')
output.puts(' CMock_Verify();')
output.puts('}')
end
def create_run_test(output)
require 'erb'
template = ERB.new(File.read(File.join(__dir__, 'run_test.erb')), nil, '<>')
output.puts("\n" + template.result(binding))
end
def create_args_wrappers(output, tests)
return unless @options[:use_param_tests]
output.puts("\n/*=======Parameterized Test Wrappers=====*/")
tests.each do |test|
next if test[:args].nil? || test[:args].empty?
test[:args].each.with_index(1) do |args, idx|
output.puts("static void runner_args#{idx}_#{test[:test]}(void)")
output.puts('{')
output.puts(" #{test[:test]}(#{args});")
output.puts("}\n")
end
end
end
def create_main(output, filename, tests, used_mocks)
output.puts("\n/*=======MAIN=====*/")
main_name = @options[:main_name].to_sym == :auto ? "main_#{filename.gsub('.c', '')}" : (@options[:main_name]).to_s
if @options[:cmdline_args]
if main_name != 'main'
output.puts("#{@options[:main_export_decl]} int #{main_name}(int argc, char** argv);")
end
output.puts("#{@options[:main_export_decl]} int #{main_name}(int argc, char** argv)")
output.puts('{')
output.puts(' int parse_status = UnityParseOptions(argc, argv);')
output.puts(' if (parse_status != 0)')
output.puts(' {')
output.puts(' if (parse_status < 0)')
output.puts(' {')
output.puts(" UnityPrint(\"#{filename.gsub('.c', '')}.\");")
output.puts(' UNITY_PRINT_EOL();')
tests.each do |test|
if (!@options[:use_param_tests]) || test[:args].nil? || test[:args].empty?
output.puts(" UnityPrint(\" #{test[:test]}\");")
output.puts(' UNITY_PRINT_EOL();')
else
test[:args].each do |args|
output.puts(" UnityPrint(\" #{test[:test]}(#{args})\");")
output.puts(' UNITY_PRINT_EOL();')
end
end
end
output.puts(' return 0;')
output.puts(' }')
output.puts(' return parse_status;')
output.puts(' }')
else
main_return = @options[:omit_begin_end] ? 'void' : 'int'
if main_name != 'main'
output.puts("#{@options[:main_export_decl]} #{main_return} #{main_name}(void);")
end
output.puts("#{main_return} #{main_name}(void)")
output.puts('{')
end
output.puts(' suiteSetUp();') if @options[:has_suite_setup]
if @options[:omit_begin_end]
output.puts(" UnitySetTestFile(\"#{filename.gsub(/\\/, '\\\\\\')}\");")
else
output.puts(" UnityBegin(\"#{filename.gsub(/\\/, '\\\\\\')}\");")
end
tests.each do |test|
if (!@options[:use_param_tests]) || test[:args].nil? || test[:args].empty?
output.puts(" run_test(#{test[:test]}, \"#{test[:test]}\", #{test[:line_number]});")
else
test[:args].each.with_index(1) do |args, idx|
wrapper = "runner_args#{idx}_#{test[:test]}"
testname = "#{test[:test]}(#{args})".dump
output.puts(" run_test(#{wrapper}, #{testname}, #{test[:line_number]});")
end
end
end
output.puts
output.puts(' CMock_Guts_MemFreeFinal();') unless used_mocks.empty?
if @options[:has_suite_teardown]
if @options[:omit_begin_end]
output.puts(' (void) suite_teardown(0);')
else
output.puts(' return suiteTearDown(UnityEnd());')
end
else
output.puts(' return UnityEnd();') unless @options[:omit_begin_end]
end
output.puts('}')
end
def create_h_file(output, filename, tests, testfile_includes, used_mocks)
filename = File.basename(filename).gsub(/[-\/\\\.\,\s]/, '_').upcase
output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */')
output.puts("#ifndef _#{filename}")
output.puts("#define _#{filename}\n\n")
output.puts("#include \"#{@options[:framework]}.h\"")
output.puts('#include "cmock.h"') unless used_mocks.empty?
@options[:includes].flatten.uniq.compact.each do |inc|
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}")
end
testfile_includes.each do |inc|
output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}")
end
output.puts "\n"
tests.each do |test|
if test[:params].nil? || test[:params].empty?
output.puts("void #{test[:test]}(void);")
else
output.puts("void #{test[:test]}(#{test[:params]});")
end
end
output.puts("#endif\n\n")
end
end
if $0 == __FILE__
options = { includes: [] }
# parse out all the options first (these will all be removed as we go)
ARGV.reject! do |arg|
case arg
when '-cexception'
options[:plugins] = [:cexception]
true
when /\.*\.ya?ml$/
options = UnityTestRunnerGenerator.grab_config(arg)
true
when /--(\w+)=\"?(.*)\"?/
options[Regexp.last_match(1).to_sym] = Regexp.last_match(2)
true
when /\.*\.(?:hpp|hh|H|h)$/
options[:includes] << arg
true
else false
end
end
# make sure there is at least one parameter left (the input file)
unless ARGV[0]
puts ["\nusage: ruby #{__FILE__} (files) (options) input_test_file (output)",
"\n input_test_file - this is the C file you want to create a runner for",
' output - this is the name of the runner file to generate',
' defaults to (input_test_file)_Runner',
' files:',
' *.yml / *.yaml - loads configuration from here in :unity or :cmock',
' *.h - header files are added as #includes in runner',
' options:',
' -cexception - include cexception support',
' -externc - add extern "C" for cpp support',
' --setup_name="" - redefine setUp func name to something else',
' --teardown_name="" - redefine tearDown func name to something else',
' --main_name="" - redefine main func name to something else',
' --test_prefix="" - redefine test prefix from default test|spec|should',
' --test_reset_name="" - redefine resetTest func name to something else',
' --test_verify_name="" - redefine verifyTest func name to something else',
' --suite_setup="" - code to execute for setup of entire suite',
' --suite_teardown="" - code to execute for teardown of entire suite',
' --use_param_tests=1 - enable parameterized tests (disabled by default)',
' --omit_begin_end=1 - omit calls to UnityBegin and UnityEnd (disabled by default)',
' --header_file="" - path/name of test header file to generate too'].join("\n")
exit 1
end
# create the default test runner name if not specified
ARGV[1] = ARGV[0].gsub('.c', '_Runner.c') unless ARGV[1]
UnityTestRunnerGenerator.new(options).run(ARGV[0], ARGV[1])
end

View File

@ -1,322 +0,0 @@
#============================================================
# Author: John Theofanopoulos
# A simple parser. Takes the output files generated during the
# build process and extracts information relating to the tests.
#
# Notes:
# To capture an output file under VS builds use the following:
# devenv [build instructions] > Output.txt & type Output.txt
#
# To capture an output file under Linux builds use the following:
# make | tee Output.txt
#
# This script can handle the following output formats:
# - normal output (raw unity)
# - fixture output (unity_fixture.h/.c)
# - fixture output with verbose flag set ("-v")
#
# To use this parser use the following command
# ruby parseOutput.rb [options] [file]
# options: -xml : produce a JUnit compatible XML file
# file: file to scan for results
#============================================================
# Parser class for handling the input file
class ParseOutput
def initialize
# internal data
@class_name_idx = 0
@path_delim = nil
# xml output related
@xml_out = false
@array_list = false
# current suite name and statistics
@test_suite = nil
@total_tests = 0
@test_passed = 0
@test_failed = 0
@test_ignored = 0
end
# Set the flag to indicate if there will be an XML output file or not
def set_xml_output
@xml_out = true
end
# If write our output to XML
def write_xml_output
output = File.open('report.xml', 'w')
output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
@array_list.each do |item|
output << item << "\n"
end
end
# Pushes the suite info as xml to the array list, which will be written later
def push_xml_output_suite_info
# Insert opening tag at front
heading = '<testsuite name="Unity" tests="' + @total_tests.to_s + '" failures="' + @test_failed.to_s + '"' + ' skips="' + @test_ignored.to_s + '">'
@array_list.insert(0, heading)
# Push back the closing tag
@array_list.push '</testsuite>'
end
# Pushes xml output data to the array list, which will be written later
def push_xml_output_passed(test_name)
@array_list.push ' <testcase classname="' + @test_suite + '" name="' + test_name + '"/>'
end
# Pushes xml output data to the array list, which will be written later
def push_xml_output_failed(test_name, reason)
@array_list.push ' <testcase classname="' + @test_suite + '" name="' + test_name + '">'
@array_list.push ' <failure type="ASSERT FAILED">' + reason + '</failure>'
@array_list.push ' </testcase>'
end
# Pushes xml output data to the array list, which will be written later
def push_xml_output_ignored(test_name, reason)
@array_list.push ' <testcase classname="' + @test_suite + '" name="' + test_name + '">'
@array_list.push ' <skipped type="TEST IGNORED">' + reason + '</skipped>'
@array_list.push ' </testcase>'
end
# This function will try and determine when the suite is changed. This is
# is the name that gets added to the classname parameter.
def test_suite_verify(test_suite_name)
# Split the path name
test_name = test_suite_name.split(@path_delim)
# Remove the extension and extract the base_name
base_name = test_name[test_name.size - 1].split('.')[0]
# Return if the test suite hasn't changed
return unless base_name.to_s != @test_suite.to_s
@test_suite = base_name
printf "New Test: %s\n", @test_suite
end
# Prepares the line for verbose fixture output ("-v")
def prepare_fixture_line(line)
line = line.sub('IGNORE_TEST(', '')
line = line.sub('TEST(', '')
line = line.sub(')', ',')
line = line.chomp
array = line.split(',')
array.map { |x| x.to_s.lstrip.chomp }
end
# Test was flagged as having passed so format the output.
# This is using the Unity fixture output and not the original Unity output.
def test_passed_unity_fixture(array)
class_name = array[0]
test_name = array[1]
test_suite_verify(class_name)
printf "%-40s PASS\n", test_name
push_xml_output_passed(test_name) if @xml_out
end
# Test was flagged as having failed so format the output.
# This is using the Unity fixture output and not the original Unity output.
def test_failed_unity_fixture(array)
class_name = array[0]
test_name = array[1]
test_suite_verify(class_name)
reason_array = array[2].split(':')
reason = reason_array[-1].lstrip.chomp + ' at line: ' + reason_array[-4]
printf "%-40s FAILED\n", test_name
push_xml_output_failed(test_name, reason) if @xml_out
end
# Test was flagged as being ignored so format the output.
# This is using the Unity fixture output and not the original Unity output.
def test_ignored_unity_fixture(array)
class_name = array[0]
test_name = array[1]
reason = 'No reason given'
if array.size > 2
reason_array = array[2].split(':')
tmp_reason = reason_array[-1].lstrip.chomp
reason = tmp_reason == 'IGNORE' ? 'No reason given' : tmp_reason
end
test_suite_verify(class_name)
printf "%-40s IGNORED\n", test_name
push_xml_output_ignored(test_name, reason) if @xml_out
end
# Test was flagged as having passed so format the output
def test_passed(array)
last_item = array.length - 1
test_name = array[last_item - 1]
test_suite_verify(array[@class_name_idx])
printf "%-40s PASS\n", test_name
return unless @xml_out
push_xml_output_passed(test_name) if @xml_out
end
# Test was flagged as having failed so format the line
def test_failed(array)
last_item = array.length - 1
test_name = array[last_item - 2]
reason = array[last_item].chomp.lstrip + ' at line: ' + array[last_item - 3]
class_name = array[@class_name_idx]
if test_name.start_with? 'TEST('
array2 = test_name.split(' ')
test_suite = array2[0].sub('TEST(', '')
test_suite = test_suite.sub(',', '')
class_name = test_suite
test_name = array2[1].sub(')', '')
end
test_suite_verify(class_name)
printf "%-40s FAILED\n", test_name
push_xml_output_failed(test_name, reason) if @xml_out
end
# Test was flagged as being ignored so format the output
def test_ignored(array)
last_item = array.length - 1
test_name = array[last_item - 2]
reason = array[last_item].chomp.lstrip
class_name = array[@class_name_idx]
if test_name.start_with? 'TEST('
array2 = test_name.split(' ')
test_suite = array2[0].sub('TEST(', '')
test_suite = test_suite.sub(',', '')
class_name = test_suite
test_name = array2[1].sub(')', '')
end
test_suite_verify(class_name)
printf "%-40s IGNORED\n", test_name
push_xml_output_ignored(test_name, reason) if @xml_out
end
# Adjusts the os specific members according to the current path style
# (Windows or Unix based)
def detect_os_specifics(line)
if line.include? '\\'
# Windows X:\Y\Z
@class_name_idx = 1
@path_delim = '\\'
else
# Unix Based /X/Y/Z
@class_name_idx = 0
@path_delim = '/'
end
end
# Main function used to parse the file that was captured.
def process(file_name)
@array_list = []
puts 'Parsing file: ' + file_name
@test_passed = 0
@test_failed = 0
@test_ignored = 0
puts ''
puts '=================== RESULTS ====================='
puts ''
File.open(file_name).each do |line|
# Typical test lines look like these:
# ----------------------------------------------------
# 1. normal output:
# <path>/<test_file>.c:36:test_tc1000_opsys:FAIL: Expected 1 Was 0
# <path>/<test_file>.c:112:test_tc5004_initCanChannel:IGNORE: Not Yet Implemented
# <path>/<test_file>.c:115:test_tc5100_initCanVoidPtrs:PASS
#
# 2. fixture output
# <path>/<test_file>.c:63:TEST(<test_group>, <test_function>):FAIL: Expected 0x00001234 Was 0x00005A5A
# <path>/<test_file>.c:36:TEST(<test_group>, <test_function>):IGNORE
# Note: "PASS" information won't be generated in this mode
#
# 3. fixture output with verbose information ("-v")
# TEST(<test_group, <test_file>)<path>/<test_file>:168::FAIL: Expected 0x8D Was 0x8C
# TEST(<test_group>, <test_file>)<path>/<test_file>:22::IGNORE: This Test Was Ignored On Purpose
# IGNORE_TEST(<test_group, <test_file>)
# TEST(<test_group, <test_file>) PASS
#
# Note: Where path is different on Unix vs Windows devices (Windows leads with a drive letter)!
detect_os_specifics(line)
line_array = line.split(':')
# If we were able to split the line then we can look to see if any of our target words
# were found. Case is important.
next unless (line_array.size >= 4) || (line.start_with? 'TEST(') || (line.start_with? 'IGNORE_TEST(')
# check if the output is fixture output (with verbose flag "-v")
if (line.start_with? 'TEST(') || (line.start_with? 'IGNORE_TEST(')
line_array = prepare_fixture_line(line)
if line.include? ' PASS'
test_passed_unity_fixture(line_array)
@test_passed += 1
elsif line.include? 'FAIL'
test_failed_unity_fixture(line_array)
@test_failed += 1
elsif line.include? 'IGNORE'
test_ignored_unity_fixture(line_array)
@test_ignored += 1
end
# normal output / fixture output (without verbose "-v")
elsif line.include? ':PASS'
test_passed(line_array)
@test_passed += 1
elsif line.include? ':FAIL'
test_failed(line_array)
@test_failed += 1
elsif line.include? ':IGNORE:'
test_ignored(line_array)
@test_ignored += 1
elsif line.include? ':IGNORE'
line_array.push('No reason given')
test_ignored(line_array)
@test_ignored += 1
end
@total_tests = @test_passed + @test_failed + @test_ignored
end
puts ''
puts '=================== SUMMARY ====================='
puts ''
puts 'Tests Passed : ' + @test_passed.to_s
puts 'Tests Failed : ' + @test_failed.to_s
puts 'Tests Ignored : ' + @test_ignored.to_s
return unless @xml_out
# push information about the suite
push_xml_output_suite_info
# write xml output file
write_xml_output
end
end
# If the command line has no values in, used a default value of Output.txt
parse_my_file = ParseOutput.new
if ARGV.size >= 1
ARGV.each do |arg|
if arg == '-xml'
parse_my_file.set_xml_output
else
parse_my_file.process(arg)
break
end
end
end

View File

@ -1,37 +0,0 @@
/*=======Test Runner Used To Run Each Test=====*/
static void run_test(UnityTestFunction func, const char* name, UNITY_LINE_TYPE line_num)
{
Unity.CurrentTestName = name;
Unity.CurrentTestLineNumber = line_num;
#ifdef UNITY_USE_COMMAND_LINE_ARGS
if (!UnityTestMatches())
return;
#endif
Unity.NumberOfTests++;
UNITY_CLR_DETAILS();
UNITY_EXEC_TIME_START();
CMock_Init();
if (TEST_PROTECT())
{
<% if @options[:plugins].include?(:cexception) %>
CEXCEPTION_T e;
Try {
<%= @options[:setup_name] %>();
func();
} Catch(e) {
TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!");
}
<% else %>
<%= @options[:setup_name] %>();
func();
<% end %>
}
if (TEST_PROTECT())
{
<%= @options[:teardown_name] %>();
CMock_Verify();
}
CMock_Destroy();
UNITY_EXEC_TIME_STOP();
UnityConcludeTest();
}

View File

@ -1,251 +0,0 @@
#!/usr/bin/ruby
#
# unity_to_junit.rb
#
require 'fileutils'
require 'optparse'
require 'ostruct'
require 'set'
require 'pp'
VERSION = 1.0
class ArgvParser
#
# Return a structure describing the options.
#
def self.parse(args)
# The options specified on the command line will be collected in *options*.
# We set default values here.
options = OpenStruct.new
options.results_dir = '.'
options.root_path = '.'
options.out_file = 'results.xml'
opts = OptionParser.new do |o|
o.banner = 'Usage: unity_to_junit.rb [options]'
o.separator ''
o.separator 'Specific options:'
o.on('-r', '--results <dir>', 'Look for Unity Results files here.') do |results|
# puts "results #{results}"
options.results_dir = results
end
o.on('-p', '--root_path <path>', 'Prepend this path to files in results.') do |root_path|
options.root_path = root_path
end
o.on('-o', '--output <filename>', 'XML file to generate.') do |out_file|
# puts "out_file: #{out_file}"
options.out_file = out_file
end
o.separator ''
o.separator 'Common options:'
# No argument, shows at tail. This will print an options summary.
o.on_tail('-h', '--help', 'Show this message') do
puts o
exit
end
# Another typical switch to print the version.
o.on_tail('--version', 'Show version') do
puts "unity_to_junit.rb version #{VERSION}"
exit
end
end
opts.parse!(args)
options
end
end
class UnityToJUnit
include FileUtils::Verbose
attr_reader :report, :total_tests, :failures, :ignored
attr_writer :targets, :root, :out_file
def initialize
@report = ''
@unit_name = ''
end
def run
# Clean up result file names
results = @targets.map { |target| target.tr('\\', '/') }
# puts "Output File: #{@out_file}"
f = File.new(@out_file, 'w')
write_xml_header(f)
write_suites_header(f)
results.each do |result_file|
lines = File.readlines(result_file).map(&:chomp)
raise "Empty test result file: #{result_file}" if lines.empty?
result_output = get_details(result_file, lines)
tests, failures, ignored = parse_test_summary(lines)
result_output[:counts][:total] = tests
result_output[:counts][:failed] = failures
result_output[:counts][:ignored] = ignored
result_output[:counts][:passed] = (result_output[:counts][:total] - result_output[:counts][:failed] - result_output[:counts][:ignored])
# use line[0] from the test output to get the test_file path and name
test_file_str = lines[0].tr('\\', '/')
test_file_str = test_file_str.split(':')
test_file = if test_file_str.length < 2
result_file
else
test_file_str[0] + ':' + test_file_str[1]
end
result_output[:source][:path] = File.dirname(test_file)
result_output[:source][:file] = File.basename(test_file)
# save result_output
@unit_name = File.basename(test_file, '.*')
write_suite_header(result_output[:counts], f)
write_failures(result_output, f)
write_tests(result_output, f)
write_ignored(result_output, f)
write_suite_footer(f)
end
write_suites_footer(f)
f.close
end
def usage(err_msg = nil)
puts "\nERROR: "
puts err_msg if err_msg
puts 'Usage: unity_to_junit.rb [options]'
puts ''
puts 'Specific options:'
puts ' -r, --results <dir> Look for Unity Results files here.'
puts ' -p, --root_path <path> Prepend this path to files in results.'
puts ' -o, --output <filename> XML file to generate.'
puts ''
puts 'Common options:'
puts ' -h, --help Show this message'
puts ' --version Show version'
exit 1
end
protected
def get_details(_result_file, lines)
results = results_structure
lines.each do |line|
line = line.tr('\\', '/')
_src_file, src_line, test_name, status, msg = line.split(/:/)
case status
when 'IGNORE' then results[:ignores] << { test: test_name, line: src_line, message: msg }
when 'FAIL' then results[:failures] << { test: test_name, line: src_line, message: msg }
when 'PASS' then results[:successes] << { test: test_name, line: src_line, message: msg }
end
end
results
end
def parse_test_summary(summary)
raise "Couldn't parse test results: #{summary}" unless summary.find { |v| v =~ /(\d+) Tests (\d+) Failures (\d+) Ignored/ }
[Regexp.last_match(1).to_i, Regexp.last_match(2).to_i, Regexp.last_match(3).to_i]
end
private
def results_structure
{
source: { path: '', file: '' },
successes: [],
failures: [],
ignores: [],
counts: { total: 0, passed: 0, failed: 0, ignored: 0 },
stdout: []
}
end
def write_xml_header(stream)
stream.puts "<?xml version='1.0' encoding='utf-8' ?>"
end
def write_suites_header(stream)
stream.puts '<testsuites>'
end
def write_suite_header(counts, stream)
stream.puts "\t<testsuite errors=\"0\" skipped=\"#{counts[:ignored]}\" failures=\"#{counts[:failed]}\" tests=\"#{counts[:total]}\" name=\"unity\">"
end
def write_failures(results, stream)
result = results[:failures]
result.each do |item|
filename = File.join(results[:source][:path], File.basename(results[:source][:file], '.*'))
stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\">"
stream.puts "\t\t\t<failure message=\"#{item[:message]}\" type=\"Assertion\"/>"
stream.puts "\t\t\t<system-err>&#xD;[File] #{filename}&#xD;[Line] #{item[:line]}&#xD;</system-err>"
stream.puts "\t\t</testcase>"
end
end
def write_tests(results, stream)
result = results[:successes]
result.each do |item|
stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\" />"
end
end
def write_ignored(results, stream)
result = results[:ignores]
result.each do |item|
filename = File.join(results[:source][:path], File.basename(results[:source][:file], '.*'))
puts "Writing ignored tests for test harness: #{filename}"
stream.puts "\t\t<testcase classname=\"#{@unit_name}\" name=\"#{item[:test]}\" time=\"0\">"
stream.puts "\t\t\t<skipped message=\"#{item[:message]}\" type=\"Assertion\"/>"
stream.puts "\t\t\t<system-err>&#xD;[File] #{filename}&#xD;[Line] #{item[:line]}&#xD;</system-err>"
stream.puts "\t\t</testcase>"
end
end
def write_suite_footer(stream)
stream.puts "\t</testsuite>"
end
def write_suites_footer(stream)
stream.puts '</testsuites>'
end
end
if $0 == __FILE__
# parse out the command options
options = ArgvParser.parse(ARGV)
# create an instance to work with
utj = UnityToJUnit.new
begin
# look in the specified or current directory for result files
targets = "#{options.results_dir.tr('\\', '/')}**/*.test*"
results = Dir[targets]
raise "No *.testpass, *.testfail, or *.testresults files found in '#{targets}'" if results.empty?
utj.targets = results
# set the root path
utj.root = options.root_path
# set the output XML file name
# puts "Output File from options: #{options.out_file}"
utj.out_file = options.out_file
# run the summarizer
puts utj.run
rescue StandardError => e
utj.usage e.message
end
end

View File

@ -1,25 +0,0 @@
# ==========================================
# Unity Project - A Test Framework for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
require'yaml'
module RakefileHelpers
class TestFileFilter
def initialize(all_files = false)
@all_files = all_files
return unless @all_files
return unless File.exist?('test_file_filter.yml')
filters = YAML.load_file('test_file_filter.yml')
@all_files = filters[:all_files]
@only_files = filters[:only_files]
@exclude_files = filters[:exclude_files]
end
attr_accessor :all_files, :only_files, :exclude_files
end
end

View File

@ -1,6 +0,0 @@
module TypeSanitizer
def self.sanitize_c_identifier(unsanitized)
# convert filename to valid C identifier by replacing invalid chars with '_'
unsanitized.gsub(/[-\/\\\.\,\s]/, '_')
end
end

View File

@ -1,139 +0,0 @@
#! python3
# ==========================================
# Unity Project - A Test Framework for C
# Copyright (c) 2015 Alexander Mueller / XelaRellum@web.de
# [Released under MIT License. Please refer to license.txt for details]
# Based on the ruby script by Mike Karlesky, Mark VanderVoord, Greg Williams
# ==========================================
import sys
import os
import re
from glob import glob
class UnityTestSummary:
def __init__(self):
self.report = ''
self.total_tests = 0
self.failures = 0
self.ignored = 0
def run(self):
# Clean up result file names
results = []
for target in self.targets:
results.append(target.replace('\\', '/'))
# Dig through each result file, looking for details on pass/fail:
failure_output = []
ignore_output = []
for result_file in results:
lines = list(map(lambda line: line.rstrip(), open(result_file, "r").read().split('\n')))
if len(lines) == 0:
raise Exception("Empty test result file: %s" % result_file)
details = self.get_details(result_file, lines)
failures = details['failures']
ignores = details['ignores']
if len(failures) > 0: failure_output.append('\n'.join(failures))
if len(ignores) > 0: ignore_output.append('n'.join(ignores))
tests,failures,ignored = self.parse_test_summary('\n'.join(lines))
self.total_tests += tests
self.failures += failures
self.ignored += ignored
if self.ignored > 0:
self.report += "\n"
self.report += "--------------------------\n"
self.report += "UNITY IGNORED TEST SUMMARY\n"
self.report += "--------------------------\n"
self.report += "\n".join(ignore_output)
if self.failures > 0:
self.report += "\n"
self.report += "--------------------------\n"
self.report += "UNITY FAILED TEST SUMMARY\n"
self.report += "--------------------------\n"
self.report += '\n'.join(failure_output)
self.report += "\n"
self.report += "--------------------------\n"
self.report += "OVERALL UNITY TEST SUMMARY\n"
self.report += "--------------------------\n"
self.report += "{total_tests} TOTAL TESTS {failures} TOTAL FAILURES {ignored} IGNORED\n".format(total_tests = self.total_tests, failures=self.failures, ignored=self.ignored)
self.report += "\n"
return self.report
def set_targets(self, target_array):
self.targets = target_array
def set_root_path(self, path):
self.root = path
def usage(self, err_msg=None):
print("\nERROR: ")
if err_msg:
print(err_msg)
print("\nUsage: unity_test_summary.py result_file_directory/ root_path/")
print(" result_file_directory - The location of your results files.")
print(" Defaults to current directory if not specified.")
print(" Should end in / if specified.")
print(" root_path - Helpful for producing more verbose output if using relative paths.")
sys.exit(1)
def get_details(self, result_file, lines):
results = { 'failures': [], 'ignores': [], 'successes': [] }
for line in lines:
parts = line.split(':')
if len(parts) == 5:
src_file,src_line,test_name,status,msg = parts
elif len(parts) == 4:
src_file,src_line,test_name,status = parts
msg = ''
else:
continue
if len(self.root) > 0:
line_out = "%s%s" % (self.root, line)
else:
line_out = line
if status == 'IGNORE':
results['ignores'].append(line_out)
elif status == 'FAIL':
results['failures'].append(line_out)
elif status == 'PASS':
results['successes'].append(line_out)
return results
def parse_test_summary(self, summary):
m = re.search(r"([0-9]+) Tests ([0-9]+) Failures ([0-9]+) Ignored", summary)
if not m:
raise Exception("Couldn't parse test results: %s" % summary)
return int(m.group(1)), int(m.group(2)), int(m.group(3))
if __name__ == '__main__':
uts = UnityTestSummary()
try:
#look in the specified or current directory for result files
if len(sys.argv) > 1:
targets_dir = sys.argv[1]
else:
targets_dir = './'
targets = list(map(lambda x: x.replace('\\', '/'), glob(targets_dir + '**/*.test*', recursive=True)))
if len(targets) == 0:
raise Exception("No *.testpass or *.testfail files found in '%s'" % targets_dir)
uts.set_targets(targets)
#set the root path
if len(sys.argv) > 2:
root_path = sys.argv[2]
else:
root_path = os.path.split(__file__)[0]
uts.set_root_path(root_path)
#run the summarizer
print(uts.run())
except Exception as e:
uts.usage(e)

View File

@ -1,135 +0,0 @@
# ==========================================
# Unity Project - A Test Framework for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
# !/usr/bin/ruby
#
# unity_test_summary.rb
#
require 'fileutils'
require 'set'
class UnityTestSummary
include FileUtils::Verbose
attr_reader :report, :total_tests, :failures, :ignored
attr_writer :targets, :root
def initialize(_opts = {})
@report = ''
@total_tests = 0
@failures = 0
@ignored = 0
end
def run
# Clean up result file names
results = @targets.map { |target| target.tr('\\', '/') }
# Dig through each result file, looking for details on pass/fail:
failure_output = []
ignore_output = []
results.each do |result_file|
lines = File.readlines(result_file).map(&:chomp)
raise "Empty test result file: #{result_file}" if lines.empty?
output = get_details(result_file, lines)
failure_output << output[:failures] unless output[:failures].empty?
ignore_output << output[:ignores] unless output[:ignores].empty?
tests, failures, ignored = parse_test_summary(lines)
@total_tests += tests
@failures += failures
@ignored += ignored
end
if @ignored > 0
@report += "\n"
@report += "--------------------------\n"
@report += "UNITY IGNORED TEST SUMMARY\n"
@report += "--------------------------\n"
@report += ignore_output.flatten.join("\n")
end
if @failures > 0
@report += "\n"
@report += "--------------------------\n"
@report += "UNITY FAILED TEST SUMMARY\n"
@report += "--------------------------\n"
@report += failure_output.flatten.join("\n")
end
@report += "\n"
@report += "--------------------------\n"
@report += "OVERALL UNITY TEST SUMMARY\n"
@report += "--------------------------\n"
@report += "#{@total_tests} TOTAL TESTS #{@failures} TOTAL FAILURES #{@ignored} IGNORED\n"
@report += "\n"
end
def usage(err_msg = nil)
puts "\nERROR: "
puts err_msg if err_msg
puts "\nUsage: unity_test_summary.rb result_file_directory/ root_path/"
puts ' result_file_directory - The location of your results files.'
puts ' Defaults to current directory if not specified.'
puts ' Should end in / if specified.'
puts ' root_path - Helpful for producing more verbose output if using relative paths.'
exit 1
end
protected
def get_details(_result_file, lines)
results = { failures: [], ignores: [], successes: [] }
lines.each do |line|
_src_file, _src_line, _test_name, status, _msg = line.split(/:/)
line_out = (@root && (@root != 0) ? "#{@root}#{line}" : line).gsub(/\//, '\\')
case status
when 'IGNORE' then results[:ignores] << line_out
when 'FAIL' then results[:failures] << line_out
when 'PASS' then results[:successes] << line_out
end
end
results
end
def parse_test_summary(summary)
raise "Couldn't parse test results: #{summary}" unless summary.find { |v| v =~ /(\d+) Tests (\d+) Failures (\d+) Ignored/ }
[Regexp.last_match(1).to_i, Regexp.last_match(2).to_i, Regexp.last_match(3).to_i]
end
end
if $0 == __FILE__
# parse out the command options
opts, args = ARGV.partition { |v| v =~ /^--\w+/ }
opts.map! { |v| v[2..-1].to_sym }
# create an instance to work with
uts = UnityTestSummary.new(opts)
begin
# look in the specified or current directory for result files
args[0] ||= './'
targets = "#{ARGV[0].tr('\\', '/')}**/*.test*"
results = Dir[targets]
raise "No *.testpass, *.testfail, or *.testresults files found in '#{targets}'" if results.empty?
uts.targets = results
# set the root path
args[1] ||= Dir.pwd + '/'
uts.root = ARGV[1]
# run the summarizer
puts uts.run
rescue StandardError => e
uts.usage e.message
end
end

View File

@ -1,146 +0,0 @@
import sys
import os
from glob import glob
from pyparsing import *
from junit_xml import TestSuite, TestCase
class UnityTestSummary:
def __init__(self):
self.report = ''
self.total_tests = 0
self.failures = 0
self.ignored = 0
self.targets = 0
self.root = None
self.test_suites = dict()
def run(self):
# Clean up result file names
results = []
for target in self.targets:
results.append(target.replace('\\', '/'))
# Dig through each result file, looking for details on pass/fail:
for result_file in results:
lines = list(map(lambda line: line.rstrip(), open(result_file, "r").read().split('\n')))
if len(lines) == 0:
raise Exception("Empty test result file: %s" % result_file)
# define an expression for your file reference
entry_one = Combine(
oneOf(list(alphas)) + ':/' +
Word(alphanums + '_-./'))
entry_two = Word(printables + ' ', excludeChars=':')
entry = entry_one | entry_two
delimiter = Literal(':').suppress()
tc_result_line = Group(entry.setResultsName('tc_file_name') + delimiter + entry.setResultsName(
'tc_line_nr') + delimiter + entry.setResultsName('tc_name') + delimiter + entry.setResultsName(
'tc_status') + Optional(
delimiter + entry.setResultsName('tc_msg'))).setResultsName("tc_line")
eol = LineEnd().suppress()
sol = LineStart().suppress()
blank_line = sol + eol
tc_summary_line = Group(Word(nums).setResultsName("num_of_tests") + "Tests" + Word(nums).setResultsName(
"num_of_fail") + "Failures" + Word(nums).setResultsName("num_of_ignore") + "Ignored").setResultsName(
"tc_summary")
tc_end_line = Or(Literal("FAIL"), Literal('Ok')).setResultsName("tc_result")
# run it and see...
pp1 = tc_result_line | Optional(tc_summary_line | tc_end_line)
pp1.ignore(blank_line | OneOrMore("-"))
result = list()
for l in lines:
result.append((pp1.parseString(l)).asDict())
# delete empty results
result = filter(None, result)
tc_list = list()
for r in result:
if 'tc_line' in r:
tmp_tc_line = r['tc_line']
# get only the file name which will be used as the classname
file_name = tmp_tc_line['tc_file_name'].split('\\').pop().split('/').pop().rsplit('.', 1)[0]
tmp_tc = TestCase(name=tmp_tc_line['tc_name'], classname=file_name)
if 'tc_status' in tmp_tc_line:
if str(tmp_tc_line['tc_status']) == 'IGNORE':
if 'tc_msg' in tmp_tc_line:
tmp_tc.add_skipped_info(message=tmp_tc_line['tc_msg'],
output=r'[File]={0}, [Line]={1}'.format(
tmp_tc_line['tc_file_name'], tmp_tc_line['tc_line_nr']))
else:
tmp_tc.add_skipped_info(message=" ")
elif str(tmp_tc_line['tc_status']) == 'FAIL':
if 'tc_msg' in tmp_tc_line:
tmp_tc.add_failure_info(message=tmp_tc_line['tc_msg'],
output=r'[File]={0}, [Line]={1}'.format(
tmp_tc_line['tc_file_name'], tmp_tc_line['tc_line_nr']))
else:
tmp_tc.add_failure_info(message=" ")
tc_list.append((str(result_file), tmp_tc))
for k, v in tc_list:
try:
self.test_suites[k].append(v)
except KeyError:
self.test_suites[k] = [v]
ts = []
for suite_name in self.test_suites:
ts.append(TestSuite(suite_name, self.test_suites[suite_name]))
with open('result.xml', 'w') as f:
TestSuite.to_file(f, ts, prettyprint='True', encoding='utf-8')
return self.report
def set_targets(self, target_array):
self.targets = target_array
def set_root_path(self, path):
self.root = path
@staticmethod
def usage(err_msg=None):
print("\nERROR: ")
if err_msg:
print(err_msg)
print("\nUsage: unity_test_summary.py result_file_directory/ root_path/")
print(" result_file_directory - The location of your results files.")
print(" Defaults to current directory if not specified.")
print(" Should end in / if specified.")
print(" root_path - Helpful for producing more verbose output if using relative paths.")
sys.exit(1)
if __name__ == '__main__':
uts = UnityTestSummary()
try:
# look in the specified or current directory for result files
if len(sys.argv) > 1:
targets_dir = sys.argv[1]
else:
targets_dir = './'
targets = list(map(lambda x: x.replace('\\', '/'), glob(targets_dir + '*.test*')))
if len(targets) == 0:
raise Exception("No *.testpass or *.testfail files found in '%s'" % targets_dir)
uts.set_targets(targets)
# set the root path
if len(sys.argv) > 2:
root_path = sys.argv[2]
else:
root_path = os.path.split(__file__)[0]
uts.set_root_path(root_path)
# run the summarizer
print(uts.run())
except Exception as e:
UnityTestSummary.usage(e)

View File

@ -1,72 +0,0 @@
# ==========================================
# Unity Project - A Test Framework for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
#We try to detect the OS we are running on, and adjust commands as needed
ifeq ($(OS),Windows_NT)
ifeq ($(shell uname -s),) # not in a bash-like shell
CLEANUP = del /F /Q
MKDIR = mkdir
else # in a bash-like shell, like msys
CLEANUP = rm -f
MKDIR = mkdir -p
endif
TARGET_EXTENSION=.exe
else
CLEANUP = rm -f
MKDIR = mkdir -p
TARGET_EXTENSION=.out
endif
C_COMPILER=gcc
ifeq ($(shell uname -s), Darwin)
C_COMPILER=clang
endif
UNITY_ROOT=../..
CFLAGS=-std=c89
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wpointer-arith
CFLAGS += -Wcast-align
CFLAGS += -Wwrite-strings
CFLAGS += -Wswitch-default
CFLAGS += -Wunreachable-code
CFLAGS += -Winit-self
CFLAGS += -Wmissing-field-initializers
CFLAGS += -Wno-unknown-pragmas
CFLAGS += -Wstrict-prototypes
CFLAGS += -Wundef
CFLAGS += -Wold-style-definition
#CFLAGS += -Wno-misleading-indentation
TARGET_BASE1=test1
TARGET_BASE2=test2
TARGET1 = $(TARGET_BASE1)$(TARGET_EXTENSION)
TARGET2 = $(TARGET_BASE2)$(TARGET_EXTENSION)
SRC_FILES1=$(UNITY_ROOT)/src/unity.c src/ProductionCode.c test/TestProductionCode.c test/test_runners/TestProductionCode_Runner.c
SRC_FILES2=$(UNITY_ROOT)/src/unity.c src/ProductionCode2.c test/TestProductionCode2.c test/test_runners/TestProductionCode2_Runner.c
INC_DIRS=-Isrc -I$(UNITY_ROOT)/src
SYMBOLS=
all: clean default
default: $(SRC_FILES1) $(SRC_FILES2)
$(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_FILES1) -o $(TARGET1)
$(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_FILES2) -o $(TARGET2)
- ./$(TARGET1)
- ./$(TARGET2)
test/test_runners/TestProductionCode_Runner.c: test/TestProductionCode.c
ruby $(UNITY_ROOT)/auto/generate_test_runner.rb test/TestProductionCode.c test/test_runners/TestProductionCode_Runner.c
test/test_runners/TestProductionCode2_Runner.c: test/TestProductionCode2.c
ruby $(UNITY_ROOT)/auto/generate_test_runner.rb test/TestProductionCode2.c test/test_runners/TestProductionCode2_Runner.c
clean:
$(CLEANUP) $(TARGET1) $(TARGET2)
ci: CFLAGS += -Werror
ci: default

View File

@ -1,5 +0,0 @@
Example 1
=========
Close to the simplest possible example of Unity, using only basic features.
Run make to build & run the example tests.

View File

@ -1,24 +0,0 @@
#include "ProductionCode.h"
int Counter = 0;
int NumbersToFind[9] = { 0, 34, 55, 66, 32, 11, 1, 77, 888 }; /* some obnoxious array to search that is 1-based indexing instead of 0. */
/* This function is supposed to search through NumbersToFind and find a particular number.
* If it finds it, the index is returned. Otherwise 0 is returned which sorta makes sense since
* NumbersToFind is indexed from 1. Unfortunately it's broken
* (and should therefore be caught by our tests) */
int FindFunction_WhichIsBroken(int NumberToFind)
{
int i = 0;
while (i < 8) /* Notice I should have been in braces */
i++;
if (NumbersToFind[i] == NumberToFind) /* Yikes! I'm getting run after the loop finishes instead of during it! */
return i;
return 0;
}
int FunctionWhichReturnsLocalVariable(void)
{
return Counter;
}

View File

@ -1,3 +0,0 @@
int FindFunction_WhichIsBroken(int NumberToFind);
int FunctionWhichReturnsLocalVariable(void);

View File

@ -1,11 +0,0 @@
#include "ProductionCode2.h"
char* ThisFunctionHasNotBeenTested(int Poor, char* LittleFunction)
{
(void)Poor;
(void)LittleFunction;
/* Since There Are No Tests Yet, This Function Could Be Empty For All We Know.
* Which isn't terribly useful... but at least we put in a TEST_IGNORE so we won't forget */
return (char*)0;
}

View File

@ -1,2 +0,0 @@
char* ThisFunctionHasNotBeenTested(int Poor, char* LittleFunction);

View File

@ -1,62 +0,0 @@
#include "ProductionCode.h"
#include "unity.h"
/* sometimes you may want to get at local data in a module.
* for example: If you plan to pass by reference, this could be useful
* however, it should often be avoided */
extern int Counter;
void setUp(void)
{
/* This is run before EACH TEST */
Counter = 0x5a5a;
}
void tearDown(void)
{
}
void test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode(void)
{
/* All of these should pass */
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(78));
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(2));
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(33));
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(999));
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(-1));
}
void test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken(void)
{
/* You should see this line fail in your test summary */
TEST_ASSERT_EQUAL(1, FindFunction_WhichIsBroken(34));
/* Notice the rest of these didn't get a chance to run because the line above failed.
* Unit tests abort each test function on the first sign of trouble.
* Then NEXT test function runs as normal. */
TEST_ASSERT_EQUAL(8, FindFunction_WhichIsBroken(8888));
}
void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue(void)
{
/* This should be true because setUp set this up for us before this test */
TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable());
/* This should be true because we can still change our answer */
Counter = 0x1234;
TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable());
}
void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain(void)
{
/* This should be true again because setup was rerun before this test (and after we changed it to 0x1234) */
TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable());
}
void test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed(void)
{
/* Sometimes you get the test wrong. When that happens, you get a failure too... and a quick look should tell
* you what actually happened...which in this case was a failure to setup the initial condition. */
TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable());
}

View File

@ -1,31 +0,0 @@
#include "ProductionCode2.h"
#include "unity.h"
/* These should be ignored because they are commented out in various ways:
#include "whatever.h"
#include "somethingelse.h"
*/
void setUp(void)
{
}
void tearDown(void)
{
}
void test_IgnoredTest(void)
{
TEST_IGNORE_MESSAGE("This Test Was Ignored On Purpose");
}
void test_AnotherIgnoredTest(void)
{
TEST_IGNORE_MESSAGE("These Can Be Useful For Leaving Yourself Notes On What You Need To Do Yet");
}
void test_ThisFunctionHasNotBeenTested_NeedsToBeImplemented(void)
{
TEST_IGNORE(); /* Like This */
}

View File

@ -1,53 +0,0 @@
/* AUTOGENERATED FILE. DO NOT EDIT. */
/*=======Test Runner Used To Run Each Test Below=====*/
#define RUN_TEST(TestFunc, TestLineNum) \
{ \
Unity.CurrentTestName = #TestFunc; \
Unity.CurrentTestLineNumber = TestLineNum; \
Unity.NumberOfTests++; \
if (TEST_PROTECT()) \
{ \
setUp(); \
TestFunc(); \
} \
if (TEST_PROTECT()) \
{ \
tearDown(); \
} \
UnityConcludeTest(); \
}
/*=======Automagically Detected Files To Include=====*/
#include "unity.h"
#include <setjmp.h>
#include <stdio.h>
#include "ProductionCode2.h"
/*=======External Functions This Runner Calls=====*/
extern void setUp(void);
extern void tearDown(void);
extern void test_IgnoredTest(void);
extern void test_AnotherIgnoredTest(void);
extern void test_ThisFunctionHasNotBeenTested_NeedsToBeImplemented(void);
/*=======Test Reset Option=====*/
void resetTest(void);
void resetTest(void)
{
tearDown();
setUp();
}
/*=======MAIN=====*/
int main(void)
{
UnityBegin("test/TestProductionCode2.c");
RUN_TEST(test_IgnoredTest, 18);
RUN_TEST(test_AnotherIgnoredTest, 23);
RUN_TEST(test_ThisFunctionHasNotBeenTested_NeedsToBeImplemented, 28);
return (UnityEnd());
}

View File

@ -1,57 +0,0 @@
/* AUTOGENERATED FILE. DO NOT EDIT. */
/*=======Test Runner Used To Run Each Test Below=====*/
#define RUN_TEST(TestFunc, TestLineNum) \
{ \
Unity.CurrentTestName = #TestFunc; \
Unity.CurrentTestLineNumber = TestLineNum; \
Unity.NumberOfTests++; \
if (TEST_PROTECT()) \
{ \
setUp(); \
TestFunc(); \
} \
if (TEST_PROTECT()) \
{ \
tearDown(); \
} \
UnityConcludeTest(); \
}
/*=======Automagically Detected Files To Include=====*/
#include "unity.h"
#include <setjmp.h>
#include <stdio.h>
#include "ProductionCode.h"
/*=======External Functions This Runner Calls=====*/
extern void setUp(void);
extern void tearDown(void);
extern void test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode(void);
extern void test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken(void);
extern void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue(void);
extern void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain(void);
extern void test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed(void);
/*=======Test Reset Option=====*/
void resetTest(void);
void resetTest(void)
{
tearDown();
setUp();
}
/*=======MAIN=====*/
int main(void)
{
UnityBegin("test/TestProductionCode.c");
RUN_TEST(test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode, 20);
RUN_TEST(test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken, 30);
RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue, 41);
RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain, 51);
RUN_TEST(test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed, 57);
return (UnityEnd());
}

View File

@ -1,71 +0,0 @@
# ==========================================
# Unity Project - A Test Framework for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
#We try to detect the OS we are running on, and adjust commands as needed
ifeq ($(OS),Windows_NT)
ifeq ($(shell uname -s),) # not in a bash-like shell
CLEANUP = del /F /Q
MKDIR = mkdir
else # in a bash-like shell, like msys
CLEANUP = rm -f
MKDIR = mkdir -p
endif
TARGET_EXTENSION=.exe
else
CLEANUP = rm -f
MKDIR = mkdir -p
TARGET_EXTENSION=.out
endif
C_COMPILER=gcc
ifeq ($(shell uname -s), Darwin)
C_COMPILER=clang
endif
UNITY_ROOT=../..
CFLAGS=-std=c99
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -Wpointer-arith
CFLAGS += -Wcast-align
CFLAGS += -Wwrite-strings
CFLAGS += -Wswitch-default
CFLAGS += -Wunreachable-code
CFLAGS += -Winit-self
CFLAGS += -Wmissing-field-initializers
CFLAGS += -Wno-unknown-pragmas
CFLAGS += -Wstrict-prototypes
CFLAGS += -Wundef
CFLAGS += -Wold-style-definition
#CFLAGS += -Wno-misleading-indentation
TARGET_BASE1=all_tests
TARGET1 = $(TARGET_BASE1)$(TARGET_EXTENSION)
SRC_FILES1=\
$(UNITY_ROOT)/src/unity.c \
$(UNITY_ROOT)/extras/fixture/src/unity_fixture.c \
src/ProductionCode.c \
src/ProductionCode2.c \
test/TestProductionCode.c \
test/TestProductionCode2.c \
test/test_runners/TestProductionCode_Runner.c \
test/test_runners/TestProductionCode2_Runner.c \
test/test_runners/all_tests.c
INC_DIRS=-Isrc -I$(UNITY_ROOT)/src -I$(UNITY_ROOT)/extras/fixture/src
SYMBOLS=-DUNITY_FIXTURE_NO_EXTRAS
all: clean default
default:
$(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_FILES1) -o $(TARGET1)
- ./$(TARGET1) -v
clean:
$(CLEANUP) $(TARGET1)
ci: CFLAGS += -Werror
ci: default

View File

@ -1,5 +0,0 @@
Example 2
=========
Same as the first example, but now using Unity's test fixture to group tests
together. Using the test fixture also makes writing test runners much easier.

View File

@ -1,24 +0,0 @@
#include "ProductionCode.h"
int Counter = 0;
int NumbersToFind[9] = { 0, 34, 55, 66, 32, 11, 1, 77, 888 }; //some obnoxious array to search that is 1-based indexing instead of 0.
// This function is supposed to search through NumbersToFind and find a particular number.
// If it finds it, the index is returned. Otherwise 0 is returned which sorta makes sense since
// NumbersToFind is indexed from 1. Unfortunately it's broken
// (and should therefore be caught by our tests)
int FindFunction_WhichIsBroken(int NumberToFind)
{
int i = 0;
while (i < 8) //Notice I should have been in braces
i++;
if (NumbersToFind[i] == NumberToFind) //Yikes! I'm getting run after the loop finishes instead of during it!
return i;
return 0;
}
int FunctionWhichReturnsLocalVariable(void)
{
return Counter;
}

View File

@ -1,3 +0,0 @@
int FindFunction_WhichIsBroken(int NumberToFind);
int FunctionWhichReturnsLocalVariable(void);

View File

@ -1,11 +0,0 @@
#include "ProductionCode2.h"
char* ThisFunctionHasNotBeenTested(int Poor, char* LittleFunction)
{
(void)Poor;
(void)LittleFunction;
//Since There Are No Tests Yet, This Function Could Be Empty For All We Know.
// Which isn't terribly useful... but at least we put in a TEST_IGNORE so we won't forget
return (char*)0;
}

View File

@ -1,2 +0,0 @@
char* ThisFunctionHasNotBeenTested(int Poor, char* LittleFunction);

View File

@ -1,64 +0,0 @@
#include "ProductionCode.h"
#include "unity.h"
#include "unity_fixture.h"
TEST_GROUP(ProductionCode);
//sometimes you may want to get at local data in a module.
//for example: If you plan to pass by reference, this could be useful
//however, it should often be avoided
extern int Counter;
TEST_SETUP(ProductionCode)
{
//This is run before EACH TEST
Counter = 0x5a5a;
}
TEST_TEAR_DOWN(ProductionCode)
{
}
TEST(ProductionCode, FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode)
{
//All of these should pass
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(78));
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(2));
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(33));
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(999));
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(-1));
}
TEST(ProductionCode, FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken)
{
// You should see this line fail in your test summary
TEST_ASSERT_EQUAL(1, FindFunction_WhichIsBroken(34));
// Notice the rest of these didn't get a chance to run because the line above failed.
// Unit tests abort each test function on the first sign of trouble.
// Then NEXT test function runs as normal.
TEST_ASSERT_EQUAL(8, FindFunction_WhichIsBroken(8888));
}
TEST(ProductionCode, FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue)
{
//This should be true because setUp set this up for us before this test
TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable());
//This should be true because we can still change our answer
Counter = 0x1234;
TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable());
}
TEST(ProductionCode, FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain)
{
//This should be true again because setup was rerun before this test (and after we changed it to 0x1234)
TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable());
}
TEST(ProductionCode, FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed)
{
//Sometimes you get the test wrong. When that happens, you get a failure too... and a quick look should tell
// you what actually happened...which in this case was a failure to setup the initial condition.
TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable());
}

View File

@ -1,33 +0,0 @@
#include "ProductionCode2.h"
#include "unity.h"
#include "unity_fixture.h"
TEST_GROUP(ProductionCode2);
/* These should be ignored because they are commented out in various ways:
#include "whatever.h"
*/
//#include "somethingelse.h"
TEST_SETUP(ProductionCode2)
{
}
TEST_TEAR_DOWN(ProductionCode2)
{
}
TEST(ProductionCode2, IgnoredTest)
{
TEST_IGNORE_MESSAGE("This Test Was Ignored On Purpose");
}
TEST(ProductionCode2, AnotherIgnoredTest)
{
TEST_IGNORE_MESSAGE("These Can Be Useful For Leaving Yourself Notes On What You Need To Do Yet");
}
TEST(ProductionCode2, ThisFunctionHasNotBeenTested_NeedsToBeImplemented)
{
TEST_IGNORE(); //Like This
}

View File

@ -1,9 +0,0 @@
#include "unity.h"
#include "unity_fixture.h"
TEST_GROUP_RUNNER(ProductionCode2)
{
RUN_TEST_CASE(ProductionCode2, IgnoredTest);
RUN_TEST_CASE(ProductionCode2, AnotherIgnoredTest);
RUN_TEST_CASE(ProductionCode2, ThisFunctionHasNotBeenTested_NeedsToBeImplemented);
}

View File

@ -1,11 +0,0 @@
#include "unity.h"
#include "unity_fixture.h"
TEST_GROUP_RUNNER(ProductionCode)
{
RUN_TEST_CASE(ProductionCode, FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode);
RUN_TEST_CASE(ProductionCode, FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken);
RUN_TEST_CASE(ProductionCode, FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue);
RUN_TEST_CASE(ProductionCode, FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain);
RUN_TEST_CASE(ProductionCode, FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed);
}

View File

@ -1,12 +0,0 @@
#include "unity_fixture.h"
static void RunAllTests(void)
{
RUN_TEST_GROUP(ProductionCode);
RUN_TEST_GROUP(ProductionCode2);
}
int main(int argc, const char * argv[])
{
return UnityMain(argc, argv, RunAllTests);
}

View File

@ -1,10 +0,0 @@
#include "unity.h"
#include "UnityHelper.h"
#include <stdio.h>
#include <string.h>
void AssertEqualExampleStruct(const EXAMPLE_STRUCT_T expected, const EXAMPLE_STRUCT_T actual, const unsigned short line)
{
UNITY_TEST_ASSERT_EQUAL_INT(expected.x, actual.x, line, "Example Struct Failed For Field x");
UNITY_TEST_ASSERT_EQUAL_INT(expected.y, actual.y, line, "Example Struct Failed For Field y");
}

View File

@ -1,12 +0,0 @@
#ifndef _TESTHELPER_H
#define _TESTHELPER_H
#include "Types.h"
void AssertEqualExampleStruct(const EXAMPLE_STRUCT_T expected, const EXAMPLE_STRUCT_T actual, const unsigned short line);
#define UNITY_TEST_ASSERT_EQUAL_EXAMPLE_STRUCT_T(expected, actual, line, message) AssertEqualExampleStruct(expected, actual, line);
#define TEST_ASSERT_EQUAL_EXAMPLE_STRUCT_T(expected, actual) UNITY_TEST_ASSERT_EQUAL_EXAMPLE_STRUCT_T(expected, actual, __LINE__, NULL);
#endif // _TESTHELPER_H

View File

@ -1,38 +0,0 @@
require 'rake'
require 'rake/clean'
require_relative 'rakefile_helper'
TEMP_DIRS = [
File.join(__dir__, 'build')
].freeze
TEMP_DIRS.each do |dir|
directory(dir)
CLOBBER.include(dir)
end
task prepare_for_tests: TEMP_DIRS
# Load default configuration, for now
DEFAULT_CONFIG_FILE = 'target_gcc_32.yml'.freeze
configure_toolchain(DEFAULT_CONFIG_FILE)
task unit: [:prepare_for_tests] do
run_tests unit_test_files
end
desc 'Generate test summary'
task :summary do
report_summary
end
desc 'Build and test Unity'
task all: %i[clean unit summary]
task default: %i[clobber all]
task ci: [:default]
task cruise: [:default]
desc 'Load configuration'
task :config, :config_file do |_t, args|
configure_toolchain(args[:config_file])
end

View File

@ -1,250 +0,0 @@
require 'yaml'
require 'fileutils'
require_relative '../../auto/unity_test_summary'
require_relative '../../auto/generate_test_runner'
require_relative '../../auto/colour_reporter'
C_EXTENSION = '.c'.freeze
def load_configuration(config_file)
$cfg_file = config_file
$cfg = YAML.load(File.read($cfg_file))
end
def configure_clean
CLEAN.include($cfg['compiler']['build_path'] + '*.*') unless $cfg['compiler']['build_path'].nil?
end
def configure_toolchain(config_file = DEFAULT_CONFIG_FILE)
config_file += '.yml' unless config_file =~ /\.yml$/
load_configuration(config_file)
configure_clean
end
def unit_test_files
path = $cfg['compiler']['unit_tests_path'] + 'Test*' + C_EXTENSION
path.tr!('\\', '/')
FileList.new(path)
end
def local_include_dirs
include_dirs = $cfg['compiler']['includes']['items'].dup
include_dirs.delete_if { |dir| dir.is_a?(Array) }
include_dirs
end
def extract_headers(filename)
includes = []
lines = File.readlines(filename)
lines.each do |line|
m = line.match(/^\s*#include\s+\"\s*(.+\.[hH])\s*\"/)
includes << m[1] unless m.nil?
end
includes
end
def find_source_file(header, paths)
paths.each do |dir|
src_file = dir + header.ext(C_EXTENSION)
return src_file if File.exist?(src_file)
end
nil
end
def tackit(strings)
result = if strings.is_a?(Array)
"\"#{strings.join}\""
else
strings
end
result
end
def squash(prefix, items)
result = ''
items.each { |item| result += " #{prefix}#{tackit(item)}" }
result
end
def build_compiler_fields
command = tackit($cfg['compiler']['path'])
defines = if $cfg['compiler']['defines']['items'].nil?
''
else
squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'])
end
options = squash('', $cfg['compiler']['options'])
includes = squash($cfg['compiler']['includes']['prefix'], $cfg['compiler']['includes']['items'])
includes = includes.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
{ command: command, defines: defines, options: options, includes: includes }
end
def compile(file, _defines = [])
compiler = build_compiler_fields
cmd_str = "#{compiler[:command]}#{compiler[:defines]}#{compiler[:options]}#{compiler[:includes]} #{file} " \
"#{$cfg['compiler']['object_files']['prefix']}#{$cfg['compiler']['object_files']['destination']}"
obj_file = "#{File.basename(file, C_EXTENSION)}#{$cfg['compiler']['object_files']['extension']}"
execute(cmd_str + obj_file)
obj_file
end
def build_linker_fields
command = tackit($cfg['linker']['path'])
options = if $cfg['linker']['options'].nil?
''
else
squash('', $cfg['linker']['options'])
end
includes = if $cfg['linker']['includes'].nil? || $cfg['linker']['includes']['items'].nil?
''
else
squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items'])
end.gsub(/\\ /, ' ').gsub(/\\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
{ command: command, options: options, includes: includes }
end
def link_it(exe_name, obj_list)
linker = build_linker_fields
cmd_str = "#{linker[:command]}#{linker[:options]}#{linker[:includes]} " +
(obj_list.map { |obj| "#{$cfg['linker']['object_files']['path']}#{obj} " }).join +
$cfg['linker']['bin_files']['prefix'] + ' ' +
$cfg['linker']['bin_files']['destination'] +
exe_name + $cfg['linker']['bin_files']['extension']
execute(cmd_str)
end
def build_simulator_fields
return nil if $cfg['simulator'].nil?
command = if $cfg['simulator']['path'].nil?
''
else
(tackit($cfg['simulator']['path']) + ' ')
end
pre_support = if $cfg['simulator']['pre_support'].nil?
''
else
squash('', $cfg['simulator']['pre_support'])
end
post_support = if $cfg['simulator']['post_support'].nil?
''
else
squash('', $cfg['simulator']['post_support'])
end
{ command: command, pre_support: pre_support, post_support: post_support }
end
def execute(command_string, verbose = true, raise_on_fail = true)
report command_string
output = `#{command_string}`.chomp
report(output) if verbose && !output.nil? && !output.empty?
if !$?.nil? && !$?.exitstatus.zero? && raise_on_fail
raise "Command failed. (Returned #{$?.exitstatus})"
end
output
end
def report_summary
summary = UnityTestSummary.new
summary.root = __dir__
results_glob = "#{$cfg['compiler']['build_path']}*.test*"
results_glob.tr!('\\', '/')
results = Dir[results_glob]
summary.targets = results
summary.run
fail_out 'FAIL: There were failures' if summary.failures > 0
end
def run_tests(test_files)
report 'Running system tests...'
# Tack on TEST define for compiling unit tests
load_configuration($cfg_file)
test_defines = ['TEST']
$cfg['compiler']['defines']['items'] = [] if $cfg['compiler']['defines']['items'].nil?
$cfg['compiler']['defines']['items'] << 'TEST'
include_dirs = local_include_dirs
# Build and execute each unit test
test_files.each do |test|
obj_list = []
# Detect dependencies and build required required modules
extract_headers(test).each do |header|
# Compile corresponding source file if it exists
src_file = find_source_file(header, include_dirs)
obj_list << compile(src_file, test_defines) unless src_file.nil?
end
# Build the test runner (generate if configured to do so)
test_base = File.basename(test, C_EXTENSION)
runner_name = test_base + '_Runner.c'
if $cfg['compiler']['runner_path'].nil?
runner_path = $cfg['compiler']['build_path'] + runner_name
test_gen = UnityTestRunnerGenerator.new($cfg_file)
test_gen.run(test, runner_path)
else
runner_path = $cfg['compiler']['runner_path'] + runner_name
end
obj_list << compile(runner_path, test_defines)
# Build the test module
obj_list << compile(test, test_defines)
# Link the test executable
link_it(test_base, obj_list)
# Execute unit test and generate results file
simulator = build_simulator_fields
executable = $cfg['linker']['bin_files']['destination'] + test_base + $cfg['linker']['bin_files']['extension']
cmd_str = if simulator.nil?
executable
else
"#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}"
end
output = execute(cmd_str, true, false)
test_results = $cfg['compiler']['build_path'] + test_base
test_results += if output.match(/OK$/m).nil?
'.testfail'
else
'.testpass'
end
File.open(test_results, 'w') { |f| f.print output }
end
end
def build_application(main)
report 'Building application...'
obj_list = []
load_configuration($cfg_file)
main_path = $cfg['compiler']['source_path'] + main + C_EXTENSION
# Detect dependencies and build required required modules
include_dirs = get_local_include_dirs
extract_headers(main_path).each do |header|
src_file = find_source_file(header, include_dirs)
obj_list << compile(src_file) unless src_file.nil?
end
# Build the main source file
main_base = File.basename(main_path, C_EXTENSION)
obj_list << compile(main_path)
# Create the executable
link_it(main_base, obj_list)
end
def fail_out(msg)
puts msg
puts 'Not returning exit code so continuous integration can pass'
# exit(-1) # Only removed to pass example_3, which has failing tests on purpose.
# Still fail if the build fails for any other reason.
end

View File

@ -1,13 +0,0 @@
Example 3
=========
This example project gives an example of some passing, ignored, and failing tests.
It's simple and meant for you to look over and get an idea for what all of this stuff does.
You can build and test using rake. The rake version will let you test with gcc or a couple
versions of IAR. You can tweak the yaml files to get those versions running.
Ruby is required if you're using the rake version (obviously). This version shows off most of
Unity's advanced features (automatically creating test runners, fancy summaries, etc.)
Without ruby, you have to maintain your own test runners. Do that for a while and you'll learn
why you really want to start using the Ruby tools.

View File

@ -1,24 +0,0 @@
#include "ProductionCode.h"
int Counter = 0;
int NumbersToFind[9] = { 0, 34, 55, 66, 32, 11, 1, 77, 888 }; //some obnoxious array to search that is 1-based indexing instead of 0.
// This function is supposed to search through NumbersToFind and find a particular number.
// If it finds it, the index is returned. Otherwise 0 is returned which sorta makes sense since
// NumbersToFind is indexed from 1. Unfortunately it's broken
// (and should therefore be caught by our tests)
int FindFunction_WhichIsBroken(int NumberToFind)
{
int i = 0;
while (i < 8) //Notice I should have been in braces
i++;
if (NumbersToFind[i] == NumberToFind) //Yikes! I'm getting run after the loop finishes instead of during it!
return i;
return 0;
}
int FunctionWhichReturnsLocalVariable(void)
{
return Counter;
}

View File

@ -1,3 +0,0 @@
int FindFunction_WhichIsBroken(int NumberToFind);
int FunctionWhichReturnsLocalVariable(void);

View File

@ -1,11 +0,0 @@
#include "ProductionCode2.h"
char* ThisFunctionHasNotBeenTested(int Poor, char* LittleFunction)
{
(void)Poor;
(void)LittleFunction;
//Since There Are No Tests Yet, This Function Could Be Empty For All We Know.
// Which isn't terribly useful... but at least we put in a TEST_IGNORE so we won't forget
return (char*)0;
}

View File

@ -1,2 +0,0 @@
char* ThisFunctionHasNotBeenTested(int Poor, char* LittleFunction);

View File

@ -1,47 +0,0 @@
# Copied from ~Unity/targets/gcc_32.yml
unity_root: &unity_root '../..'
unity_source: &unity_source '../../src/'
compiler:
path: gcc
source_path: &source_path 'src/'
unit_tests_path: &unit_tests_path 'test/'
build_path: &build_path 'build/'
options:
- '-c'
- '-m32'
- '-Wall'
- '-Wno-address'
- '-std=c99'
- '-pedantic'
includes:
prefix: '-I'
items:
- *source_path
- *unity_source
- *unit_tests_path
defines:
prefix: '-D'
items:
- UNITY_INCLUDE_DOUBLE
- UNITY_SUPPORT_TEST_CASES
object_files:
prefix: '-o'
extension: '.o'
destination: *build_path
linker:
path: gcc
options:
- -lm
- '-m32'
includes:
prefix: '-I'
object_files:
path: *build_path
extension: '.o'
bin_files:
prefix: '-o'
extension: '.exe'
destination: *build_path
colour: true
:unity:
:plugins: []

View File

@ -1,62 +0,0 @@
#include "ProductionCode.h"
#include "unity.h"
//sometimes you may want to get at local data in a module.
//for example: If you plan to pass by reference, this could be useful
//however, it should often be avoided
extern int Counter;
void setUp(void)
{
//This is run before EACH TEST
Counter = 0x5a5a;
}
void tearDown(void)
{
}
void test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode(void)
{
//All of these should pass
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(78));
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(1));
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(33));
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(999));
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(-1));
}
void test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken(void)
{
// You should see this line fail in your test summary
TEST_ASSERT_EQUAL(1, FindFunction_WhichIsBroken(34));
// Notice the rest of these didn't get a chance to run because the line above failed.
// Unit tests abort each test function on the first sign of trouble.
// Then NEXT test function runs as normal.
TEST_ASSERT_EQUAL(8, FindFunction_WhichIsBroken(8888));
}
void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue(void)
{
//This should be true because setUp set this up for us before this test
TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable());
//This should be true because we can still change our answer
Counter = 0x1234;
TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable());
}
void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain(void)
{
//This should be true again because setup was rerun before this test (and after we changed it to 0x1234)
TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable());
}
void test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed(void)
{
//Sometimes you get the test wrong. When that happens, you get a failure too... and a quick look should tell
// you what actually happened...which in this case was a failure to setup the initial condition.
TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable());
}

View File

@ -1,31 +0,0 @@
#include "ProductionCode2.h"
#include "unity.h"
/* These should be ignored because they are commented out in various ways:
#include "whatever.h"
*/
//#include "somethingelse.h"
void setUp(void)
{
}
void tearDown(void)
{
}
void test_IgnoredTest(void)
{
TEST_IGNORE_MESSAGE("This Test Was Ignored On Purpose");
}
void test_AnotherIgnoredTest(void)
{
TEST_IGNORE_MESSAGE("These Can Be Useful For Leaving Yourself Notes On What You Need To Do Yet");
}
void test_ThisFunctionHasNotBeenTested_NeedsToBeImplemented(void)
{
TEST_IGNORE(); //Like This
}

View File

@ -1,12 +0,0 @@
#
# build script written by : Michael Brockus.
# github repo author: Mike Karlesky, Mark VanderVoord, Greg Williams.
#
# license: MIT
#
project('example-4', 'c')
unity_dep = dependency('unity', fallback : ['unity', 'unity_dep'])
subdir('src')
subdir('test')

View File

@ -1,15 +0,0 @@
Example 4
=========
Close to the simplest possible example of Unity, using only basic features.
to build this example run "meson setup <build dir name>".
Meson uses the Ninja build system to actually build the code. To start the
build, simply type the following command.
"ninja -C <build dir name>"
Meson provides native support for running tests. The command to do that is simple.
"meson test -C <build dir name>".

View File

@ -1,24 +0,0 @@
#include "ProductionCode.h"
int Counter = 0;
int NumbersToFind[9] = { 0, 34, 55, 66, 32, 11, 1, 77, 888 }; /* some obnoxious array to search that is 1-based indexing instead of 0. */
/* This function is supposed to search through NumbersToFind and find a particular number.
* If it finds it, the index is returned. Otherwise 0 is returned which sorta makes sense since
* NumbersToFind is indexed from 1. Unfortunately it's broken
* (and should therefore be caught by our tests) */
int FindFunction_WhichIsBroken(int NumberToFind)
{
int i = 0;
while (i < 8) /* Notice I should have been in braces */
i++;
if (NumbersToFind[i] == NumberToFind) /* Yikes! I'm getting run after the loop finishes instead of during it! */
return i;
return 0;
}
int FunctionWhichReturnsLocalVariable(void)
{
return Counter;
}

View File

@ -1,3 +0,0 @@
int FindFunction_WhichIsBroken(int NumberToFind);
int FunctionWhichReturnsLocalVariable(void);

View File

@ -1,11 +0,0 @@
#include "ProductionCode2.h"
char* ThisFunctionHasNotBeenTested(int Poor, char* LittleFunction)
{
(void)Poor;
(void)LittleFunction;
/* Since There Are No Tests Yet, This Function Could Be Empty For All We Know.
* Which isn't terribly useful... but at least we put in a TEST_IGNORE so we won't forget */
return (char*)0;
}

View File

@ -1,2 +0,0 @@
char* ThisFunctionHasNotBeenTested(int Poor, char* LittleFunction);

View File

@ -1,16 +0,0 @@
#
# build script written by : Michael Brockus.
# github repo author: Mike Karlesky, Mark VanderVoord, Greg Williams.
#
# license: MIT
#
inc_dir = include_directories('.')
lib_list = {'a': ['ProductionCode.c' ], 'b': ['ProductionCode2.c']}
foreach lib, src : lib_list
set_variable(lib + '_lib',
static_library(lib + '_lib', sources: src, include_directories: inc_dir))
endforeach
a_dep = declare_dependency(link_with: a_lib, include_directories: inc_dir)
b_dep = declare_dependency(link_with: b_lib, include_directories: inc_dir)

View File

@ -1,4 +0,0 @@
[wrap-git]
directory = unity
url = https://github.com/ThrowTheSwitch/Unity.git
revision = head

View File

@ -1,63 +0,0 @@
#include "ProductionCode.h"
#include "unity.h"
/* sometimes you may want to get at local data in a module.
* for example: If you plan to pass by reference, this could be useful
* however, it should often be avoided */
extern int Counter;
void setUp(void)
{
/* This is run before EACH TEST */
Counter = 0x5a5a;
}
void tearDown(void)
{
}
void test_FindFunction_WhichIsBroken_ShouldReturnZeroIfItemIsNotInList_WhichWorksEvenInOurBrokenCode(void)
{
/* All of these should pass */
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(78));
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(2));
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(33));
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(999));
TEST_ASSERT_EQUAL(0, FindFunction_WhichIsBroken(-1));
}
void test_FindFunction_WhichIsBroken_ShouldReturnTheIndexForItemsInList_WhichWillFailBecauseOurFunctionUnderTestIsBroken(void)
{
/* You should see this line fail in your test summary */
TEST_ASSERT_EQUAL(1, FindFunction_WhichIsBroken(34));
/* Notice the rest of these didn't get a chance to run because the line above failed.
* Unit tests abort each test function on the first sign of trouble.
* Then NEXT test function runs as normal. */
TEST_ASSERT_EQUAL(8, FindFunction_WhichIsBroken(8888));
}
void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValue(void)
{
/* This should be true because setUp set this up for us before this test */
TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable());
/* This should be true because we can still change our answer */
Counter = 0x1234;
TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable());
}
void test_FunctionWhichReturnsLocalVariable_ShouldReturnTheCurrentCounterValueAgain(void)
{
/* This should be true again because setup was rerun before this test (and after we changed it to 0x1234) */
TEST_ASSERT_EQUAL_HEX(0x5a5a, FunctionWhichReturnsLocalVariable());
}
void test_FunctionWhichReturnsLocalVariable_ShouldReturnCurrentCounter_ButFailsBecauseThisTestIsActuallyFlawed(void)
{
/* Sometimes you get the test wrong. When that happens, you get a failure too... and a quick look should tell
* you what actually happened...which in this case was a failure to setup the initial condition. */
TEST_ASSERT_EQUAL_HEX(0x1234, FunctionWhichReturnsLocalVariable());
}

Some files were not shown because too many files have changed in this diff Show More