Added a test suite generator tool written in FTL.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/branches/stable_17.6.x@10616 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
parent
218295a815
commit
ebd93bd85e
|
@ -91,6 +91,7 @@
|
|||
*** 17.6.1 ***
|
||||
- NEW: Improved RT and NIL test suite to report version numbers and
|
||||
configuration settings.
|
||||
- NEW: Added a test suite generator tool written in FTL.
|
||||
- NEW: Added to the HAL USB driver a new function usbWakeupHost() for
|
||||
standby exit.
|
||||
- HAL: Fixed USB GET_DESCRIPTOR not handled for Interface Recipients (bug #885).
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
[#ftl]
|
||||
[#--
|
||||
ChibiOS/RT - Copyright (C) 2006-2017 Giovanni Di Sirio
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
--]
|
||||
|
||||
[#--
|
||||
-- Returns the trimmed text "s" making sure it is terminated by a dot.
|
||||
-- The empty string is always returned as an empty string, the dot is not
|
||||
-- added.
|
||||
--]
|
||||
[#function WithDot s]
|
||||
[#local s = s?trim /]
|
||||
[#if s == ""]
|
||||
[#return s /]
|
||||
[/#if]
|
||||
[#if s?ends_with(".")]
|
||||
[#return s /]
|
||||
[/#if]
|
||||
[#return s + "." /]
|
||||
[/#function]
|
||||
|
||||
[#--
|
||||
-- Returns the trimmed text "s" making sure it is not terminated by a dot.
|
||||
--]
|
||||
[#function WithoutDot s]
|
||||
[#local s = s?trim /]
|
||||
[#if s?ends_with(".")]
|
||||
[#return s?substring(0, s?length - 1) /]
|
||||
[/#if]
|
||||
[#return s /]
|
||||
[/#function]
|
||||
|
||||
[#--
|
||||
-- Returns the trimmed text "s" making sure it is terminated by a dot if the
|
||||
-- text is composed of multiple phrases, if the text is composed of a single
|
||||
-- phrase then makes sure it is *not* terminated by a dot.
|
||||
-- A phrase is recognized by the pattern ". " into the text.
|
||||
-- The empty string is always returned as an empty string, the dot is never
|
||||
-- added.
|
||||
--]
|
||||
[#function IntelligentDot s]
|
||||
[#local s = s?trim /]
|
||||
[#if s?contains(". ")]
|
||||
[#return WithDot(s) /]
|
||||
[/#if]
|
||||
[#return WithoutDot(s) /]
|
||||
[/#function]
|
||||
|
||||
[#--
|
||||
-- Formats a text string in a sequence of strings no longer than "len" (first
|
||||
-- line) or "lenn" (subsequent lines).
|
||||
-- White spaces are normalized between words, sequences of white spaces become
|
||||
-- a single space.
|
||||
--]
|
||||
[#function StringToText len1 lenn s]
|
||||
[#local words=s?word_list /]
|
||||
[#local line="" /]
|
||||
[#local lines=[] /]
|
||||
[#list words as word]
|
||||
[#if lines?size == 0]
|
||||
[#local len = len1 /]
|
||||
[#else]
|
||||
[#local len = lenn /]
|
||||
[/#if]
|
||||
[#if (line?length + word?length + 1 > len)]
|
||||
[#local lines = lines + [line?trim] /]
|
||||
[#local line = word + " " /]
|
||||
[#else]
|
||||
[#local line = line + word + " " /]
|
||||
[/#if]
|
||||
[/#list]
|
||||
[#if line != ""]
|
||||
[#local lines = lines + [line?trim] /]
|
||||
[/#if]
|
||||
[#return lines /]
|
||||
[/#function]
|
||||
|
||||
[#--
|
||||
-- Emits a string "s" as a formatted text, the first line is prefixed by the
|
||||
-- "p1" parameter, subsequent lines are prefixed by the "pn" paramenter.
|
||||
-- Emitted lines are no longer than the "len" parameter.
|
||||
-- White spaces are normalized between words.
|
||||
--]
|
||||
[#macro FormatStringAsText p1 pn s len]
|
||||
[#local lines = StringToText(len - p1?length, len - pn?length, s) /]
|
||||
[#list lines as line]
|
||||
[#if line_index == 0]
|
||||
${p1}${line}
|
||||
[#else]
|
||||
${pn}${line}
|
||||
[/#if]
|
||||
[/#list]
|
||||
[/#macro]
|
||||
|
||||
[#--
|
||||
-- Emits a C function body code reformatting the indentation using the
|
||||
-- specified tab size and line prefix.
|
||||
--]
|
||||
[#macro EmitIndentedCCode start tab ccode]
|
||||
[#assign lines = ccode?string?split("^", "rm") /]
|
||||
[#list lines as line]
|
||||
[#if (line_index > 0) || (line?trim?length > 0)]
|
||||
[#if line?trim?length > 0]
|
||||
[#if line[0] == "#"]
|
||||
${line?chop_linebreak}
|
||||
[#else]
|
||||
${start + line?chop_linebreak}
|
||||
[/#if]
|
||||
[#else]
|
||||
|
||||
[/#if]
|
||||
[/#if]
|
||||
[/#list]
|
||||
[/#macro]
|
|
@ -0,0 +1,74 @@
|
|||
[#ftl]
|
||||
[#import "/@ftllibs/libutils.ftl" as utils /]
|
||||
[@pp.dropOutputFile /]
|
||||
[@pp.changeOutputFile name="test_root.c" /]
|
||||
[#list conf.*.application.instances.instance as inst]
|
||||
[#if inst.@id?string == "org.chibios.spc5.components.portable.chibios_unitary_tests_engine"]
|
||||
[#assign instance = inst /]
|
||||
[#break]
|
||||
[/#if]
|
||||
[/#list]
|
||||
[@utils.EmitIndentedCCode "" 2 instance.description.copyright.value[0] /]
|
||||
|
||||
/**
|
||||
* @mainpage Test Suite Specification
|
||||
[#if instance.description.introduction.value[0]?trim != ""]
|
||||
[@utils.FormatStringAsText " * "
|
||||
" * "
|
||||
utils.WithDot(instance.description.introduction.value[0]?trim?cap_first)
|
||||
72 /]
|
||||
[#else]
|
||||
* No introduction.
|
||||
[/#if]
|
||||
*
|
||||
* <h2>Test Sequences</h2>
|
||||
[#if instance.sequences.sequence?size > 0]
|
||||
[#list instance.sequences.sequence as sequence]
|
||||
* - @subpage test_sequence_${(sequence_index + 1)?string("000")}
|
||||
[/#list]
|
||||
* .
|
||||
[#else]
|
||||
* No test sequences defined in the test suite.
|
||||
[/#if]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file test_root.c
|
||||
* @brief Test Suite root structures code.
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
#include "ch_test.h"
|
||||
#include "test_root.h"
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Array of all the test sequences.
|
||||
*/
|
||||
const testcase_t * const *test_suite[] = {
|
||||
[#list instance.sequences.sequence as sequence]
|
||||
[#if sequence.condition.value[0]?trim?length > 0]
|
||||
#if (${sequence.condition.value[0]}) || defined(__DOXYGEN__)
|
||||
[/#if]
|
||||
test_sequence_${(sequence_index + 1)?string("000")},
|
||||
[#if sequence.condition.value[0]?trim?length > 0]
|
||||
#endif
|
||||
[/#if]
|
||||
[/#list]
|
||||
NULL
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Shared code. */
|
||||
/*===========================================================================*/
|
||||
|
||||
[#if instance.global_data_and_code.global_code.value[0]?trim?length > 0]
|
||||
[@utils.EmitIndentedCCode "" 2 instance.global_data_and_code.global_code.value[0] /]
|
||||
|
||||
[/#if]
|
||||
#endif /* !defined(__DOXYGEN__) */
|
|
@ -0,0 +1,50 @@
|
|||
[#ftl]
|
||||
[#import "/@ftllibs/libutils.ftl" as utils /]
|
||||
[@pp.dropOutputFile /]
|
||||
[@pp.changeOutputFile name="test_root.h" /]
|
||||
[#list conf.*.application.instances.instance as inst]
|
||||
[#if inst.@id?string == "org.chibios.spc5.components.portable.chibios_unitary_tests_engine"]
|
||||
[#assign instance = inst /]
|
||||
[#break]
|
||||
[/#if]
|
||||
[/#list]
|
||||
[@utils.EmitIndentedCCode "" 2 instance.description.copyright.value[0] /]
|
||||
|
||||
/**
|
||||
* @file test_root.h
|
||||
* @brief Test Suite root structures header.
|
||||
*/
|
||||
|
||||
#ifndef TEST_ROOT_H
|
||||
#define TEST_ROOT_H
|
||||
|
||||
[#list instance.sequences.sequence as sequence]
|
||||
#include "test_sequence_${(sequence_index + 1)?string("000")}.h"
|
||||
[/#list]
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
extern const testcase_t * const *test_suite[];
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Shared definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
[#if instance.global_data_and_code.global_definitions.value[0]?trim?length > 0]
|
||||
[@utils.EmitIndentedCCode "" 2 instance.global_data_and_code.global_definitions.value[0] /]
|
||||
|
||||
[/#if]
|
||||
#endif /* !defined(__DOXYGEN__) */
|
||||
|
||||
#endif /* TEST_ROOT_H */
|
|
@ -0,0 +1,210 @@
|
|||
[#ftl]
|
||||
[#import "/@ftllibs/libutils.ftl" as utils /]
|
||||
[@pp.dropOutputFile /]
|
||||
[#list conf.*.application.instances.instance as inst]
|
||||
[#if inst.@id?string == "org.chibios.spc5.components.portable.chibios_unitary_tests_engine"]
|
||||
[#assign instance = inst /]
|
||||
[#break]
|
||||
[/#if]
|
||||
[/#list]
|
||||
[#list instance.sequences.sequence as sequence]
|
||||
[@pp.changeOutputFile name="test_sequence_" + (sequence_index + 1)?string("000") + ".c" /]
|
||||
[@utils.EmitIndentedCCode "" 2 instance.description.copyright.value[0] /]
|
||||
|
||||
#include "hal.h"
|
||||
#include "ch_test.h"
|
||||
#include "test_root.h"
|
||||
|
||||
/**
|
||||
* @file test_sequence_${(sequence_index + 1)?string("000")}.c
|
||||
* @brief Test Sequence ${(sequence_index + 1)?string("000")} code.
|
||||
*
|
||||
* @page test_sequence_${(sequence_index + 1)?string("000")} [${(sequence_index + 1)?string}] ${utils.WithoutDot(sequence.brief.value[0]?string)}
|
||||
*
|
||||
* File: @ref test_sequence_${(sequence_index + 1)?string("000")}.c
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
[@utils.FormatStringAsText " * "
|
||||
" * "
|
||||
utils.WithDot(sequence.description.value[0]?string)
|
||||
72 /]
|
||||
*
|
||||
[#if sequence.condition.value[0]?trim?length > 0]
|
||||
* <h2>Conditions</h2>
|
||||
* This sequence is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - ${sequence.condition.value[0]}
|
||||
* .
|
||||
*
|
||||
[/#if]
|
||||
* <h2>Test Cases</h2>
|
||||
[#if sequence.cases.case?size > 0]
|
||||
[#list sequence.cases.case as case]
|
||||
* - @subpage test_${(sequence_index + 1)?string("000")}_${(case_index + 1)?string("000")}
|
||||
[/#list]
|
||||
* .
|
||||
[#else]
|
||||
* No test cases defined in the test sequence.
|
||||
[/#if]
|
||||
*/
|
||||
|
||||
[#if sequence.condition.value[0]?trim?length > 0]
|
||||
#if (${sequence.condition.value[0]}) || defined(__DOXYGEN__)
|
||||
|
||||
[/#if]
|
||||
/****************************************************************************
|
||||
* Shared code.
|
||||
****************************************************************************/
|
||||
|
||||
[#if sequence.shared_code.value[0]?trim?length > 0]
|
||||
[@utils.EmitIndentedCCode "" 2 sequence.shared_code.value[0] /]
|
||||
[/#if]
|
||||
|
||||
/****************************************************************************
|
||||
* Test cases.
|
||||
****************************************************************************/
|
||||
|
||||
[#list sequence.cases.case as case]
|
||||
[#-- Building the sequence of the requirements covered by
|
||||
this test case.--]
|
||||
[#assign reqseq = [] /]
|
||||
[#list case.steps.step as step]
|
||||
[#assign reqseq = reqseq + step.tags.value[0]?string?trim?word_list /]
|
||||
[/#list]
|
||||
[#assign reqseq = reqseq?sort /]
|
||||
[#-- Checking if a condition should be generated.--]
|
||||
[#if case.condition.value[0]?trim?length > 0]
|
||||
#if (${case.condition.value[0]?trim}) || defined(__DOXYGEN__)
|
||||
[/#if]
|
||||
[#-- Header generation.--]
|
||||
/**
|
||||
* @page test_${(sequence_index + 1)?string("000")}_${(case_index + 1)?string("000")} [${(sequence_index + 1)?string}.${(case_index + 1)?string}] ${utils.WithoutDot(case.brief.value[0])}
|
||||
*
|
||||
* <h2>Description</h2>
|
||||
[@utils.FormatStringAsText " * "
|
||||
" * "
|
||||
utils.WithDot(case.description.value[0]?string)
|
||||
72 /]
|
||||
*
|
||||
[#if case.condition.value[0]?trim?length > 0]
|
||||
* <h2>Conditions</h2>
|
||||
* This test is only executed if the following preprocessor condition
|
||||
* evaluates to true:
|
||||
* - ${case.condition.value[0]}
|
||||
* .
|
||||
*
|
||||
[/#if]
|
||||
* <h2>Test Steps</h2>
|
||||
[#list case.steps.step as step]
|
||||
[@utils.FormatStringAsText " * - "
|
||||
" * "
|
||||
utils.WithDot("[" + (sequence_index + 1)?string + "." + (case_index + 1)?string + "." + (step_index + 1)?string + "] " + step.description.value[0]?string)
|
||||
72 /]
|
||||
[/#list]
|
||||
[#if case.steps.step?size > 0]
|
||||
* .
|
||||
[/#if]
|
||||
[#if reqseq?size > 0]
|
||||
* <h2>Covered Requirements</h2>
|
||||
[#assign reqs = "" /]
|
||||
[#list reqseq as r]
|
||||
[#assign reqs = reqs + r /]
|
||||
[#if r_has_next]
|
||||
[#assign reqs = reqs + ", " /]
|
||||
[/#if]
|
||||
[/#list]
|
||||
[@utils.FormatStringAsText " * "
|
||||
" * "
|
||||
utils.WithDot(reqs)
|
||||
72 /]
|
||||
[/#if]
|
||||
*/
|
||||
|
||||
[#if case.various_code.setup_code.value[0]?trim?length > 0]
|
||||
static void test_${(sequence_index + 1)?string("000")}_${(case_index + 1)?string("000")}_setup(void) {
|
||||
[@utils.EmitIndentedCCode " " 2 case.various_code.setup_code.value[0] /]
|
||||
}
|
||||
|
||||
[/#if]
|
||||
[#if case.various_code.teardown_code.value[0]?trim?length > 0]
|
||||
static void test_${(sequence_index + 1)?string("000")}_${(case_index + 1)?string("000")}_teardown(void) {
|
||||
[@utils.EmitIndentedCCode " " 2 case.various_code.teardown_code.value[0] /]
|
||||
}
|
||||
|
||||
[/#if]
|
||||
static void test_${(sequence_index + 1)?string("000")}_${(case_index + 1)?string("000")}_execute(void) {
|
||||
[#if case.various_code.local_variables.value[0]?trim?length > 0]
|
||||
[@utils.EmitIndentedCCode " " 2 case.various_code.local_variables.value[0] /]
|
||||
[/#if]
|
||||
[#list case.steps.step as step]
|
||||
|
||||
[@utils.FormatStringAsText " /* "
|
||||
" "
|
||||
utils.WithDot("[" + (sequence_index + 1)?string + "." + (case_index + 1)?string + "." + (step_index + 1)?string + "] " + step.description.value[0]?string) + "*/"
|
||||
72 /]
|
||||
test_set_step(${(step_index + 1)?string});
|
||||
{
|
||||
[#if step.tags.value[0]?string?trim != ""]
|
||||
[#assign reqseq = step.tags.value[0]?string?trim?word_list?sort /]
|
||||
[#assign reqs = "" /]
|
||||
[#list reqseq as r]
|
||||
[#assign reqs = reqs + r /]
|
||||
[#if r_has_next]
|
||||
[#assign reqs = reqs + ", " /]
|
||||
[/#if]
|
||||
[/#list]
|
||||
[@utils.FormatStringAsText " /* @covers "
|
||||
" "
|
||||
utils.WithDot(reqs) + "*/"
|
||||
72 /]
|
||||
[/#if]
|
||||
[#if step.code.value[0]?trim?length > 0]
|
||||
[@utils.EmitIndentedCCode " " 2 step.code.value[0] /]
|
||||
[/#if]
|
||||
}
|
||||
[/#list]
|
||||
}
|
||||
|
||||
static const testcase_t test_${(sequence_index + 1)?string("000")}_${(case_index + 1)?string("000")} = {
|
||||
"${utils.WithoutDot(case.brief.value[0]?string)}",
|
||||
[#if case.various_code.setup_code.value[0]?trim?length > 0]
|
||||
test_${(sequence_index + 1)?string("000")}_${(case_index + 1)?string("000")}_setup,
|
||||
[#else]
|
||||
NULL,
|
||||
[/#if]
|
||||
[#if case.various_code.teardown_code.value[0]?trim?length > 0]
|
||||
test_${(sequence_index + 1)?string("000")}_${(case_index + 1)?string("000")}_teardown,
|
||||
[#else]
|
||||
NULL,
|
||||
[/#if]
|
||||
test_${(sequence_index + 1)?string("000")}_${(case_index + 1)?string("000")}_execute
|
||||
};
|
||||
[#if case.condition.value[0]?trim?length > 0]
|
||||
#endif /* ${case.condition.value[0]?trim} */
|
||||
[/#if]
|
||||
|
||||
[/#list]
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief ${utils.WithDot(sequence.brief.value[0]?string)}
|
||||
*/
|
||||
const testcase_t * const test_sequence_${(sequence_index + 1)?string("000")}[] = {
|
||||
[#list sequence.cases.case as case]
|
||||
[#if case.condition.value[0]?trim?length > 0]
|
||||
#if (${case.condition.value[0]?trim}) || defined(__DOXYGEN__)
|
||||
[/#if]
|
||||
&test_${(sequence_index + 1)?string("000")}_${(case_index + 1)?string("000")},
|
||||
[#if case.condition.value[0]?trim?length > 0]
|
||||
#endif
|
||||
[/#if]
|
||||
[/#list]
|
||||
NULL
|
||||
};
|
||||
[#if sequence.condition.value[0]?trim?length > 0]
|
||||
|
||||
#endif /* ${sequence.condition.value[0]} */
|
||||
[/#if]
|
||||
[/#list]
|
|
@ -0,0 +1,25 @@
|
|||
[#ftl]
|
||||
[#import "/@ftllibs/libutils.ftl" as utils /]
|
||||
[@pp.dropOutputFile /]
|
||||
[#list conf.*.application.instances.instance as inst]
|
||||
[#if inst.@id?string == "org.chibios.spc5.components.portable.chibios_unitary_tests_engine"]
|
||||
[#assign instance = inst /]
|
||||
[#break]
|
||||
[/#if]
|
||||
[/#list]
|
||||
[#list instance.sequences.sequence as sequence]
|
||||
[@pp.changeOutputFile name="test_sequence_" + (sequence_index + 1)?string("000") + ".h" /]
|
||||
[@utils.EmitIndentedCCode "" 2 instance.description.copyright.value[0] /]
|
||||
|
||||
/**
|
||||
* @file test_sequence_${(sequence_index + 1)?string("000")}.h
|
||||
* @brief Test Sequence ${(sequence_index + 1)?string("000")} header.
|
||||
*/
|
||||
|
||||
#ifndef TEST_SEQUENCE_${(sequence_index + 1)?string("000")}_H
|
||||
#define TEST_SEQUENCE_${(sequence_index + 1)?string("000")}_H
|
||||
|
||||
extern const testcase_t * const test_sequence_${(sequence_index + 1)?string("000")}[];
|
||||
|
||||
#endif /* TEST_SEQUENCE_${(sequence_index + 1)?string("000")}_H */
|
||||
[/#list]
|
Loading…
Reference in New Issue