From e2224bca2e936daf0d7649540f4eaaf19c53c2bb Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@k1024.org>
Date: Mon, 25 Nov 2019 04:22:15 +0100
Subject: [PATCH] Convert test suite to pytest

Much more parametrisation, which means:

- more test cases covered (testing more/all object types in most
  functions)
- more granular tests, which should help diagnose of failures
---
 .travis.yml        |  13 +-
 Makefile           |  10 +-
 test/test_xattr.py | 643 +++++++++++++++++++++------------------------
 3 files changed, 316 insertions(+), 350 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index df6c50d..463cf4c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,8 @@
 language: python
 
+# enable caching of installed packages.
+cache: pip
+
 # let's test as many versions as we can!
 python:
     - "3.4"
@@ -19,13 +22,17 @@ matrix:
       python:
 
 # install coverage helper:
-install: gem install coveralls-lcov
+install:
+  - gem install coveralls-lcov
+  - pip install pytest
 
 # the test command:
 script:
-  - python ./setup.py test
+  - python ./setup.py build_ext -i
+  - python -m pytest test
   - make clean
-  - CFLAGS="-coverage" python ./setup.py test
+  - CFLAGS="-coverage" python ./setup.py build_ext -i
+  - python -m pytest test
 
 # install lcov, platform-specific but clean:
 addons:
diff --git a/Makefile b/Makefile
index e8e685a..78e6818 100644
--- a/Makefile
+++ b/Makefile
@@ -47,13 +47,15 @@ test:
 	  for flavour in "" "-dbg"; do \
 	    if type python$$ver$$flavour >/dev/null; then \
 	      echo Testing with python$$ver$$flavour; \
-	      python$$ver$$flavour ./setup.py test -q; \
+	      python$$ver$$flavour setup.py build_ext -i; \
+	      python$$ver$$flavour -m pytest test; \
 	    fi; \
 	  done; \
 	done;
-	@if type pypy >/dev/null; then \
-	  echo Testing with pypy; \
-	  pypy ./setup.py test -q; \
+	@if type pypy3 >/dev/null; then \
+	  echo Testing with pypy3; \
+	  pypy3 setup.py build_ext -i; \
+	  pypy3 -m pytest test; \
 	fi
 
 benchmark: $(MODNAME)
diff --git a/test/test_xattr.py b/test/test_xattr.py
index b477aa2..9dca8ac 100644
--- a/test/test_xattr.py
+++ b/test/test_xattr.py
@@ -2,10 +2,10 @@
 #
 
 import sys
-import unittest
 import tempfile
 import os
 import errno
+import pytest
 
 import xattr
 from xattr import NS_USER, XATTR_CREATE, XATTR_REPLACE
@@ -43,6 +43,8 @@ if PY3K:
     EMPTY_VAL = EMPTY_VAL.encode()
     LARGE_VAL = LARGE_VAL.encode()
 
+# Helper functions
+
 def ignore_tuples(attrs):
     """Remove ignored attributes from the output of xattr.get_all."""
     return [attr for attr in attrs
@@ -61,355 +63,310 @@ def tuples_equal(attrs, value):
     """Helper to check list equivalence, skipping TEST_IGNORE_XATTRS."""
     assert ignore_tuples(attrs) == value
 
-
-class xattrTest(unittest.TestCase):
-    def setUp(self):
-        """set up function"""
-        self.rmfiles = []
-        self.rmdirs = []
-
-    def tearDown(self):
-        """tear down function"""
-        for fname in self.rmfiles:
-            try:
-                os.unlink(fname)
-            except EnvironmentError:
-                continue
-        for dname in self.rmdirs:
-            try:
-                os.rmdir(dname)
-            except EnvironmentError:
-                continue
-
-    def _getfile(self):
-        """create a temp file"""
-        fh, fname = tempfile.mkstemp(".test", "xattr-", TEST_DIR)
-        self.rmfiles.append(fname)
-        return fh, fname
-
-    def _getdir(self):
-        """create a temp dir"""
-        dname = tempfile.mkdtemp(".test", "xattr-", TEST_DIR)
-        self.rmdirs.append(dname)
-        return dname
-
-    def _getsymlink(self, dangling=True):
-        """create a symlink"""
-        fh, fname = self._getfile()
-        os.close(fh)
-        if dangling:
-            os.unlink(fname)
-        sname = fname + ".symlink"
-        os.symlink(fname, sname)
-        self.rmfiles.append(sname)
-        return fname, sname
-
-    def _checkDeprecated(self, item, symlink=False):
-        """check deprecated list, set, get operations against an item"""
-        lists_equal(xattr.listxattr(item, symlink), [])
-        self.assertRaises(EnvironmentError, xattr.setxattr, item,
-                          USER_ATTR, USER_VAL,
-                          XATTR_REPLACE, symlink)
-        xattr.setxattr(item, USER_ATTR, USER_VAL, 0, symlink)
-        self.assertRaises(EnvironmentError, xattr.setxattr, item,
-                          USER_ATTR, USER_VAL, XATTR_CREATE, symlink)
-        lists_equal(xattr.listxattr(item, symlink), [USER_ATTR])
-        self.assertEqual(xattr.getxattr(item, USER_ATTR, symlink),
-                         USER_VAL)
-        tuples_equal(xattr.get_all(item, nofollow=symlink),
-                          [(USER_ATTR, USER_VAL)])
-        xattr.removexattr(item, USER_ATTR, symlink)
-        lists_equal(xattr.listxattr(item, symlink), [])
-        tuples_equal(xattr.get_all(item, nofollow=symlink),
-                         [])
-        self.assertRaises(EnvironmentError, xattr.removexattr,
-                          item, USER_ATTR, symlink)
-
-    def _checkListSetGet(self, item, symlink=False, use_ns=False):
-        """check list, set, get operations against an item"""
-        lists_equal(xattr.list(item, symlink), [])
-        self.assertRaises(EnvironmentError, xattr.set, item,
-                          USER_ATTR, USER_VAL,
-                          flags=XATTR_REPLACE,
-                          nofollow=symlink)
-        self.assertRaises(EnvironmentError, xattr.set, item,
-                          USER_NN, USER_VAL,
-                          flags=XATTR_REPLACE,
-                          namespace=NAMESPACE,
-                          nofollow=symlink)
-        if use_ns:
-            xattr.set(item, USER_NN, USER_VAL,
-                      namespace=NAMESPACE,
-                      nofollow=symlink)
-        else:
-            xattr.set(item, USER_ATTR, USER_VAL,
-                      nofollow=symlink)
-        self.assertRaises(EnvironmentError, xattr.set, item,
-                          USER_ATTR, USER_VAL,
-                          flags=XATTR_CREATE,
-                          nofollow=symlink)
-        self.assertRaises(EnvironmentError, xattr.set, item,
-                          USER_NN, USER_VAL,
-                          flags=XATTR_CREATE,
-                          namespace=NAMESPACE,
-                          nofollow=symlink)
-        lists_equal(xattr.list(item, nofollow=symlink), [USER_ATTR])
-        lists_equal(xattr.list(item, nofollow=symlink,
-                                  namespace=EMPTY_NS),
-                       [USER_ATTR])
-        self.assertEqual(xattr.list(item, namespace=NAMESPACE, nofollow=symlink),
-                         [USER_NN])
-        self.assertEqual(xattr.get(item, USER_ATTR, nofollow=symlink),
-                         USER_VAL)
-        self.assertEqual(xattr.get(item, USER_NN, nofollow=symlink,
-                                   namespace=NAMESPACE), USER_VAL)
-        tuples_equal(xattr.get_all(item, nofollow=symlink),
-                         [(USER_ATTR, USER_VAL)])
-        self.assertEqual(xattr.get_all(item, nofollow=symlink,
-                                       namespace=NAMESPACE),
-                         [(USER_NN, USER_VAL)])
-        if use_ns:
-            xattr.remove(item, USER_NN, namespace=NAMESPACE, nofollow=symlink)
-        else:
-            xattr.remove(item, USER_ATTR, nofollow=symlink)
-        lists_equal(xattr.list(item, nofollow=symlink), [])
-        tuples_equal(xattr.get_all(item, nofollow=symlink),
-                         [])
-        self.assertRaises(EnvironmentError, xattr.remove,
-                          item, USER_ATTR, nofollow=symlink)
-        self.assertRaises(EnvironmentError, xattr.remove, item,
-                          USER_NN, namespace=NAMESPACE, nofollow=symlink)
-
-    def testNoXattrDeprecated(self):
-        """test no attributes (deprecated functions)"""
-        fh, fname = self._getfile()
-        lists_equal(xattr.listxattr(fname), [])
-        tuples_equal(xattr.get_all(fname), [])
-        self.assertRaises(EnvironmentError, xattr.getxattr, fname,
-                              USER_ATTR)
-        dname = self._getdir()
-        lists_equal(xattr.listxattr(dname), [])
-        tuples_equal(xattr.get_all(dname), [])
-        self.assertRaises(EnvironmentError, xattr.getxattr, dname,
-                              USER_ATTR)
-        _, sname = self._getsymlink()
-        lists_equal(xattr.listxattr(sname, True), [])
-        tuples_equal(xattr.get_all(sname, nofollow=True), [])
-        self.assertRaises(EnvironmentError, xattr.getxattr, fname,
-                              USER_ATTR, True)
-
-
-    def testNoXattr(self):
-        """test no attributes"""
-        fh, fname = self._getfile()
-        lists_equal(xattr.list(fname), [])
-        self.assertEqual(xattr.list(fname, namespace=NAMESPACE), [])
-        tuples_equal(xattr.get_all(fname), [])
-        self.assertEqual(xattr.get_all(fname, namespace=NAMESPACE), [])
-        self.assertRaises(EnvironmentError, xattr.get, fname,
-                              USER_NN, namespace=NAMESPACE)
-        dname = self._getdir()
-        lists_equal(xattr.list(dname), [])
-        self.assertEqual(xattr.list(dname, namespace=NAMESPACE), [])
-        tuples_equal(xattr.get_all(dname), [])
-        self.assertEqual(xattr.get_all(dname, namespace=NAMESPACE), [])
-        self.assertRaises(EnvironmentError, xattr.get, dname,
-                              USER_NN, namespace=NAMESPACE)
-        _, sname = self._getsymlink()
-        lists_equal(xattr.list(sname, nofollow=True), [])
-        self.assertEqual(xattr.list(sname, nofollow=True,
-                                    namespace=NAMESPACE), [])
-        tuples_equal(xattr.get_all(sname, nofollow=True), [])
-        self.assertEqual(xattr.get_all(sname, nofollow=True,
-                                           namespace=NAMESPACE), [])
-        self.assertRaises(EnvironmentError, xattr.get, sname,
-                              USER_NN, namespace=NAMESPACE, nofollow=True)
-
-    def testFileByNameDeprecated(self):
-        """test set and retrieve one attribute by file name (deprecated)"""
-        fh, fname = self._getfile()
-        self._checkDeprecated(fname)
-        os.close(fh)
-
-    def testFileByName(self):
-        """test set and retrieve one attribute by file name"""
-        fh, fname = self._getfile()
-        self._checkListSetGet(fname)
-        self._checkListSetGet(fname, use_ns=True)
-        os.close(fh)
-
-    def testFileByDescriptorDeprecated(self):
-        """test file descriptor operations (deprecated functions)"""
-        fh, fname = self._getfile()
-        self._checkDeprecated(fh)
-        os.close(fh)
-
-    def testFileByDescriptor(self):
-        """test file descriptor operations"""
-        fh, fname = self._getfile()
-        self._checkListSetGet(fh)
-        self._checkListSetGet(fh, use_ns=True)
-        os.close(fh)
-
-    def testFileByObjectDeprecated(self):
-        """test file descriptor operations (deprecated functions)"""
-        fh, fname = self._getfile()
-        fo = os.fdopen(fh)
-        self._checkDeprecated(fo)
-        fo.close()
-
-    def testFileByObject(self):
-        """test file descriptor operations"""
-        fh, fname = self._getfile()
-        fo = os.fdopen(fh)
-        self._checkListSetGet(fo)
-        self._checkListSetGet(fo, use_ns=True)
-        fo.close()
-
-    def testMixedAccessDeprecated(self):
-        """test mixed access to file (deprecated functions)"""
-        fh, fname = self._getfile()
-        fo = os.fdopen(fh)
+# Fixtures and helpers
+
+@pytest.fixture
+def testdir():
+    """per-test temp dir based in TEST_DIR"""
+    with tempfile.TemporaryDirectory(dir=TEST_DIR) as dname:
+        yield dname
+
+def get_file(path):
+    fh, fname = tempfile.mkstemp(".test", "xattr-", path)
+    return fh, fname
+
+def get_file_name(path):
+    fh, fname = get_file(path)
+    os.close(fh)
+    return fname
+
+def get_file_fd(path):
+    return get_file(path)[0]
+
+def get_file_object(path):
+    fd = get_file(path)[0]
+    return os.fdopen(fd)
+
+def get_dir(path):
+    return tempfile.mkdtemp(".test", "xattr-", path)
+
+def get_symlink(path, dangling=True):
+    """create a symlink"""
+    fh, fname = get_file(path)
+    os.close(fh)
+    if dangling:
+        os.unlink(fname)
+    sname = fname + ".symlink"
+    os.symlink(fname, sname)
+    return fname, sname
+
+def get_valid_symlink(path):
+    return get_symlink(path, dangling=False)[1]
+
+def get_dangling_symlink(path):
+    return get_symlink(path, dangling=True)[1]
+
+# Note: user attributes are only allowed on files and directories, so
+# we have to skip the symlinks here. See xattr(7).
+ITEMS_P = [
+    (get_file_name, False),
+    (get_file_fd, False),
+    (get_file_object, False),
+    (get_dir, False),
+    (get_valid_symlink, False),
+#    (get_valid_symlink, True),
+#    (get_dangling_symlink, True),
+]
+
+ITEMS_D = [
+    "file name",
+    "file FD",
+    "file object",
+    "directory",
+    "file via symlink",
+#    "valid symlink",
+#    "dangling symlink",
+]
+
+@pytest.fixture(params=ITEMS_P, ids=ITEMS_D)
+def subject(testdir, request):
+    return request.param[0](testdir), request.param[1]
+
+@pytest.fixture(params=[True, False], ids=["with namespace", "no namespace"])
+def use_ns(request):
+    return request.param
+
+@pytest.fixture(params=[True, False], ids=["dangling", "valid"])
+def use_dangling(request):
+    return request.param
+
+### Test functions
+
+def test_empty_value(subject):
+    item, nofollow = subject
+    xattr.set(item, USER_ATTR, EMPTY_VAL, nofollow=nofollow)
+    assert xattr.get(item, USER_ATTR, nofollow=nofollow) == EMPTY_VAL
+
+def test_large_value(subject):
+    item, nofollow = subject
+    xattr.set(item, USER_ATTR, LARGE_VAL)
+    assert xattr.get(item, USER_ATTR, nofollow=nofollow) == LARGE_VAL
+
+
+def test_file_mixed_access_deprecated(testdir):
+    """test mixed access to file (deprecated functions)"""
+    fh, fname = get_file(testdir)
+    with os.fdopen(fh) as fo:
         lists_equal(xattr.listxattr(fname), [])
         xattr.setxattr(fname, USER_ATTR, USER_VAL)
         lists_equal(xattr.listxattr(fh), [USER_ATTR])
-        self.assertEqual(xattr.getxattr(fo, USER_ATTR), USER_VAL)
+        assert xattr.getxattr(fo, USER_ATTR) == USER_VAL
         tuples_equal(xattr.get_all(fo), [(USER_ATTR, USER_VAL)])
         tuples_equal(xattr.get_all(fname),
-                         [(USER_ATTR, USER_VAL)])
-        fo.close()
+                     [(USER_ATTR, USER_VAL)])
 
-    def testMixedAccess(self):
-        """test mixed access to file"""
-        fh, fname = self._getfile()
-        fo = os.fdopen(fh)
+def test_file_mixed_access(testdir):
+    """test mixed access to file"""
+    fh, fname = get_file(testdir)
+    with os.fdopen(fh) as fo:
         lists_equal(xattr.list(fname), [])
         xattr.set(fname, USER_ATTR, USER_VAL)
         lists_equal(xattr.list(fh), [USER_ATTR])
-        self.assertEqual(xattr.list(fh, namespace=NAMESPACE), [USER_NN])
-        self.assertEqual(xattr.get(fo, USER_ATTR), USER_VAL)
-        self.assertEqual(xattr.get(fo, USER_NN, namespace=NAMESPACE),
-                         USER_VAL)
+        assert xattr.list(fh, namespace=NAMESPACE) == [USER_NN]
+        assert xattr.get(fo, USER_ATTR) == USER_VAL
+        assert xattr.get(fo, USER_NN, namespace=NAMESPACE) == USER_VAL
         tuples_equal(xattr.get_all(fo),
-                         [(USER_ATTR, USER_VAL)])
-        self.assertEqual(xattr.get_all(fo, namespace=NAMESPACE),
-                         [(USER_NN, USER_VAL)])
-        tuples_equal(xattr.get_all(fname),
-                         [(USER_ATTR, USER_VAL)])
-        self.assertEqual(xattr.get_all(fname, namespace=NAMESPACE),
-                         [(USER_NN, USER_VAL)])
-        fo.close()
-
-    def testDirOpsDeprecated(self):
-        """test attribute setting on directories (deprecated functions)"""
-        dname = self._getdir()
-        self._checkDeprecated(dname)
-
-    def testDirOps(self):
-        """test attribute setting on directories"""
-        dname = self._getdir()
-        self._checkListSetGet(dname)
-        self._checkListSetGet(dname, use_ns=True)
-
-    def testBinaryPayloadDeprecated(self):
-        """test binary values (deprecated functions)"""
-        fh, fname = self._getfile()
-        os.close(fh)
-        BINVAL = "abc" + '\0' + "def"
-        if PY3K:
-            BINVAL = BINVAL.encode()
-        xattr.setxattr(fname, USER_ATTR, BINVAL)
-        lists_equal(xattr.listxattr(fname), [USER_ATTR])
-        self.assertEqual(xattr.getxattr(fname, USER_ATTR), BINVAL)
-        tuples_equal(xattr.get_all(fname), [(USER_ATTR, BINVAL)])
-        xattr.removexattr(fname, USER_ATTR)
-
-    def testBinaryPayload(self):
-        """test binary values"""
-        fh, fname = self._getfile()
-        os.close(fh)
-        BINVAL = "abc" + '\0' + "def"
-        if PY3K:
-            BINVAL = BINVAL.encode()
-        xattr.set(fname, USER_ATTR, BINVAL)
-        lists_equal(xattr.list(fname), [USER_ATTR])
-        self.assertEqual(xattr.list(fname, namespace=NAMESPACE), [USER_NN])
-        self.assertEqual(xattr.get(fname, USER_ATTR), BINVAL)
-        self.assertEqual(xattr.get(fname, USER_NN,
-                                   namespace=NAMESPACE), BINVAL)
-        tuples_equal(xattr.get_all(fname), [(USER_ATTR, BINVAL)])
-        self.assertEqual(xattr.get_all(fname, namespace=NAMESPACE),
-                         [(USER_NN, BINVAL)])
-        xattr.remove(fname, USER_ATTR)
-
-    def testManyOpsDeprecated(self):
-        """test many ops (deprecated functions)"""
-        fh, fname = self._getfile()
-        xattr.setxattr(fh, USER_ATTR, USER_VAL)
-        VL = [USER_ATTR]
-        for i in range(MANYOPS_COUNT):
-            lists_equal(xattr.listxattr(fh), VL)
-        for i in range(MANYOPS_COUNT):
-            self.assertEqual(xattr.getxattr(fh, USER_ATTR), USER_VAL)
-        for i in range(MANYOPS_COUNT):
-            tuples_equal(xattr.get_all(fh),
-                             [(USER_ATTR, USER_VAL)])
-
-    def testManyOps(self):
-        """test many ops"""
-        fh, fname = self._getfile()
-        xattr.set(fh, USER_ATTR, USER_VAL)
-        VL = [USER_ATTR]
-        VN = [USER_NN]
-        for i in range(MANYOPS_COUNT):
-            lists_equal(xattr.list(fh), VL)
-            lists_equal(xattr.list(fh, namespace=EMPTY_NS), VL)
-            self.assertEqual(xattr.list(fh, namespace=NAMESPACE), VN)
-        for i in range(MANYOPS_COUNT):
-            self.assertEqual(xattr.get(fh, USER_ATTR), USER_VAL)
-            self.assertEqual(xattr.get(fh, USER_NN, namespace=NAMESPACE),
-                             USER_VAL)
-        for i in range(MANYOPS_COUNT):
-            tuples_equal(xattr.get_all(fh),
-                             [(USER_ATTR, USER_VAL)])
-            self.assertEqual(xattr.get_all(fh, namespace=NAMESPACE),
-                             [(USER_NN, USER_VAL)])
-
-    def testNoneNamespace(self):
-        fh, fname = self._getfile()
-        self.assertRaises(TypeError, xattr.get, fh, USER_ATTR,
-                          namespace=None)
-
-    def testEmptyValue(self):
-        fh, fname = self._getfile()
-        xattr.set(fh, USER_ATTR, EMPTY_VAL)
-        self.assertEqual(xattr.get(fh, USER_ATTR), EMPTY_VAL)
-
-    def testWrongCall(self):
-       for call in [xattr.get,
-                    xattr.list, xattr.listxattr,
-                    xattr.remove, xattr.removexattr,
-                    xattr.set, xattr.setxattr,
-                    xattr.get, xattr.getxattr]:
-           self.assertRaises(TypeError, call)
-
-    def testWrongType(self):
-        self.assertRaises(TypeError, xattr.get, object(), USER_ATTR)
-        for call in [xattr.listxattr, xattr.list]:
-            self.assertRaises(TypeError, call, object())
-        for call in [xattr.remove, xattr.removexattr,
-                     xattr.get, xattr.getxattr]:
-            self.assertRaises(TypeError, call, object(), USER_ATTR)
-        for call in [xattr.set, xattr.setxattr]:
-            self.assertRaises(TypeError, call, object(), USER_ATTR, USER_VAL)
-
-
-    def testLargeAttribute(self):
-        fh, fname = self._getfile()
-
-        xattr.set(fh, USER_ATTR, LARGE_VAL)
-        self.assertEqual(xattr.get(fh, USER_ATTR), LARGE_VAL)
-
-
-if __name__ == "__main__":
-    unittest.main()
+                     [(USER_ATTR, USER_VAL)])
+        assert xattr.get_all(fo, namespace=NAMESPACE) == \
+            [(USER_NN, USER_VAL)]
+        tuples_equal(xattr.get_all(fname), [(USER_ATTR, USER_VAL)])
+        assert xattr.get_all(fname, namespace=NAMESPACE) == \
+            [(USER_NN, USER_VAL)]
+
+def test_ListSetGet(subject, use_ns):
+    """check list, set, get operations against an item"""
+    item = subject[0]
+    lists_equal(xattr.list(item), [])
+    with pytest.raises(EnvironmentError):
+        if use_ns:
+            xattr.set(item, USER_NN, USER_VAL, flags=XATTR_REPLACE,
+                      namespace=NAMESPACE)
+        else:
+            xattr.set(item, USER_ATTR, USER_VAL, flags=XATTR_REPLACE)
+    if use_ns:
+        xattr.set(item, USER_NN, USER_VAL,
+                  namespace=NAMESPACE)
+    else:
+        xattr.set(item, USER_ATTR, USER_VAL)
+    with pytest.raises(EnvironmentError):
+        if use_ns:
+            xattr.set(item, USER_NN, USER_VAL,
+                      flags=XATTR_CREATE, namespace=NAMESPACE)
+        else:
+            xattr.set(item, USER_ATTR, USER_VAL, flags=XATTR_CREATE)
+    if use_ns:
+        assert xattr.list(item, namespace=NAMESPACE) == [USER_NN]
+    else:
+        lists_equal(xattr.list(item), [USER_ATTR])
+        lists_equal(xattr.list(item, namespace=EMPTY_NS),
+                    [USER_ATTR])
+    if use_ns:
+        assert xattr.get(item, USER_NN, namespace=NAMESPACE) == USER_VAL
+    else:
+        assert xattr.get(item, USER_ATTR) == USER_VAL
+    if use_ns:
+        assert xattr.get_all(item, namespace=NAMESPACE) == \
+            [(USER_NN, USER_VAL)]
+    else:
+        tuples_equal(xattr.get_all(item),
+                     [(USER_ATTR, USER_VAL)])
+    if use_ns:
+        xattr.remove(item, USER_NN, namespace=NAMESPACE)
+    else:
+        xattr.remove(item, USER_ATTR)
+    lists_equal(xattr.list(item), [])
+    tuples_equal(xattr.get_all(item), [])
+    with pytest.raises(EnvironmentError):
+        if use_ns:
+            xattr.remove(item, USER_NN, namespace=NAMESPACE)
+        else:
+            xattr.remove(item, USER_ATTR)
+
+def test_ListSetGetDeprecated(subject):
+    """check deprecated list, set, get operations against an item"""
+    item = subject[0]
+    lists_equal(xattr.listxattr(item), [])
+    with pytest.raises(EnvironmentError):
+        xattr.setxattr(item, USER_ATTR, USER_VAL, XATTR_REPLACE)
+    xattr.setxattr(item, USER_ATTR, USER_VAL, 0)
+    with pytest.raises(EnvironmentError):
+        xattr.setxattr(item, USER_ATTR, USER_VAL, XATTR_CREATE)
+    lists_equal(xattr.listxattr(item), [USER_ATTR])
+    assert xattr.getxattr(item, USER_ATTR) == USER_VAL
+    tuples_equal(xattr.get_all(item), [(USER_ATTR, USER_VAL)])
+    xattr.removexattr(item, USER_ATTR)
+    lists_equal(xattr.listxattr(item), [])
+    tuples_equal(xattr.get_all(item), [])
+    with pytest.raises(EnvironmentError):
+        xattr.removexattr(item, USER_ATTR)
+
+def test_many_ops(subject):
+    """test many ops"""
+    item = subject[0]
+    xattr.set(item, USER_ATTR, USER_VAL)
+    VL = [USER_ATTR]
+    VN = [USER_NN]
+    for i in range(MANYOPS_COUNT):
+        lists_equal(xattr.list(item), VL)
+        lists_equal(xattr.list(item, namespace=EMPTY_NS), VL)
+        assert xattr.list(item, namespace=NAMESPACE) == VN
+    for i in range(MANYOPS_COUNT):
+        assert xattr.get(item, USER_ATTR) == USER_VAL
+        assert xattr.get(item, USER_NN, namespace=NAMESPACE) == USER_VAL
+    for i in range(MANYOPS_COUNT):
+        tuples_equal(xattr.get_all(item),
+                     [(USER_ATTR, USER_VAL)])
+        assert xattr.get_all(item, namespace=NAMESPACE) == \
+            [(USER_NN, USER_VAL)]
+
+def test_many_ops_deprecated(subject):
+    """test many ops (deprecated functions)"""
+    item = subject[0]
+    xattr.setxattr(item, USER_ATTR, USER_VAL)
+    VL = [USER_ATTR]
+    for i in range(MANYOPS_COUNT):
+        lists_equal(xattr.listxattr(item), VL)
+    for i in range(MANYOPS_COUNT):
+        assert xattr.getxattr(item, USER_ATTR) == USER_VAL
+    for i in range(MANYOPS_COUNT):
+        tuples_equal(xattr.get_all(item),
+                     [(USER_ATTR, USER_VAL)])
+
+def test_no_attributes_deprecated(subject):
+    """test no attributes (deprecated functions)"""
+    item = subject[0]
+    lists_equal(xattr.listxattr(item), [])
+    tuples_equal(xattr.get_all(item), [])
+    with pytest.raises(EnvironmentError):
+        xattr.getxattr(item, USER_ATTR)
+
+def test_no_attributes_deprecated_symlinks(testdir, use_dangling):
+    """test no attributes on symlinks (deprecated functions)"""
+    _, sname = get_symlink(testdir, dangling=use_dangling)
+    lists_equal(xattr.listxattr(sname, True), [])
+    tuples_equal(xattr.get_all(sname, nofollow=True), [])
+    with pytest.raises(EnvironmentError):
+        xattr.getxattr(sname, USER_ATTR, True)
+
+def test_no_attributes(subject):
+    """test no attributes"""
+    item = subject[0]
+    lists_equal(xattr.list(item), [])
+    assert xattr.list(item, namespace=NAMESPACE) == []
+    tuples_equal(xattr.get_all(item), [])
+    assert xattr.get_all(item, namespace=NAMESPACE) == []
+    with pytest.raises(EnvironmentError):
+        xattr.get(item, USER_NN, namespace=NAMESPACE)
+
+def test_no_attributes_symlinks(testdir, use_dangling):
+    """test no attributes on symlinks"""
+    _, sname = get_symlink(testdir, dangling=use_dangling)
+    lists_equal(xattr.list(sname, nofollow=True), [])
+    assert xattr.list(sname, nofollow=True,
+                      namespace=NAMESPACE) == []
+    tuples_equal(xattr.get_all(sname, nofollow=True), [])
+    assert xattr.get_all(sname, nofollow=True,
+                         namespace=NAMESPACE) == []
+    with pytest.raises(EnvironmentError):
+        xattr.get(sname, USER_NN, namespace=NAMESPACE, nofollow=True)
+
+def test_binary_payload_deprecated(subject):
+    """test binary values (deprecated functions)"""
+    item = subject[0]
+    BINVAL = b"abc\0def"
+    xattr.setxattr(item, USER_ATTR, BINVAL)
+    lists_equal(xattr.listxattr(item), [USER_ATTR])
+    assert xattr.getxattr(item, USER_ATTR) == BINVAL
+    tuples_equal(xattr.get_all(item), [(USER_ATTR, BINVAL)])
+    xattr.removexattr(item, USER_ATTR)
+
+def test_binary_payload(subject):
+    """test binary values"""
+    item = subject[0]
+    BINVAL = b"abc\0def"
+    xattr.set(item, USER_ATTR, BINVAL)
+    lists_equal(xattr.list(item), [USER_ATTR])
+    assert xattr.list(item, namespace=NAMESPACE) == [USER_NN]
+    assert xattr.get(item, USER_ATTR) == BINVAL
+    assert xattr.get(item, USER_NN, namespace=NAMESPACE) == BINVAL
+    tuples_equal(xattr.get_all(item), [(USER_ATTR, BINVAL)])
+    assert xattr.get_all(item, namespace=NAMESPACE) == [(USER_NN, BINVAL)]
+    xattr.remove(item, USER_ATTR)
+
+def test_none_namespace(subject):
+    with pytest.raises(TypeError):
+        xattr.get(subject[0], USER_ATTR, namespace=None)
+
+@pytest.mark.parametrize(
+    "call",
+    [xattr.get, xattr.list, xattr.listxattr,
+     xattr.remove, xattr.removexattr,
+     xattr.set, xattr.setxattr,
+     xattr.get, xattr.getxattr])
+def test_wrong_call(call):
+    with pytest.raises(TypeError):
+        call()
+
+@pytest.mark.parametrize(
+    "call, args", [(xattr.get, [USER_ATTR]),
+                   (xattr.listxattr, []),
+                   (xattr.list, []),
+                   (xattr.remove, [USER_ATTR]),
+                   (xattr.removexattr, [USER_ATTR]),
+                   (xattr.get, [USER_ATTR]),
+                   (xattr.getxattr, [USER_ATTR]),
+                   (xattr.set, [USER_ATTR, USER_VAL]),
+                   (xattr.setxattr, [USER_ATTR, USER_VAL])])
+def test_wrong_argument_type(call, args):
+    with pytest.raises(TypeError):
+        call(object(), *args)
-- 
2.39.5