Skip to content

Commit

Permalink
Merge pull request #8 from karlobermeyer/sp_tests
Browse files Browse the repository at this point in the history
Implement test framework for shortest path calculation
  • Loading branch information
hawkinsw authored Feb 16, 2021
2 parents 3263d85 + df38d4b commit d95c801
Show file tree
Hide file tree
Showing 15 changed files with 470 additions and 8 deletions.
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,23 @@ Description: a subroutine of `visibiity_polygon_demonstration.m` and
`shortest_path_demo.m` used to read a VisiLibity style Environment file into a
Matlab cell array.

## Testing
Testing frameworks are available for visibility polygon and shortest path
calculations.

### Visibility polygon calculation testing
TBD

### Shortest path calculation testing

The script `test_shortest_path.sh` will execute all the tests in the `shortest_path_tests` (by default) directory.

Every test requires three files:
1. `<name>.environment`: The environment in which to find a shortest path between two points. Specify this like any other environment file.
2. `<name>.guards`: The location of 2 (two) points in the environment and not in a hole. The first point is the start point and the second point is the end point. The test will calculate the shortest path between those points with respect to the environment defined in `<name>.environment`.
3. `<name>.result`: The vertices of the shortest path between the points defined in <name>.guards in the environment defined in `<name>.environment`.

The test passes when the path specified in the result file matches the path actually calculated by VisiLibity.

## License

Expand All @@ -146,4 +162,4 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with VisiLibity. If not, see <http://www.gnu.org/licenses/>.
with VisiLibity. If not, see <http://www.gnu.org/licenses/>.
7 changes: 5 additions & 2 deletions src/makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#Phony target.
current_target: main
all: main test_shortest_path


#Compiler flags
Expand All @@ -12,16 +12,19 @@ LDFLAGS = -O2

#Modules
main.o: main.cpp visilibity.hpp
test_shortest_path.o: test_shortest_path.cpp visilibity.hpp
visilibity.o: visilibity.cpp visilibity.hpp


#Executables
main: main.o visilibity.o
g++ -o main $(CXXFLAGS) main.o visilibity.o

test_shortest_path: test_shortest_path.o visilibity.o
g++ -o test_shortest_path $(CXXFLAGS) test_shortest_path.o visilibity.o

clean:
rm main *~ *.o *.do *.db
rm main *~ *.o *.do *.db test_shortest_path
clear
pwd
ls
11 changes: 11 additions & 0 deletions src/shortest_path_tests/test.environment
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//Environment Model
//Outer Boundary x-y coordinates listed counterclockwise
0.0 0.0
10.0 0.0
10.0 10.0
0.0 10.0
//Hole x-y coordinates listed clockwise
4.0 4.0
4.0 7.0
8.0 7.0
8.0 4.0
3 changes: 3 additions & 0 deletions src/shortest_path_tests/test.guards
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//Guard x-y coordinates
1.0 1.0
9.0 9.0
3 changes: 3 additions & 0 deletions src/shortest_path_tests/test.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
1.0 1.0
4.0 7.0
9.0 9.0
11 changes: 11 additions & 0 deletions src/shortest_path_tests/test1.environment
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//Environment Model
//Outer Boundary x-y coordinates listed counterclockwise
0.0 0.0
10.0 0.0
10.0 10.0
0.0 10.0
//Hole x-y coordinates listed clockwise
4.0 4.0
4.0 7.0
8.0 7.0
8.0 4.0
3 changes: 3 additions & 0 deletions src/shortest_path_tests/test1.guards
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//Guard x-y coordinates
1.0 1.0
9.0 9.0
3 changes: 3 additions & 0 deletions src/shortest_path_tests/test1.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
1.0 1.0
4.0 7.0
9.0 9.0
14 changes: 14 additions & 0 deletions src/shortest_path_tests/test2.environment
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//Environment Model
//Outer Boundary x-y coordinates listed counterclockwise
0.0 0.0
10.0 0.0
10.0 10.0
0.0 10.0
//Hole x-y coordinates listed clockwise
2.0 2.0
2.0 3.0
4.0 3.0
///////
7.0 3.0
6.0 4.0
8.0 5.0
3 changes: 3 additions & 0 deletions src/shortest_path_tests/test2.guards
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//Guard x-y coordinates
5.0 1.0
7.0 6.0
3 changes: 3 additions & 0 deletions src/shortest_path_tests/test2.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
5.0000000000 1.0000000000
6.0000000000 4.0000000000
7.0000000000 6.0000000000
136 changes: 136 additions & 0 deletions src/test_shortest_path.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* This program will create a testable scenario based on user input for
* generating the shortest path between two points in an environment and compare
* that with expected results.
*
* Usage:
* ./test_shortest_path <test environment file> <test path start/finish file>
* <test results file>
*
* See README.md for information about the format of these files.
*/

#include "visilibity.hpp" //VisiLibity header file
#include <cmath> //Puts math functions in std namespace
#include <cstdlib> //Gives rand, srand, exit
#include <cstring> //Gives C-string manipulation
#include <ctime> //Gives Unix time
#include <fstream> //File I/O
#include <iostream> //std I/O
#include <sstream> //Gives string streams
#include <string> //Gives string class
#include <vector> //std vectors
//#define NDEBUG //Turns off assert.
#include <cassert>

// ASCII escape sequences for formatting terminal text.
std::string alert("\a"); // Beep
std::string normal("\x1b[0m"); // Designated fg color default bg color
std::string red("\x1b[31m");
std::string red_blink("\x1b[5;31m");
std::string black("\E[30;47m");
std::string green("\E[32m");
std::string yellow("\E[33;40m");
std::string blue("\E[34;47m");
std::string magenta("\x1b[35m");
std::string cyan("\E[36m");
std::string white_bold("\E[1;37;40m");
std::string clear_display("\E[2J");

void print_usage(const char *const self_name) {
std::cout << self_name
<< " <test environment file> <test path start/stop file> <test "
"results file>"
<< std::endl;
std::cout
<< "\tSee README.md for information about the format of these files."
<< std::endl;
}

int main(int argc, char *argv[]) {

// Check whether the user gave us the right number of parameters. If not, tell
// them how to use our program.
if (argc != 4) {
print_usage(argv[0]);
exit(1);
}

// Variables for the filenames specified on the command line.
std::string test_environment_filename(argv[1]);
std::string test_start_finish_filename(argv[2]);
std::string test_results_filename(argv[3]);

// Set the precision of the numbers that we will print to the screen for the
// user to see.
VisiLibity::Unit_Test::set_output_precision();
// Seed the random number generator that we have to use throughout the code.
VisiLibity::Unit_Test::seed_random();

// Set geometric robustness constant
//:WARNING:
// may need to modify epsilon for Environments with greatly varying
// scale of features
double epsilon = 0.000000001;
std::cout << "The robustness constant epsilon is set to " << epsilon
<< std::endl;

// Load geometric environment model from file
std::cout << "Loading test environment file ";
// Print environment filename to screen
std::cout << test_environment_filename << " . . . ";
// Construct Environment object from file
VisiLibity::Environment test_environment(test_environment_filename);
std::cout << green << "OK" << normal << std::endl;

// Load start/finish positions from file
std::cout << "Loading test start/finish file ";
// Print start/finish filename to screen
std::cout << test_start_finish_filename << " . . . ";
// Construct a Guards object from file
VisiLibity::Guards test_start_finish(test_start_finish_filename);
std::cout << green << "OK" << normal << std::endl;

// Load the expected shortest path coordinates from file
std::cout << "Loading expected results file ";
// Print the expected shortest path coordinates filename to screen
std::cout << test_results_filename << " . . . ";
// Construct the Polyline of the expected shortest path from the file
VisiLibity::Polyline expected_shortest_path(test_results_filename);
std::cout << green << "OK" << normal << std::endl;

// Satisfy the preconditions for visibility polygon calculation by snapping
// the observers.
test_start_finish.snap_to_boundary_of(test_environment, epsilon);
test_start_finish.snap_to_vertices_of(test_environment, epsilon);

// Check whether the parameters in the input files make a testable
// scenario.
assert(VisiLibity::Shortest_Path_Test::validate(test_environment, epsilon,
test_start_finish));
std::cout
<< "Shortest path test parameters specified by input files are . . . "
<< green << "OK" << normal << std::endl;

// Compute the shortest path between the two guards.
VisiLibity::Polyline actual_shortest_path = test_environment.shortest_path(
test_start_finish[0], test_start_finish[1], epsilon);

// Print the actual and expected shortest path to help the user debug
// failures.
std::cout << "The (actual) shortest path is" << std::endl
<< magenta << actual_shortest_path << normal << std::endl;
std::cout << "The (expected) shortest path is" << std::endl
<< magenta << expected_shortest_path << normal << std::endl;

// If the actual and expected shortest paths match, then print that the test
// passed and return 0 (no error). Otherwise, Alert the user of failure and
// return 1 (error).
if (actual_shortest_path == expected_shortest_path) {
std::cout << green << "Passed" << normal << std::endl;
return 0;
} else {
std::cout << red << "Failed" << normal << std::endl;
return 1;
}
}
59 changes: 59 additions & 0 deletions src/test_shortest_path.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/bin/bash

# Run all the shortest path tests in the sp_tests directory. See README.md
# for information on how to write tests.

# Set some strings to help us format our results.
green_format='\033[0;32m'
red_format='\033[0;31m'
reset_format='\033[0m'

# Specify that all the shortest path tests are in the shortest_path_tests directory.
sp_tests_dir="shortest_path_tests"

# Make sure that the test binary is available.
make test_shortest_path
if [ $? -ne 0 ]; then
echo -e "${red_format}Error building the testing binary."
exit 1;
fi

# Calculate the list of available tests in the test directory.
tests=$(for i in `ls ${sp_tests_dir}/*`; do echo `basename $i` | awk -F. '{print $1;}' ; done | sort -u);

total_tests=0
passing_tests=0
failing_tests=0

for i in $tests; do
# Make sure that all three required files are present.
if [ \! \( -f ${sp_tests_dir}/$i.environment \) -o \! \( -f ${sp_tests_dir}/$i.guards \) -o \! \( -f ${sp_tests_dir}/$i.result \) ]; then
echo -e "${red_format}Cannot run ${i}: Missing file."
failing_tests=$(( failing_tests + 1 ))
continue
fi

# Run the test.
./test_shortest_path ${sp_tests_dir}/$i.environment ${sp_tests_dir}/$i.guards ${sp_tests_dir}/$i.result

# Handle the result.
if [ $? -ne 0 ]; then
echo "${red_format}Test Failure."
failing_tests=$(( failing_tests + 1 ))
else
echo -e "${green_format}Test Passed."
passing_tests=$(( passing_tests + 1 ))
fi

# No matter what, we ran a test so we have to add 1 to total_tests.
total_tests=$(( total_tests + 1 ))
done

echo "==============================================="
echo "Results:"
echo -e "${green_format}Passing Tests: ${passing_tests}"
echo -e "${red_format}Failing Tests: ${failing_tests}"
echo -e "${reset_format}Total Tests: ${total_tests}"

# The status code will be the number of failing tests.
exit ${failing_tests}
Loading

0 comments on commit d95c801

Please sign in to comment.