diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3edf20364f..c69abfac0e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -45,6 +45,7 @@ release.
- Added backplane options for SunIllumination and SurfaceObliqueDetectorResolution to phocube [#5467](https://github.com/DOI-USGS/ISIS3/issues/5467)
### Changed
+- Explode has been refactored to be callable; old Makefile test has been removed and replaced by a gtest. Issue: [#5557](https://github.com/USGS-Astrogeology/ISIS3/issues/5557)
- Isisminer has been refactored to be callable; old Makefile tests have been removed and replaced by gtests. Issue: [#5516](https://github.com/USGS-Astrogeology/ISIS3/issues/5516)
- Algebra has been refactored to be callable; old Makefile tests have been removed and replaced by gtests. Issue: [#5594](https://github.com/USGS-Astrogeology/ISIS3/issues/5594)
- Photrim has been refactored to be callable; old Makefile tests have been removed and replaced by gtests. Issue: [#5581](https://github.com/USGS-Astrogeology/ISIS3/issues/5581)
diff --git a/isis/src/base/apps/explode/explode.cpp b/isis/src/base/apps/explode/explode.cpp
new file mode 100644
index 0000000000..fdf39bb727
--- /dev/null
+++ b/isis/src/base/apps/explode/explode.cpp
@@ -0,0 +1,97 @@
+/** 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 "explode.h"
+
+#include "ProcessByLine.h"
+#include "IException.h"
+#include "FileName.h"
+
+namespace Isis {
+
+ // Line processing routine
+ void CopyBand(Buffer &in, Buffer &out);
+
+ /**
+ * Extracts each band of the input cube into a separate one band cube file.
+ * Given the output base name of "base", each output cube will be named
+ * e.g. base.band#.cub. The appropiate BandBin group will be created.
+ *
+ * @param ui User Interface with application parameters
+ */
+ void explode(UserInterface &ui) {
+
+ // open input cube
+ Cube icube;
+ icube.open(ui.GetCubeName("FROM"));
+
+ explode(&icube, ui);
+ }
+
+
+ /**
+ * Extracts each band of the input cube into a separate one band cube file.
+ * Given the output base name of "base", each output cube will be named
+ * e.g. base.band#.cub. The appropiate BandBin group will be created.
+ *
+ * @param ui User Interface with application parameters
+ * @param icube Input cube
+ */
+ void explode(Cube *icube, UserInterface &ui) {
+
+ Process p;
+ p.SetInputCube(icube);
+ int samps = icube->sampleCount();
+ int lines = icube->lineCount();
+ int bands = icube->bandCount();
+ QString infile = icube->fileName();
+
+ // We get the output filename so we can add attributes and extensions
+ QString outbase = ui.GetCubeName("TO");
+ CubeAttributeOutput &outatt = ui.GetOutputAttribute("TO");
+
+ // Loop and extract each band
+ for(int band = 1; band <= bands; band++) {
+ int pband = icube->physicalBand(band);
+ QString sband(toString(pband));
+
+ ProcessByLine p2;
+ Progress *prog = p2.Progress();
+ prog->SetText("Exploding band " + sband);
+
+ CubeAttributeInput inatt("+" + sband);
+ p2.SetInputCube(infile, inatt);
+
+ QString outfile = outbase + ".band";
+ if(pband / 1000 == 0) {
+ outfile += "0";
+ if(pband / 100 == 0) {
+ outfile += "0";
+ if(pband / 10 == 0) {
+ outfile += "0";
+ }
+ }
+ }
+ outfile += sband + ".cub";
+ p2.SetOutputCube(outfile, outatt, samps, lines, 1);
+
+ p2.StartProcess(CopyBand);
+ p2.EndProcess();
+ }
+
+ // Cleanup
+ p.EndProcess();
+ }
+
+ // Line processing routine
+ void CopyBand(Buffer &in, Buffer &out) {
+ for(int i = 0; i < in.size(); i++) {
+ out[i] = in[i];
+ }
+ }
+}
diff --git a/isis/src/base/apps/explode/explode.h b/isis/src/base/apps/explode/explode.h
new file mode 100644
index 0000000000..cc945f280e
--- /dev/null
+++ b/isis/src/base/apps/explode/explode.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 explode_h
+#define explode_h
+
+#include "UserInterface.h"
+
+namespace Isis{
+ extern void explode(UserInterface &ui);
+ extern void explode(Cube *icube, UserInterface &ui);
+}
+
+#endif
diff --git a/isis/src/base/apps/explode/explode.xml b/isis/src/base/apps/explode/explode.xml
index adaef0f307..c9c7e6e8ca 100644
--- a/isis/src/base/apps/explode/explode.xml
+++ b/isis/src/base/apps/explode/explode.xml
@@ -35,6 +35,9 @@
Removed references to CubeInfo
+
+ Converted to callable app and converted Makefile test to gtest.
+
diff --git a/isis/src/base/apps/explode/main.cpp b/isis/src/base/apps/explode/main.cpp
index 7a75d1ccba..f2ff2442ee 100644
--- a/isis/src/base/apps/explode/main.cpp
+++ b/isis/src/base/apps/explode/main.cpp
@@ -1,63 +1,20 @@
-#include "Isis.h"
-#include "ProcessByLine.h"
-#include "IException.h"
-#include "FileName.h"
-
-using namespace std;
-using namespace Isis;
-
-void CopyBand(Buffer &in, Buffer &out);
+/** This is free and unencumbered software released into the public domain.
-void IsisMain() {
- // Get the cube to explode
- Process p;
- Cube *icube = p.SetInputCube("FROM");
- int samps = icube->sampleCount();
- int lines = icube->lineCount();
- int bands = icube->bandCount();
- QString infile = icube->fileName();
-
- // We the output filename so we can add attributes and extensions
- UserInterface &ui = Application::GetUserInterface();
- QString outbase = ui.GetCubeName("TO");
- CubeAttributeOutput &outatt = ui.GetOutputAttribute("TO");
+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. **/
- // Loop and extract each band
- for(int band = 1; band <= bands; band++) {
- int pband = icube->physicalBand(band);
- QString sband(toString(pband));
+/* SPDX-License-Identifier: CC0-1.0 */
- ProcessByLine p2;
- Progress *prog = p2.Progress();
- prog->SetText("Exploding band " + sband);
-
- CubeAttributeInput inatt("+" + sband);
- p2.SetInputCube(infile, inatt);
+#include "Isis.h"
- QString outfile = outbase + ".band";
- if(pband / 1000 == 0) {
- outfile += "0";
- if(pband / 100 == 0) {
- outfile += "0";
- if(pband / 10 == 0) {
- outfile += "0";
- }
- }
- }
- outfile += sband + ".cub";
- p2.SetOutputCube(outfile, outatt, samps, lines, 1);
+#include "explode.h"
- p2.StartProcess(CopyBand);
- p2.EndProcess();
- }
+#include "Application.h"
- // Cleanup
- p.EndProcess();
-}
+using namespace Isis;
-// Line processing routine
-void CopyBand(Buffer &in, Buffer &out) {
- for(int i = 0; i < in.size(); i++) {
- out[i] = in[i];
- }
+void IsisMain() {
+ UserInterface &ui = Application::GetUserInterface();
+ explode(ui);
}
diff --git a/isis/src/base/apps/explode/tsts/Makefile b/isis/src/base/apps/explode/tsts/Makefile
deleted file mode 100644
index 46d84c74c2..0000000000
--- a/isis/src/base/apps/explode/tsts/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-BLANKS = "%-6s"
-LENGTH = "%-40s"
-
-include $(ISISROOT)/make/isismake.tststree
diff --git a/isis/src/base/apps/explode/tsts/case01/Makefile b/isis/src/base/apps/explode/tsts/case01/Makefile
deleted file mode 100644
index e58baa1d0d..0000000000
--- a/isis/src/base/apps/explode/tsts/case01/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-APPNAME = explode
-
-include $(ISISROOT)/make/isismake.tsts
-
-commands:
- $(APPNAME) from=$(INPUT)/isisTruth.cub \
- to= $(OUTPUT)/explTruth1 > /dev/null;
diff --git a/isis/tests/FunctionalTestsExplode.cpp b/isis/tests/FunctionalTestsExplode.cpp
new file mode 100644
index 0000000000..b639d8a25c
--- /dev/null
+++ b/isis/tests/FunctionalTestsExplode.cpp
@@ -0,0 +1,80 @@
+#include "explode.h"
+
+#include
+#include
+
+#include "CameraFixtures.h"
+#include "Cube.h"
+#include "Histogram.h"
+
+#include "gtest/gtest.h"
+
+using namespace Isis;
+
+static QString APP_XML = FileName("$ISISROOT/bin/xml/explode.xml").expanded();
+
+/**
+ * ExplodeDefault Test
+ *
+ * ExplodeDefault test given a single 5x5 input cube with 2 bands.
+ *
+ * The output cube is verified by checking the histogram statistics
+ * for each band.
+ *
+ * INPUT: testCube from DefaultCube fixture resized to 5x5x1
+ *
+ * OUTPUT: 1) explodeOut.band0001.cub
+ * 2) explodeOut.band0002.cub
+ */
+TEST_F(DefaultCube, FunctionalTestExplodeDefault) {
+
+ // reduce test cube size and create two bands
+ resizeCube(5, 5, 2);
+
+ // close and reopen test cube to ensure dn buffer is available
+ testCube->reopen("r");
+
+ // run explode
+ QVector args = {"to=" + tempDir.path() + "/explodeOut"};
+ UserInterface ui(APP_XML, args);
+
+ try {
+ explode(testCube, ui);
+ }
+ catch(IException &e) {
+ FAIL() << e.toString().toStdString().c_str() << std::endl;
+ }
+
+ // validate band 1 output cube
+ Cube outCube1(tempDir.path() + "/explodeOut.band0001.cub");
+
+ ASSERT_EQ(outCube1.sampleCount(), 5);
+ ASSERT_EQ(outCube1.lineCount(), 5);
+ ASSERT_EQ(outCube1.bandCount(), 1);
+
+ std::unique_ptr inCubeBand1Hist (testCube->histogram(1));
+ std::unique_ptr outCube1Hist (outCube1.histogram(1));
+
+ EXPECT_NEAR(outCube1Hist->Average(), inCubeBand1Hist->Average(), .000001);
+ EXPECT_NEAR(outCube1Hist->Sum(), inCubeBand1Hist->Sum(), .000001);
+ EXPECT_EQ(outCube1Hist->ValidPixels(), inCubeBand1Hist->ValidPixels());
+ EXPECT_EQ(outCube1Hist->TotalPixels(), inCubeBand1Hist->TotalPixels());
+ EXPECT_NEAR(outCube1Hist->StandardDeviation(), inCubeBand1Hist->StandardDeviation(), .000001);
+
+ // validate band 2 output cube
+ Cube outCube2(tempDir.path() + "/explodeOut.band0002.cub");
+
+ ASSERT_EQ(outCube2.sampleCount(), 5);
+ ASSERT_EQ(outCube2.lineCount(), 5);
+ ASSERT_EQ(outCube2.bandCount(), 1);
+
+ std::unique_ptr inCubeBand2Hist (testCube->histogram(2));
+ std::unique_ptr outCube2Hist (outCube2.histogram(1));
+
+ EXPECT_NEAR(outCube2Hist->Average(), inCubeBand2Hist->Average(), .000001);
+ EXPECT_NEAR(outCube2Hist->Sum(), inCubeBand2Hist->Sum(), .000001);
+ EXPECT_EQ(outCube2Hist->ValidPixels(), inCubeBand2Hist->ValidPixels());
+ EXPECT_EQ(outCube2Hist->TotalPixels(), inCubeBand2Hist->TotalPixels());
+ EXPECT_NEAR(outCube2Hist->StandardDeviation(), inCubeBand2Hist->StandardDeviation(), .000001);
+}
+