Repository: PMEAL/OpenPNM

Issue:
Unit tests for COMSOL, STL, and Salome IO classes
We don't have any unit tests for `COMSOL`, `STL`, and `Salome` IO classes at the moment. 

Discussion:

Patch:
diff --git a/openpnm/algorithms/_generic_transport.py b/openpnm/algorithms/_generic_transport.py
index e5b7581d4..84aef6658 100644
--- a/openpnm/algorithms/_generic_transport.py
+++ b/openpnm/algorithms/_generic_transport.py
@@ -451,8 +451,7 @@ class GenericTransport(GenericAlgorithm):
         self._validate_data_health()
         # Solve and apply under-relaxation
         x_new, exit_code = solver.solve(A=self.A, b=self.b, x0=x0)
-        quantity = self.settings['quantity']
-        self[quantity] = w * x_new + (1 - w) * self[quantity]
+        self.x = w * x_new + (1 - w) * self.x
         # Update A and b using the recent solution
         self._update_A_and_b()
 
diff --git a/openpnm/io/__init__.py b/openpnm/io/__init__.py
index 98527de5c..08c34b340 100644
--- a/openpnm/io/__init__.py
+++ b/openpnm/io/__init__.py
@@ -11,7 +11,7 @@ classes losses lots of vital information about the simulation, such as
 pore scale-models and parameters.
 
 """
-from ._generic import GenericIO
+from ._generic_io import GenericIO
 from ._pickle import Pickle
 from ._dict import Dict
 from ._vtk import VTK
diff --git a/openpnm/io/_comsol.py b/openpnm/io/_comsol.py
index 445bc1b49..5d317741d 100644
--- a/openpnm/io/_comsol.py
+++ b/openpnm/io/_comsol.py
@@ -1,4 +1,5 @@
 import numpy as np
+import openpnm as op
 from openpnm.io import GenericIO
 
 
@@ -15,30 +16,31 @@ class COMSOL(GenericIO):
     """
 
     @classmethod
-    def export_data(cls, network, phases=[], filename=''):
+    def export_data(cls, network, filename=None):
         r"""
         Saves the network and geometry data from the given objects into the
-        specified file. This exports in 2D only where throats and pores have
-        rectangular and circular shapes, respectively.
+        specified file. This exports in 2D only where throats and pores
+        have rectangular and circular shapes, respectively.
 
         Parameters
         ----------
         network : GenericNetwork
             The network containing the desired data
 
-        phases : list[GenericPhase]s (optional, default is none)
-
         Notes
         -----
-        This method only saves the network and geometry data, not any of the
-        pore-scale models or other attributes.  To save an actual OpenPNM
-        Project use the ``Workspace`` object.
+        This method only saves the network and geometry data, not any of
+        the pore-scale models or other attributes. To save an actual
+        OpenPNM Project use the ``Workspace`` object.
 
         """
-        project, network, phases = cls._parse_args(network=network,
-                                                   phases=phases)
+        if op.topotools.dimensionality(network).sum() == 3:
+            raise Exception("COMSOL I/O class only works for 2D networks!")
+
+        project, network, phases = cls._parse_args(network=network, phases=[])
         network = network[0]
-        f = open(filename+'.mphtxt', 'w')
+        filename = network.name if filename is None else filename
+        f = open(f"{filename}.mphtxt", 'w')
 
         header(file=f, Nr=network.Nt, Nc=network.Np)
 
diff --git a/openpnm/io/_generic.py b/openpnm/io/_generic_io.py
similarity index 100%
rename from openpnm/io/_generic.py
rename to openpnm/io/_generic_io.py
diff --git a/requirements/conda_requirements.txt b/requirements/conda_requirements.txt
index f00c26196..1c277d225 100644
--- a/requirements/conda_requirements.txt
+++ b/requirements/conda_requirements.txt
@@ -8,6 +8,7 @@ ipython
 jsonschema
 json_tricks
 matplotlib
+netgen
 networkx
 numba
 numpy


Test patch:
diff --git a/tests/unit/io/COMSOLTest.py b/tests/unit/io/COMSOLTest.py
new file mode 100644
index 000000000..043d44f7c
--- /dev/null
+++ b/tests/unit/io/COMSOLTest.py
@@ -0,0 +1,44 @@
+import os
+import py
+import numpy as np
+import openpnm as op
+import pytest
+
+
+class COMSOLTest:
+
+    def setup_class(self):
+        np.random.seed(10)
+        self.net2d = op.network.Cubic(shape=[3, 4])
+        self.net2d["pore.diameter"] = np.random.rand(self.net2d.Np)
+        self.net2d["throat.diameter"] = np.random.rand(self.net2d.Nt)
+        self.net3d = op.network.Cubic(shape=[3, 4, 5])
+        self.net3d["pore.diameter"] = np.random.rand(self.net3d.Np)
+        self.net3d["throat.diameter"] = np.random.rand(self.net3d.Nt)
+
+
+    def teardown_class(self):
+        os.remove(f"{self.net2d.name}.mphtxt")
+
+    def test_export_data_2d_network(self):
+        op.io.COMSOL.export_data(network=self.net2d)
+        assert os.path.isfile(f"{self.net2d.name}.mphtxt")
+
+    def test_export_data_3d_network(self):
+        with pytest.raises(Exception):
+            op.io.COMSOL.export_data(network=self.net3d)
+
+
+if __name__ == '__main__':
+    # All the tests in this file can be run with 'playing' this file
+    t = COMSOLTest()
+    self = t  # For interacting with the tests at the command line
+    t.setup_class()
+    for item in t.__dir__():
+        if item.startswith('test'):
+            print(f'Running test: {item}')
+            try:
+                t.__getattribute__(item)()
+            except TypeError:
+                t.__getattribute__(item)(tmpdir=py.path.local())
+    t.teardown_class()
diff --git a/tests/unit/io/STLTest.py b/tests/unit/io/STLTest.py
index da86c9008..64008ac9e 100644
--- a/tests/unit/io/STLTest.py
+++ b/tests/unit/io/STLTest.py
@@ -1,10 +1,12 @@
 import os
 import py
+import pytest
 import numpy as np
 import openpnm as op
 from openpnm.models.misc import from_neighbor_pores
 
 
+@pytest.mark.skip(reason="'netgen' is only available on conda")
 class STLTest:
 
     def setup_class(self):