Index: src/libbn/tests/CMakeLists.txt
===================================================================
--- src/libbn/tests/CMakeLists.txt	(revision 58590)
+++ src/libbn/tests/CMakeLists.txt	(working copy)
@@ -8,6 +8,7 @@
 BRLCAD_ADDEXEC(tester_bn_poly_synthetic_div bn_poly_synthetic_div.c "libbu;libbn" NO_INSTALL)
 BRLCAD_ADDEXEC(tester_bn_obr bn_obr.c "libbu;libbn" NO_INSTALL)
 BRLCAD_ADDEXEC(tester_bn_chull bn_chull.c "libbu;libbn" NO_INSTALL)
+BRLCAD_ADDEXEC(tester_bn_plane_pt bn_plane_pt.c "libbu;libbn" NO_INSTALL)
 CMAKEFILES(bn_poly_cubic_roots.c bn_poly_quartic_roots.c bn_obr.c)
 
 # For tester_bn_tri_tri_isect_coplanar, the input format is as follows:
@@ -85,6 +86,97 @@
 #  ************ obr.c tests *************
 #add_test(bn_obr_simple			tester_bn_obr) # Default points
 
+#
+#  ************ plane.c tests *************
+
+# For tester_bn_plane_pt, the input format is as follows:
+#
+# tester_bn_plane_pt <function number> <args>
+
+# For function #1 (bn_3pts_collinear), the <args> format is as follows:
+#
+# P0 P1 P2 <expected result>
+#
+# where P0-P2 are the points in question. An individual point is three
+# integer or floating point numbers separated by commas.
+
+add_test(bn_plane_3pts_collinear_false_1        tester_bn_plane_pt 1  0,0,0 1,1,1 6,3,8 0)
+add_test(bn_plane_3pts_collinear_false_2        tester_bn_plane_pt 1 0,0,0 6,3,8 1,1,1 0)
+add_test(bn_plane_3pts_collinear_false_3        tester_bn_plane_pt 1 1,1,1 0,0,0 6,3,8 0)
+add_test(bn_plane_3pts_collinear_false_4        tester_bn_plane_pt 1 1,1,1 6,3,8 0,0,0 0)
+add_test(bn_plane_3pts_collinear_false_5        tester_bn_plane_pt 1 6,3,8 1,1,1 0,0,0  0)
+add_test(bn_plane_3pts_collinear_false_6        tester_bn_plane_pt 1 6,3,8 0,0,0 1,1,1 0)
+add_test(bn_plane_3pts_collinear_same           tester_bn_plane_pt 1 5.3,8.1,9.6 5.3,8.1,9.6 5.3,8.1,9.6 0)
+add_test(bn_plane_3pts_collinear_partial_same_1 tester_bn_plane_pt 1 6,2,4 6,2,4 9.3,8.1,4.6 1)
+# This test fails, but I think that it shouldn't --- it seems to be
+# showing that point order matters since it is the same three points
+# as the preceding and following tests, but makes a different result.
+add_test(bn_plane_3pts_collinear_partial_same_2 tester_bn_plane_pt 1 9.3,8.1,4.6 6,2,4 6,2,4 1)
+add_test(bn_plane_3pts_collinear_partial_same_3 tester_bn_plane_pt 1 6,2,4 9.3,8.1,4.6 6,2,4 1)
+add_test(bn_plane_3pts_collinear_true_1         tester_bn_plane_pt 1 1.8,4.6,2.2 5.4,13.8,6.6 16.2,41.4,19.8 1)
+add_test(bn_plane_3pts_collinear_true_2         tester_bn_plane_pt 1 1.8,4.6,2.2 16.2,41.4,19.8 5.4,13.8,6.6 1)
+add_test(bn_plane_3pts_collinear_true_3         tester_bn_plane_pt 1 5.4,13.8,6.6 1.8,4.6,2.2 16.2,41.4,19.8 1)
+add_test(bn_plane_3pts_collinear_true_4         tester_bn_plane_pt 1 5.4,13.8,6.6 16.2,41.4,19.8 1.8,4.6,2.2 1)
+add_test(bn_plane_3pts_collinear_true_5         tester_bn_plane_pt 1 16.2,41.4,19.8 1.8,4.6,2.2 5.4,13.8,6.6 1)
+add_test(bn_plane_3pts_collinear_true_6         tester_bn_plane_pt 1 16.2,41.4,19.8 5.4,13.8,6.6 1.8,4.6,2.2 1)
+
+# For function #2 (bn_3pts_distinct), the <args> format is as follows:
+#
+#  P0 P1 P2 <expected result>
+#
+# where P0-P2 are the points in question. An individual point
+# is three integer or floating point numbers separated by commas.
+
+add_test(bn_plane_3pts_distinct_false_all       tester_bn_plane_pt 2 5.3,8.6,9.1 5.3,8.6,9.1 5.3,8.6,9.1 0)
+add_test(bn_plane_3pts_distinct_false_1         tester_bn_plane_pt 2 5.3,8.6,9.1 5.3,8.6,9.1 8.7,4.1,9.3 0)
+add_test(bn_plane_3pts_distinct_false_2         tester_bn_plane_pt 2 5.3,8.6,9.1 8.7,4.1,9.3 5.3,8.6,9.1 0)
+add_test(bn_plane_3pts_distinct_false_3         tester_bn_plane_pt 2 8.7,4.1,9.3 5.3,8.6,9.1 5.3,8.6,9.1 0)
+add_test(bn_plane_3pts_distinct_true_1          tester_bn_plane_pt 2 8.7,4.1,9.3 7.5,9.2,4.1 5.3,8.6,9.1 1)
+add_test(bn_plane_3pts_distinct_true_2          tester_bn_plane_pt 2 8.7,4.1,9.3 5.3,8.6,9.1 7.5,9.2,4.1 1)
+add_test(bn_plane_3pts_distinct_true_3          tester_bn_plane_pt 2 5.3,8.6,9.1 8.7,4.1,9.3 7.5,9.2,4.1 1)
+add_test(bn_plane_3pts_distinct_true_4          tester_bn_plane_pt 2 5.3,8.6,9.1 7.5,9.2,4.1 8.7,4.1,9.3 1)
+add_test(bn_plane_3pts_distinct_true_5          tester_bn_plane_pt 2 7.5,9.2,4.1 8.7,4.1,9.3 5.3,8.6,9.1 1)
+add_test(bn_plane_3pts_distinct_true_6          tester_bn_plane_pt 2 7.5,9.2,4.1 5.3,8.6,9.1 8.7,4.1,9.3 1)
+
+# For function #3 (bn_distsq_line3_pt3), the <args> format is as follows:
+#
+#  PT DIR A <expected result>
+#
+# Where PT and DIR define the parametric line in question and A is the
+# point in question.
+
+add_test(bn_plane_distsq_line3_pt3_1            tester_bn_plane_pt 3 0,0,0 1,1,1 0,0,0 0) 
+add_test(bn_plane_distsq_line3_pt3_2            tester_bn_plane_pt 3 -1,-1,-1 1,1,1 0,0,0 0)
+add_test(bn_plane_distsq_line3_pt3_3            tester_bn_plane_pt 3 0,0,0 1,1,1 0,5,0 16.666666)
+add_test(bn_plane_distsq_line3_pt3_4            tester_bn_plane_pt 3 5,6,4 9,3,8 -5,2,4 48.441558)
+
+# For function #4 (bn_distsq_pt3_lseg3_v2), the <args> format is as follows:
+#
+#  A B P <expected return> <expected distance>
+#
+# Where A and B are the endpoints of the line segment, and P is the
+# point in question.
+
+add_test(bn_plane_distsq_pt3_lseg3_v2_case0_1   tester_bn_plane_pt 4 -5,-5,-5 5,5,5 0,0,0 0 0)
+add_test(bn_plane_distsq_pt3_lseg3_v2_case1_1   tester_bn_plane_pt 4 -5,-5,-5 5,5,5 -5,-5,-5 1 0)
+add_test(bn_plane_distsq_pt3_lseg3_v2_case2_1   tester_bn_plane_pt 4 -5,-5,-5 5,5,5 5,5,5 2 0)
+add_test(bn_plane_distsq_pt3_lseg3_v2_case3_1   tester_bn_plane_pt 4 -5,-5,-5 5,5,5 -10,-5,-10 3 50)
+add_test(bn_plane_distsq_pt3_lseg3_v2_case4_1   tester_bn_plane_pt 4 -5,-5,-5 5,5,5 5,10,10 4 50)
+add_test(bn_plane_distsq_pt3_lseg3_v2_case5_1   tester_bn_plane_pt 4 -5,-5,-5 5,5,5 0,-5,-5 5 16.666666)
+
+# For function #5 (bn_mk_plane_3pts), the <args> format is as follows:
+#
+#  A B C <expected return
+#
+# Where A, B, and C are the points in question. This test function
+# does not currently support checking the resultant plane.
+
+add_test(bn_plane_mk_plane_3pts_fail_same       tester_bn_plane_pt 5 0,0,0 0,0,0 0,0,0 -1)
+add_test(bn_plane_mk_plane_3pts_fail_colinear_1 tester_bn_plane_pt 5 0,0,0 5,8,2 0,0,0 -1)
+add_test(bn_plane_mk_plane_3pts_fail_colinear_2 tester_bn_plane_pt 5 5,8,2 0,0,0 0,0,0 -1)
+add_test(bn_plane_mk_plane_3pts_fail_colinear_3 tester_bn_plane_pt 5 -10,-10,-10 0,0,0 5,5,5 -1)
+add_test(bn_plane_mk_plane_3pts_succeed         tester_bn_plane_pt 5 -10,-10,-10 7,3,8 19,4,2 0)
+
 # Local Variables:
 # tab-width: 8
 # mode: cmake
Index: src/libbn/tests/bn_plane_pt.c
===================================================================
--- src/libbn/tests/bn_plane_pt.c	(revision 0)
+++ src/libbn/tests/bn_plane_pt.c	(working copy)
@@ -0,0 +1,232 @@
+/*         B N _ P L A N E _ 3 P T S _ D I S T I N C T . C
+ * BRL-CAD
+ *
+ * Copyright (c) 2013 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY 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 this file; see the file named COPYING for more
+ * information.
+ */
+
+#include "common.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bu.h"
+#include "bn.h"
+
+/* This macro scans argv[pos] into f1,f2,f3 temp variables and inserts
+   the result into the X,Y,Z parts of var */
+#define POINT_SCANF(var, f1, f2, f3, pos) \
+    sscanf(argv[pos], "%f,%f,%f", &f1, &f2, &f3);	\
+    var[X] = f1;		      \
+    var[Y] = f2;		      \
+    var[Z] = f3;
+
+struct bn_tol
+init_tol()
+{
+    struct bn_tol tol;
+
+    /* These values were stolen from ../bntester.c */
+    tol.magic = BN_TOL_MAGIC;
+    tol.dist = BN_TOL_DIST;
+    tol.dist_sq = tol.dist * tol.dist;
+    tol.perp = 1e-6;
+    tol.para = 1.0 - tol.perp;
+
+    return tol;
+}
+
+int
+test_bn_3pts_collinear(int argc, char **argv)
+{
+    int expected_result = 0;
+    int actual_result = 0;
+    float f1, f2, f3 = 0.0;
+    point_t P0 = VINIT_ZERO;
+    point_t P1 = VINIT_ZERO;
+    point_t P2 = VINIT_ZERO;
+    struct bn_tol tol = init_tol();
+
+    if (argc != 6) {
+	bu_exit(1, "ERROR: input format is P0x,P0y,P0z P1x,P1y,P1z P2x,P2y,P2z expected_result [%s]\n", argv[0]);
+    }
+
+    POINT_SCANF(P0,f1,f2,f3,2);
+    POINT_SCANF(P1,f1,f2,f3,3);
+    POINT_SCANF(P2,f1,f2,f3,4);
+    sscanf(argv[5], "%d", &expected_result);
+
+    actual_result = bn_3pts_collinear(P0, P1, P2, &tol);
+
+    bu_log("result: %d\n", actual_result);
+
+    return !EQUAL(expected_result, actual_result);
+}
+
+int
+test_bn_3pts_distinct(int argc, char **argv)
+{
+    int expected_result = 0;
+    int actual_result = 0;
+    float f1, f2, f3 = 0.0;
+    point_t P0 = VINIT_ZERO;
+    point_t P1 = VINIT_ZERO;
+    point_t P2 = VINIT_ZERO;
+    struct bn_tol tol = init_tol();
+
+    if (argc != 6) {
+	bu_exit(1, "ERROR: input format is P0x,P0y,P0z P1x,P1y,P1z P2x,P2y,P2z expected_result [%s]\n", argv[0]);
+    }
+
+    POINT_SCANF(P0,f1,f2,f3,2);
+    POINT_SCANF(P1,f1,f2,f3,3);
+    POINT_SCANF(P2,f1,f2,f3,4);
+    sscanf(argv[5], "%d", &expected_result);
+
+    actual_result = bn_3pts_distinct(P0, P1, P2, &tol);
+
+    bu_log("result: %d\n", actual_result);
+
+    return !EQUAL(expected_result, actual_result);
+}
+
+int
+test_bn_distsq_line3_pt3(int argc, char **argv)
+{
+    float expected_result = 0;
+    float actual_result = 0;
+    float f1, f2, f3 = 0.0;
+    point_t PT = VINIT_ZERO;
+    vect_t DIR = VINIT_ZERO;
+    point_t A = VINIT_ZERO;
+
+    if (argc != 6) {
+	bu_exit(1, "ERROR: input format is PTx,PTy,PTz DIRx,DIRy,DIRz Ax,Ay,Az expected_result [%s]\n", argv[0]);
+    }
+
+    POINT_SCANF(PT,f1,f2,f3,2);
+    POINT_SCANF(DIR,f1,f2,f3,3);
+    POINT_SCANF(A,f1,f2,f3,4);
+    sscanf(argv[5], "%f", &expected_result);
+
+    actual_result = bn_distsq_line3_pt3(PT, DIR, A);
+
+    bu_log("result: %f\n", actual_result);
+
+    return !EQUAL(expected_result, actual_result);
+}
+
+int
+test_bn_distsq_pt3_lseg3_v2(int argc, char **argv)
+{
+    int expected_return = 0;
+    fastf_t expected_dist = 0;
+    int actual_return = 0;
+    fastf_t actual_dist = 0;
+    float f1, f2, f3 = 0.0;
+    point_t A = VINIT_ZERO;
+    point_t B = VINIT_ZERO;
+    point_t P = VINIT_ZERO;
+    struct bn_tol tol = init_tol();
+
+    if (argc != 7) {
+	bu_exit(1, "ERROR: input format is Ax,Ay,Az Bx,By,Bz Px,Py,Pz expected_return expected_dist [%s]\n", argv[0]);
+    }
+
+    POINT_SCANF(A,f1,f2,f3,2);
+    POINT_SCANF(B,f1,f2,f3,3);
+    POINT_SCANF(P,f1,f2,f3,4);
+    sscanf(argv[5], "%d", &expected_return);
+    sscanf(argv[6], "%f", &f1);
+    expected_dist = f1;
+
+    actual_return = bn_distsq_pt3_lseg3_v2(&actual_dist, A, B, P, &tol);
+
+    bu_log("return: %d\n", actual_return);
+    bu_log("dist: %f\n", actual_dist);
+
+    if(expected_return == actual_return && NEAR_EQUAL(expected_dist, actual_dist, BN_TOL_DIST)) {
+	return 0;
+    } else {
+	return -1;
+    }
+}
+
+int
+test_bn_mk_plane_3pts(int argc, char **argv)
+{
+    int expected_return = 0;
+    int actual_return = 0;
+    float f1, f2, f3 = 0.0;
+    point_t A = VINIT_ZERO;
+    point_t B = VINIT_ZERO;
+    point_t C = VINIT_ZERO;
+    plane_t plane = HINIT_ZERO;
+    struct bn_tol tol = init_tol();
+
+    if (argc != 6) {
+	bu_exit(1, "ERROR: input format is Ax,Ay,Az Bx,By,Bz Cx,Cy,Cz expected_return [%s]\n", argv[0]);
+    }
+
+    POINT_SCANF(A,f1,f2,f3,2);
+    POINT_SCANF(B,f1,f2,f3,3);
+    POINT_SCANF(C,f1,f2,f3,4);
+    sscanf(argv[5], "%d", &expected_return);
+
+    actual_return = bn_mk_plane_3pts(plane,A,B,C,&tol);
+
+    bu_log("return: %f\n", actual_return);
+
+    return !EQUAL(expected_return, actual_return);
+}
+
+int
+main(int argc, char **argv)
+{
+    int function_num = 0;
+
+    if (argc < 1) {
+	bu_exit(1, "ERROR: input format is function_num function_test_args [%s]\n", argv[0]);
+    }
+
+    sscanf(argv[1], "%d", &function_num);
+    switch (function_num) {
+        case 1:
+	    return test_bn_3pts_collinear(argc,argv);
+        case 2:
+	    return test_bn_3pts_distinct(argc,argv);
+        case 3:
+	    return test_bn_distsq_line3_pt3(argc,argv);
+        case 4:
+	    return test_bn_distsq_pt3_lseg3_v2(argc,argv);
+        case 5:
+	    return test_bn_mk_plane_3pts(argc,argv);
+    }
+    return 1;
+}
+
+
+/** @} */
+/*
+ * Local Variables:
+ * mode: C
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */
