Index: tools/tools/smoketestsuite/LICENSE =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2017, Shivansh Rai +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Index: tools/tools/smoketestsuite/README.md =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/README.md @@ -0,0 +1,60 @@ +# Smoke testing of base utilities (FreeBSD) + +Test generation tool made as a part of [Google Summer of Code '17 with FreeBSD](https://summerofcode.withgoogle.com/projects/#6426676740227072). +**Refer the [FreeBSD wiki](https://wiki.freebsd.org/SummerOfCode2017/SmokeTestingOfBaseUtilities) for an overview and updates.** + +## Directory Structure +``` +. +├── deprecated_tests +│   └── ........................:: Tests pertaining to initial test plan +└── src ........................:: Automation tool pertaining to new test plan + ├── annotations + │   └── ....................:: Annotation files (generated/user-defined) + ├── generated_tests + │   └── ....................:: Generated atf-sh test scripts + ├── scripts + │ └── ....................:: Handy scripts + ├── generate_test.cpp ......:: Test generator + ├── read_annotations.cpp ...:: Annotation parser + └── utils.cpp ..............:: Index generator +``` + +## Automation tool +An (in-progress) implementation of the automation tool briefly described [here](https://lists.freebsd.org/pipermail/soc-status/2017-July/001079.html). +The following diagram summarizes how different components fit with the testcase-generator - + +![Automation-Tool](architecture.png) + +- - - + +## Dependencies +* Boost C++ libraries : The tool was tested to work with the port `boost-all-1.64.0`. + +## Instructions + +Clone the repository via - +``` +git clone git@github.com:shivansh/smoketestsuite.git ~/smoketestsuite +``` +The location `~/smoketestsuite` is important! If using a different location, the scripts under [src/scripts](src/scripts) need to be updated accordingly (for the time being). + +### Populating groff scripts +* The directory [src/groff](src/groff) should be populated with the relevant groff scripts before proceeding for test generation. These scripts are available in the FreeBSD source tree. For filtering the utilities section wise, [fetch_groff.sh](src/scripts/fetch_groff.sh) sets the variable `section` to a default value of **1**. This value can be changed at will. However, it should be noted that currently the tool is tested to successfully generate **section 1 utilities** and might probably fail for other section numbers. + +* The variable `src` in [fetch_groff.sh](src/scripts/fetch_groff.sh) should be updated to the local location of the FreeBSD source. The default value is `~/freebsd`. + +* For populating `src/groff`, execute from [src](src) - + ``` + make fetch_utils + make fetch_groff + ``` + +### Generating tests +Execute the following commands inside [src](src) - +``` +make clean +make && make run +``` + +A few demo tests are located in [src/generated_tests](src/generated_tests). Index: tools/tools/smoketestsuite/src/Makefile =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/Makefile @@ -0,0 +1,39 @@ +# $FreeBSD$ +# +# Makefile for building automation tool + +CC = c++ +CFLAGS = -I/usr/local/include -std=c++11 +LIBS = -L/usr/local/lib -lboost_system -lboost_thread +OBJS = utils.o read_annotations.o add_testcase.o generate_test.o + +generate_tests : $(OBJS) + $(CC) $(CFLAGS) -o $(.TARGET) $(.ALLSRC) $(LIBS) + +$(OBJS) : $(.PREFIX).cpp $(.PREFIX).h + $(CC) $(CFLAGS) -c $(.PREFIX).cpp + +.PHONY: clean clean_tests run \ + fetch_groff fetch_utils \ + validate_changes + +clean: + rm -f generate_tests $(OBJS) + +clean_tests: + rm -f generated_tests/* + +run: + @echo Generating annotations... + sh scripts/generate_annot.sh + @echo Generating test files... + ./generate_tests + +fetch_groff: + sh scripts/fetch_groff.sh + +fetch_utils: + sh scripts/fetch_utils.sh + +validate_changes: + sh scripts/validate.sh Index: tools/tools/smoketestsuite/src/add_testcase.h =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/add_testcase.h @@ -0,0 +1,40 @@ +// +// Copyright 2017 Shivansh Rai +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// $FreeBSD$ + +namespace add_testcase { + void + add_known_testcase(std::string, std::string, std::string, \ + std::string, std::ofstream&); + + void + add_unknown_testcase(std::string, std::string, std::string, \ + int, std::string&); + + void + add_noargs_testcase(std::string, std::pair, \ + std::ofstream&); +} Index: tools/tools/smoketestsuite/src/add_testcase.cpp =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/add_testcase.cpp @@ -0,0 +1,168 @@ +// +// Copyright 2017 Shivansh Rai +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// $FreeBSD$ + +#include +#include +#include "add_testcase.h" + +// Adds a test-case for an option with known usage. +void +add_testcase::add_known_testcase(std::string option, + std::string util_with_section, + std::string descr, + std::string output, + std::ofstream& test_script) +{ + std::string testcase_name; + std::string utility = util_with_section.substr(0, + util_with_section.length() - 3); + + // Add testcase name. + test_script << "atf_test_case "; + if (!option.empty()) { + testcase_name = option; + testcase_name.append("_flag"); + } + else + testcase_name = "no_arguments"; + test_script << testcase_name + "\n"; + + // Add testcase description. + test_script << testcase_name + + "_head()\n{\n\tatf_set \"descr\" "; + if (!descr.empty()) + test_script << descr; + else + test_script << "\"Verify the usage of option \'" + option + "\'\""; + test_script << "\n}\n\n"; + + // Add body of the testcase. + test_script << testcase_name + "_body()\n{" + + "\n\tatf_check -s exit:0 -o "; + + // Match the usage output if generated. + if (!output.empty()) + test_script << "inline:\"" + output + "\" "; + else + test_script << "empty "; + test_script << utility; + if (!option.empty()) + test_script << " -" + option; + test_script << "\n}\n\n"; +} + +// Adds a test-case for an option with unknown usage. +void +add_testcase::add_unknown_testcase(std::string option, + std::string util_with_section, + std::string output, + int exitstatus, + std::string& testcase_buffer) +{ + std::string utility = util_with_section.substr(0, + util_with_section.length() - 3); + + testcase_buffer.append("\n\tatf_check -s not-exit:0 -e "); + + // Check if a usage message was produced. + if (!output.compare(0, 6, "usage:")) + testcase_buffer.append("match:\"$usage_output\" "); + else if (!output.empty()) + testcase_buffer.append("inline:\"" + output + "\" "); + else + testcase_buffer.append("empty "); + + testcase_buffer.append(utility); + + if (!option.empty()) + testcase_buffer.append(" -" + option); +} + +// Adds a test-case for usage without any arguments. +void +add_testcase::add_noargs_testcase(std::string util_with_section, + std::pair output, + std::ofstream& test_script) +{ + std::string descr; + std::string utility = util_with_section.substr(0, + util_with_section.length() - 3); + + if (output.second) { + // An error was encountered. + test_script << std::string("atf_test_case no_arguments\n") + + "no_arguments_head()\n{\n\tatf_set \"descr\" "; + if (!output.first.empty()) { + // We expect a usage message to be generated in this case. + if (!output.first.compare(0, 6, "usage:")) { + descr = "\"Verify that " + util_with_section + + " fails and generates a valid usage" + + " message when no arguments are supplied\""; + + test_script << descr + "\n}\n\nno_arguments_body()\n{" + + "\n\tatf_check -s not-exit:0 -e match:\"$usage_output\" " + + utility; + } + else { + descr = "\"Verify that " + util_with_section + + " fails and generates a valid output" + + " when no arguments are supplied\""; + + test_script << descr + "\n}\n\nno_arguments_body()\n{" + + "\n\tatf_check -s not-exit:0 -e inline:\"" + + output.first + "\" " + + utility; + } + } + + else { + descr = "\"Verify that " + util_with_section + + "fails silently when no arguments are supplied\"" ; + test_script << descr + "\n}\n\nno_arguments_body()\n{" + + "\n\tatf_check -s not-exit:0 -e empty " + + utility; + } + + test_script << "\n}\n\n"; + } + + else { + // The command ran successfully, hence we guessed + // a correct usage for the utility under test. + if (!output.first.empty()) + descr = "\"Verify that " + util_with_section + + " executes successfully and produces a valid" + + " output when invoked without any arguments\""; + else + descr = "\"Verify that " + util_with_section + + " executes successfully and silently" + + " when invoked without any arguments\""; + + add_testcase::add_known_testcase("", util_with_section, descr, + output.first, test_script); + } +} Index: tools/tools/smoketestsuite/src/annotations/date_test.annot =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/annotations/date_test.annot @@ -0,0 +1,5 @@ +R_flag +j_flag +n_flag +no_arguments +u_flag Index: tools/tools/smoketestsuite/src/generate_test.h =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/generate_test.h @@ -0,0 +1,33 @@ +// +// Copyright 2017 Shivansh Rai +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// $FreeBSD$ + +#include "utils.h" + +namespace generate_test { + std::pair exec(const char*); + void generate_test(std::string, std::string); +} Index: tools/tools/smoketestsuite/src/generate_test.cpp =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/generate_test.cpp @@ -0,0 +1,290 @@ +// +// Copyright 2017 Shivansh Rai +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// $FreeBSD$ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "generate_test.h" +#include "add_testcase.h" +#include "read_annotations.h" + +#define TIMEOUT 1 // threshold (seconds) for a function call to return. + +// Executes the passed argument "cmd" in a shell +// and returns its output and the exit status. +std::pair +generate_test::exec(const char* cmd) +{ + const int bufsize = 128; + std::array buffer; + std::string usage_output; + FILE* pipe = popen(cmd, "r"); + + if (!pipe) + throw std::runtime_error("popen() failed!"); + + try { + while (!feof(pipe)) + if (std::fgets(buffer.data(), bufsize, pipe) != NULL) + usage_output += buffer.data(); + } + catch(...) { + pclose(pipe); + throw "Unable to execute the command: " + std::string(cmd); + } + + return std::make_pair + ((std::string)usage_output, WEXITSTATUS(pclose(pipe))); +} + +// Generate a test for the given utility. +void +generate_test::generate_test(std::string utility, + std::string section) +{ + std::list ident_opt_list; // List of identified option relations. + std::vector usage_messages; // Vector to store usage messages for comparison. + std::string command; // Command to be executed in shell. + std::string descr; // Testcase description. + std::string testcase_list; // List of testcases. + std::string testcase_buffer; // Buffer for (temporarily) holding testcase data. + std::string test_file; // atf-sh test name. + std::string util_with_section; // Section number appended to utility. + std::ofstream test_ofs; // Output stream for the atf-sh test. + std::ifstream license_ifs; // Input stream for license. + std::pair output; // Return value type for `exec()`. + std::unordered_set annot; // Hashset of utility specific annotations. + int temp; + + // Read annotations and populate hash set "annot". + annotations::read_annotations(utility, annot); + + util_with_section = utility + '(' + section + ')'; + + utils::opt_def f_opts; + ident_opt_list = f_opts.check_opts(utility); + test_file = "generated_tests/" + utility + "_test.sh"; + + // Add license in the generated test scripts. + test_ofs.open(test_file, std::ios::out); + license_ifs.open("license", std::ios::in); + + test_ofs << license_ifs.rdbuf(); + license_ifs.close(); + + // If a known option was encountered (i.e. `ident_opt_list` is + // populated), produce a testcase to check the validity of the + // result of that option. If no known option was encountered, + // produce testcases to verify the correct (generated) usage + // message when using the supported options incorrectly. + + // Add testcases for known options. + if (!ident_opt_list.empty()) { + for (const auto &i : ident_opt_list) { + command = utility + " -" + i->value + " 2>&1"; + output = generate_test::exec(command.c_str()); + if (!output.first.compare(0, 6, "usage:")) { + add_testcase::add_known_testcase(i->value, util_with_section, + descr, output.first, test_ofs); + } + else { + // A usage message was produced, i.e. we + // failed to guess the correct usage. + add_testcase::add_unknown_testcase(i->value, util_with_section, output.first, + output.second, testcase_buffer); + } + testcase_list.append("\tatf_add_test_case " + i->value + "_flag\n"); + } + } + + // Add testcases for the options whose usage is not known (yet). + if (!f_opts.opt_list.empty()) { + + // For the purpose of adding a "$usage_output" variable, + // we choose the option which produces one. + // TODO Avoid double executions of an option, i.e. one while + // selecting usage message and another while generating testcase. + + if (f_opts.opt_list.size() == 1) { + // Utility supports a single option, check if it produces a usage message. + command = utility + " -" + f_opts.opt_list.front() + " 2>&1"; + output = generate_test::exec(command.c_str()); + + if (output.second) + test_ofs << "usage_output=\'" + output.first + "\'\n\n"; + } + + else { + // Utility supports multiple options. In case the usage message + // is consistent for atleast "two" options, we reduce duplication + // by assigning a variable "usage_output" in the test script. + for (const auto &i : f_opts.opt_list) { + command = utility + " -" + i + " 2>&1"; + output = generate_test::exec(command.c_str()); + + if (output.second && usage_messages.size() < 3) + usage_messages.push_back(output.first); + } + + temp = usage_messages.size(); + for (int j = 0; j < temp; j++) { + if (!(usage_messages.at(j)).compare(usage_messages.at((j+1) % temp))) { + test_ofs << "usage_output=\'" + + output.first.substr(0, 7 + utility.size()) + + "\'\n\n"; + break; + } + } + } + + // Execute the utility with supported options + // and add (+ve)/(-ve) testcases accordingly. + for (const auto &i : f_opts.opt_list) { + // If the option is annotated, skip it. + if (annot.find(i) != annot.end()) + continue; + + command = utility + " -" + i + " 2>&1"; + output = generate_test::exec(command.c_str()); + + if (output.second) { + // Non-zero exit status was encountered. + add_testcase::add_unknown_testcase(i, util_with_section, output.first, + output.second, testcase_buffer); + } + else { + // EXIT_SUCCESS was encountered. Hence, + // the guessed usage was correct. + add_testcase::add_known_testcase(i, util_with_section, "", + output.first, test_ofs); + testcase_list.append(std::string("\tatf_add_test_case ") + + i + "_flag\n"); + } + } + + testcase_list.append("\tatf_add_test_case invalid_usage\n"); + test_ofs << std::string("atf_test_case invalid_usage\ninvalid_usage_head()\n") + + "{\n\tatf_set \"descr\" \"Verify that an invalid usage " + + "with a supported option produces a valid error message" + + "\"\n}\n\ninvalid_usage_body()\n{"; + + test_ofs << testcase_buffer + "\n}\n\n"; + } + + // Add a testcase under "no_arguments" for + // running the utility without any arguments. + if (annot.find("*") == annot.end()) { + command = utility + " 2>&1"; + output = generate_test::exec(command.c_str()); + add_testcase::add_noargs_testcase(util_with_section, output, test_ofs); + testcase_list.append("\tatf_add_test_case no_arguments\n"); + } + + test_ofs << "atf_init_test_cases()\n{\n" + testcase_list + "}\n"; + test_ofs.close(); +} + +int +main() +{ + std::ifstream groff_list; + std::list> utility_list; + std::string test_file; // atf-sh test name. + std::string util_name; // Utility name. + struct stat buffer; + struct dirent *ent; + DIR *dir; + char answer; // User input to determine overwriting of test files. + int flag = 0; + + // For testing (or generating tests for only selected utilities), + // the utility_list can be populated above during declaration. + if (utility_list.empty()) { + if ((dir = opendir("groff"))) { + while ((ent = readdir(dir))) { + util_name = ent->d_name; + utility_list.push_back(std::make_pair + (util_name.substr(0, util_name.length() - 2), + util_name.substr(util_name.length() - 1, 1))); + } + closedir(dir); + } + else { + fprintf(stderr, "Could not open directory: groff/"); + return EXIT_FAILURE; + } + } + + for (const auto &util : utility_list) { + test_file = "generated_tests/" + util.first + "_test.sh"; + + // Check if the test file already exists. In + // case it does, confirm before proceeding. + if (!flag && !stat(test_file.c_str(), &buffer)) { + std::cout << "Test file(s) already exists. Overwrite? [y/n] "; + std::cin >> answer; + + switch (answer) { + case 'n': + case 'N': + fprintf(stderr, "Stopping execution\n"); + flag = 1; + break; + + default: + // TODO capture newline character + flag = 1; + break; + } + } + + std::cout << "Generating test for: " + util.first + + '('+ util.second + ')' << " ..."; + + boost::thread api_caller(generate_test::generate_test, util.first, util.second); + if (api_caller.timed_join(boost::posix_time::seconds(TIMEOUT))) { + // API call successfully returned within TIMEOUT (seconds). + std::cout << "Successful\n"; + } + else { + // API call timed out. + std::cout << "Failed!\n"; + // Remove the incomplete test file. + remove(("generated_tests/" + util.first + "_test.sh").c_str()); + } + } + + return EXIT_SUCCESS; +} Index: tools/tools/smoketestsuite/src/generated_tests/README.md =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/generated_tests/README.md @@ -0,0 +1,20 @@ +# Generated tests +**NOTE:** The generated tests are maintained at [shivansh/smoketests](https://github.com/shivansh/smoketests). The directory [generated_tests](src/generated_tests) only contains a few demos. +The following table summarizes the type of test-cases produced for 3 (randomly chosen) utilities. + +| **Test** | **Positive test-cases** | **Negative test-cases** | +----------------------------|:-------------------:|:-------------------:| +[date_test.sh](src/generated_tests/date_test.sh) | ~~5~~ 0 | ~~2~~ 6 +[ln_test.sh](src/generated_tests/ln_test.sh) | 0 | 11 +[stdbuf_test.sh](src/generated_tests/stdbuf_test.sh)| 1 | ~~0~~ 3 + +Some key-points worth noting : +* [date_test.sh](src/generated_tests/date_test.sh) is time/timezone dependent, hence all the test-cases apart from `invalid_usage` will fail. The aim for using this utility is to demonstrate that the tool can generate positive test-cases along with negative ones. It also demonstrates the need to sanity check the tests. + - After adding functionality to generate annotations, the 5 timezone dependent testcases were removed. + - Adding functionality for long options increased the number of negative testcases by 4. + +* [ln_test.sh](src/generated_tests/ln_test.sh) demonstrates that if the utility produces a common usage message for every invalid usage, then the tool can define a variable containing this message and avoid duplication while generating the test-cases. Also, all the negative tests are collated under a single testcase named `invalid_usage`. + +* The groff script for `stdbuf(1)` is slightly different than others, hence +the tool couldn’t generate any negative test-case in [stdbuf_test.sh](src/generated_tests/stdbuf_test.sh) as it couldn't pick up the supported options. This scenario will be taken into account next. The aim for using this utility is to demonstrate that the tool will always produce atleast one positive/negative testcase. + - Adding functionality for long options increased the number of negative testcases by 3. Index: tools/tools/smoketestsuite/src/generated_tests/date_test.sh =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/generated_tests/date_test.sh @@ -0,0 +1,66 @@ +# +# Copyright 2017 Shivansh Rai +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +atf_test_case invalid_usage +invalid_usage_head() +{ + atf_set "descr" "Verify that an invalid usage with a supported option produces a valid error message" +} + +invalid_usage_body() +{ + atf_check -s not-exit:0 -e inline:"date: option requires an argument -- d +usage: date [-jnRu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ... + [-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format] +" date -d + atf_check -s not-exit:0 -e inline:"date: option requires an argument -- f +usage: date [-jnRu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ... + [-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format] +" date -f + atf_check -s not-exit:0 -e inline:"date: option requires an argument -- r +usage: date [-jnRu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ... + [-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format] +" date -r + atf_check -s not-exit:0 -e inline:"date: option requires an argument -- r +usage: date [-jnRu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ... + [-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format] +" date -r + atf_check -s not-exit:0 -e inline:"date: option requires an argument -- t +usage: date [-jnRu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ... + [-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format] +" date -t + atf_check -s not-exit:0 -e inline:"date: option requires an argument -- v +usage: date [-jnRu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ... + [-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format] +" date -v +} + +atf_init_test_cases() +{ + atf_add_test_case invalid_usage +} Index: tools/tools/smoketestsuite/src/generated_tests/ln_test.sh =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/generated_tests/ln_test.sh @@ -0,0 +1,66 @@ +# +# Copyright 2017 Shivansh Rai +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +usage_output='usage: ln' + +atf_test_case invalid_usage +invalid_usage_head() +{ + atf_set "descr" "Verify that an invalid usage with a supported option produces a valid error message" +} + +invalid_usage_body() +{ + atf_check -s not-exit:0 -e match:"$usage_output" ln -F + atf_check -s not-exit:0 -e match:"$usage_output" ln -L + atf_check -s not-exit:0 -e match:"$usage_output" ln -P + atf_check -s not-exit:0 -e match:"$usage_output" ln -f + atf_check -s not-exit:0 -e match:"$usage_output" ln -h + atf_check -s not-exit:0 -e match:"$usage_output" ln -i + atf_check -s not-exit:0 -e match:"$usage_output" ln -n + atf_check -s not-exit:0 -e match:"$usage_output" ln -s + atf_check -s not-exit:0 -e match:"$usage_output" ln -v + atf_check -s not-exit:0 -e match:"$usage_output" ln -w +} + +atf_test_case no_arguments +no_arguments_head() +{ + atf_set "descr" "Verify that ln(1) fails and generates a valid usage message when no arguments are supplied" +} + +no_arguments_body() +{ + atf_check -s not-exit:0 -e match:"$usage_output" ln +} + +atf_init_test_cases() +{ + atf_add_test_case invalid_usage + atf_add_test_case no_arguments +} Index: tools/tools/smoketestsuite/src/generated_tests/mkdir_test.sh =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/generated_tests/mkdir_test.sh @@ -0,0 +1,61 @@ +# +# Copyright 2017 Shivansh Rai +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +usage_output='usage: mkdir' + +atf_test_case invalid_usage +invalid_usage_head() +{ + atf_set "descr" "Verify that an invalid usage with a supported option produces a valid error message" +} + +invalid_usage_body() +{ + atf_check -s not-exit:0 -e inline:"mkdir: option requires an argument -- m +usage: mkdir [-pv] [-m mode] directory_name ... +" mkdir -m + atf_check -s not-exit:0 -e match:"$usage_output" mkdir -p + atf_check -s not-exit:0 -e match:"$usage_output" mkdir -v +} + +atf_test_case no_arguments +no_arguments_head() +{ + atf_set "descr" "Verify that mkdir(1) fails and generates a valid usage message when no arguments are supplied" +} + +no_arguments_body() +{ + atf_check -s not-exit:0 -e match:"$usage_output" mkdir +} + +atf_init_test_cases() +{ + atf_add_test_case invalid_usage + atf_add_test_case no_arguments +} Index: tools/tools/smoketestsuite/src/generated_tests/rmdir_test.sh =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/generated_tests/rmdir_test.sh @@ -0,0 +1,58 @@ +# +# Copyright 2017 Shivansh Rai +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +usage_output='usage: rmdir' + +atf_test_case invalid_usage +invalid_usage_head() +{ + atf_set "descr" "Verify that an invalid usage with a supported option produces a valid error message" +} + +invalid_usage_body() +{ + atf_check -s not-exit:0 -e match:"$usage_output" rmdir -p + atf_check -s not-exit:0 -e match:"$usage_output" rmdir -v +} + +atf_test_case no_arguments +no_arguments_head() +{ + atf_set "descr" "Verify that rmdir(1) fails and generates a valid usage message when no arguments are supplied" +} + +no_arguments_body() +{ + atf_check -s not-exit:0 -e match:"$usage_output" rmdir +} + +atf_init_test_cases() +{ + atf_add_test_case invalid_usage + atf_add_test_case no_arguments +} Index: tools/tools/smoketestsuite/src/generated_tests/stdbuf_test.sh =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/generated_tests/stdbuf_test.sh @@ -0,0 +1,63 @@ +# +# Copyright 2017 Shivansh Rai +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +atf_test_case invalid_usage +invalid_usage_head() +{ + atf_set "descr" "Verify that an invalid usage with a supported option produces a valid error message" +} + +invalid_usage_body() +{ + atf_check -s not-exit:0 -e inline:"stdbuf: option requires an argument -- e +Usage: stdbuf [-e 0|L|] [-i 0|L|] [-o 0|L|] [args ...] +" stdbuf -e + atf_check -s not-exit:0 -e inline:"stdbuf: option requires an argument -- i +Usage: stdbuf [-e 0|L|] [-i 0|L|] [-o 0|L|] [args ...] +" stdbuf -i + atf_check -s not-exit:0 -e inline:"stdbuf: option requires an argument -- o +Usage: stdbuf [-e 0|L|] [-i 0|L|] [-o 0|L|] [args ...] +" stdbuf -o +} + +atf_test_case no_arguments +no_arguments_head() +{ + atf_set "descr" "Verify that stdbuf(1) executes successfully and silently when invoked without any arguments" +} + +no_arguments_body() +{ + atf_check -s exit:0 -o empty stdbuf +} + +atf_init_test_cases() +{ + atf_add_test_case invalid_usage + atf_add_test_case no_arguments +} Index: tools/tools/smoketestsuite/src/license =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/license @@ -0,0 +1,28 @@ +# +# Copyright 2017 Shivansh Rai +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + Index: tools/tools/smoketestsuite/src/read_annotations.h =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/read_annotations.h @@ -0,0 +1,33 @@ +// +// Copyright 2017 Shivansh Rai +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// $FreeBSD$ + +#include + +namespace annotations { + void read_annotations(std::string, \ + std::unordered_set&); +} Index: tools/tools/smoketestsuite/src/read_annotations.cpp =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/read_annotations.cpp @@ -0,0 +1,58 @@ +// +// Copyright 2017 Shivansh Rai +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// $FreeBSD$ + +#include +#include +#include +#include +#include "read_annotations.h" + +// Read the annotation files and skip +// generation of the respective tests. +void +annotations::read_annotations(std::string utility, + std::unordered_set& annot) +{ + std::string line; + // TODO do this for all the annotation files + std::ifstream annot_fstream; + annot_fstream.open("annotations/" + utility + "_test.annot"); + + while (getline(annot_fstream, line)) { + // Add a unique identifier for no_arguments testcase + if (!line.compare(0, 12, "no_arguments")) + annot.insert("*"); + + // Add flag value for supported argument testcases + // Doing so we ignore the "invalid_usage" testcase + // as it is guaranteed to always succeed. + else if (!line.compare(2, 4, "flag")) + annot.insert(line.substr(0, 1)); + } + + annot_fstream.close(); +} Index: tools/tools/smoketestsuite/src/scripts/README.md =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/scripts/README.md @@ -0,0 +1,8 @@ +# Handy scripts + +Script Name | Functionality +----------- | ------------- +[fetch_groff.sh](fetch_groff.sh) | Lists location of all section 1 utilities +[fetch_utils.sh](fetch_utils.sh) | Saves all the base utilities in the src tree in **utils_list** +[generate_annot.sh](generate_annot.sh) | Populates annotation files under [annotations](../annotations) +[validate.sh](validate.sh) | Validates side-effects of newly introduced changes in the tool Index: tools/tools/smoketestsuite/src/scripts/fetch_groff.sh =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/scripts/fetch_groff.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# +# Copyright 2017 Shivansh Rai +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# Script for listing location of groff scripts of utilities in section 1. + +set -e + +src="$HOME/freebsd" +dir_list="$HOME/smoketestsuite/src/scripts/utils_list" +groff_src="$HOME/smoketestsuite/src/groff" +section=1 # Section number for filtering the base utilities + +rm -rf "$groff_src" && mkdir "$groff_src" +cd "$src" + +while IFS= read -r dir_entry +do + for file in "$dir_entry"/* + do + case "$file" in + *."$section") cp "$file" "$HOME/smoketestsuite/src/groff/" + esac + done +done< "$dir_list" Index: tools/tools/smoketestsuite/src/scripts/fetch_utils.sh =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/scripts/fetch_utils.sh @@ -0,0 +1,42 @@ +#! /bin/sh +# +# Copyright 2017 Shivansh Rai +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# Script for listing all the base utilities in FreeBSD. +# The output "utils_list" of this script is required by "fetch_groff.sh". + +set -e +src="$HOME/freebsd" +dir="$HOME/smoketestsuite/src/scripts" + +fetch_utils() { + cd "$src" + find . -name Makefile | xargs grep -l 'PROG\|PROG_CXX' \ + | sed -e 's|/Makefile$||' | cut -c 3- +} + +rm -f utils_list + +(fetch_utils) >> "$dir/utils_list" Index: tools/tools/smoketestsuite/src/scripts/generate_annot.sh =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/scripts/generate_annot.sh @@ -0,0 +1,92 @@ +#!/bin/sh +# +# Copyright 2017 Shivansh Rai +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# +# Script for generating annotations based on generated tests. + +pwd=$(pwd) +suffix="_test" +extension=".sh" +update_required=0 + +message="Following annotation files were updated. \n" + +printf " ++--------------------------------------------------+ +| Checking if any annotation file is to be updated | ++--------------------------------------------------+\n" + +for f in "generated_tests"/* +do + annotations="" + file=$(basename "$f") + test=${file%$extension} + utility=${test%$suffix} + test_dir="/usr/tests/bin/$utility" + + ( + cd "$test_dir" || exit + report=$(kyua report) + i=2 + + while true + do + testcase=$(printf "%s" "$report" | awk 'NR=='"$i"' {print $1}') + status=$(printf "%s" "$report" | awk 'NR=='"$i"' {print $3}') + check=$(printf "%s" "$testcase" | cut -s -f1 -d":") + + if [ "$check" != "$test" ]; then + if [ "$annotations" ]; then + if [ $update_required = 0 ]; then + printf $message + update_required=1 + fi + + annotations_file="$pwd/annotations/$test.annot" + # Append only the new annotations + printf "$annotations" > "$annotations_file.temp" + [ ! -e "$annotations_file" ] && touch "$annotations_file" + comm -13 "$annotations_file" "$annotations_file.temp" >> \ + "$annotations_file" && printf "\t%s\n" "annotations/$test.annot" + rm -f "$annotations_file.temp" + fi + + break + fi + + if [ "$status" = "failed:" ]; then + testcase=${testcase#"$test:"} + annotations="$annotations$testcase\n" + fi + + i=$((i+1)) + done + ) + +done + +printf "==============================================================================\n\n" Index: tools/tools/smoketestsuite/src/scripts/validate.sh =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/scripts/validate.sh @@ -0,0 +1,56 @@ +#!/bin/sh +# +# Copyright 2017 Shivansh Rai +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# Script for validating side-effects of newly introduced changes. + +remote=origin + +git checkout testing +if [ $? != 0 ]; then + git fetch && git checkout $remote/testing && git checkout -b testing +fi + +git rebase master + +# Generate tests +make +echo 'y\n' | make run + +git status | grep -q generated_tests +if [ $? != 0 ]; then + echo " + +----------------------------------+ + | New changes have no side-effects | + +----------------------------------+ + " + git checkout master +else + echo " + +--------------------------------------------------+ + | New changes introduced side-effects. Stopping... | + +--------------------------------------------------+ + " +fi Index: tools/tools/smoketestsuite/src/utils.h =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/utils.h @@ -0,0 +1,51 @@ +// +// Copyright 2017 Shivansh Rai +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// $FreeBSD$ + +#include +#include + +namespace utils { + + // Option relation which maps option names to + // a unique identifier in their description. + typedef struct opt_rel { + char type; // Option type: (s)short/(l)long. + std::string value; // Name of the option. + std::string keyword; // The keyword which should be looked up in the + // message (if) produced when using this option. + } opt_rel; + + class opt_def { + public: + std::list opt_list; // list of all the accepted options with unknown usage. + std::unordered_map opt_map; // Map "option value" to "option definition". + std::unordered_map::iterator opt_map_iter; + + void insert_opts(); + std::list check_opts(std::string); + }; +} Index: tools/tools/smoketestsuite/src/utils.cpp =================================================================== --- /dev/null +++ tools/tools/smoketestsuite/src/utils.cpp @@ -0,0 +1,130 @@ +// +// Copyright 2017 Shivansh Rai +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +// SUCH DAMAGE. +// +// $FreeBSD$ + +#include +#include +#include +#include "utils.h" + +// Insert a list of user-defined option definitions +// into a hashmap. These specific option definitions +// are the ones which one can be easily tested. +void +utils::opt_def::insert_opts() +{ + // Option definitions. + opt_rel h_def; // '-h' + h_def.type = 's'; + h_def.value = "h"; + h_def.keyword = "help"; + + opt_rel v_def; // '-v' + v_def.type = 's'; + v_def.value = "v"; + v_def.keyword = "version"; + + // `opt_map` contains all the options + // which can be "easily" tested. + opt_map.insert(std::make_pair + ("h", (opt_rel)h_def)); + opt_map.insert(std::make_pair + ("v", (opt_rel)v_def)); +}; + +// For the utility under test, find the supported options +// present in the hashmap generated by insert_opts() +// and return them in a form of list of option relations. +std::list +utils::opt_def::check_opts(std::string utility) +{ + std::string line; // An individual line in a man-page. + std::string opt_name; // Name of the option. + std::string opt_ident = ".It Fl"; // Identifier for an option in man page. + std::string buffer; // Option description extracted from man-page. + std::string opt_string; // Identified option names. + int opt_pos; // Starting index of the (identified) option. + int space_index; // First occurrence of space character + // in a multi-word option definition. + std::list ident_opt_list; // List of identified option relations (opt_rel's). + + // Generate the hashmap opt_map. + insert_opts(); + + // TODO: Section number cannot be hardcoded. + std::ifstream infile("groff/" + utility + ".1"); + + // Search for all the options accepted by the + // utility and collect those present in `opt_map`. + while (std::getline(infile, line)) { + if ((opt_pos = line.find(opt_ident)) != std::string::npos) { + opt_pos += opt_ident.length() + 1; // Locate the position of option name. + + if (opt_pos > line.length()) { + // This condition will trigger when a utility + // supports an empty argument, e.g. tset(issue #9) + continue; + } + + // Check for long options ; While here, also sanitize + // multi-word option definitions in a man page to properly + // extract short options from option definitions such as: + // .It Fl r Ar seconds (taken from date(1)). + if ((space_index = line.find(" ", opt_pos + 1, 1)) + != std::string::npos) + opt_name = line.substr(opt_pos, space_index - opt_pos); + else + opt_name = line.substr(opt_pos); + + // Check if the identified option matches the identifier. + // `opt_list.back()` is the previously checked option, the + // description of which is now stored in `buffer`. + if (!opt_list.empty() && + (opt_map_iter = opt_map.find(opt_list.back())) + != opt_map.end() && + buffer.find((opt_map_iter->second).keyword) != std::string::npos) { + ident_opt_list.push_back(&(opt_map_iter->second)); + + // Since the usage of the option under test + // is known, we remove it from `opt_list`. + opt_list.pop_back(); + } + + // Update the list of valid options. + opt_list.push_back(opt_name); + + // Empty the buffer for next option's description. + buffer.clear(); + } + else { + // Collect the option description until next + // valid option definition is encountered. + buffer.append(line); + } + } + + return ident_opt_list; +}