diff --git a/.gitignore b/.gitignore
index 193ead661b72436f8867bda4806b9a2fda43c93b..b28cdb65a8e8b61bcade31cae58e225dbf6a6ae9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -322,6 +322,9 @@ dlls/ntdll/tests/ntdll_crosstest.exe
 dlls/ntdll/tests/testlist.c
 dlls/ntdll/version.res
 dlls/ntdsapi/libntdsapi.def
+dlls/ntdsapi/tests/*.ok
+dlls/ntdsapi/tests/ntdsapi_crosstest.exe
+dlls/ntdsapi/tests/testlist.c
 dlls/ntoskrnl.exe/libntoskrnl.exe.def
 dlls/ntprint/ntprint.res
 dlls/ntprint/tests/*.ok
@@ -763,6 +766,7 @@ programs/winetest/msvcrtd_test.exe
 programs/winetest/msxml3_test.exe
 programs/winetest/netapi32_test.exe
 programs/winetest/ntdll_test.exe
+programs/winetest/ntdsapi_test.exe
 programs/winetest/ntprint_test.exe
 programs/winetest/odbccp32_test.exe
 programs/winetest/ole32_test.exe
diff --git a/Makefile.in b/Makefile.in
index 5365471f6e262d9d2aa181da624524d6b31e2226..5558f399b4dc4085464a7aad7e2f68ece9426fb3 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -333,6 +333,7 @@ ALL_MAKEFILES = \
 	dlls/ntdll/Makefile \
 	dlls/ntdll/tests/Makefile \
 	dlls/ntdsapi/Makefile \
+	dlls/ntdsapi/tests/Makefile \
 	dlls/ntoskrnl.exe/Makefile \
 	dlls/ntprint/Makefile \
 	dlls/ntprint/tests/Makefile \
@@ -722,6 +723,7 @@ dlls/newdev/Makefile: dlls/newdev/Makefile.in dlls/Makedll.rules
 dlls/ntdll/Makefile: dlls/ntdll/Makefile.in dlls/Makedll.rules
 dlls/ntdll/tests/Makefile: dlls/ntdll/tests/Makefile.in dlls/Maketest.rules
 dlls/ntdsapi/Makefile: dlls/ntdsapi/Makefile.in dlls/Makedll.rules
+dlls/ntdsapi/tests/Makefile: dlls/ntdsapi/tests/Makefile.in dlls/Maketest.rules
 dlls/ntoskrnl.exe/Makefile: dlls/ntoskrnl.exe/Makefile.in dlls/Makedll.rules
 dlls/ntprint/Makefile: dlls/ntprint/Makefile.in dlls/Makedll.rules
 dlls/ntprint/tests/Makefile: dlls/ntprint/tests/Makefile.in dlls/Maketest.rules
diff --git a/configure b/configure
index 238a278702647a02b64d981982c3fd99831c3f5f..563ee34c8bcd51e43a80dceec4b8834f5cc3d801 100755
--- a/configure
+++ b/configure
@@ -21459,6 +21459,8 @@ ac_config_files="$ac_config_files dlls/ntdll/tests/Makefile"
 
 ac_config_files="$ac_config_files dlls/ntdsapi/Makefile"
 
+ac_config_files="$ac_config_files dlls/ntdsapi/tests/Makefile"
+
 ac_config_files="$ac_config_files dlls/ntoskrnl.exe/Makefile"
 
 ac_config_files="$ac_config_files dlls/ntprint/Makefile"
@@ -22598,6 +22600,7 @@ do
     "dlls/ntdll/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/ntdll/Makefile" ;;
     "dlls/ntdll/tests/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/ntdll/tests/Makefile" ;;
     "dlls/ntdsapi/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/ntdsapi/Makefile" ;;
+    "dlls/ntdsapi/tests/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/ntdsapi/tests/Makefile" ;;
     "dlls/ntoskrnl.exe/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/ntoskrnl.exe/Makefile" ;;
     "dlls/ntprint/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/ntprint/Makefile" ;;
     "dlls/ntprint/tests/Makefile") CONFIG_FILES="$CONFIG_FILES dlls/ntprint/tests/Makefile" ;;
diff --git a/configure.ac b/configure.ac
index b81e11c515da5bd03955a2d69a9dfd16ffae08ac..2de529391f0ef45b296219aa6d0876c31a68a324 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1831,6 +1831,7 @@ AC_CONFIG_FILES([dlls/newdev/Makefile])
 AC_CONFIG_FILES([dlls/ntdll/Makefile])
 AC_CONFIG_FILES([dlls/ntdll/tests/Makefile])
 AC_CONFIG_FILES([dlls/ntdsapi/Makefile])
+AC_CONFIG_FILES([dlls/ntdsapi/tests/Makefile])
 AC_CONFIG_FILES([dlls/ntoskrnl.exe/Makefile])
 AC_CONFIG_FILES([dlls/ntprint/Makefile])
 AC_CONFIG_FILES([dlls/ntprint/tests/Makefile])
diff --git a/dlls/Makefile.in b/dlls/Makefile.in
index 758f0bde04cc8942b6d2ea2fbca9e60bb73642a3..4d02b13607f5e0bcb9bd868ea36a774214f9d403 100644
--- a/dlls/Makefile.in
+++ b/dlls/Makefile.in
@@ -296,6 +296,7 @@ TESTSUBDIRS = \
 	msxml3/tests \
 	netapi32/tests \
 	ntdll/tests \
+	ntdsapi/tests \
 	ntprint/tests \
 	odbccp32/tests \
 	ole32/tests \
diff --git a/dlls/ntdsapi/tests/Makefile.in b/dlls/ntdsapi/tests/Makefile.in
new file mode 100644
index 0000000000000000000000000000000000000000..05a7d2f8072497d6a2de0e7bb4dfbd5636a8194c
--- /dev/null
+++ b/dlls/ntdsapi/tests/Makefile.in
@@ -0,0 +1,13 @@
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
+TESTDLL   = ntdsapi.dll
+IMPORTS   = ntdsapi kernel32
+
+CTESTS = \
+	ntdsapi.c
+
+@MAKE_TEST_RULES@
+
+@DEPENDENCIES@  # everything below this line is overwritten by make depend
diff --git a/dlls/ntdsapi/tests/ntdsapi.c b/dlls/ntdsapi/tests/ntdsapi.c
new file mode 100644
index 0000000000000000000000000000000000000000..70cbe3e043dfee14a3f1edccb56608b209b4e7fc
--- /dev/null
+++ b/dlls/ntdsapi/tests/ntdsapi.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008 Robert Shearman (for CodeWeavers)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winnls.h"
+#include "ntdsapi.h"
+
+#include "wine/test.h"
+
+static const char *wine_dbgstr_w(LPCWSTR str)
+{
+    static char buf[512];
+    if (!str)
+        return "(null)";
+    WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL);
+    return buf;
+}
+
+static void test_DsMakeSpn(void)
+{
+    DWORD ret;
+    WCHAR spn[256];
+    DWORD spn_length;
+    static const WCHAR wszServiceClass[] = {'c','l','a','s','s',0};
+    static const WCHAR wszServiceHost[] = {'h','o','s','t',0};
+    static const WCHAR wszInstanceName[] = {'i','n','s','t','a','n','c','e',0};
+    static const WCHAR wszReferrer[] = {'r','e','f','e','r','r','e','r',0};
+    static const WCHAR wszSpn1[] = {'c','l','a','s','s','/','h','o','s','t',0};
+    static const WCHAR wszSpn2[] = {'c','l','a','s','s','/','i','n','s','t','a','n','c','e','/','h','o','s','t',0};
+    static const WCHAR wszSpn3[] = {'c','l','a','s','s','/','i','n','s','t','a','n','c','e',':','5','5','5','/','h','o','s','t',0};
+    static const WCHAR wszSpn4[] = {'c','l','a','s','s','/','i','n','s','t','a','n','c','e',':','5','5','5','/','h','o','s','t',0};
+    static const WCHAR wszSpn5[] = {'c','l','a','s','s','/','h','o','s','t',':','5','5','5',0};
+
+    spn[0] = '\0';
+
+    spn_length = sizeof(spn)/sizeof(spn[0]);
+    ret = DsMakeSpnW(NULL, NULL, NULL, 0, NULL, &spn_length, spn);
+    todo_wine
+    ok(ret == ERROR_INVALID_PARAMETER, "DsMakeSpnW should have failed with ERROR_INVALID_PARAMETER instead of %d\n", ret);
+
+    spn_length = sizeof(spn)/sizeof(spn[0]);
+    ret = DsMakeSpnW(NULL, wszServiceHost, NULL, 0, NULL, &spn_length, spn);
+    todo_wine
+    ok(ret == ERROR_INVALID_PARAMETER, "DsMakeSpnW should have failed with ERROR_INVALID_PARAMETER instead of %d\n", ret);
+
+    spn_length = sizeof(spn)/sizeof(spn[0]);
+    ret = DsMakeSpnW(wszServiceClass, wszServiceHost, NULL, 0, NULL, &spn_length, spn);
+    todo_wine {
+    ok(ret == ERROR_SUCCESS, "DsMakeSpnW should have succeeded instead of failing with %d\n", ret);
+    ok(!lstrcmpW(spn, wszSpn1), "DsMakeSpnW returned unexpected SPN %s\n", wine_dbgstr_w(spn));
+    ok(spn_length == lstrlenW(wszSpn1) + 1, "DsMakeSpnW should have returned spn_length of %d instead of %d\n", lstrlenW(wszSpn1) + 1, spn_length);
+    }
+
+    spn_length = sizeof(spn)/sizeof(spn[0]);
+    ret = DsMakeSpnW(wszServiceClass, wszServiceHost, wszInstanceName, 0, NULL, &spn_length, spn);
+    todo_wine {
+    ok(ret == ERROR_SUCCESS, "DsMakeSpnW should have succeeded instead of failing with %d\n", ret);
+    ok(!lstrcmpW(spn, wszSpn2), "DsMakeSpnW returned unexpected SPN %s\n", wine_dbgstr_w(spn));
+    ok(spn_length == lstrlenW(wszSpn2) + 1, "DsMakeSpnW should have returned spn_length of %d instead of %d\n", lstrlenW(wszSpn2) + 1, spn_length);
+    }
+
+    spn_length = sizeof(spn)/sizeof(spn[0]);
+    ret = DsMakeSpnW(wszServiceClass, wszServiceHost, wszInstanceName, 555, NULL, &spn_length, spn);
+    todo_wine {
+    ok(ret == ERROR_SUCCESS, "DsMakeSpnW should have succeeded instead of failing with %d\n", ret);
+    ok(!lstrcmpW(spn, wszSpn3), "DsMakeSpnW returned unexpected SPN %s\n", wine_dbgstr_w(spn));
+    ok(spn_length == lstrlenW(wszSpn3) + 1, "DsMakeSpnW should have returned spn_length of %d instead of %d\n", lstrlenW(wszSpn3) + 1, spn_length);
+    }
+
+    spn_length = sizeof(spn)/sizeof(spn[0]);
+    ret = DsMakeSpnW(wszServiceClass, wszServiceHost, wszInstanceName, 555, wszReferrer, &spn_length, spn);
+    todo_wine {
+    ok(ret == ERROR_SUCCESS, "DsMakeSpnW should have succeeded instead of failing with %d\n", ret);
+    ok(!lstrcmpW(spn, wszSpn4), "DsMakeSpnW returned unexpected SPN %s\n", wine_dbgstr_w(spn));
+    ok(spn_length == lstrlenW(wszSpn4) + 1, "DsMakeSpnW should have returned spn_length of %d instead of %d\n", lstrlenW(wszSpn4) + 1, spn_length);
+    }
+
+    spn_length = sizeof(spn)/sizeof(spn[0]);
+    ret = DsMakeSpnW(wszServiceClass, wszServiceHost, NULL, 555, wszReferrer, &spn_length, spn);
+    todo_wine {
+    ok(ret == ERROR_SUCCESS, "DsMakeSpnW should have succeeded instead of failing with %d\n", ret);
+    ok(!lstrcmpW(spn, wszSpn5), "DsMakeSpnW returned unexpected SPN %s\n", wine_dbgstr_w(spn));
+    ok(spn_length == lstrlenW(wszSpn5) + 1, "DsMakeSpnW should have returned spn_length of %d instead of %d\n", lstrlenW(wszSpn5) + 1, spn_length);
+    }
+}
+
+START_TEST( ntdsapi )
+{
+    test_DsMakeSpn();
+}
diff --git a/programs/winetest/Makefile.in b/programs/winetest/Makefile.in
index d3681a3e1fe43e439733cfac2e466b8239bf7d91..02448ab8adfb92f91fad6c421905c9624e84a177 100644
--- a/programs/winetest/Makefile.in
+++ b/programs/winetest/Makefile.in
@@ -62,6 +62,7 @@ TESTBINS = \
 	msxml3_test.exe \
 	netapi32_test.exe \
 	ntdll_test.exe \
+	ntdsapi_test.exe \
 	ntprint_test.exe \
 	odbccp32_test.exe \
 	ole32_test.exe \
@@ -179,6 +180,8 @@ netapi32_test.exe: $(DLLDIR)/netapi32/tests/netapi32_test.exe$(DLLEXT)
 	cp $(DLLDIR)/netapi32/tests/netapi32_test.exe$(DLLEXT) $@ && $(STRIP) $@
 ntdll_test.exe: $(DLLDIR)/ntdll/tests/ntdll_test.exe$(DLLEXT)
 	cp $(DLLDIR)/ntdll/tests/ntdll_test.exe$(DLLEXT) $@ && $(STRIP) $@
+ntdsapi_test.exe: $(DLLDIR)/ntdsapi/tests/ntdsapi_test.exe$(DLLEXT)
+	cp $(DLLDIR)/ntdsapi/tests/ntdsapi_test.exe$(DLLEXT) $@ && $(STRIP) $@
 ntprint_test.exe: $(DLLDIR)/ntprint/tests/ntprint_test.exe$(DLLEXT)
 	cp $(DLLDIR)/ntprint/tests/ntprint_test.exe$(DLLEXT) $@ && $(STRIP) $@
 odbccp32_test.exe: $(DLLDIR)/odbccp32/tests/odbccp32_test.exe$(DLLEXT)
diff --git a/programs/winetest/winetest.rc b/programs/winetest/winetest.rc
index 4b67bd2ca7437af94c6ccba3533d6c242fb25260..7f155d804eec3d65a22fd1038ed1312ef51f818e 100644
--- a/programs/winetest/winetest.rc
+++ b/programs/winetest/winetest.rc
@@ -120,6 +120,7 @@ msvcrtd_test.exe TESTRES "msvcrtd_test.exe"
 msxml3_test.exe TESTRES "msxml3_test.exe"
 netapi32_test.exe TESTRES "netapi32_test.exe"
 ntdll_test.exe TESTRES "ntdll_test.exe"
+ntdsapi_test.exe TESTRES "ntdsapi_test.exe"
 ntprint_test.exe TESTRES "ntprint_test.exe"
 odbccp32_test.exe TESTRES "odbccp32_test.exe"
 ole32_test.exe TESTRES "ole32_test.exe"