diff --git a/CHANGELOG.md b/CHANGELOG.md
index 81fc6e90e2..2ef0ed0da3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -39,6 +39,7 @@ release.
- Added backplane options for SunIllumination and SurfaceObliqueDetectorResolution to phocube [#5467](https://github.com/DOI-USGS/ISIS3/issues/5467)
### Changed
+- Bandtrim has been refactored to be callable; old Makefile tests have been removed and replaced by gtests. Issue: [#5571](https://github.com/USGS-Astrogeology/ISIS3/issues/5571)
- Modified kaguyasp2isis to work with new (detached) data [#5436](https://github.com/DOI-USGS/ISIS3/issues/5436)
- Added jigsaw error message for csminit'd images without csm parameters[#5486](https://github.com/DOI-USGS/ISIS3/issues/5486)
- Changed `qwt` dependency version to 6.2.0 or below [#5498](https://github.com/DOI-USGS/ISIS3/issues/5498)
diff --git a/isis/src/base/apps/bandtrim/bandtrim.cpp b/isis/src/base/apps/bandtrim/bandtrim.cpp
new file mode 100644
index 0000000000..07e60d98e3
--- /dev/null
+++ b/isis/src/base/apps/bandtrim/bandtrim.cpp
@@ -0,0 +1,74 @@
+/** This is free and unencumbered software released into the public domain.
+
+The authors of ISIS do not claim copyright on the contents of this file.
+For more details about the LICENSE terms and the AUTHORS, you will
+find files of those names at the top level of this repository. **/
+
+/* SPDX-License-Identifier: CC0-1.0 */
+
+#include "bandtrim.h"
+
+#include "Cube.h"
+#include "ProcessByBrick.h"
+#include "SpecialPixel.h"
+
+namespace Isis {
+
+ // Process to trim spectral pixels if any are null
+ void BandTrimSpectral(Buffer &in, Buffer &out);
+
+ /**
+ * Bandtrim searches for NULL pixels in all bands of a cube.
+ * When a NULL pixel is found the corresponding pixel is set
+ * to NULL in all other bands.
+ *
+ * @param ui User Interface with application parameters
+ */
+ void bandtrim(UserInterface &ui) {
+
+ // open cube
+ Cube icube;
+ icube.open(ui.GetCubeName("FROM"));
+
+ bandtrim(&icube, ui);
+ }
+
+
+ /**
+ * Bandtrim searches for NULL pixels in all bands of a cube.
+ * When a NULL pixel is found the corresponding pixel is set
+ * to NULL in all other bands.
+ *
+ * @param icube Input cube
+ * @param ui User Interface with application parameters
+ */
+ void bandtrim(Cube *icube, UserInterface &ui) {
+ ProcessByBrick p;
+ p.SetInputCube(icube);
+ p.SetBrickSize(1, 1, icube->bandCount());
+
+ QString fname = ui.GetCubeName("TO");
+ CubeAttributeOutput &atts = ui.GetOutputAttribute("TO");
+ p.SetOutputCube(fname, atts);
+
+ p.StartProcess(BandTrimSpectral);
+ p.EndProcess();
+ }
+
+ // Process to trim spectral pixels if any are null
+ void BandTrimSpectral(Buffer &in, Buffer &out) {
+ // Copy input to output and check to see if we should null
+ bool nullPixels = false;
+ for(int i = 0; i < in.size(); i++) {
+ out[i] = in[i];
+ if(in[i] == Isis::Null) nullPixels = true;
+ }
+
+ // Null all pixels in the spectra if necessary
+ if(nullPixels) {
+ for(int i = 0; i < in.size(); i++) {
+ out[i] = Isis::Null;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/isis/src/base/apps/bandtrim/bandtrim.h b/isis/src/base/apps/bandtrim/bandtrim.h
new file mode 100644
index 0000000000..03447a91d8
--- /dev/null
+++ b/isis/src/base/apps/bandtrim/bandtrim.h
@@ -0,0 +1,19 @@
+/** This is free and unencumbered software released into the public domain.
+
+The authors of ISIS do not claim copyright on the contents of this file.
+For more details about the LICENSE terms and the AUTHORS, you will
+find files of those names at the top level of this repository. **/
+
+/* SPDX-License-Identifier: CC0-1.0 */
+
+#ifndef bandtrim_h
+#define bandtrim_h
+
+#include "UserInterface.h"
+
+namespace Isis{
+ extern void bandtrim(UserInterface &ui);
+ extern void bandtrim(Cube *iCube, UserInterface &ui);
+}
+
+#endif
diff --git a/isis/src/base/apps/bandtrim/bandtrim.xml b/isis/src/base/apps/bandtrim/bandtrim.xml
index 525a4e6f19..fd550ac313 100644
--- a/isis/src/base/apps/bandtrim/bandtrim.xml
+++ b/isis/src/base/apps/bandtrim/bandtrim.xml
@@ -35,6 +35,9 @@
Removed references to CubeInfo
+
+ Converted to callable app and converted Makefile tests to gtests.
+
diff --git a/isis/src/base/apps/bandtrim/main.cpp b/isis/src/base/apps/bandtrim/main.cpp
index d577d27cfe..b163580e1c 100644
--- a/isis/src/base/apps/bandtrim/main.cpp
+++ b/isis/src/base/apps/bandtrim/main.cpp
@@ -1,34 +1,20 @@
-#include "Isis.h"
-#include "ProcessByBrick.h"
-#include "SpecialPixel.h"
+/** This is free and unencumbered software released into the public domain.
-using namespace std;
-using namespace Isis;
+The authors of ISIS do not claim copyright on the contents of this file.
+For more details about the LICENSE terms and the AUTHORS, you will
+find files of those names at the top level of this repository. **/
-void BandTrim(Buffer &in, Buffer &out);
+/* SPDX-License-Identifier: CC0-1.0 */
-void IsisMain() {
- ProcessByBrick p;
- Cube *icube = p.SetInputCube("FROM");
- p.SetBrickSize(1, 1, icube->bandCount());
- p.SetOutputCube("TO");
- p.StartProcess(BandTrim);
- p.EndProcess();
-}
+#include "Isis.h"
-// Trim spectral pixels if anyone of them is null
-void BandTrim(Buffer &in, Buffer &out) {
- // Copy input to output and check to see if we should null
- bool nullPixels = false;
- for(int i = 0; i < in.size(); i++) {
- out[i] = in[i];
- if(in[i] == Isis::Null) nullPixels = true;
- }
+#include "bandtrim.h"
- // Null all pixels in the spectra if necessary
- if(nullPixels) {
- for(int i = 0; i < in.size(); i++) {
- out[i] = Isis::Null;
- }
- }
+#include "Application.h"
+
+using namespace Isis;
+
+void IsisMain() {
+ UserInterface &ui = Application::GetUserInterface();
+ bandtrim(ui);
}
diff --git a/isis/src/base/apps/bandtrim/tsts/Makefile b/isis/src/base/apps/bandtrim/tsts/Makefile
deleted file mode 100644
index 46d84c74c2..0000000000
--- a/isis/src/base/apps/bandtrim/tsts/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-BLANKS = "%-6s"
-LENGTH = "%-40s"
-
-include $(ISISROOT)/make/isismake.tststree
diff --git a/isis/src/base/apps/bandtrim/tsts/default/Makefile b/isis/src/base/apps/bandtrim/tsts/default/Makefile
deleted file mode 100644
index 4360b7671b..0000000000
--- a/isis/src/base/apps/bandtrim/tsts/default/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-APPNAME = bandtrim
-
-include $(ISISROOT)/make/isismake.tsts
-
-commands:
- $(APPNAME) FROM=$(INPUT)/input.cub TO=$(OUTPUT)/truth.cub > /dev/null;
diff --git a/isis/src/base/apps/bandtrim/tsts/oneband/Makefile b/isis/src/base/apps/bandtrim/tsts/oneband/Makefile
deleted file mode 100644
index 4360b7671b..0000000000
--- a/isis/src/base/apps/bandtrim/tsts/oneband/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-APPNAME = bandtrim
-
-include $(ISISROOT)/make/isismake.tsts
-
-commands:
- $(APPNAME) FROM=$(INPUT)/input.cub TO=$(OUTPUT)/truth.cub > /dev/null;
diff --git a/isis/tests/FunctionalTestsBandtrim.cpp b/isis/tests/FunctionalTestsBandtrim.cpp
new file mode 100644
index 0000000000..71f39029e5
--- /dev/null
+++ b/isis/tests/FunctionalTestsBandtrim.cpp
@@ -0,0 +1,192 @@
+
+#include
+#include
+
+#include "Brick.h"
+#include "CameraFixtures.h"
+#include "Histogram.h"
+#include "bandtrim.h"
+
+#include "gtest/gtest.h"
+
+using namespace Isis;
+
+static QString APP_XML = FileName("$ISISROOT/bin/xml/bandtrim.xml").expanded();
+
+/**
+ * BandtrimDefault Test
+ *
+ * BandtrimDefault test given a single 5x5 input cube with 7 bands.
+ * One pixel in each band is set to Isis::Null as below.
+ * N implies a Null pixel, N1 is band 1, N2 is band 2, etc.
+ * All Null pixels should be duplicated across each band in the
+ * output Cube.
+ *
+ * The output cube is verified by checking the histogram statistics
+ * for each band.
+ *
+ * | |N1| |N2| |
+ * | | | | | |
+ * |N3| |N4| |N5|
+ * | | | | | |
+ * | |N6| |N7| |
+ *
+ * INPUT: testCube from DefaultCube fixture modified as above.
+ *
+ * OUTPUT: bandtrimDefaultOut.cub
+ *
+ */
+TEST_F(DefaultCube, FunctionalTestBandtrimDefault) {
+
+ // reduce test cube size, create seven bands
+ resizeCube(5, 5, 7);
+
+ // set one pixel in each of the seven bands to Isis::Null
+ // following the pattern in the comment block above
+
+ Brick b(1, 1, 1, testCube->pixelType()); // create buffer of size 1 pixel
+
+ b.SetBasePosition(2, 1, 1);
+ b[0] = Isis::Null;
+ testCube->write(b);
+
+ b.SetBasePosition(4, 1, 2);
+ b[0] = Isis::Null;
+ testCube->write(b);
+
+ b.SetBasePosition(1, 3, 3);
+ b[0] = Isis::Null;
+ testCube->write(b);
+
+ b.SetBasePosition(3, 3, 4);
+ b[0] = Isis::Null;
+ testCube->write(b);
+
+ b.SetBasePosition(5, 3, 5);
+ b[0] = Isis::Null;
+ testCube->write(b);
+
+ b.SetBasePosition(2, 5, 6);
+ b[0] = Isis::Null;
+ testCube->write(b);
+
+ b.SetBasePosition(4, 5, 7);
+ b[0] = Isis::Null;
+ testCube->write(b);
+
+ // run bandtrim
+ QVector args = {"to=" + tempDir.path() + "/bandtrimDefaultOut.cub"};
+ UserInterface ui(APP_XML, args);
+
+ try {
+ bandtrim(testCube, ui);
+ }
+ catch(IException &e) {
+ FAIL() << e.toString().toStdString().c_str() << std::endl;
+ }
+
+ // Open output cube
+ Cube outCube(tempDir.path() + "/bandtrimDefaultOut.cub");
+
+ // validate histogram statistics for each band in output cube
+ std::unique_ptr band1Hist (outCube.histogram(1));
+ std::unique_ptr band2Hist (outCube.histogram(2));
+ std::unique_ptr band3Hist (outCube.histogram(3));
+ std::unique_ptr band4Hist (outCube.histogram(4));
+ std::unique_ptr band5Hist (outCube.histogram(5));
+ std::unique_ptr band6Hist (outCube.histogram(6));
+ std::unique_ptr band7Hist (outCube.histogram(7));
+
+ EXPECT_EQ(band1Hist->ValidPixels(), 18);
+ EXPECT_EQ(band1Hist->Average(), 13);
+ EXPECT_EQ(band1Hist->Sum(), 234);
+ EXPECT_EQ(band2Hist->ValidPixels(), 18);
+ EXPECT_EQ(band2Hist->Average(), 38);
+ EXPECT_EQ(band2Hist->Sum(), 684);
+ EXPECT_EQ(band3Hist->ValidPixels(), 18);
+ EXPECT_EQ(band3Hist->Average(), 63);
+ EXPECT_EQ(band3Hist->Sum(), 1134);
+ EXPECT_EQ(band4Hist->ValidPixels(), 18);
+ EXPECT_EQ(band4Hist->Average(), 88);
+ EXPECT_EQ(band4Hist->Sum(), 1584);
+ EXPECT_EQ(band5Hist->ValidPixels(), 18);
+ EXPECT_EQ(band5Hist->Average(), 113);
+ EXPECT_EQ(band5Hist->Sum(), 2034);
+ EXPECT_EQ(band6Hist->ValidPixels(), 18);
+ EXPECT_EQ(band6Hist->Average(), 138);
+ EXPECT_EQ(band6Hist->Sum(), 2484);
+ EXPECT_EQ(band7Hist->ValidPixels(), 18);
+ EXPECT_EQ(band7Hist->Average(), 163);
+ EXPECT_EQ(band7Hist->Sum(), 2934);
+
+ outCube.close();
+}
+
+
+/**
+ * BandtrimOneBand Test
+ *
+ * BandtrimOneBand test given a single 5x5 input cube with 1 band.
+ * The four pixels in the upper left corner are set to Isis::Null
+ * as below. N implies a Null pixel.
+ *
+ * The output cube is verified by checking histogram statistics.
+ *
+ * |N|N| | | |
+ * |N|N| | | |
+ * | | | | | |
+ * | | | | | |
+ * | | | | | |
+ *
+ * INPUT: testCube from DefaultCube fixture
+ *
+ * OUTPUT: bandtrimOneBandOut.cub
+ */
+TEST_F(DefaultCube, FunctionalTestBandtrimOneBand) {
+
+ // reduce test cube size
+ resizeCube(5, 5, 1);
+
+ // set 4 pixel block in upper left corner to Isis::Null
+ Brick b(1, 1, 1, testCube->pixelType()); // create buffer of size 1 pixels
+ b.SetBasePosition(1, 1, 1);
+ b[0] = Isis::Null;
+ testCube->write(b);
+
+ b.SetBasePosition(2, 1, 1);
+ b[0] = Isis::Null;
+ testCube->write(b);
+
+ b.SetBasePosition(1, 2, 1);
+ b[0] = Isis::Null;
+ testCube->write(b);
+
+ b.SetBasePosition(2, 2, 1);
+ b[0] = Isis::Null;
+ testCube->write(b);
+
+ // run bandtrim
+ QVector args = {"to=" + tempDir.path() + "/bandtrimOneBandOut.cub"};
+
+ UserInterface ui(APP_XML, args);
+
+ try {
+ bandtrim(testCube, ui);
+ }
+ catch(IException &e) {
+ FAIL() << e.toString().toStdString().c_str() << std::endl;
+ }
+
+ // Open output cube
+ Cube outCube(tempDir.path() + "/bandtrimOneBandOut.cub");
+
+ // validate histogram statistics for each band in output cube
+ std::unique_ptr band1Hist (outCube.histogram(1));
+
+ EXPECT_EQ(band1Hist->ValidPixels(), 21);
+ EXPECT_EQ(band1Hist->Average(), 14.714285714285714);
+ EXPECT_EQ(band1Hist->Sum(), 309);
+
+ outCube.close();
+}
+