Testing sequence of if == int statements¶
Sometimes in programs we see the following pattern
if X == int_1:
pass
elif X == int_2:
pass
elif X == int_3:
pass
X
is compared to several allowed values of type integer.
It is important to notice that X
accepts a descrete set of
allowed values. When we forget to test with values outside the allowed set
mutation testing will produce surviving mutants.
Note
The order of if statements isn’t important.
Reproducer¶
$ pip install nose
$ pip install https://github.com/sixty-north/cosmic-ray/zipball/master
$ cosmic-ray run --test-runner nose --baseline=10 example.json selinux.py -- tests.py:Test_mode_from_int
$ cosmic-ray report example.json
job ID 3:Outcome.SURVIVED:selinux
command: cosmic-ray worker selinux replace_Eq_with_GtE 2 nose -- -v tests.py:Test_mode_from_int
--- mutation diff ---
--- a/example_08/selinux.py
+++ b/example_08/selinux.py
@@ -7,7 +7,7 @@
retval += 'disabled'
elif (int_mode == modes.SELINUX_ENFORCING):
retval += 'enforcing'
- elif (int_mode == modes.SELINUX_PERMISSIVE):
+ elif (int_mode >= modes.SELINUX_PERMISSIVE):
retval += 'permissive'
return retval
job ID 16:Outcome.SURVIVED:selinux
command: cosmic-ray worker selinux replace_Eq_with_LtE 0 nose -- -v tests.py:Test_mode_from_int
--- mutation diff ---
--- a/example_08/selinux.py
+++ b/example_08/selinux.py
@@ -3,7 +3,7 @@
def mode_from_int(int_mode):
retval = ''
- if (int_mode == modes.SELINUX_DISABLED):
+ if (int_mode <= modes.SELINUX_DISABLED):
retval += 'disabled'
elif (int_mode == modes.SELINUX_ENFORCING):
retval += 'enforcing'
job ID 17:Outcome.SURVIVED:selinux
command: cosmic-ray worker selinux replace_Eq_with_LtE 1 nose -- -v tests.py:Test_mode_from_int
--- mutation diff ---
--- a/example_08/selinux.py
+++ b/example_08/selinux.py
@@ -5,7 +5,7 @@
retval = ''
if (int_mode == modes.SELINUX_DISABLED):
retval += 'disabled'
- elif (int_mode == modes.SELINUX_ENFORCING):
+ elif (int_mode <= modes.SELINUX_ENFORCING):
retval += 'enforcing'
elif (int_mode == modes.SELINUX_PERMISSIVE):
retval += 'permissive'
job ID 18:Outcome.SURVIVED:selinux
command: cosmic-ray worker selinux replace_Eq_with_LtE 2 nose -- -v tests.py:Test_mode_from_int
--- mutation diff ---
--- a/example_08/selinux.py
+++ b/example_08/selinux.py
@@ -7,7 +7,7 @@
retval += 'disabled'
elif (int_mode == modes.SELINUX_ENFORCING):
retval += 'enforcing'
- elif (int_mode == modes.SELINUX_PERMISSIVE):
+ elif (int_mode <= modes.SELINUX_PERMISSIVE):
retval += 'permissive'
return retval
total jobs: 24
complete: 24 (100.00%)
survival rate: 16.67%
Killing the mutants¶
To kill all mutants we need to test with values outside the allowed set
$ cosmic-ray run --test-runner nose --baseline=10 example.json selinux.py -- tests.py:TestCompletely
$ cosmic-ray report example.json
Source code¶
SELINUX_DISABLED = 0
SELINUX_ENFORCING = 1
SELINUX_PERMISSIVE = 2
import modes
def mode_from_int(int_mode):
retval = ""
if int_mode == modes.SELINUX_DISABLED:
retval += "disabled"
elif int_mode == modes.SELINUX_ENFORCING:
retval += "enforcing"
elif int_mode == modes.SELINUX_PERMISSIVE:
retval += "permissive"
# it doesn't matter if we have a trailing else clause or not
# uncomment this to experiment
# else:
# retval += "unknown"
return retval
import modes
import selinux
import unittest
class Test_mode_from_int(unittest.TestCase):
def test_with_disabled(self):
m = selinux.mode_from_int(modes.SELINUX_DISABLED)
self.assertEqual(m, "disabled")
def test_with_enforcing(self):
m = selinux.mode_from_int(modes.SELINUX_ENFORCING)
self.assertEqual(m, "enforcing")
def test_with_permissive(self):
m = selinux.mode_from_int(modes.SELINUX_PERMISSIVE)
self.assertEqual(m, "permissive")
class TestCompletely(Test_mode_from_int):
def test_with_values_outside_set(self):
for mode in [-1, 9999]:
m = selinux.mode_from_int(mode)
self.assertEqual(m, "")
if __name__ == "__main__":
unittest.main()