diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..a1e1e97
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln merge=binary
+#*.csproj merge=binary
+#*.vbproj merge=binary
+#*.vcxproj merge=binary
+#*.vcproj merge=binary
+#*.dbproj merge=binary
+#*.fsproj merge=binary
+#*.lsproj merge=binary
+#*.wixproj merge=binary
+#*.modelproj merge=binary
+#*.sqlproj merge=binary
+#*.wwaproj merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg binary
+#*.png binary
+#*.gif binary
+
+###############################################################################
+# diff behavior for common document formats
+#
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the
+# entries below.
+###############################################################################
+#*.doc diff=astextplain
+#*.DOC diff=astextplain
+#*.docx diff=astextplain
+#*.DOCX diff=astextplain
+#*.dot diff=astextplain
+#*.DOT diff=astextplain
+#*.pdf diff=astextplain
+#*.PDF diff=astextplain
+#*.rtf diff=astextplain
+#*.RTF diff=astextplain
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9491a2f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,363 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Oo]ut/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
\ No newline at end of file
diff --git a/DevopsTest.Tests/Assemblies/tSQLtCLR.dll b/DevopsTest.Tests/Assemblies/tSQLtCLR.dll
new file mode 100644
index 0000000..eb31531
Binary files /dev/null and b/DevopsTest.Tests/Assemblies/tSQLtCLR.dll differ
diff --git a/DevopsTest.Tests/DevopsTest.Tests.sqlproj b/DevopsTest.Tests/DevopsTest.Tests.sqlproj
new file mode 100644
index 0000000..9575e7f
--- /dev/null
+++ b/DevopsTest.Tests/DevopsTest.Tests.sqlproj
@@ -0,0 +1,288 @@
+
+
+
+ Debug
+ AnyCPU
+ DevopsTest.Tests
+ 2.0
+ 4.1
+ {36e394df-c0d4-4dbc-aab4-74ab0bbd2e54}
+ Microsoft.Data.Tools.Schema.Sql.Sql150DatabaseSchemaProvider
+ Database
+
+
+ DevopsTest.Tests
+ DevopsTest.Tests
+ 1033,CI
+ BySchemaAndSchemaType
+ True
+ v4.7.2
+ CS
+ Properties
+ False
+ True
+ True
+ SQL_Latin1_General_CP1_CI_AS
+ PRIMARY
+
+
+ bin\Release\
+ $(MSBuildProjectName).sql
+ False
+ pdbonly
+ true
+ false
+ true
+ prompt
+ 4
+
+
+ bin\Debug\
+ $(MSBuildProjectName).sql
+ false
+ true
+ full
+ false
+ true
+ true
+ prompt
+ 4
+
+
+ 11.0
+
+ True
+ 11.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Assemblies\tSQLtCLR.dll
+ tSQLtCLR
+ True
+ False
+ dbo
+ SAFE
+
+
+
+
+ C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\Extensions\Microsoft\SQLDB\Extensions\SqlServer\130\SqlSchemas\master.dacpac
+ False
+ sys
+
+
+ $(DacPacRootPath)\Extensions\Microsoft\SQLDB\Extensions\SqlServer\150\SqlSchemas\master.dacpac
+ False
+ sys
+
+
+
+
+ DevopsTest
+ {32c5d1b5-d115-46ef-90b7-8cd27fb6c5ee}
+ True
+ False
+ DevopsTest
+
+
+
+
+ DevopsTest
+ $(SqlCmdVar__1)
+
+
+
\ No newline at end of file
diff --git a/DevopsTest.Tests/Security/BookTests.sql b/DevopsTest.Tests/Security/BookTests.sql
new file mode 100644
index 0000000..c4e13d4
--- /dev/null
+++ b/DevopsTest.Tests/Security/BookTests.sql
@@ -0,0 +1,7 @@
+CREATE SCHEMA [BookTests]
+ AUTHORIZATION [dbo];
+
+
+GO
+EXECUTE sp_addextendedproperty @name = N'tSQLt.TestClass', @value = 1, @level0type = N'SCHEMA', @level0name = N'BookTests';
+
diff --git a/DevopsTest.Tests/Security/RoleMemberships.sql b/DevopsTest.Tests/Security/RoleMemberships.sql
new file mode 100644
index 0000000..c831663
--- /dev/null
+++ b/DevopsTest.Tests/Security/RoleMemberships.sql
@@ -0,0 +1,2 @@
+ALTER ROLE [db_owner] ADD MEMBER [g1];
+
diff --git a/DevopsTest.Tests/Security/g1.sql b/DevopsTest.Tests/Security/g1.sql
new file mode 100644
index 0000000..65dcf8d
--- /dev/null
+++ b/DevopsTest.Tests/Security/g1.sql
@@ -0,0 +1,2 @@
+CREATE USER [g1] FOR LOGIN [g1];
+
diff --git a/DevopsTest.Tests/Security/g1_1.sql b/DevopsTest.Tests/Security/g1_1.sql
new file mode 100644
index 0000000..d41ad56
--- /dev/null
+++ b/DevopsTest.Tests/Security/g1_1.sql
@@ -0,0 +1,3 @@
+CREATE LOGIN [g1]
+ WITH PASSWORD = N'b0ypxsfq+cwmdzcqdfvNbrvimsFT7_$!~ AV.Major
diff --git a/DevopsTest.Tests/tSQLt/Functions/@tSQLt_RunOnlyOnHostPlatform.sql b/DevopsTest.Tests/tSQLt/Functions/@tSQLt_RunOnlyOnHostPlatform.sql
new file mode 100644
index 0000000..06c3b98
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/@tSQLt_RunOnlyOnHostPlatform.sql
@@ -0,0 +1,12 @@
+CREATE FUNCTION tSQLt.[@tSQLt:RunOnlyOnHostPlatform](@HostPlatform NVARCHAR(MAX))
+RETURNS TABLE
+AS
+RETURN
+ SELECT SkipTestFunction.*
+ FROM (SELECT I.HostPlatform FROM tSQLt.Info() AS I WHERE I.HostPlatform <> @HostPlatform) AV
+ CROSS APPLY tSQLt.[@tSQLt:SkipTest]('HostPlatform is required to be '''+
+ @HostPlatform +
+ ''', but is '''+
+ AV.HostPlatform +
+ '''.'
+ ) AS SkipTestFunction;
diff --git a/DevopsTest.Tests/tSQLt/Functions/@tSQLt_SkipTest.sql b/DevopsTest.Tests/tSQLt/Functions/@tSQLt_SkipTest.sql
new file mode 100644
index 0000000..4f41231
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/@tSQLt_SkipTest.sql
@@ -0,0 +1,7 @@
+CREATE FUNCTION tSQLt.[@tSQLt:SkipTest](@SkipReason NVARCHAR(MAX))
+RETURNS TABLE
+AS
+RETURN
+ SELECT 'EXEC tSQLt.Private_SkipTestAnnotationHelper @SkipReason = '''+
+ ISNULL(NULLIF(REPLACE(@SkipReason,'''',''''''),''),'')+
+ ''';' AS AnnotationCmd;
diff --git a/DevopsTest.Tests/tSQLt/Functions/F_Num.sql b/DevopsTest.Tests/tSQLt/Functions/F_Num.sql
new file mode 100644
index 0000000..5729eec
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/F_Num.sql
@@ -0,0 +1,17 @@
+
+
+
+CREATE FUNCTION [tSQLt].[F_Num](
+ @N INT
+)
+RETURNS TABLE
+AS
+RETURN WITH C0(c) AS (SELECT 1 UNION ALL SELECT 1),
+ C1(c) AS (SELECT 1 FROM C0 AS A CROSS JOIN C0 AS B),
+ C2(c) AS (SELECT 1 FROM C1 AS A CROSS JOIN C1 AS B),
+ C3(c) AS (SELECT 1 FROM C2 AS A CROSS JOIN C2 AS B),
+ C4(c) AS (SELECT 1 FROM C3 AS A CROSS JOIN C3 AS B),
+ C5(c) AS (SELECT 1 FROM C4 AS A CROSS JOIN C4 AS B),
+ C6(c) AS (SELECT 1 FROM C5 AS A CROSS JOIN C5 AS B)
+ SELECT TOP(CASE WHEN @N>0 THEN @N ELSE 0 END) ROW_NUMBER() OVER (ORDER BY c) no
+ FROM C6;
diff --git a/DevopsTest.Tests/tSQLt/Functions/FriendlySQLServerVersion.sql b/DevopsTest.Tests/tSQLt/Functions/FriendlySQLServerVersion.sql
new file mode 100644
index 0000000..86b1f0d
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/FriendlySQLServerVersion.sql
@@ -0,0 +1,21 @@
+CREATE FUNCTION tSQLt.FriendlySQLServerVersion(@ProductVersion NVARCHAR(128))
+/* Important: Do not rename the @ProductVersion parameter! */
+RETURNS TABLE
+AS
+RETURN
+/* Important: Do not rename the @ProductVersion parameter! */
+/*StartSnip*/
+ SELECT
+ @ProductVersion ProductVersion,
+ CASE
+ WHEN SSV.Major = '15' THEN '2019'
+ WHEN SSV.Major = '14' THEN '2017'
+ WHEN SSV.Major = '13' THEN '2016'
+ WHEN SSV.Major = '12' THEN '2014'
+ WHEN SSV.Major = '11' THEN '2012'
+ WHEN SSV.Major = '10' AND SSV.Minor IN ('50','5') THEN '2008R2'
+ WHEN SSV.Major = '10' AND SSV.Minor IN ('00','0') THEN '2008'
+ END FriendlyVersion
+/*EndSnip*/
+/* Important: Do not rename the @ProductVersion parameter! */
+ FROM tSQLt.Private_SplitSqlVersion(@ProductVersion) AS SSV;
diff --git a/DevopsTest.Tests/tSQLt/Functions/GetTestResultFormatter.sql b/DevopsTest.Tests/tSQLt/Functions/GetTestResultFormatter.sql
new file mode 100644
index 0000000..b6d6457
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/GetTestResultFormatter.sql
@@ -0,0 +1,16 @@
+
+CREATE FUNCTION tSQLt.GetTestResultFormatter()
+RETURNS NVARCHAR(MAX)
+AS
+BEGIN
+ DECLARE @FormatterName NVARCHAR(MAX);
+
+ SELECT @FormatterName = CAST(value AS NVARCHAR(MAX))
+ FROM sys.extended_properties
+ WHERE name = N'tSQLt.ResultsFormatter'
+ AND major_id = OBJECT_ID('tSQLt.Private_OutputTestResults');
+
+ SELECT @FormatterName = COALESCE(@FormatterName, 'tSQLt.DefaultResultFormatter');
+
+ RETURN @FormatterName;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Info.sql b/DevopsTest.Tests/tSQLt/Functions/Info.sql
new file mode 100644
index 0000000..225e7a6
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Info.sql
@@ -0,0 +1,22 @@
+CREATE FUNCTION tSQLt.Info()
+RETURNS TABLE
+AS
+RETURN
+SELECT Version = '1.0.7950.1808',
+ ClrVersion = (SELECT tSQLt.Private::Info()),
+ ClrSigningKey = (SELECT tSQLt.Private::SigningKey()),
+ InstalledOnSqlVersion = (SELECT SqlVersion FROM tSQLt.Private_InstallationInfo()),
+ V.SqlVersion,
+ V.SqlBuild,
+ V.SqlEdition,
+ V.HostPlatform
+ FROM
+ (
+ SELECT CAST(PSSV.Major+'.'+PSSV.Minor AS NUMERIC(10,2)) AS SqlVersion,
+ CAST(PSSV.Build+'.'+PSSV.Revision AS NUMERIC(10,2)) AS SqlBuild,
+ PSV.Edition AS SqlEdition,
+ PHP.host_platform AS HostPlatform
+ FROM tSQLt.Private_SqlVersion() AS PSV
+ CROSS APPLY tSQLt.Private_SplitSqlVersion(PSV.ProductVersion) AS PSSV
+ CROSS JOIN tSQLt.Private_HostPlatform AS PHP
+ )V;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_CreateFakeFunctionStatement.sql b/DevopsTest.Tests/tSQLt/Functions/Private_CreateFakeFunctionStatement.sql
new file mode 100644
index 0000000..ccc66bb
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_CreateFakeFunctionStatement.sql
@@ -0,0 +1,83 @@
+CREATE FUNCTION tSQLt.Private_CreateFakeFunctionStatement(
+ @FunctionObjectId INT,
+ @ReturnValue NVARCHAR(MAX)
+)
+RETURNS TABLE
+AS
+RETURN
+ SELECT
+ 'CREATE FUNCTION ' + QUOTENAME(OBJECT_SCHEMA_NAME(@FunctionObjectId)) + '.' + QUOTENAME(OBJECT_NAME(@FunctionObjectId)) +
+ '(' +
+ ISNULL(PAS.ParametersAndReturnScalar, '') +
+ ISNULL(') RETURNS TABLE AS RETURN ' + T.TypeOnlySelectStatement,'') + ';' CreateStatement,
+ T.TypeOnlySelectStatement
+ FROM
+ (
+ SELECT
+ (
+ SELECT
+ CASE P.is_output
+ WHEN 0 THEN CASE WHEN P._RN_ = 1 THEN '' ELSE ',' END +P.name+' '+T.TypeName
+ WHEN 1 THEN ') RETURNS '+T.TypeName+' AS BEGIN RETURN CAST('+ISNULL(''''+@ReturnValue+'''','NULL')+' AS '+T.TypeName+'); END'
+ END
+ FROM
+ (
+ SELECT
+ ROW_NUMBER()OVER(ORDER BY PP.is_output ASC,PP.parameter_id ASC) _RN_,
+ PP.*
+ FROM
+ (
+ SELECT
+ object_id,
+ name,
+ parameter_id,
+ system_type_id,
+ user_type_id,
+ max_length,
+ precision,
+ scale,
+ is_output
+ FROM sys.parameters
+ ) AS PP
+ WHERE PP.object_id = @FunctionObjectId
+ )AS P
+ CROSS APPLY tSQLt.Private_GetFullTypeName(P.user_type_id,P.max_length,P.precision,P.scale,NULL) AS T
+ ORDER BY P._RN_
+ FOR XML PATH(''),TYPE
+ ).value('.','NVARCHAR(MAX)') ParametersAndReturnScalar
+ )PAS
+ CROSS JOIN
+ (
+ SELECT
+ (
+ SELECT
+ CASE WHEN P.column_id = 1
+ THEN 'SELECT TOP(0) '
+ ELSE ','
+ END +
+ 'CAST(NULL AS '+T.TypeName+') AS '+QUOTENAME(P.name)
+ FROM
+ (
+ SELECT
+ ROW_NUMBER()OVER(ORDER BY PP.column_id ASC) _RN_,
+ PP.*
+ FROM
+ (
+ SELECT
+ object_id,
+ name,
+ column_id,
+ system_type_id,
+ user_type_id,
+ max_length,
+ precision,
+ scale
+ FROM sys.columns
+ ) AS PP
+ WHERE PP.object_id = @FunctionObjectId
+ )AS P
+ CROSS APPLY tSQLt.Private_GetFullTypeName(P.user_type_id,P.max_length,P.precision,P.scale,NULL) AS T
+ ORDER BY P._RN_
+ FOR XML PATH(''),TYPE
+ ).value('.','NVARCHAR(MAX)') TypeOnlySelectStatement
+ )T
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_CreateFakeTableStatement.sql b/DevopsTest.Tests/tSQLt/Functions/Private_CreateFakeTableStatement.sql
new file mode 100644
index 0000000..2157db2
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_CreateFakeTableStatement.sql
@@ -0,0 +1,37 @@
+CREATE FUNCTION tSQLt.Private_CreateFakeTableStatement(
+ @OriginalTableObjectId INT,
+ @FullFakeTableName NVARCHAR(MAX),
+ @Identity BIT,
+ @ComputedColumns BIT,
+ @Defaults BIT,
+ @PreserveNOTNULL BIT
+)
+RETURNS TABLE
+AS
+RETURN
+ SELECT
+ 'CREATE TABLE ' + @FullFakeTableName + '(' + STUFF(Cols,1,1,'') + ')' CreateTableStatement,
+ 'CREATE TYPE ' + @FullFakeTableName + ' AS TABLE(' + STUFF(Cols,1,1,'') + ')' CreateTableTypeStatement
+ FROM
+ (
+ SELECT
+ (
+ SELECT
+ ',' +
+ QUOTENAME(name) +
+ cc.ColumnDefinition +
+ dc.DefaultDefinition +
+ id.IdentityDefinition +
+ CASE WHEN cc.IsComputedColumn = 1 OR id.IsIdentityColumn = 1
+ THEN ''
+ ELSE CASE WHEN @PreserveNOTNULL = 1 AND c.is_nullable = 0 THEN ' NOT NULL' ELSE ' NULL' END
+ END
+ FROM sys.columns c
+ CROSS APPLY tSQLt.Private_GetDataTypeOrComputedColumnDefinition(c.user_type_id, c.max_length, c.precision, c.scale, c.collation_name, c.object_id, c.column_id, @ComputedColumns) cc
+ CROSS APPLY tSQLt.Private_GetDefaultConstraintDefinition(c.object_id, c.column_id, @Defaults) AS dc
+ CROSS APPLY tSQLt.Private_GetIdentityDefinition(c.object_id, c.column_id, @Identity) AS id
+ WHERE object_id = @OriginalTableObjectId
+ ORDER BY column_id
+ FOR XML PATH(''), TYPE
+ ).value('.', 'NVARCHAR(MAX)')
+ ) AS X(Cols);
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_FindConstraint.sql b/DevopsTest.Tests/tSQLt/Functions/Private_FindConstraint.sql
new file mode 100644
index 0000000..f06f7b6
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_FindConstraint.sql
@@ -0,0 +1,15 @@
+
+CREATE FUNCTION tSQLt.Private_FindConstraint
+(
+ @TableObjectId INT,
+ @ConstraintName NVARCHAR(MAX)
+)
+RETURNS TABLE
+AS
+RETURN
+ SELECT TOP(1) constraints.object_id AS ConstraintObjectId, type_desc AS ConstraintType
+ FROM sys.objects constraints
+ CROSS JOIN tSQLt.Private_GetOriginalTableInfo(@TableObjectId) orgTbl
+ WHERE @ConstraintName IN (constraints.name, QUOTENAME(constraints.name))
+ AND constraints.parent_object_id = orgTbl.OrgTableObjectId
+ ORDER BY LEN(constraints.name) ASC;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetAnnotationList.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetAnnotationList.sql
new file mode 100644
index 0000000..3774895
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetAnnotationList.sql
@@ -0,0 +1,9 @@
+CREATE FUNCTION [tSQLt].[Private_GetAnnotationList]
+(@ProcedureDefinition NVARCHAR (MAX) NULL)
+RETURNS
+ TABLE (
+ [AnnotationNo] INT NULL,
+ [Annotation] NVARCHAR (MAX) NULL)
+AS
+ EXTERNAL NAME [tSQLtCLR].[tSQLtCLR.Annotations].[GetAnnotationList]
+
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetCleanObjectName.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetCleanObjectName.sql
new file mode 100644
index 0000000..590e759
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetCleanObjectName.sql
@@ -0,0 +1,7 @@
+
+CREATE FUNCTION [tSQLt].[Private_GetCleanObjectName](@ObjectName NVARCHAR(MAX))
+RETURNS NVARCHAR(MAX)
+AS
+BEGIN
+ RETURN (SELECT OBJECT_NAME(OBJECT_ID(@ObjectName)));
+END;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetCleanSchemaName.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetCleanSchemaName.sql
new file mode 100644
index 0000000..41a9fcc
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetCleanSchemaName.sql
@@ -0,0 +1,15 @@
+
+/*******************************************************************************************/
+/*******************************************************************************************/
+/*******************************************************************************************/
+CREATE FUNCTION tSQLt.Private_GetCleanSchemaName(@SchemaName NVARCHAR(MAX), @ObjectName NVARCHAR(MAX))
+RETURNS NVARCHAR(MAX)
+AS
+BEGIN
+ RETURN (SELECT SCHEMA_NAME(schema_id)
+ FROM sys.objects
+ WHERE object_id = CASE WHEN ISNULL(@SchemaName,'') in ('','[]')
+ THEN OBJECT_ID(@ObjectName)
+ ELSE OBJECT_ID(@SchemaName + '.' + @ObjectName)
+ END);
+END;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetCommaSeparatedColumnList.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetCommaSeparatedColumnList.sql
new file mode 100644
index 0000000..98f25e7
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetCommaSeparatedColumnList.sql
@@ -0,0 +1,14 @@
+CREATE FUNCTION tSQLt.Private_GetCommaSeparatedColumnList (@Table NVARCHAR(MAX), @ExcludeColumn NVARCHAR(MAX))
+RETURNS NVARCHAR(MAX)
+AS
+BEGIN
+ RETURN STUFF((
+ SELECT ',' + CASE WHEN system_type_id = TYPE_ID('timestamp') THEN ';TIMESTAMP columns are unsupported!;' ELSE QUOTENAME(name) END
+ FROM sys.columns
+ WHERE object_id = OBJECT_ID(@Table)
+ AND name <> @ExcludeColumn
+ ORDER BY column_id
+ FOR XML PATH(''), TYPE).value('.','NVARCHAR(MAX)')
+ ,1, 1, '');
+
+END;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetConfiguration.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetConfiguration.sql
new file mode 100644
index 0000000..1b35f40
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetConfiguration.sql
@@ -0,0 +1,10 @@
+CREATE FUNCTION tSQLt.Private_GetConfiguration(
+ @Name NVARCHAR(100)
+)
+RETURNS TABLE
+AS
+RETURN
+ SELECT PC.Name,
+ PC.Value
+ FROM tSQLt.Private_Configurations AS PC
+ WHERE PC.Name = @Name;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetConstraintType.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetConstraintType.sql
new file mode 100644
index 0000000..de56860
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetConstraintType.sql
@@ -0,0 +1,9 @@
+
+CREATE FUNCTION tSQLt.Private_GetConstraintType(@TableObjectId INT, @ConstraintName NVARCHAR(MAX))
+RETURNS TABLE
+AS
+RETURN
+ SELECT object_id,type,type_desc
+ FROM sys.objects
+ WHERE object_id = OBJECT_ID(SCHEMA_NAME(schema_id)+'.'+@ConstraintName)
+ AND parent_object_id = @TableObjectId;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetDataTypeOrComputedColumnDefinition.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetDataTypeOrComputedColumnDefinition.sql
new file mode 100644
index 0000000..1ca4034
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetDataTypeOrComputedColumnDefinition.sql
@@ -0,0 +1,20 @@
+CREATE FUNCTION tSQLt.Private_GetDataTypeOrComputedColumnDefinition(@UserTypeId INT, @MaxLength INT, @Precision INT, @Scale INT, @CollationName NVARCHAR(MAX), @ObjectId INT, @ColumnId INT, @ReturnDetails BIT)
+RETURNS TABLE
+AS
+RETURN SELECT
+ COALESCE(cc.IsComputedColumn, 0) AS IsComputedColumn,
+ COALESCE(cc.ComputedColumnDefinition, GFTN.TypeName) AS ColumnDefinition
+ FROM (SELECT @UserTypeId, @MaxLength, @Precision, @Scale, @CollationName, @ObjectId, @ColumnId, @ReturnDetails)
+ AS V(UserTypeId, MaxLength, Precision, Scale, CollationName, ObjectId, ColumnId, ReturnDetails)
+ CROSS APPLY tSQLt.Private_GetFullTypeName(V.UserTypeId, V.MaxLength, V.Precision, V.Scale, V.CollationName) AS GFTN
+ LEFT JOIN (SELECT 1 AS IsComputedColumn,
+ ' AS '+ cci.definition + CASE WHEN cci.is_persisted = 1 THEN ' PERSISTED' ELSE '' END AS ComputedColumnDefinition,
+ cci.object_id,
+ cci.column_id
+ FROM sys.computed_columns cci
+ )cc
+ ON cc.object_id = V.ObjectId
+ AND cc.column_id = V.ColumnId
+ AND V.ReturnDetails = 1;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetDefaultConstraintDefinition.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetDefaultConstraintDefinition.sql
new file mode 100644
index 0000000..582f430
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetDefaultConstraintDefinition.sql
@@ -0,0 +1,15 @@
+CREATE FUNCTION tSQLt.Private_GetDefaultConstraintDefinition(@ObjectId INT, @ColumnId INT, @ReturnDetails BIT)
+RETURNS TABLE
+AS
+RETURN SELECT
+ COALESCE(IsDefault, 0) AS IsDefault,
+ COALESCE(DefaultDefinition, '') AS DefaultDefinition
+ FROM (SELECT 1) X(X)
+ LEFT JOIN (SELECT 1 AS IsDefault,' DEFAULT '+ definition AS DefaultDefinition,parent_object_id,parent_column_id
+ FROM sys.default_constraints
+ )dc
+ ON dc.parent_object_id = @ObjectId
+ AND dc.parent_column_id = @ColumnId
+ AND @ReturnDetails = 1;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetForeignKeyDefinition.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetForeignKeyDefinition.sql
new file mode 100644
index 0000000..2561978
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetForeignKeyDefinition.sql
@@ -0,0 +1,53 @@
+
+CREATE FUNCTION tSQLt.Private_GetForeignKeyDefinition(
+ @SchemaName NVARCHAR(MAX),
+ @ParentTableName NVARCHAR(MAX),
+ @ForeignKeyName NVARCHAR(MAX),
+ @NoCascade BIT
+)
+RETURNS TABLE
+AS
+RETURN SELECT 'CONSTRAINT ' + name + ' FOREIGN KEY (' +
+ parCols + ') REFERENCES ' + refName + '(' + refCols + ')'+
+ CASE WHEN @NoCascade = 1 THEN ''
+ ELSE delete_referential_action_cmd + ' ' + update_referential_action_cmd
+ END AS cmd,
+ CASE
+ WHEN RefTableIsFakedInd = 1
+ THEN 'CREATE UNIQUE INDEX ' + tSQLt.Private::CreateUniqueObjectName() + ' ON ' + refName + '(' + refCols + ');'
+ ELSE ''
+ END CreIdxCmd
+ FROM (SELECT QUOTENAME(SCHEMA_NAME(k.schema_id)) AS SchemaName,
+ QUOTENAME(k.name) AS name,
+ QUOTENAME(OBJECT_NAME(k.parent_object_id)) AS parName,
+ QUOTENAME(SCHEMA_NAME(refTab.schema_id)) + '.' + QUOTENAME(refTab.name) AS refName,
+ parCol.ColNames AS parCols,
+ refCol.ColNames AS refCols,
+ 'ON UPDATE '+
+ CASE k.update_referential_action
+ WHEN 0 THEN 'NO ACTION'
+ WHEN 1 THEN 'CASCADE'
+ WHEN 2 THEN 'SET NULL'
+ WHEN 3 THEN 'SET DEFAULT'
+ END AS update_referential_action_cmd,
+ 'ON DELETE '+
+ CASE k.delete_referential_action
+ WHEN 0 THEN 'NO ACTION'
+ WHEN 1 THEN 'CASCADE'
+ WHEN 2 THEN 'SET NULL'
+ WHEN 3 THEN 'SET DEFAULT'
+ END AS delete_referential_action_cmd,
+ CASE WHEN e.name IS NULL THEN 0
+ ELSE 1
+ END AS RefTableIsFakedInd
+ FROM sys.foreign_keys k
+ CROSS APPLY tSQLt.Private_GetForeignKeyParColumns(k.object_id) AS parCol
+ CROSS APPLY tSQLt.Private_GetForeignKeyRefColumns(k.object_id) AS refCol
+ LEFT JOIN sys.extended_properties e
+ ON e.name = 'tSQLt.FakeTable_OrgTableName'
+ AND e.value = OBJECT_NAME(k.referenced_object_id)
+ JOIN sys.tables refTab
+ ON COALESCE(e.major_id,k.referenced_object_id) = refTab.object_id
+ WHERE k.parent_object_id = OBJECT_ID(@SchemaName + '.' + @ParentTableName)
+ AND k.object_id = OBJECT_ID(@SchemaName + '.' + @ForeignKeyName)
+ )x;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetForeignKeyParColumns.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetForeignKeyParColumns.sql
new file mode 100644
index 0000000..54ec178
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetForeignKeyParColumns.sql
@@ -0,0 +1,13 @@
+CREATE FUNCTION tSQLt.Private_GetForeignKeyParColumns(
+ @ConstraintObjectId INT
+)
+RETURNS TABLE
+AS
+RETURN SELECT STUFF((
+ SELECT ','+QUOTENAME(pci.name) FROM sys.foreign_key_columns c
+ JOIN sys.columns pci
+ ON pci.object_id = c.parent_object_id
+ AND pci.column_id = c.parent_column_id
+ WHERE @ConstraintObjectId = c.constraint_object_id
+ FOR XML PATH(''),TYPE
+ ).value('.','NVARCHAR(MAX)'),1,1,'') AS ColNames
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetForeignKeyRefColumns.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetForeignKeyRefColumns.sql
new file mode 100644
index 0000000..9622b97
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetForeignKeyRefColumns.sql
@@ -0,0 +1,14 @@
+
+CREATE FUNCTION tSQLt.Private_GetForeignKeyRefColumns(
+ @ConstraintObjectId INT
+)
+RETURNS TABLE
+AS
+RETURN SELECT STUFF((
+ SELECT ','+QUOTENAME(rci.name) FROM sys.foreign_key_columns c
+ JOIN sys.columns rci
+ ON rci.object_id = c.referenced_object_id
+ AND rci.column_id = c.referenced_column_id
+ WHERE @ConstraintObjectId = c.constraint_object_id
+ FOR XML PATH(''),TYPE
+ ).value('.','NVARCHAR(MAX)'),1,1,'') AS ColNames;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetFullTypeName.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetFullTypeName.sql
new file mode 100644
index 0000000..383c6bc
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetFullTypeName.sql
@@ -0,0 +1,28 @@
+CREATE FUNCTION tSQLt.Private_GetFullTypeName(@TypeId INT, @Length INT, @Precision INT, @Scale INT, @CollationName NVARCHAR(MAX))
+RETURNS TABLE
+AS
+RETURN SELECT X.SchemaName + '.' + X.Name + X.Suffix + X.Collation AS TypeName, X.SchemaName, X.Name, X.Suffix, X.is_table_type AS IsTableType
+FROM(
+ SELECT QUOTENAME(SCHEMA_NAME(T.schema_id)) SchemaName, QUOTENAME(T.name) Name,
+ CASE WHEN T.max_length = -1
+ THEN ''
+ WHEN @Length = -1
+ THEN '(MAX)'
+ WHEN T.name LIKE 'n%char'
+ THEN '(' + CAST(@Length / 2 AS NVARCHAR) + ')'
+ WHEN T.name LIKE '%char' OR T.name LIKE '%binary'
+ THEN '(' + CAST(@Length AS NVARCHAR) + ')'
+ WHEN T.name IN ('decimal', 'numeric')
+ THEN '(' + CAST(@Precision AS NVARCHAR) + ',' + CAST(@Scale AS NVARCHAR) + ')'
+ WHEN T.name IN ('datetime2', 'datetimeoffset', 'time')
+ THEN '(' + CAST(@Scale AS NVARCHAR) + ')'
+ ELSE ''
+ END Suffix,
+ CASE WHEN @CollationName IS NULL OR T.is_user_defined = 1 THEN ''
+ ELSE ' COLLATE ' + @CollationName
+ END Collation,
+ T.is_table_type
+ FROM tSQLt.Private_SysTypes AS T WHERE T.user_type_id = @TypeId
+ )X;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetIdentityDefinition.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetIdentityDefinition.sql
new file mode 100644
index 0000000..cc9baea
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetIdentityDefinition.sql
@@ -0,0 +1,19 @@
+
+CREATE FUNCTION tSQLt.Private_GetIdentityDefinition(@ObjectId INT, @ColumnId INT, @ReturnDetails BIT)
+RETURNS TABLE
+AS
+RETURN SELECT
+ COALESCE(IsIdentity, 0) AS IsIdentityColumn,
+ COALESCE(IdentityDefinition, '') AS IdentityDefinition
+ FROM (SELECT 1) X(X)
+ LEFT JOIN (SELECT 1 AS IsIdentity,
+ ' IDENTITY(' + CAST(seed_value AS NVARCHAR(MAX)) + ',' + CAST(increment_value AS NVARCHAR(MAX)) + ')' AS IdentityDefinition,
+ object_id,
+ column_id
+ FROM sys.identity_columns
+ ) AS id
+ ON id.object_id = @ObjectId
+ AND id.column_id = @ColumnId
+ AND @ReturnDetails = 1;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetLastTestNameIfNotProvided.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetLastTestNameIfNotProvided.sql
new file mode 100644
index 0000000..f129b12
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetLastTestNameIfNotProvided.sql
@@ -0,0 +1,18 @@
+
+----------------------------------------------------------------------
+CREATE FUNCTION tSQLt.Private_GetLastTestNameIfNotProvided(@TestName NVARCHAR(MAX))
+RETURNS NVARCHAR(MAX)
+AS
+BEGIN
+ IF(LTRIM(ISNULL(@TestName,'')) = '')
+ BEGIN
+ SELECT @TestName = TestName
+ FROM tSQLt.Run_LastExecution le
+ JOIN sys.dm_exec_sessions es
+ ON le.SessionId = es.session_id
+ AND le.LoginTime = es.login_time
+ WHERE es.session_id = @@SPID;
+ END
+
+ RETURN @TestName;
+END
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetOriginalTableInfo.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetOriginalTableInfo.sql
new file mode 100644
index 0000000..add8238
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetOriginalTableInfo.sql
@@ -0,0 +1,11 @@
+
+CREATE FUNCTION tSQLt.Private_GetOriginalTableInfo(@TableObjectId INT)
+RETURNS TABLE
+AS
+ RETURN SELECT CAST(value AS NVARCHAR(4000)) OrgTableName,
+ OBJECT_ID(QUOTENAME(OBJECT_SCHEMA_NAME(@TableObjectId)) + '.' + QUOTENAME(CAST(value AS NVARCHAR(4000)))) OrgTableObjectId
+ FROM sys.extended_properties
+ WHERE class_desc = 'OBJECT_OR_COLUMN'
+ AND major_id = @TableObjectId
+ AND minor_id = 0
+ AND name = 'tSQLt.FakeTable_OrgTableName';
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetOriginalTableName.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetOriginalTableName.sql
new file mode 100644
index 0000000..94066a5
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetOriginalTableName.sql
@@ -0,0 +1,16 @@
+
+
+/*******************************************************************************************/
+/*******************************************************************************************/
+/*******************************************************************************************/
+CREATE FUNCTION tSQLt.Private_GetOriginalTableName(@SchemaName NVARCHAR(MAX), @TableName NVARCHAR(MAX)) --DELETE!!!
+RETURNS NVARCHAR(MAX)
+AS
+BEGIN
+ RETURN (SELECT CAST(value AS NVARCHAR(4000))
+ FROM sys.extended_properties
+ WHERE class_desc = 'OBJECT_OR_COLUMN'
+ AND major_id = OBJECT_ID(@SchemaName + '.' + @TableName)
+ AND minor_id = 0
+ AND name = 'tSQLt.FakeTable_OrgTableName');
+END;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetQuotedFullName.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetQuotedFullName.sql
new file mode 100644
index 0000000..20b8184
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetQuotedFullName.sql
@@ -0,0 +1,9 @@
+
+CREATE FUNCTION tSQLt.Private_GetQuotedFullName(@Objectid INT)
+RETURNS NVARCHAR(517)
+AS
+BEGIN
+ DECLARE @QuotedName NVARCHAR(517);
+ SELECT @QuotedName = QUOTENAME(OBJECT_SCHEMA_NAME(@Objectid)) + '.' + QUOTENAME(OBJECT_NAME(@Objectid));
+ RETURN @QuotedName;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetQuotedTableNameForConstraint.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetQuotedTableNameForConstraint.sql
new file mode 100644
index 0000000..06c8b91
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetQuotedTableNameForConstraint.sql
@@ -0,0 +1,18 @@
+CREATE FUNCTION tSQLt.Private_GetQuotedTableNameForConstraint(@ConstraintObjectId INT)
+RETURNS TABLE
+AS
+RETURN
+ SELECT QUOTENAME(SCHEMA_NAME(newtbl.schema_id)) + '.' + QUOTENAME(OBJECT_NAME(newtbl.object_id)) QuotedTableName,
+ SCHEMA_NAME(newtbl.schema_id) SchemaName,
+ OBJECT_NAME(newtbl.object_id) TableName,
+ OBJECT_NAME(constraints.parent_object_id) OrgTableName
+ FROM sys.objects AS constraints
+ JOIN sys.extended_properties AS p
+ JOIN sys.objects AS newtbl
+ ON newtbl.object_id = p.major_id
+ AND p.minor_id = 0
+ AND p.class_desc = 'OBJECT_OR_COLUMN'
+ AND p.name = 'tSQLt.FakeTable_OrgTableName'
+ ON OBJECT_NAME(constraints.parent_object_id) = CAST(p.value AS NVARCHAR(4000))
+ AND constraints.schema_id = newtbl.schema_id
+ AND constraints.object_id = @ConstraintObjectId;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetSchemaId.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetSchemaId.sql
new file mode 100644
index 0000000..a668f91
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetSchemaId.sql
@@ -0,0 +1,13 @@
+
+CREATE FUNCTION tSQLt.Private_GetSchemaId(@SchemaName NVARCHAR(MAX))
+RETURNS INT
+AS
+BEGIN
+ RETURN (
+ SELECT TOP(1) schema_id
+ FROM sys.schemas
+ WHERE @SchemaName IN (name, QUOTENAME(name), QUOTENAME(name, '"'))
+ ORDER BY
+ CASE WHEN name = @SchemaName THEN 0 ELSE 1 END
+ );
+END;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_GetUniqueConstraintDefinition.sql b/DevopsTest.Tests/tSQLt/Functions/Private_GetUniqueConstraintDefinition.sql
new file mode 100644
index 0000000..fc96034
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_GetUniqueConstraintDefinition.sql
@@ -0,0 +1,54 @@
+CREATE FUNCTION tSQLt.Private_GetUniqueConstraintDefinition
+(
+ @ConstraintObjectId INT,
+ @QuotedTableName NVARCHAR(MAX)
+)
+RETURNS TABLE
+AS
+RETURN
+ SELECT 'ALTER TABLE '+
+ @QuotedTableName +
+ ' ADD CONSTRAINT ' +
+ QUOTENAME(OBJECT_NAME(@ConstraintObjectId)) +
+ ' ' +
+ CASE WHEN KC.type_desc = 'UNIQUE_CONSTRAINT'
+ THEN 'UNIQUE'
+ ELSE 'PRIMARY KEY'
+ END +
+ '(' +
+ STUFF((
+ SELECT ','+QUOTENAME(C.name)
+ FROM sys.index_columns AS IC
+ JOIN sys.columns AS C
+ ON IC.object_id = C.object_id
+ AND IC.column_id = C.column_id
+ WHERE KC.unique_index_id = IC.index_id
+ AND KC.parent_object_id = IC.object_id
+ FOR XML PATH(''),TYPE
+ ).value('.','NVARCHAR(MAX)'),
+ 1,
+ 1,
+ ''
+ ) +
+ ');' AS CreateConstraintCmd,
+ CASE WHEN KC.type_desc = 'UNIQUE_CONSTRAINT'
+ THEN ''
+ ELSE (
+ SELECT 'ALTER TABLE ' +
+ @QuotedTableName +
+ ' ALTER COLUMN ' +
+ QUOTENAME(C.name)+
+ cc.ColumnDefinition +
+ ' NOT NULL;'
+ FROM sys.index_columns AS IC
+ JOIN sys.columns AS C
+ ON IC.object_id = C.object_id
+ AND IC.column_id = C.column_id
+ CROSS APPLY tSQLt.Private_GetDataTypeOrComputedColumnDefinition(C.user_type_id, C.max_length, C.precision, C.scale, C.collation_name, C.object_id, C.column_id, 0) cc
+ WHERE KC.unique_index_id = IC.index_id
+ AND KC.parent_object_id = IC.object_id
+ FOR XML PATH(''),TYPE
+ ).value('.','NVARCHAR(MAX)')
+ END AS NotNullColumnCmd
+ FROM sys.key_constraints AS KC
+ WHERE KC.object_id = @ConstraintObjectId;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_InstallationInfo.sql b/DevopsTest.Tests/tSQLt/Functions/Private_InstallationInfo.sql
new file mode 100644
index 0000000..ccc7c96
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_InstallationInfo.sql
@@ -0,0 +1 @@
+CREATE FUNCTION tSQLt.Private_InstallationInfo() RETURNS TABLE AS RETURN SELECT CAST(15.00 AS NUMERIC(10,2)) AS SqlVersion;
\ No newline at end of file
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_IsTestClass.sql b/DevopsTest.Tests/tSQLt/Functions/Private_IsTestClass.sql
new file mode 100644
index 0000000..0e5f47e
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_IsTestClass.sql
@@ -0,0 +1,16 @@
+
+CREATE FUNCTION tSQLt.Private_IsTestClass(@TestClassName NVARCHAR(MAX))
+RETURNS BIT
+AS
+BEGIN
+ RETURN
+ CASE
+ WHEN EXISTS(
+ SELECT 1
+ FROM tSQLt.TestClasses
+ WHERE SchemaId = tSQLt.Private_GetSchemaId(@TestClassName)
+ )
+ THEN 1
+ ELSE 0
+ END;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_ListTestAnnotations.sql b/DevopsTest.Tests/tSQLt/Functions/Private_ListTestAnnotations.sql
new file mode 100644
index 0000000..0d6fa3d
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_ListTestAnnotations.sql
@@ -0,0 +1,11 @@
+CREATE FUNCTION tSQLt.Private_ListTestAnnotations(
+ @TestObjectId INT
+)
+RETURNS TABLE
+AS
+RETURN
+ SELECT
+ GAL.AnnotationNo,
+ REPLACE(GAL.Annotation,'''','''''') AS EscapedAnnotationString,
+ 'tSQLt.'+GAL.Annotation AS Annotation
+ FROM tSQLt.Private_GetAnnotationList(OBJECT_DEFINITION(@TestObjectId))AS GAL;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_PrepareTestResultForOutput.sql b/DevopsTest.Tests/tSQLt/Functions/Private_PrepareTestResultForOutput.sql
new file mode 100644
index 0000000..7f05148
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_PrepareTestResultForOutput.sql
@@ -0,0 +1,7 @@
+CREATE FUNCTION tSQLt.Private_PrepareTestResultForOutput()
+RETURNS TABLE
+AS
+RETURN
+ SELECT ROW_NUMBER() OVER(ORDER BY Result DESC, Name ASC) No,Name [Test Case Name],
+ RIGHT(SPACE(7)+CAST(DATEDIFF(MILLISECOND,TestStartTime,TestEndTime) AS VARCHAR(7)),7) AS [Dur(ms)], Result
+ FROM tSQLt.TestResult;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_QuoteClassNameForNewTestClass.sql b/DevopsTest.Tests/tSQLt/Functions/Private_QuoteClassNameForNewTestClass.sql
new file mode 100644
index 0000000..13b672b
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_QuoteClassNameForNewTestClass.sql
@@ -0,0 +1,12 @@
+
+CREATE FUNCTION tSQLt.Private_QuoteClassNameForNewTestClass(@ClassName NVARCHAR(MAX))
+ RETURNS NVARCHAR(MAX)
+AS
+BEGIN
+ RETURN
+ CASE WHEN @ClassName LIKE '[[]%]' THEN @ClassName
+ ELSE QUOTENAME(@ClassName)
+ END;
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_ResolveApplyConstraintParameters.sql b/DevopsTest.Tests/tSQLt/Functions/Private_ResolveApplyConstraintParameters.sql
new file mode 100644
index 0000000..305be50
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_ResolveApplyConstraintParameters.sql
@@ -0,0 +1,19 @@
+
+CREATE FUNCTION tSQLt.Private_ResolveApplyConstraintParameters
+(
+ @A NVARCHAR(MAX),
+ @B NVARCHAR(MAX),
+ @C NVARCHAR(MAX)
+)
+RETURNS TABLE
+AS
+RETURN
+ SELECT ConstraintObjectId, ConstraintType
+ FROM tSQLt.Private_FindConstraint(OBJECT_ID(@A), @B)
+ WHERE @C IS NULL
+ UNION ALL
+ SELECT *
+ FROM tSQLt.Private_FindConstraint(OBJECT_ID(@A + '.' + @B), @C)
+ UNION ALL
+ SELECT *
+ FROM tSQLt.Private_FindConstraint(OBJECT_ID(@C + '.' + @A), @B);
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_ResolveFakeTableNamesForBackwardCompatibility.sql b/DevopsTest.Tests/tSQLt/Functions/Private_ResolveFakeTableNamesForBackwardCompatibility.sql
new file mode 100644
index 0000000..426e3df
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_ResolveFakeTableNamesForBackwardCompatibility.sql
@@ -0,0 +1,12 @@
+
+CREATE FUNCTION tSQLt.Private_ResolveFakeTableNamesForBackwardCompatibility
+ (@TableName NVARCHAR(MAX), @SchemaName NVARCHAR(MAX))
+RETURNS TABLE AS
+RETURN
+ SELECT QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) AS CleanSchemaName,
+ QUOTENAME(OBJECT_NAME(object_id)) AS CleanTableName
+ FROM (SELECT CASE
+ WHEN @SchemaName IS NULL THEN OBJECT_ID(@TableName)
+ ELSE COALESCE(OBJECT_ID(@SchemaName + '.' + @TableName),OBJECT_ID(@TableName + '.' + @SchemaName))
+ END object_id
+ ) ids;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_ResolveName.sql b/DevopsTest.Tests/tSQLt/Functions/Private_ResolveName.sql
new file mode 100644
index 0000000..a735304
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_ResolveName.sql
@@ -0,0 +1,19 @@
+
+CREATE FUNCTION tSQLt.Private_ResolveName(@Name NVARCHAR(MAX))
+RETURNS TABLE
+AS
+RETURN
+ WITH resolvedNames(ord, schemaId, objectId, quotedSchemaName, quotedObjectName, quotedFullName, isTestClass, isTestCase, isSchema) AS
+ (SELECT 1, schemaId, NULL, quotedSchemaName, NULL, quotedSchemaName, isTestClass, 0, 1
+ FROM tSQLt.Private_ResolveSchemaName(@Name)
+ UNION ALL
+ SELECT 2, schemaId, objectId, quotedSchemaName, quotedObjectName, quotedFullName, 0, isTestCase, 0
+ FROM tSQLt.Private_ResolveObjectName(@Name)
+ UNION ALL
+ SELECT 3, NULL, NULL, NULL, NULL, NULL, 0, 0, 0
+ )
+ SELECT TOP(1) schemaId, objectId, quotedSchemaName, quotedObjectName, quotedFullName, isTestClass, isTestCase, isSchema
+ FROM resolvedNames
+ WHERE schemaId IS NOT NULL
+ OR ord = 3
+ ORDER BY ord
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_ResolveObjectName.sql b/DevopsTest.Tests/tSQLt/Functions/Private_ResolveObjectName.sql
new file mode 100644
index 0000000..e481a80
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_ResolveObjectName.sql
@@ -0,0 +1,25 @@
+
+CREATE FUNCTION tSQLt.Private_ResolveObjectName(@Name NVARCHAR(MAX))
+RETURNS TABLE
+AS
+RETURN
+ WITH ids(schemaId, objectId) AS
+ (SELECT SCHEMA_ID(OBJECT_SCHEMA_NAME(OBJECT_ID(@Name))),
+ OBJECT_ID(@Name)
+ ),
+ idsWithNames(schemaId, objectId, quotedSchemaName, quotedObjectName) AS
+ (SELECT schemaId, objectId,
+ QUOTENAME(SCHEMA_NAME(schemaId)) AS quotedSchemaName,
+ QUOTENAME(OBJECT_NAME(objectId)) AS quotedObjectName
+ FROM ids
+ )
+ SELECT schemaId,
+ objectId,
+ quotedSchemaName,
+ quotedObjectName,
+ quotedSchemaName + '.' + quotedObjectName AS quotedFullName,
+ CASE WHEN LOWER(quotedObjectName) LIKE '[[]test%]'
+ AND objectId = OBJECT_ID(quotedSchemaName + '.' + quotedObjectName,'P')
+ THEN 1 ELSE 0 END AS isTestCase
+ FROM idsWithNames;
+
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_ResolveSchemaName.sql b/DevopsTest.Tests/tSQLt/Functions/Private_ResolveSchemaName.sql
new file mode 100644
index 0000000..0211337
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_ResolveSchemaName.sql
@@ -0,0 +1,21 @@
+
+CREATE FUNCTION tSQLt.Private_ResolveSchemaName(@Name NVARCHAR(MAX))
+RETURNS TABLE
+AS
+RETURN
+ WITH ids(schemaId) AS
+ (SELECT tSQLt.Private_GetSchemaId(@Name)
+ ),
+ idsWithNames(schemaId, quotedSchemaName) AS
+ (SELECT schemaId,
+ QUOTENAME(SCHEMA_NAME(schemaId))
+ FROM ids
+ )
+ SELECT schemaId,
+ quotedSchemaName,
+ CASE WHEN EXISTS(SELECT 1 FROM tSQLt.TestClasses WHERE TestClasses.SchemaId = idsWithNames.schemaId)
+ THEN 1
+ ELSE 0
+ END AS isTestClass,
+ CASE WHEN schemaId IS NOT NULL THEN 1 ELSE 0 END AS isSchema
+ FROM idsWithNames;
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_ScriptIndex.sql b/DevopsTest.Tests/tSQLt/Functions/Private_ScriptIndex.sql
new file mode 100644
index 0000000..f31a14e
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_ScriptIndex.sql
@@ -0,0 +1,74 @@
+CREATE FUNCTION tSQLt.Private_ScriptIndex
+(
+ @object_id INT,
+ @index_id INT
+)
+RETURNS TABLE
+AS
+RETURN
+ SELECT I.index_id,
+ I.name AS index_name,
+ I.is_primary_key,
+ I.is_unique,
+ I.is_disabled,
+ 'CREATE ' +
+ CASE WHEN I.is_unique = 1 THEN 'UNIQUE ' ELSE '' END +
+ CASE I.type
+ WHEN 1 THEN 'CLUSTERED'
+ WHEN 2 THEN 'NONCLUSTERED'
+ WHEN 5 THEN 'CLUSTERED COLUMNSTORE'
+ WHEN 6 THEN 'NONCLUSTERED COLUMNSTORE'
+ ELSE '{Index Type Not Supported!}'
+ END +
+ ' INDEX ' +
+ QUOTENAME(I.name)+
+ ' ON ' + QUOTENAME(OBJECT_SCHEMA_NAME(@object_id)) + '.' + QUOTENAME(OBJECT_NAME(@object_id)) +
+ CASE WHEN I.type NOT IN (5)
+ THEN
+ '('+
+ CL.column_list +
+ ')'
+ ELSE ''
+ END +
+ CASE WHEN I.has_filter = 1
+ THEN 'WHERE' + I.filter_definition
+ ELSE ''
+ END +
+ CASE WHEN I.is_hypothetical = 1
+ THEN 'WITH(STATISTICS_ONLY = -1)'
+ ELSE ''
+ END +
+ ';' AS create_cmd
+ FROM tSQLt.Private_SysIndexes AS I
+ CROSS APPLY
+ (
+ SELECT
+ (
+ SELECT
+ CASE WHEN OIC.rn > 1 THEN ',' ELSE '' END +
+ CASE WHEN OIC.rn = 1 AND OIC.is_included_column = 1 AND I.type NOT IN (6) THEN ')INCLUDE(' ELSE '' END +
+ QUOTENAME(OIC.name) +
+ CASE WHEN OIC.is_included_column = 0
+ THEN CASE WHEN OIC.is_descending_key = 1 THEN 'DESC' ELSE 'ASC' END
+ ELSE ''
+ END
+ FROM
+ (
+ SELECT C.name,
+ IC.is_descending_key,
+ IC.key_ordinal,
+ IC.is_included_column,
+ ROW_NUMBER()OVER(PARTITION BY IC.is_included_column ORDER BY IC.key_ordinal, IC.index_column_id) AS rn
+ FROM sys.index_columns AS IC
+ JOIN sys.columns AS C
+ ON IC.column_id = C.column_id
+ AND IC.object_id = C.object_id
+ WHERE IC.object_id = I.object_id
+ AND IC.index_id = I.index_id
+ )OIC
+ ORDER BY OIC.is_included_column, OIC.rn
+ FOR XML PATH(''),TYPE
+ ).value('.','NVARCHAR(MAX)') AS column_list
+ )CL
+ WHERE I.object_id = @object_id
+ AND I.index_id = ISNULL(@index_id,I.index_id);
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_SplitSqlVersion.sql b/DevopsTest.Tests/tSQLt/Functions/Private_SplitSqlVersion.sql
new file mode 100644
index 0000000..71ad41a
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_SplitSqlVersion.sql
@@ -0,0 +1,15 @@
+CREATE FUNCTION tSQLt.Private_SplitSqlVersion(@ProductVersion NVARCHAR(128))
+/* Important: Do not rename the @ProducVersion parameter! */
+RETURNS TABLE
+AS
+RETURN
+/* Important: Do not rename the @ProducVersion parameter! */
+/*StartSnip*/
+SELECT REVERSE(PARSENAME(X.RP,1)) Major,
+ REVERSE(PARSENAME(X.RP,2)) Minor,
+ REVERSE(PARSENAME(X.RP,3)) Build,
+ REVERSE(PARSENAME(X.RP,4)) Revision
+ FROM (SELECT REVERSE(@ProductVersion)) AS X(RP)
+/*EndSnip*/
+;
+/* Important: Do not rename the @ProducVersion parameter! */
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_SqlVariantFormatter.sql b/DevopsTest.Tests/tSQLt/Functions/Private_SqlVariantFormatter.sql
new file mode 100644
index 0000000..8a8925d
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_SqlVariantFormatter.sql
@@ -0,0 +1,23 @@
+
+CREATE FUNCTION tSQLt.Private_SqlVariantFormatter(@Value SQL_VARIANT)
+RETURNS NVARCHAR(MAX)
+AS
+BEGIN
+ RETURN CASE UPPER(CAST(SQL_VARIANT_PROPERTY(@Value,'BaseType')AS sysname))
+ WHEN 'FLOAT' THEN CONVERT(NVARCHAR(MAX),@Value,2)
+ WHEN 'REAL' THEN CONVERT(NVARCHAR(MAX),@Value,1)
+ WHEN 'MONEY' THEN CONVERT(NVARCHAR(MAX),@Value,2)
+ WHEN 'SMALLMONEY' THEN CONVERT(NVARCHAR(MAX),@Value,2)
+ WHEN 'DATE' THEN CONVERT(NVARCHAR(MAX),@Value,126)
+ WHEN 'DATETIME' THEN CONVERT(NVARCHAR(MAX),@Value,126)
+ WHEN 'DATETIME2' THEN CONVERT(NVARCHAR(MAX),@Value,126)
+ WHEN 'DATETIMEOFFSET' THEN CONVERT(NVARCHAR(MAX),@Value,126)
+ WHEN 'SMALLDATETIME' THEN CONVERT(NVARCHAR(MAX),@Value,126)
+ WHEN 'TIME' THEN CONVERT(NVARCHAR(MAX),@Value,126)
+ WHEN 'BINARY' THEN CONVERT(NVARCHAR(MAX),@Value,1)
+ WHEN 'VARBINARY' THEN CONVERT(NVARCHAR(MAX),@Value,1)
+ ELSE CAST(@Value AS NVARCHAR(MAX))
+ END;
+END
+
+
diff --git a/DevopsTest.Tests/tSQLt/Functions/Private_SqlVersion.sql b/DevopsTest.Tests/tSQLt/Functions/Private_SqlVersion.sql
new file mode 100644
index 0000000..788f742
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/Private_SqlVersion.sql
@@ -0,0 +1,7 @@
+CREATE FUNCTION tSQLt.Private_SqlVersion()
+RETURNS TABLE
+AS
+RETURN
+ SELECT
+ CAST(SERVERPROPERTY('ProductVersion')AS NVARCHAR(128)) ProductVersion,
+ CAST(SERVERPROPERTY('Edition')AS NVARCHAR(128)) Edition
diff --git a/DevopsTest.Tests/tSQLt/Functions/TestCaseSummary.sql b/DevopsTest.Tests/tSQLt/Functions/TestCaseSummary.sql
new file mode 100644
index 0000000..9048b05
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Functions/TestCaseSummary.sql
@@ -0,0 +1,21 @@
+
+----------------------------------------------------------------------
+
+CREATE FUNCTION tSQLt.TestCaseSummary()
+RETURNS TABLE
+AS
+RETURN WITH A(Cnt, SuccessCnt, SkippedCnt, FailCnt, ErrorCnt) AS (
+ SELECT COUNT(1),
+ ISNULL(SUM(CASE WHEN Result = 'Success' THEN 1 ELSE 0 END), 0),
+ ISNULL(SUM(CASE WHEN Result = 'Skipped' THEN 1 ELSE 0 END), 0),
+ ISNULL(SUM(CASE WHEN Result = 'Failure' THEN 1 ELSE 0 END), 0),
+ ISNULL(SUM(CASE WHEN Result = 'Error' THEN 1 ELSE 0 END), 0)
+ FROM tSQLt.TestResult
+
+ )
+ SELECT 'Test Case Summary: ' + CAST(Cnt AS NVARCHAR) + ' test case(s) executed, '+
+ CAST(SuccessCnt AS NVARCHAR) + ' succeeded, '+
+ CAST(SkippedCnt AS NVARCHAR) + ' skipped, '+
+ CAST(FailCnt AS NVARCHAR) + ' failed, '+
+ CAST(ErrorCnt AS NVARCHAR) + ' errored.' Msg,*
+ FROM A;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/ApplyConstraint.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/ApplyConstraint.sql
new file mode 100644
index 0000000..4e9fc59
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/ApplyConstraint.sql
@@ -0,0 +1,36 @@
+
+CREATE PROCEDURE tSQLt.ApplyConstraint
+ @TableName NVARCHAR(MAX),
+ @ConstraintName NVARCHAR(MAX),
+ @SchemaName NVARCHAR(MAX) = NULL, --parameter preserved for backward compatibility. Do not use. Will be removed soon.
+ @NoCascade BIT = 0
+AS
+BEGIN
+ DECLARE @ConstraintType NVARCHAR(MAX);
+ DECLARE @ConstraintObjectId INT;
+
+ SELECT @ConstraintType = ConstraintType, @ConstraintObjectId = ConstraintObjectId
+ FROM tSQLt.Private_ResolveApplyConstraintParameters (@TableName, @ConstraintName, @SchemaName);
+
+ IF @ConstraintType = 'CHECK_CONSTRAINT'
+ BEGIN
+ EXEC tSQLt.Private_ApplyCheckConstraint @ConstraintObjectId;
+ RETURN 0;
+ END
+
+ IF @ConstraintType = 'FOREIGN_KEY_CONSTRAINT'
+ BEGIN
+ EXEC tSQLt.Private_ApplyForeignKeyConstraint @ConstraintObjectId, @NoCascade;
+ RETURN 0;
+ END;
+
+ IF @ConstraintType IN('UNIQUE_CONSTRAINT', 'PRIMARY_KEY_CONSTRAINT')
+ BEGIN
+ EXEC tSQLt.Private_ApplyUniqueConstraint @ConstraintObjectId;
+ RETURN 0;
+ END;
+
+ RAISERROR ('ApplyConstraint could not resolve the object names, ''%s'', ''%s''. Be sure to call ApplyConstraint and pass in two parameters, such as: EXEC tSQLt.ApplyConstraint ''MySchema.MyTable'', ''MyConstraint''',
+ 16, 10, @TableName, @ConstraintName);
+ RETURN 0;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/ApplyTrigger.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/ApplyTrigger.sql
new file mode 100644
index 0000000..3579029
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/ApplyTrigger.sql
@@ -0,0 +1,34 @@
+
+CREATE PROCEDURE tSQLt.ApplyTrigger
+ @TableName NVARCHAR(MAX),
+ @TriggerName NVARCHAR(MAX)
+AS
+BEGIN
+ DECLARE @OrgTableObjectId INT;
+ SELECT @OrgTableObjectId = OrgTableObjectId FROM tSQLt.Private_GetOriginalTableInfo(OBJECT_ID(@TableName)) orgTbl
+ IF(@OrgTableObjectId IS NULL)
+ BEGIN
+ RAISERROR('%s does not exist or was not faked by tSQLt.FakeTable.', 16, 10, @TableName);
+ END;
+
+ DECLARE @FullTriggerName NVARCHAR(MAX);
+ DECLARE @TriggerObjectId INT;
+ SELECT @FullTriggerName = QUOTENAME(SCHEMA_NAME(schema_id))+'.'+QUOTENAME(name), @TriggerObjectId = object_id
+ FROM sys.objects WHERE PARSENAME(@TriggerName,1) = name AND parent_object_id = @OrgTableObjectId;
+
+ DECLARE @TriggerCode NVARCHAR(MAX);
+ SELECT @TriggerCode = m.definition
+ FROM sys.sql_modules m
+ WHERE m.object_id = @TriggerObjectId;
+
+ IF (@TriggerCode IS NULL)
+ BEGIN
+ RAISERROR('%s is not a trigger on %s', 16, 10, @TriggerName, @TableName);
+ END;
+
+ EXEC tSQLt.RemoveObject @FullTriggerName;
+
+ EXEC(@TriggerCode);
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/AssertEmptyTable.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertEmptyTable.sql
new file mode 100644
index 0000000..6feed4f
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertEmptyTable.sql
@@ -0,0 +1,34 @@
+
+CREATE PROCEDURE tSQLt.AssertEmptyTable
+ @TableName NVARCHAR(MAX),
+ @Message NVARCHAR(MAX) = ''
+AS
+BEGIN
+ EXEC tSQLt.AssertObjectExists @TableName;
+
+ DECLARE @FullName NVARCHAR(MAX);
+ IF(OBJECT_ID(@TableName) IS NULL AND OBJECT_ID('tempdb..'+@TableName) IS NOT NULL)
+ BEGIN
+ SET @FullName = CASE WHEN LEFT(@TableName,1) = '[' THEN @TableName ELSE QUOTENAME(@TableName)END;
+ END;
+ ELSE
+ BEGIN
+ SET @FullName = tSQLt.Private_GetQuotedFullName(OBJECT_ID(@TableName));
+ END;
+
+ DECLARE @cmd NVARCHAR(MAX);
+ DECLARE @exists INT;
+ SET @cmd = 'SELECT @exists = CASE WHEN EXISTS(SELECT 1 FROM '+@FullName+') THEN 1 ELSE 0 END;'
+ EXEC sp_executesql @cmd,N'@exists INT OUTPUT', @exists OUTPUT;
+
+ IF(@exists = 1)
+ BEGIN
+ DECLARE @TableToText NVARCHAR(MAX);
+ EXEC tSQLt.TableToText @TableName = @FullName,@txt = @TableToText OUTPUT;
+ DECLARE @Msg NVARCHAR(MAX);
+ SET @Msg = @FullName + ' was not empty:' + CHAR(13) + CHAR(10)+ @TableToText;
+ EXEC tSQLt.Fail @Message,@Msg;
+ END
+END
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/AssertEquals.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertEquals.sql
new file mode 100644
index 0000000..c6c462a
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertEquals.sql
@@ -0,0 +1,17 @@
+
+
+CREATE PROCEDURE tSQLt.AssertEquals
+ @Expected SQL_VARIANT,
+ @Actual SQL_VARIANT,
+ @Message NVARCHAR(MAX) = ''
+AS
+BEGIN
+ IF ((@Expected = @Actual) OR (@Actual IS NULL AND @Expected IS NULL))
+ RETURN 0;
+
+ DECLARE @Msg NVARCHAR(MAX);
+ SELECT @Msg = 'Expected: <' + ISNULL(CAST(@Expected AS NVARCHAR(MAX)), 'NULL') +
+ '> but was: <' + ISNULL(CAST(@Actual AS NVARCHAR(MAX)), 'NULL') + '>';
+ IF((COALESCE(@Message,'') <> '') AND (@Message NOT LIKE '% ')) SET @Message = @Message + ' ';
+ EXEC tSQLt.Fail @Message, @Msg;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/AssertEqualsString.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertEqualsString.sql
new file mode 100644
index 0000000..bc6fc2f
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertEqualsString.sql
@@ -0,0 +1,16 @@
+CREATE PROCEDURE tSQLt.AssertEqualsString
+ @Expected NVARCHAR(MAX),
+ @Actual NVARCHAR(MAX),
+ @Message NVARCHAR(MAX) = ''
+AS
+BEGIN
+ IF ((@Expected = @Actual) OR (@Actual IS NULL AND @Expected IS NULL))
+ RETURN 0;
+
+ DECLARE @Msg NVARCHAR(MAX);
+ SELECT @Msg = CHAR(13)+CHAR(10)+
+ 'Expected: ' + ISNULL('<'+@Expected+'>', 'NULL') +
+ CHAR(13)+CHAR(10)+
+ 'but was : ' + ISNULL('<'+@Actual+'>', 'NULL');
+ EXEC tSQLt.Fail @Message, @Msg;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/AssertEqualsTable.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertEqualsTable.sql
new file mode 100644
index 0000000..245096d
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertEqualsTable.sql
@@ -0,0 +1,47 @@
+
+CREATE PROCEDURE tSQLt.AssertEqualsTable
+ @Expected NVARCHAR(MAX),
+ @Actual NVARCHAR(MAX),
+ @Message NVARCHAR(MAX) = NULL,
+ @FailMsg NVARCHAR(MAX) = 'Unexpected/missing resultset rows!'
+AS
+BEGIN
+
+ EXEC tSQLt.AssertObjectExists @Expected;
+ EXEC tSQLt.AssertObjectExists @Actual;
+
+ DECLARE @ResultTable NVARCHAR(MAX);
+ DECLARE @ResultColumn NVARCHAR(MAX);
+ DECLARE @ColumnList NVARCHAR(MAX);
+ DECLARE @UnequalRowsExist INT;
+ DECLARE @CombinedMessage NVARCHAR(MAX);
+
+ SELECT @ResultTable = tSQLt.Private::CreateUniqueObjectName();
+ SELECT @ResultColumn = 'RC_' + @ResultTable;
+
+ EXEC tSQLt.Private_CreateResultTableForCompareTables
+ @ResultTable = @ResultTable,
+ @ResultColumn = @ResultColumn,
+ @BaseTable = @Expected;
+
+ SELECT @ColumnList = tSQLt.Private_GetCommaSeparatedColumnList(@ResultTable, @ResultColumn);
+
+ EXEC tSQLt.Private_ValidateThatAllDataTypesInTableAreSupported @ResultTable, @ColumnList;
+
+ EXEC @UnequalRowsExist = tSQLt.Private_CompareTables
+ @Expected = @Expected,
+ @Actual = @Actual,
+ @ResultTable = @ResultTable,
+ @ColumnList = @ColumnList,
+ @MatchIndicatorColumnName = @ResultColumn;
+
+ SET @CombinedMessage = ISNULL(@Message + CHAR(13) + CHAR(10),'') + @FailMsg;
+ EXEC tSQLt.Private_CompareTablesFailIfUnequalRowsExists
+ @UnequalRowsExist = @UnequalRowsExist,
+ @ResultTable = @ResultTable,
+ @ResultColumn = @ResultColumn,
+ @ColumnList = @ColumnList,
+ @FailMsg = @CombinedMessage;
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/AssertEqualsTableSchema.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertEqualsTableSchema.sql
new file mode 100644
index 0000000..e4f5c3c
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertEqualsTableSchema.sql
@@ -0,0 +1,43 @@
+CREATE PROCEDURE tSQLt.AssertEqualsTableSchema
+ @Expected NVARCHAR(MAX),
+ @Actual NVARCHAR(MAX),
+ @Message NVARCHAR(MAX) = NULL
+AS
+BEGIN
+ INSERT INTO tSQLt.Private_AssertEqualsTableSchema_Expected([RANK(column_id)],name,system_type_id,user_type_id,max_length,precision,scale,collation_name,is_nullable)
+ SELECT
+ RANK()OVER(ORDER BY C.column_id),
+ C.name,
+ CAST(C.system_type_id AS NVARCHAR(MAX))+QUOTENAME(TS.name) system_type_id,
+ CAST(C.user_type_id AS NVARCHAR(MAX))+CASE WHEN TU.system_type_id<> TU.user_type_id THEN QUOTENAME(SCHEMA_NAME(TU.schema_id))+'.' ELSE '' END + QUOTENAME(TU.name) user_type_id,
+ C.max_length,
+ C.precision,
+ C.scale,
+ C.collation_name,
+ C.is_nullable
+ FROM sys.columns AS C
+ JOIN sys.types AS TS
+ ON C.system_type_id = TS.user_type_id
+ JOIN sys.types AS TU
+ ON C.user_type_id = TU.user_type_id
+ WHERE C.object_id = OBJECT_ID(@Expected);
+ INSERT INTO tSQLt.Private_AssertEqualsTableSchema_Actual([RANK(column_id)],name,system_type_id,user_type_id,max_length,precision,scale,collation_name,is_nullable)
+ SELECT
+ RANK()OVER(ORDER BY C.column_id),
+ C.name,
+ CAST(C.system_type_id AS NVARCHAR(MAX))+QUOTENAME(TS.name) system_type_id,
+ CAST(C.user_type_id AS NVARCHAR(MAX))+CASE WHEN TU.system_type_id<> TU.user_type_id THEN QUOTENAME(SCHEMA_NAME(TU.schema_id))+'.' ELSE '' END + QUOTENAME(TU.name) user_type_id,
+ C.max_length,
+ C.precision,
+ C.scale,
+ C.collation_name,
+ C.is_nullable
+ FROM sys.columns AS C
+ JOIN sys.types AS TS
+ ON C.system_type_id = TS.user_type_id
+ JOIN sys.types AS TU
+ ON C.user_type_id = TU.user_type_id
+ WHERE C.object_id = OBJECT_ID(@Actual);
+
+ EXEC tSQLt.AssertEqualsTable 'tSQLt.Private_AssertEqualsTableSchema_Expected','tSQLt.Private_AssertEqualsTableSchema_Actual',@Message=@Message,@FailMsg='Unexpected/missing column(s)';
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/AssertLike.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertLike.sql
new file mode 100644
index 0000000..9f949c3
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertLike.sql
@@ -0,0 +1,21 @@
+CREATE PROCEDURE [tSQLt].[AssertLike]
+ @ExpectedPattern NVARCHAR(MAX),
+ @Actual NVARCHAR(MAX),
+ @Message NVARCHAR(MAX) = ''
+AS
+BEGIN
+ IF (LEN(@ExpectedPattern) > 4000)
+ BEGIN
+ RAISERROR ('@ExpectedPattern may not exceed 4000 characters.', 16, 10);
+ END;
+
+ IF ((@Actual LIKE @ExpectedPattern) OR (@Actual IS NULL AND @ExpectedPattern IS NULL))
+ BEGIN
+ RETURN 0;
+ END
+
+ DECLARE @Msg NVARCHAR(MAX);
+ SELECT @Msg = CHAR(13) + CHAR(10) + 'Expected: <' + ISNULL(@ExpectedPattern, 'NULL') + '>' +
+ CHAR(13) + CHAR(10) + ' but was: <' + ISNULL(@Actual, 'NULL') + '>';
+ EXEC tSQLt.Fail @Message, @Msg;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/AssertNotEquals.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertNotEquals.sql
new file mode 100644
index 0000000..8161f12
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertNotEquals.sql
@@ -0,0 +1,20 @@
+
+CREATE PROCEDURE tSQLt.AssertNotEquals
+ @Expected SQL_VARIANT,
+ @Actual SQL_VARIANT,
+ @Message NVARCHAR(MAX) = ''
+AS
+BEGIN
+ IF (@Expected = @Actual)
+ OR (@Expected IS NULL AND @Actual IS NULL)
+ BEGIN
+ DECLARE @Msg NVARCHAR(MAX);
+ SET @Msg = 'Expected actual value to not ' +
+ COALESCE('equal <' + tSQLt.Private_SqlVariantFormatter(@Expected)+'>', 'be NULL') +
+ '.';
+ EXEC tSQLt.Fail @Message,@Msg;
+ END;
+ RETURN 0;
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/AssertObjectDoesNotExist.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertObjectDoesNotExist.sql
new file mode 100644
index 0000000..ef2781d
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertObjectDoesNotExist.sql
@@ -0,0 +1,16 @@
+
+CREATE PROCEDURE tSQLt.AssertObjectDoesNotExist
+ @ObjectName NVARCHAR(MAX),
+ @Message NVARCHAR(MAX) = ''
+AS
+BEGIN
+ DECLARE @Msg NVARCHAR(MAX);
+ IF OBJECT_ID(@ObjectName) IS NOT NULL
+ OR(@ObjectName LIKE '#%' AND OBJECT_ID('tempdb..'+@ObjectName) IS NOT NULL)
+ BEGIN
+ SELECT @Msg = '''' + @ObjectName + ''' does exist!';
+ EXEC tSQLt.Fail @Message,@Msg;
+ END;
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/AssertObjectExists.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertObjectExists.sql
new file mode 100644
index 0000000..ff26899
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertObjectExists.sql
@@ -0,0 +1,29 @@
+
+CREATE PROCEDURE tSQLt.AssertObjectExists
+ @ObjectName NVARCHAR(MAX),
+ @Message NVARCHAR(MAX) = ''
+AS
+BEGIN
+ DECLARE @Msg NVARCHAR(MAX);
+ IF(@ObjectName LIKE '#%')
+ BEGIN
+ IF OBJECT_ID('tempdb..'+@ObjectName) IS NULL
+ BEGIN
+ SELECT @Msg = '''' + COALESCE(@ObjectName, 'NULL') + ''' does not exist';
+ EXEC tSQLt.Fail @Message, @Msg;
+ RETURN 1;
+ END;
+ END
+ ELSE
+ BEGIN
+ IF OBJECT_ID(@ObjectName) IS NULL
+ BEGIN
+ SELECT @Msg = '''' + COALESCE(@ObjectName, 'NULL') + ''' does not exist';
+ EXEC tSQLt.Fail @Message, @Msg;
+ RETURN 1;
+ END;
+ END;
+ RETURN 0;
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/AssertResultSetsHaveSameMetaData.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertResultSetsHaveSameMetaData.sql
new file mode 100644
index 0000000..16e792a
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertResultSetsHaveSameMetaData.sql
@@ -0,0 +1,4 @@
+CREATE PROCEDURE [tSQLt].[AssertResultSetsHaveSameMetaData]
+@expectedCommand NVARCHAR (MAX) NULL, @actualCommand NVARCHAR (MAX) NULL
+AS EXTERNAL NAME [tSQLtCLR].[tSQLtCLR.StoredProcedures].[AssertResultSetsHaveSameMetaData]
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/AssertStringIn.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertStringIn.sql
new file mode 100644
index 0000000..59dfd3f
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/AssertStringIn.sql
@@ -0,0 +1,16 @@
+
+CREATE PROCEDURE tSQLt.AssertStringIn
+ @Expected tSQLt.AssertStringTable READONLY,
+ @Actual NVARCHAR(MAX),
+ @Message NVARCHAR(MAX) = ''
+AS
+BEGIN
+ IF(NOT EXISTS(SELECT 1 FROM @Expected WHERE value = @Actual))
+ BEGIN
+ DECLARE @ExpectedMessage NVARCHAR(MAX);
+ SELECT value INTO #ExpectedSet FROM @Expected;
+ EXEC tSQLt.TableToText @TableName = '#ExpectedSet', @OrderBy = 'value',@txt = @ExpectedMessage OUTPUT;
+ SET @ExpectedMessage = ISNULL('<'+@Actual+'>','NULL')+CHAR(13)+CHAR(10)+'is not in'+CHAR(13)+CHAR(10)+@ExpectedMessage;
+ EXEC tSQLt.Fail @Message, @ExpectedMessage;
+ END;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/CaptureOutput.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/CaptureOutput.sql
new file mode 100644
index 0000000..e828ea0
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/CaptureOutput.sql
@@ -0,0 +1,4 @@
+CREATE PROCEDURE [tSQLt].[CaptureOutput]
+@command NVARCHAR (MAX) NULL
+AS EXTERNAL NAME [tSQLtCLR].[tSQLtCLR.StoredProcedures].[CaptureOutput]
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/DefaultResultFormatter.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/DefaultResultFormatter.sql
new file mode 100644
index 0000000..e004e6d
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/DefaultResultFormatter.sql
@@ -0,0 +1,47 @@
+CREATE PROCEDURE tSQLt.DefaultResultFormatter
+AS
+BEGIN
+ DECLARE @TestList NVARCHAR(MAX);
+ DECLARE @Dashes NVARCHAR(MAX);
+ DECLARE @CountSummaryMsg NVARCHAR(MAX);
+ DECLARE @NewLine NVARCHAR(MAX);
+ DECLARE @IsSuccess INT;
+ DECLARE @SuccessCnt INT;
+ DECLARE @Severity INT;
+ DECLARE @SummaryError INT;
+
+ SELECT *
+ INTO #TestResultOutput
+ FROM tSQLt.Private_PrepareTestResultForOutput() AS PTRFO;
+
+ EXEC tSQLt.TableToText @TestList OUTPUT, '#TestResultOutput', 'No';
+
+ SELECT @CountSummaryMsg = Msg,
+ @IsSuccess = 1 - SIGN(FailCnt + ErrorCnt),
+ @SuccessCnt = SuccessCnt
+ FROM tSQLt.TestCaseSummary();
+
+ SELECT @SummaryError = CAST(PC.Value AS INT)
+ FROM tSQLt.Private_Configurations AS PC
+ WHERE PC.Name = 'SummaryError';
+
+ SELECT @Severity = 16*(1-@IsSuccess);
+ IF(@SummaryError = 0)
+ BEGIN
+ SET @Severity = 0;
+ END;
+
+ SELECT @Dashes = REPLICATE('-',LEN(@CountSummaryMsg)),
+ @NewLine = CHAR(13)+CHAR(10);
+
+
+ EXEC tSQLt.Private_Print @NewLine,0;
+ EXEC tSQLt.Private_Print '+----------------------+',0;
+ EXEC tSQLt.Private_Print '|Test Execution Summary|',0;
+ EXEC tSQLt.Private_Print '+----------------------+',0;
+ EXEC tSQLt.Private_Print @NewLine,0;
+ EXEC tSQLt.Private_Print @TestList,0;
+ EXEC tSQLt.Private_Print @Dashes,0;
+ EXEC tSQLt.Private_Print @CountSummaryMsg, @Severity;
+ EXEC tSQLt.Private_Print @Dashes,0;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/DropClass.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/DropClass.sql
new file mode 100644
index 0000000..6275152
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/DropClass.sql
@@ -0,0 +1,73 @@
+
+CREATE PROCEDURE tSQLt.DropClass
+ @ClassName NVARCHAR(MAX)
+AS
+BEGIN
+ DECLARE @Cmd NVARCHAR(MAX);
+
+ WITH ObjectInfo(name, type) AS
+ (
+ SELECT QUOTENAME(SCHEMA_NAME(O.schema_id))+'.'+QUOTENAME(O.name) , O.type
+ FROM sys.objects AS O
+ WHERE O.schema_id = SCHEMA_ID(@ClassName)
+ ),
+ TypeInfo(name) AS
+ (
+ SELECT QUOTENAME(SCHEMA_NAME(T.schema_id))+'.'+QUOTENAME(T.name)
+ FROM sys.types AS T
+ WHERE T.schema_id = SCHEMA_ID(@ClassName)
+ ),
+ XMLSchemaInfo(name) AS
+ (
+ SELECT QUOTENAME(SCHEMA_NAME(XSC.schema_id))+'.'+QUOTENAME(XSC.name)
+ FROM sys.xml_schema_collections AS XSC
+ WHERE XSC.schema_id = SCHEMA_ID(@ClassName)
+ ),
+ DropStatements(no,cmd) AS
+ (
+ SELECT 10,
+ 'DROP ' +
+ CASE type WHEN 'P' THEN 'PROCEDURE'
+ WHEN 'PC' THEN 'PROCEDURE'
+ WHEN 'U' THEN 'TABLE'
+ WHEN 'IF' THEN 'FUNCTION'
+ WHEN 'TF' THEN 'FUNCTION'
+ WHEN 'FN' THEN 'FUNCTION'
+ WHEN 'FT' THEN 'FUNCTION'
+ WHEN 'V' THEN 'VIEW'
+ END +
+ ' ' +
+ name +
+ ';'
+ FROM ObjectInfo
+ UNION ALL
+ SELECT 20,
+ 'DROP TYPE ' +
+ name +
+ ';'
+ FROM TypeInfo
+ UNION ALL
+ SELECT 30,
+ 'DROP XML SCHEMA COLLECTION ' +
+ name +
+ ';'
+ FROM XMLSchemaInfo
+ UNION ALL
+ SELECT 10000,'DROP SCHEMA ' + QUOTENAME(name) +';'
+ FROM sys.schemas
+ WHERE schema_id = SCHEMA_ID(PARSENAME(@ClassName,1))
+ ),
+ StatementBlob(xml)AS
+ (
+ SELECT cmd [text()]
+ FROM DropStatements
+ ORDER BY no
+ FOR XML PATH(''), TYPE
+ )
+ SELECT @Cmd = xml.value('/', 'NVARCHAR(MAX)')
+ FROM StatementBlob;
+
+ EXEC(@Cmd);
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/EnableExternalAccess.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/EnableExternalAccess.sql
new file mode 100644
index 0000000..9ccbfa4
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/EnableExternalAccess.sql
@@ -0,0 +1,37 @@
+CREATE PROCEDURE tSQLt.EnableExternalAccess
+ @try BIT = 0,
+ @enable BIT = 1
+AS
+BEGIN
+ IF((SELECT HostPlatform FROM tSQLt.Info()) = 'Linux')
+ BEGIN
+ IF(@try = 0)
+ BEGIN
+ RAISERROR('tSQLt.EnableExternalAccess is not supported on Linux.',16,10);
+ END;
+ RETURN -1;
+ END;
+ BEGIN TRY
+ IF @enable = 1
+ BEGIN
+ EXEC('ALTER ASSEMBLY tSQLtCLR WITH PERMISSION_SET = EXTERNAL_ACCESS;');
+ END
+ ELSE
+ BEGIN
+ EXEC('ALTER ASSEMBLY tSQLtCLR WITH PERMISSION_SET = SAFE;');
+ END
+ END TRY
+ BEGIN CATCH
+ IF(@try = 0)
+ BEGIN
+ DECLARE @Message NVARCHAR(4000);
+ SET @Message = 'The attempt to ' +
+ CASE WHEN @enable = 1 THEN 'enable' ELSE 'disable' END +
+ ' tSQLt features requiring EXTERNAL_ACCESS failed' +
+ ': '+ERROR_MESSAGE();
+ RAISERROR(@Message,16,10);
+ END;
+ RETURN -1;
+ END CATCH;
+ RETURN 0;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/ExpectException.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/ExpectException.sql
new file mode 100644
index 0000000..1dddc7d
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/ExpectException.sql
@@ -0,0 +1,21 @@
+
+CREATE PROCEDURE tSQLt.ExpectException
+@ExpectedMessage NVARCHAR(MAX) = NULL,
+@ExpectedSeverity INT = NULL,
+@ExpectedState INT = NULL,
+@Message NVARCHAR(MAX) = NULL,
+@ExpectedMessagePattern NVARCHAR(MAX) = NULL,
+@ExpectedErrorNumber INT = NULL
+AS
+BEGIN
+ IF(EXISTS(SELECT 1 FROM #ExpectException WHERE ExpectException = 1))
+ BEGIN
+ DELETE #ExpectException;
+ RAISERROR('Each test can only contain one call to tSQLt.ExpectException.',16,10);
+ END;
+
+ INSERT INTO #ExpectException(ExpectException, ExpectedMessage, ExpectedSeverity, ExpectedState, ExpectedMessagePattern, ExpectedErrorNumber, FailMessage)
+ VALUES(1, @ExpectedMessage, @ExpectedSeverity, @ExpectedState, @ExpectedMessagePattern, @ExpectedErrorNumber, @Message);
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/ExpectNoException.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/ExpectNoException.sql
new file mode 100644
index 0000000..5436bd1
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/ExpectNoException.sql
@@ -0,0 +1,21 @@
+
+CREATE PROCEDURE tSQLt.ExpectNoException
+ @Message NVARCHAR(MAX) = NULL
+AS
+BEGIN
+ IF(EXISTS(SELECT 1 FROM #ExpectException WHERE ExpectException = 0))
+ BEGIN
+ DELETE #ExpectException;
+ RAISERROR('Each test can only contain one call to tSQLt.ExpectNoException.',16,10);
+ END;
+ IF(EXISTS(SELECT 1 FROM #ExpectException WHERE ExpectException = 1))
+ BEGIN
+ DELETE #ExpectException;
+ RAISERROR('tSQLt.ExpectNoException cannot follow tSQLt.ExpectException inside a single test.',16,10);
+ END;
+
+ INSERT INTO #ExpectException(ExpectException, FailMessage)
+ VALUES(0, @Message);
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Fail.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Fail.sql
new file mode 100644
index 0000000..22d3932
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Fail.sql
@@ -0,0 +1,54 @@
+
+CREATE PROCEDURE tSQLt.Fail
+ @Message0 NVARCHAR(MAX) = '',
+ @Message1 NVARCHAR(MAX) = '',
+ @Message2 NVARCHAR(MAX) = '',
+ @Message3 NVARCHAR(MAX) = '',
+ @Message4 NVARCHAR(MAX) = '',
+ @Message5 NVARCHAR(MAX) = '',
+ @Message6 NVARCHAR(MAX) = '',
+ @Message7 NVARCHAR(MAX) = '',
+ @Message8 NVARCHAR(MAX) = '',
+ @Message9 NVARCHAR(MAX) = ''
+AS
+BEGIN
+ DECLARE @WarningMessage NVARCHAR(MAX);
+ SET @WarningMessage = '';
+
+ IF XACT_STATE() = -1
+ BEGIN
+ SET @WarningMessage = CHAR(13)+CHAR(10)+'Warning: Uncommitable transaction detected!';
+
+ DECLARE @TranName NVARCHAR(MAX);
+ SELECT @TranName = TranName
+ FROM tSQLt.TestResult
+ WHERE Id = (SELECT MAX(Id) FROM tSQLt.TestResult);
+
+ DECLARE @TranCount INT;
+ SET @TranCount = @@TRANCOUNT;
+ ROLLBACK;
+ WHILE(@TranCount>0)
+ BEGIN
+ BEGIN TRAN;
+ SET @TranCount = @TranCount -1;
+ END;
+ SAVE TRAN @TranName;
+ END;
+
+ INSERT INTO tSQLt.TestMessage(Msg)
+ SELECT COALESCE(@Message0, '!NULL!')
+ + COALESCE(@Message1, '!NULL!')
+ + COALESCE(@Message2, '!NULL!')
+ + COALESCE(@Message3, '!NULL!')
+ + COALESCE(@Message4, '!NULL!')
+ + COALESCE(@Message5, '!NULL!')
+ + COALESCE(@Message6, '!NULL!')
+ + COALESCE(@Message7, '!NULL!')
+ + COALESCE(@Message8, '!NULL!')
+ + COALESCE(@Message9, '!NULL!')
+ + @WarningMessage;
+
+ RAISERROR('tSQLt.Failure',16,10);
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/FakeFunction.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/FakeFunction.sql
new file mode 100644
index 0000000..032e934
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/FakeFunction.sql
@@ -0,0 +1,30 @@
+CREATE PROCEDURE tSQLt.FakeFunction
+ @FunctionName NVARCHAR(MAX),
+ @FakeFunctionName NVARCHAR(MAX) = NULL,
+ @FakeDataSource NVARCHAR(MAX) = NULL
+
+AS
+BEGIN
+ DECLARE @FunctionObjectId INT;
+ DECLARE @FakeFunctionObjectId INT;
+ DECLARE @IsScalarFunction BIT;
+
+ EXEC tSQLt.Private_ValidateObjectsCompatibleWithFakeFunction
+ @FunctionName = @FunctionName,
+ @FakeFunctionName = @FakeFunctionName,
+ @FakeDataSource = @FakeDataSource,
+ @FunctionObjectId = @FunctionObjectId OUT,
+ @FakeFunctionObjectId = @FakeFunctionObjectId OUT,
+ @IsScalarFunction = @IsScalarFunction OUT;
+
+ EXEC tSQLt.RemoveObject @ObjectName = @FunctionName;
+
+ EXEC tSQLt.Private_CreateFakeFunction
+ @FunctionName = @FunctionName,
+ @FakeFunctionName = @FakeFunctionName,
+ @FakeDataSource = @FakeDataSource,
+ @FunctionObjectId = @FunctionObjectId,
+ @FakeFunctionObjectId = @FakeFunctionObjectId,
+ @IsScalarFunction = @IsScalarFunction;
+
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/FakeTable.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/FakeTable.sql
new file mode 100644
index 0000000..392e34b
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/FakeTable.sql
@@ -0,0 +1,53 @@
+
+CREATE PROCEDURE tSQLt.FakeTable
+ @TableName NVARCHAR(MAX),
+ @SchemaName NVARCHAR(MAX) = NULL, --parameter preserved for backward compatibility. Do not use. Will be removed soon.
+ @Identity BIT = NULL,
+ @ComputedColumns BIT = NULL,
+ @Defaults BIT = NULL
+AS
+BEGIN
+ DECLARE @OrigSchemaName NVARCHAR(MAX);
+ DECLARE @OrigTableName NVARCHAR(MAX);
+ DECLARE @NewNameOfOriginalTable NVARCHAR(4000);
+ DECLARE @OrigTableFullName NVARCHAR(MAX); SET @OrigTableFullName = NULL;
+
+ SELECT @OrigSchemaName = @SchemaName,
+ @OrigTableName = @TableName
+
+ IF(@OrigTableName NOT IN (PARSENAME(@OrigTableName,1),QUOTENAME(PARSENAME(@OrigTableName,1)))
+ AND @OrigSchemaName IS NOT NULL)
+ BEGIN
+ RAISERROR('When @TableName is a multi-part identifier, @SchemaName must be NULL!',16,10);
+ END
+
+ SELECT @SchemaName = CleanSchemaName,
+ @TableName = CleanTableName
+ FROM tSQLt.Private_ResolveFakeTableNamesForBackwardCompatibility(@TableName, @SchemaName);
+
+ EXEC tSQLt.Private_ValidateFakeTableParameters @SchemaName,@OrigTableName,@OrigSchemaName;
+
+ EXEC tSQLt.Private_RenameObjectToUniqueName @SchemaName, @TableName, @NewNameOfOriginalTable OUTPUT;
+
+ SELECT @OrigTableFullName = S.base_object_name
+ FROM sys.synonyms AS S
+ WHERE S.object_id = OBJECT_ID(@SchemaName + '.' + @NewNameOfOriginalTable);
+
+ IF(@OrigTableFullName IS NOT NULL)
+ BEGIN
+ IF(COALESCE(OBJECT_ID(@OrigTableFullName,'U'),OBJECT_ID(@OrigTableFullName,'V')) IS NULL)
+ BEGIN
+ RAISERROR('Cannot fake synonym %s.%s as it is pointing to %s, which is not a table or view!',16,10,@SchemaName,@TableName,@OrigTableFullName);
+ END;
+ END;
+ ELSE
+ BEGIN
+ SET @OrigTableFullName = @SchemaName + '.' + @NewNameOfOriginalTable;
+ END;
+
+ EXEC tSQLt.Private_CreateFakeOfTable @SchemaName, @TableName, @OrigTableFullName, @Identity, @ComputedColumns, @Defaults;
+
+ EXEC tSQLt.Private_MarkFakeTable @SchemaName, @TableName, @NewNameOfOriginalTable;
+END
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/GetNewTranName.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/GetNewTranName.sql
new file mode 100644
index 0000000..8bed6cb
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/GetNewTranName.sql
@@ -0,0 +1,8 @@
+
+
+CREATE PROCEDURE tSQLt.GetNewTranName
+ @TranName CHAR(32) OUTPUT
+AS
+BEGIN
+ SELECT @TranName = LEFT('tSQLtTran'+REPLACE(CAST(NEWID() AS NVARCHAR(60)),'-',''),32);
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/InstallAssemblyKey.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/InstallAssemblyKey.sql
new file mode 100644
index 0000000..a6f280b
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/InstallAssemblyKey.sql
@@ -0,0 +1,90 @@
+CREATE PROCEDURE tSQLt.InstallAssemblyKey
+AS
+BEGIN
+ IF(NOT EXISTS(SELECT * FROM sys.fn_my_permissions(NULL,'server') AS FMP WHERE FMP.permission_name = 'CONTROL SERVER'))
+ BEGIN
+ RAISERROR('Only principals with CONTROL SERVER permission can execute this procedure.',16,10);
+ RETURN -1;
+ END;
+
+ DECLARE @cmd NVARCHAR(MAX);
+ DECLARE @cmd2 NVARCHAR(MAX);
+ DECLARE @master_sys_sp_executesql NVARCHAR(MAX); SET @master_sys_sp_executesql = 'master.sys.sp_executesql';
+ DECLARE @ProductMajorVersion INT;
+ EXEC @ProductMajorVersion = tSQLt.Private_GetSQLProductMajorVersion;
+
+ DECLARE @AssemblyKeyBytes VARBINARY(MAX),
+ @AssemblyKeyThumbPrint VARBINARY(MAX);
+
+ EXEC tSQLt.Private_GetAssemblyKeyBytes @AssemblyKeyBytes OUT, @AssemblyKeyThumbPrint OUT;
+
+ SET @cmd = 'IF EXISTS(SELECT * FROM sys.assemblies WHERE name = ''tSQLtAssemblyKey'') DROP ASSEMBLY tSQLtAssemblyKey;';
+ EXEC @master_sys_sp_executesql @cmd;
+
+ SET @cmd2 = 'SELECT @cmd = ''DROP ASSEMBLY ''+QUOTENAME(A.name)+'';'''+
+ ' FROM master.sys.assemblies AS A'+
+ ' WHERE A.clr_name LIKE ''tsqltassemblykey, %'';';
+ EXEC sys.sp_executesql @cmd2,N'@cmd NVARCHAR(MAX) OUTPUT',@cmd OUT;
+ EXEC @master_sys_sp_executesql @cmd;
+
+ DECLARE @Hash VARBINARY(64) = NULL;
+ IF(@ProductMajorVersion>=14)
+ BEGIN
+ SELECT @Hash = HASHBYTES('SHA2_512',@AssemblyKeyBytes);
+
+ SELECT @cmd =
+ 'IF NOT EXISTS (SELECT * FROM sys.trusted_assemblies WHERE [hash] = @Hash)'+
+ 'BEGIN'+
+ ' EXEC sys.sp_add_trusted_assembly @hash = @Hash, @description = N''tSQLt Ephemeral'';'+
+ 'END ELSE BEGIN'+
+ ' SELECT @Hash = NULL FROM sys.trusted_assemblies WHERE [hash] = @Hash AND description <> ''tSQLt Ephemeral'';'+
+ 'END;';
+ EXEC @master_sys_sp_executesql @cmd, N'@Hash VARBINARY(64) OUTPUT',@Hash OUT;
+ END;
+
+ SELECT @cmd =
+ 'CREATE ASSEMBLY tSQLtAssemblyKey AUTHORIZATION dbo FROM ' +
+ CONVERT(NVARCHAR(MAX),@AssemblyKeyBytes,1) +
+ ' WITH PERMISSION_SET = SAFE;'
+ EXEC @master_sys_sp_executesql @cmd;
+
+ IF SUSER_ID('tSQLtAssemblyKey') IS NOT NULL DROP LOGIN tSQLtAssemblyKey;
+
+ SET @cmd = N'IF ASYMKEY_ID(''tSQLtAssemblyKey'') IS NOT NULL DROP ASYMMETRIC KEY tSQLtAssemblyKey;';
+ EXEC @master_sys_sp_executesql @cmd;
+
+ SET @cmd2 = 'SELECT @cmd = ISNULL(''DROP LOGIN ''+QUOTENAME(SP.name)+'';'','''')+''DROP ASYMMETRIC KEY '' + QUOTENAME(AK.name) + '';'''+
+ ' FROM master.sys.asymmetric_keys AS AK'+
+ ' LEFT JOIN master.sys.server_principals AS SP'+
+ ' ON AK.sid = SP.sid'+
+ ' WHERE AK.thumbprint = @AssemblyKeyThumbPrint;';
+ EXEC sys.sp_executesql @cmd2,N'@cmd NVARCHAR(MAX) OUTPUT, @AssemblyKeyThumbPrint VARBINARY(MAX)',@cmd OUT, @AssemblyKeyThumbPrint;
+ EXEC @master_sys_sp_executesql @cmd;
+
+ SET @cmd = 'CREATE ASYMMETRIC KEY tSQLtAssemblyKey FROM ASSEMBLY tSQLtAssemblyKey;';
+ EXEC @master_sys_sp_executesql @cmd;
+
+ SET @cmd = 'CREATE LOGIN tSQLtAssemblyKey FROM ASYMMETRIC KEY tSQLtAssemblyKey;';
+ EXEC @master_sys_sp_executesql @cmd;
+
+ SET @cmd = 'DROP ASSEMBLY tSQLtAssemblyKey;';
+ EXEC @master_sys_sp_executesql @cmd;
+
+ IF(@Hash IS NOT NULL)
+ BEGIN
+ SELECT @cmd = 'EXEC sys.sp_drop_trusted_assembly @hash = @Hash;';
+ EXEC @master_sys_sp_executesql @cmd, N'@Hash VARBINARY(64)',@Hash;
+ END;
+
+ IF(@ProductMajorVersion>=14)
+ BEGIN
+ SET @cmd = 'GRANT UNSAFE ASSEMBLY TO tSQLtAssemblyKey;';
+ END
+ ELSE
+ BEGIN
+ SET @cmd = 'GRANT EXTERNAL ACCESS ASSEMBLY TO tSQLtAssemblyKey;';
+ END;
+
+ EXEC @master_sys_sp_executesql @cmd;
+
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/InstallExternalAccessKey.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/InstallExternalAccessKey.sql
new file mode 100644
index 0000000..a7e175b
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/InstallExternalAccessKey.sql
@@ -0,0 +1,6 @@
+CREATE PROCEDURE tSQLt.InstallExternalAccessKey
+AS
+BEGIN
+ EXEC tSQLt.Private_Print @Message='tSQLt.InstallExternalAccessKey is deprecated. Please use tSQLt.InstallAssemblyKey instead.';
+ EXEC tSQLt.InstallAssemblyKey;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/LogCapturedOutput.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/LogCapturedOutput.sql
new file mode 100644
index 0000000..c3cf2a6
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/LogCapturedOutput.sql
@@ -0,0 +1,8 @@
+
+CREATE PROCEDURE tSQLt.LogCapturedOutput @text NVARCHAR(MAX)
+AS
+BEGIN
+ INSERT INTO tSQLt.CaptureOutputLog (OutputText) VALUES (@text);
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/NewConnection.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/NewConnection.sql
new file mode 100644
index 0000000..b5771e9
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/NewConnection.sql
@@ -0,0 +1,4 @@
+CREATE PROCEDURE [tSQLt].[NewConnection]
+@command NVARCHAR (MAX) NULL
+AS EXTERNAL NAME [tSQLtCLR].[tSQLtCLR.StoredProcedures].[NewConnection]
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/NewTestClass.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/NewTestClass.sql
new file mode 100644
index 0000000..ac78086
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/NewTestClass.sql
@@ -0,0 +1,25 @@
+
+CREATE PROCEDURE tSQLt.NewTestClass
+ @ClassName NVARCHAR(MAX)
+AS
+BEGIN
+ BEGIN TRY
+ EXEC tSQLt.Private_DisallowOverwritingNonTestSchema @ClassName;
+
+ EXEC tSQLt.DropClass @ClassName = @ClassName;
+
+ DECLARE @QuotedClassName NVARCHAR(MAX);
+ SELECT @QuotedClassName = tSQLt.Private_QuoteClassNameForNewTestClass(@ClassName);
+
+ EXEC ('CREATE SCHEMA ' + @QuotedClassName);
+ EXEC tSQLt.Private_MarkSchemaAsTestClass @QuotedClassName;
+ END TRY
+ BEGIN CATCH
+ DECLARE @ErrMsg NVARCHAR(MAX);SET @ErrMsg = ERROR_MESSAGE() + ' (Error originated in ' + ERROR_PROCEDURE() + ')';
+ DECLARE @ErrSvr INT;SET @ErrSvr = ERROR_SEVERITY();
+
+ RAISERROR(@ErrMsg, @ErrSvr, 10);
+ END CATCH;
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/NullTestResultFormatter.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/NullTestResultFormatter.sql
new file mode 100644
index 0000000..578f92c
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/NullTestResultFormatter.sql
@@ -0,0 +1,6 @@
+
+CREATE PROCEDURE tSQLt.NullTestResultFormatter
+AS
+BEGIN
+ RETURN 0;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/PrepareServer.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/PrepareServer.sql
new file mode 100644
index 0000000..b6acd3c
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/PrepareServer.sql
@@ -0,0 +1,6 @@
+CREATE PROCEDURE tSQLt.PrepareServer
+AS
+BEGIN
+ EXEC tSQLt.Private_EnableCLR;
+ EXEC tSQLt.InstallAssemblyKey;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ApplyCheckConstraint.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ApplyCheckConstraint.sql
new file mode 100644
index 0000000..aa76547
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ApplyCheckConstraint.sql
@@ -0,0 +1,22 @@
+
+CREATE PROCEDURE tSQLt.Private_ApplyCheckConstraint
+ @ConstraintObjectId INT
+AS
+BEGIN
+ DECLARE @Cmd NVARCHAR(MAX);
+ SELECT @Cmd = 'CONSTRAINT ' + QUOTENAME(name) + ' CHECK' + definition
+ FROM sys.check_constraints
+ WHERE object_id = @ConstraintObjectId;
+
+ DECLARE @QuotedTableName NVARCHAR(MAX);
+
+ SELECT @QuotedTableName = QuotedTableName FROM tSQLt.Private_GetQuotedTableNameForConstraint(@ConstraintObjectId);
+
+ EXEC tSQLt.Private_RenameObjectToUniqueNameUsingObjectId @ConstraintObjectId;
+ SELECT @Cmd = 'ALTER TABLE ' + @QuotedTableName + ' ADD ' + @Cmd
+ FROM sys.objects
+ WHERE object_id = @ConstraintObjectId;
+
+ EXEC (@Cmd);
+
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ApplyForeignKeyConstraint.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ApplyForeignKeyConstraint.sql
new file mode 100644
index 0000000..95ba0d7
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ApplyForeignKeyConstraint.sql
@@ -0,0 +1,30 @@
+
+CREATE PROCEDURE tSQLt.Private_ApplyForeignKeyConstraint
+ @ConstraintObjectId INT,
+ @NoCascade BIT
+AS
+BEGIN
+ DECLARE @SchemaName NVARCHAR(MAX);
+ DECLARE @OrgTableName NVARCHAR(MAX);
+ DECLARE @TableName NVARCHAR(MAX);
+ DECLARE @ConstraintName NVARCHAR(MAX);
+ DECLARE @CreateFkCmd NVARCHAR(MAX);
+ DECLARE @AlterTableCmd NVARCHAR(MAX);
+ DECLARE @CreateIndexCmd NVARCHAR(MAX);
+ DECLARE @FinalCmd NVARCHAR(MAX);
+
+ SELECT @SchemaName = SchemaName,
+ @OrgTableName = OrgTableName,
+ @TableName = TableName,
+ @ConstraintName = OBJECT_NAME(@ConstraintObjectId)
+ FROM tSQLt.Private_GetQuotedTableNameForConstraint(@ConstraintObjectId);
+
+ SELECT @CreateFkCmd = cmd, @CreateIndexCmd = CreIdxCmd
+ FROM tSQLt.Private_GetForeignKeyDefinition(@SchemaName, @OrgTableName, @ConstraintName, @NoCascade);
+ SELECT @AlterTableCmd = 'ALTER TABLE ' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@TableName) +
+ ' ADD ' + @CreateFkCmd;
+ SELECT @FinalCmd = @CreateIndexCmd + @AlterTableCmd;
+
+ EXEC tSQLt.Private_RenameObjectToUniqueName @SchemaName, @ConstraintName;
+ EXEC (@FinalCmd);
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ApplyUniqueConstraint.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ApplyUniqueConstraint.sql
new file mode 100644
index 0000000..1647c6c
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ApplyUniqueConstraint.sql
@@ -0,0 +1,26 @@
+
+CREATE PROCEDURE tSQLt.Private_ApplyUniqueConstraint
+ @ConstraintObjectId INT
+AS
+BEGIN
+ DECLARE @SchemaName NVARCHAR(MAX);
+ DECLARE @OrgTableName NVARCHAR(MAX);
+ DECLARE @TableName NVARCHAR(MAX);
+ DECLARE @ConstraintName NVARCHAR(MAX);
+ DECLARE @CreateConstraintCmd NVARCHAR(MAX);
+ DECLARE @AlterColumnsCmd NVARCHAR(MAX);
+
+ SELECT @SchemaName = SchemaName,
+ @OrgTableName = OrgTableName,
+ @TableName = TableName,
+ @ConstraintName = OBJECT_NAME(@ConstraintObjectId)
+ FROM tSQLt.Private_GetQuotedTableNameForConstraint(@ConstraintObjectId);
+
+ SELECT @AlterColumnsCmd = NotNullColumnCmd,
+ @CreateConstraintCmd = CreateConstraintCmd
+ FROM tSQLt.Private_GetUniqueConstraintDefinition(@ConstraintObjectId, QUOTENAME(@SchemaName) + '.' + QUOTENAME(@TableName));
+
+ EXEC tSQLt.Private_RenameObjectToUniqueName @SchemaName, @ConstraintName;
+ EXEC (@AlterColumnsCmd);
+ EXEC (@CreateConstraintCmd);
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CleanTestResult.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CleanTestResult.sql
new file mode 100644
index 0000000..dd3ea10
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CleanTestResult.sql
@@ -0,0 +1,5 @@
+CREATE PROCEDURE tSQLt.Private_CleanTestResult
+AS
+BEGIN
+ DELETE FROM tSQLt.TestResult;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CompareTables.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CompareTables.sql
new file mode 100644
index 0000000..38f2561
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CompareTables.sql
@@ -0,0 +1,60 @@
+CREATE PROCEDURE tSQLt.Private_CompareTables
+ @Expected NVARCHAR(MAX),
+ @Actual NVARCHAR(MAX),
+ @ResultTable NVARCHAR(MAX),
+ @ColumnList NVARCHAR(MAX),
+ @MatchIndicatorColumnName NVARCHAR(MAX)
+AS
+BEGIN
+ DECLARE @cmd NVARCHAR(MAX);
+ DECLARE @RestoredRowIndexCounterColName NVARCHAR(MAX);
+ SET @RestoredRowIndexCounterColName = @MatchIndicatorColumnName + '_RR';
+
+ SELECT @cmd =
+ '
+ INSERT INTO ' + @ResultTable + ' (' + @MatchIndicatorColumnName + ', ' + @ColumnList + ')
+ SELECT
+ CASE
+ WHEN RestoredRowIndex.'+@RestoredRowIndexCounterColName+' <= CASE WHEN [_{Left}_]<[_{Right}_] THEN [_{Left}_] ELSE [_{Right}_] END
+ THEN ''=''
+ WHEN RestoredRowIndex.'+@RestoredRowIndexCounterColName+' <= [_{Left}_]
+ THEN ''<''
+ ELSE ''>''
+ END AS ' + @MatchIndicatorColumnName + ', ' + @ColumnList + '
+ FROM(
+ SELECT SUM([_{Left}_]) AS [_{Left}_],
+ SUM([_{Right}_]) AS [_{Right}_],
+ ' + @ColumnList + '
+ FROM (
+ SELECT 1 AS [_{Left}_], 0[_{Right}_], ' + @ColumnList + '
+ FROM ' + @Expected + '
+ UNION ALL
+ SELECT 0[_{Left}_], 1 AS [_{Right}_], ' + @ColumnList + '
+ FROM ' + @Actual + '
+ ) AS X
+ GROUP BY ' + @ColumnList + '
+ ) AS CollapsedRows
+ CROSS APPLY (
+ SELECT TOP(CASE WHEN [_{Left}_]>[_{Right}_] THEN [_{Left}_]
+ ELSE [_{Right}_] END)
+ ROW_NUMBER() OVER(ORDER BY(SELECT 1))
+ FROM (SELECT 1
+ FROM ' + @Actual + ' UNION ALL SELECT 1 FROM ' + @Expected + ') X(X)
+ ) AS RestoredRowIndex(' + @RestoredRowIndexCounterColName + ');';
+
+ EXEC (@cmd); --MainGroupQuery
+
+ SET @cmd = 'SET @r =
+ CASE WHEN EXISTS(
+ SELECT 1
+ FROM ' + @ResultTable +
+ ' WHERE ' + @MatchIndicatorColumnName + ' IN (''<'', ''>''))
+ THEN 1 ELSE 0
+ END';
+ DECLARE @UnequalRowsExist INT;
+ EXEC sp_executesql @cmd, N'@r INT OUTPUT',@UnequalRowsExist OUTPUT;
+
+ RETURN @UnequalRowsExist;
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CompareTablesFailIfUnequalRowsExists.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CompareTablesFailIfUnequalRowsExists.sql
new file mode 100644
index 0000000..4c2a751
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CompareTablesFailIfUnequalRowsExists.sql
@@ -0,0 +1,21 @@
+CREATE PROCEDURE tSQLt.Private_CompareTablesFailIfUnequalRowsExists
+ @UnequalRowsExist INT,
+ @ResultTable NVARCHAR(MAX),
+ @ResultColumn NVARCHAR(MAX),
+ @ColumnList NVARCHAR(MAX),
+ @FailMsg NVARCHAR(MAX)
+AS
+BEGIN
+ IF @UnequalRowsExist > 0
+ BEGIN
+ DECLARE @TableToTextResult NVARCHAR(MAX);
+ DECLARE @OutputColumnList NVARCHAR(MAX);
+ SELECT @OutputColumnList = '[_m_],' + @ColumnList;
+ EXEC tSQLt.TableToText @TableName = @ResultTable, @OrderBy = @ResultColumn, @PrintOnlyColumnNameAliasList = @OutputColumnList, @txt = @TableToTextResult OUTPUT;
+
+ DECLARE @Message NVARCHAR(MAX);
+ SELECT @Message = @FailMsg + CHAR(13) + CHAR(10);
+
+ EXEC tSQLt.Fail @Message, @TableToTextResult;
+ END;
+END
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CreateFakeFunction.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CreateFakeFunction.sql
new file mode 100644
index 0000000..a76861d
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CreateFakeFunction.sql
@@ -0,0 +1,54 @@
+CREATE PROCEDURE tSQLt.Private_CreateFakeFunction
+ @FunctionName NVARCHAR(MAX),
+ @FakeFunctionName NVARCHAR(MAX) = NULL,
+ @FunctionObjectId INT = NULL,
+ @FakeFunctionObjectId INT = NULL,
+ @IsScalarFunction BIT = NULL,
+ @FakeDataSource NVARCHAR(MAX) = NULL
+AS
+BEGIN
+ DECLARE @ReturnType NVARCHAR(MAX);
+ SELECT @ReturnType = T.TypeName
+ FROM sys.parameters AS P
+ CROSS APPLY tSQLt.Private_GetFullTypeName(P.user_type_id,P.max_length,P.precision,P.scale,NULL) AS T
+ WHERE P.object_id = @FunctionObjectId
+ AND P.parameter_id = 0;
+
+ DECLARE @ParameterList NVARCHAR(MAX);
+ SELECT @ParameterList = COALESCE(
+ STUFF((SELECT ','+P.name+' '+T.TypeName+CASE WHEN T.IsTableType = 1 THEN ' READONLY' ELSE '' END
+ FROM sys.parameters AS P
+ CROSS APPLY tSQLt.Private_GetFullTypeName(P.user_type_id,P.max_length,P.precision,P.scale,NULL) AS T
+ WHERE P.object_id = @FunctionObjectId
+ AND P.parameter_id > 0
+ ORDER BY P.parameter_id
+ FOR XML PATH(''),TYPE
+ ).value('.','NVARCHAR(MAX)'),1,1,''),'');
+
+ DECLARE @ParameterCallList NVARCHAR(MAX);
+ SELECT @ParameterCallList = COALESCE(
+ STUFF((SELECT ','+P.name
+ FROM sys.parameters AS P
+ CROSS APPLY tSQLt.Private_GetFullTypeName(P.user_type_id,P.max_length,P.precision,P.scale,NULL) AS T
+ WHERE P.object_id = @FunctionObjectId
+ AND P.parameter_id > 0
+ ORDER BY P.parameter_id
+ FOR XML PATH(''),TYPE
+ ).value('.','NVARCHAR(MAX)'),1,1,''),'');
+
+
+ IF(@IsScalarFunction = 1)
+ BEGIN
+ EXEC('CREATE FUNCTION '+@FunctionName+'('+@ParameterList+') RETURNS '+@ReturnType+' AS BEGIN RETURN '+@FakeFunctionName+'('+@ParameterCallList+');END;');
+ END
+ ELSE IF (@FakeDataSource IS NOT NULL)
+ BEGIN
+ DECLARE @newTbleName NVARCHAR(MAX);
+ EXEC tSQLt.Private_PrepareFakeFunctionOutputTable @FakeDataSource, @newTbleName OUTPUT;
+ EXEC ('CREATE FUNCTION '+@FunctionName+'('+@ParameterList+') RETURNS TABLE AS RETURN ( SELECT * FROM '+@newTbleName+');');
+ END
+ ELSE
+ BEGIN
+ EXEC('CREATE FUNCTION '+@FunctionName+'('+@ParameterList+') RETURNS TABLE AS RETURN SELECT * FROM '+@FakeFunctionName+'('+@ParameterCallList+');');
+ END;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CreateFakeOfTable.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CreateFakeOfTable.sql
new file mode 100644
index 0000000..b192d9e
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CreateFakeOfTable.sql
@@ -0,0 +1,17 @@
+
+CREATE PROCEDURE tSQLt.Private_CreateFakeOfTable
+ @SchemaName NVARCHAR(MAX),
+ @TableName NVARCHAR(MAX),
+ @OrigTableFullName NVARCHAR(MAX),
+ @Identity BIT,
+ @ComputedColumns BIT,
+ @Defaults BIT
+AS
+BEGIN
+ DECLARE @cmd NVARCHAR(MAX) =
+ (SELECT CreateTableStatement
+ FROM tSQLt.Private_CreateFakeTableStatement(OBJECT_ID(@OrigTableFullName), @SchemaName+'.'+@TableName,@Identity,@ComputedColumns,@Defaults,0));
+ EXEC (@cmd);
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CreateInstallationInfo.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CreateInstallationInfo.sql
new file mode 100644
index 0000000..fd79c60
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CreateInstallationInfo.sql
@@ -0,0 +1,13 @@
+CREATE PROCEDURE tSQLt.Private_CreateInstallationInfo
+-- Created as a stored procedure to make it testable.
+AS
+BEGIN
+ DECLARE @cmd NVARCHAR(MAX);
+ SELECT
+ @cmd = 'ALTER FUNCTION tSQLt.Private_InstallationInfo() RETURNS TABLE AS RETURN SELECT CAST('+
+ CAST(I.SqlVersion AS NVARCHAR(MAX))+
+ ' AS NUMERIC(10,2)) AS SqlVersion;'
+ FROM tSQLt.Info() AS I;
+
+ EXEC(@cmd);
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CreateProcedureSpy.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CreateProcedureSpy.sql
new file mode 100644
index 0000000..10a4819
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CreateProcedureSpy.sql
@@ -0,0 +1,13 @@
+
+CREATE PROCEDURE tSQLt.Private_CreateProcedureSpy
+ @ProcedureObjectId INT,
+ @OriginalProcedureName NVARCHAR(MAX),
+ @LogTableName NVARCHAR(MAX),
+ @CommandToExecute NVARCHAR(MAX) = NULL
+AS
+BEGIN
+
+ RETURN;
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CreateResultTableForCompareTables.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CreateResultTableForCompareTables.sql
new file mode 100644
index 0000000..62af48c
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_CreateResultTableForCompareTables.sql
@@ -0,0 +1,14 @@
+CREATE PROCEDURE tSQLt.Private_CreateResultTableForCompareTables
+ @ResultTable NVARCHAR(MAX),
+ @ResultColumn NVARCHAR(MAX),
+ @BaseTable NVARCHAR(MAX)
+AS
+BEGIN
+ DECLARE @Cmd NVARCHAR(MAX);
+ SET @Cmd = '
+ SELECT ''='' AS ' + @ResultColumn + ', Expected.* INTO ' + @ResultTable + '
+ FROM tSQLt.Private_NullCellTable N
+ LEFT JOIN ' + @BaseTable + ' AS Expected ON N.I <> N.I
+ TRUNCATE TABLE ' + @ResultTable + ';' --Need to insert an actual row to prevent IDENTITY property from transfering (IDENTITY_COL can't be NULLable);
+ EXEC(@Cmd);
+END
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_DisallowOverwritingNonTestSchema.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_DisallowOverwritingNonTestSchema.sql
new file mode 100644
index 0000000..c317532
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_DisallowOverwritingNonTestSchema.sql
@@ -0,0 +1,12 @@
+
+CREATE PROCEDURE tSQLt.Private_DisallowOverwritingNonTestSchema
+ @ClassName NVARCHAR(MAX)
+AS
+BEGIN
+ IF SCHEMA_ID(@ClassName) IS NOT NULL AND tSQLt.Private_IsTestClass(@ClassName) = 0
+ BEGIN
+ RAISERROR('Attempted to execute tSQLt.NewTestClass on ''%s'' which is an existing schema but not a test class', 16, 10, @ClassName);
+ END
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_EnableCLR.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_EnableCLR.sql
new file mode 100644
index 0000000..f5185b8
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_EnableCLR.sql
@@ -0,0 +1,6 @@
+CREATE PROCEDURE tSQLt.Private_EnableCLR
+AS
+BEGIN
+ EXEC master.sys.sp_configure @configname='clr enabled', @configvalue = 1;
+ RECONFIGURE;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GenerateCreateProcedureSpyStatement.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GenerateCreateProcedureSpyStatement.sql
new file mode 100644
index 0000000..d88001d
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GenerateCreateProcedureSpyStatement.sql
@@ -0,0 +1,95 @@
+
+CREATE PROCEDURE tSQLt.Private_GenerateCreateProcedureSpyStatement
+ @ProcedureObjectId INT,
+ @OriginalProcedureName NVARCHAR(MAX),
+ @LogTableName NVARCHAR(MAX),
+ @CommandToExecute NVARCHAR(MAX),
+ @CreateProcedureStatement NVARCHAR(MAX) OUTPUT,
+ @CreateLogTableStatement NVARCHAR(MAX) OUTPUT
+AS
+BEGIN
+ DECLARE @ProcParmList NVARCHAR(MAX),
+ @TableColList NVARCHAR(MAX),
+ @ProcParmTypeList NVARCHAR(MAX),
+ @TableColTypeList NVARCHAR(MAX);
+
+ DECLARE @Separator CHAR(1),
+ @ProcParmTypeListSeparator CHAR(1),
+ @ParamName sysname,
+ @TypeName sysname,
+ @IsOutput BIT,
+ @IsCursorRef BIT,
+ @IsTableType BIT;
+
+ SELECT @Separator = '', @ProcParmTypeListSeparator = '',
+ @ProcParmList = '', @TableColList = '', @ProcParmTypeList = '', @TableColTypeList = '';
+
+ DECLARE Parameters CURSOR FOR
+ SELECT p.name, t.TypeName, p.is_output, p.is_cursor_ref, t.IsTableType
+ FROM sys.parameters p
+ CROSS APPLY tSQLt.Private_GetFullTypeName(p.user_type_id,p.max_length,p.precision,p.scale,NULL) t
+ WHERE object_id = @ProcedureObjectId;
+
+ OPEN Parameters;
+
+ FETCH NEXT FROM Parameters INTO @ParamName, @TypeName, @IsOutput, @IsCursorRef, @IsTableType;
+ WHILE (@@FETCH_STATUS = 0)
+ BEGIN
+ IF @IsCursorRef = 0
+ BEGIN
+ SELECT @ProcParmList = @ProcParmList + @Separator +
+ CASE WHEN @IsTableType = 1
+ THEN '(SELECT * FROM '+@ParamName+' FOR XML PATH(''row''),TYPE,ROOT('''+STUFF(@ParamName,1,1,'')+'''))'
+ ELSE @ParamName
+ END,
+ @TableColList = @TableColList + @Separator + '[' + STUFF(@ParamName,1,1,'') + ']',
+ @ProcParmTypeList = @ProcParmTypeList + @ProcParmTypeListSeparator + @ParamName + ' ' + @TypeName +
+ CASE WHEN @IsTableType = 1 THEN ' READONLY' ELSE ' = NULL ' END+
+ CASE WHEN @IsOutput = 1 THEN ' OUT' ELSE '' END,
+ @TableColTypeList = @TableColTypeList + ',[' + STUFF(@ParamName,1,1,'') + '] ' +
+ CASE
+ WHEN @IsTableType = 1
+ THEN 'XML'
+ WHEN @TypeName LIKE '%nchar%'
+ OR @TypeName LIKE '%nvarchar%'
+ THEN 'NVARCHAR(MAX)'
+ WHEN @TypeName LIKE '%char%'
+ THEN 'VARCHAR(MAX)'
+ ELSE @TypeName
+ END + ' NULL';
+
+ SELECT @Separator = ',';
+ SELECT @ProcParmTypeListSeparator = ',';
+ END
+ ELSE
+ BEGIN
+ SELECT @ProcParmTypeList = @ProcParmTypeListSeparator + @ParamName + ' CURSOR VARYING OUTPUT';
+ SELECT @ProcParmTypeListSeparator = ',';
+ END;
+
+ FETCH NEXT FROM Parameters INTO @ParamName, @TypeName, @IsOutput, @IsCursorRef, @IsTableType;
+ END;
+
+ CLOSE Parameters;
+ DEALLOCATE Parameters;
+
+ DECLARE @InsertStmt NVARCHAR(MAX);
+ SELECT @InsertStmt = 'INSERT INTO ' + @LogTableName +
+ CASE WHEN @TableColList = '' THEN ' DEFAULT VALUES'
+ ELSE ' (' + @TableColList + ') SELECT ' + @ProcParmList
+ END + ';';
+
+ SELECT @CreateLogTableStatement = 'CREATE TABLE ' + @LogTableName + ' (_id_ int IDENTITY(1,1) PRIMARY KEY CLUSTERED ' + @TableColTypeList + ');';
+
+ SELECT @CreateProcedureStatement =
+ 'CREATE PROCEDURE ' + @OriginalProcedureName + ' ' + @ProcParmTypeList +
+ ' AS BEGIN ' +
+ ISNULL(@InsertStmt,'') +
+ ISNULL(@CommandToExecute + ';', '') +
+ ' RETURN;' +
+ ' END;';
+
+ RETURN;
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GetAssemblyKeyBytes.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GetAssemblyKeyBytes.sql
new file mode 100644
index 0000000..b65c552
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GetAssemblyKeyBytes.sql
@@ -0,0 +1,53 @@
+CREATE PROCEDURE tSQLt.Private_GetAssemblyKeyBytes
+ @AssemblyKeyBytes VARBINARY(MAX) = NULL OUTPUT,
+ @AssemblyKeyThumbPrint VARBINARY(MAX) = NULL OUTPUT
+AS
+ SELECT @AssemblyKeyBytes =
+0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062+
+0x652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C010300A2465E610000000000000000E00022200B013000000A0000000600000000000042280000002000000040000000000010002000000002000004000000000000+
+0x0004000000000000000080000000020000C0750000030040850000100000100000000010000010000000000000100000000000000000000000F02700004F00000000400000A003000000000000000000000000000000000000006000000C000000B82600+
+0x001C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002E746578740000004808000000200000000A0000000200+
+0x00000000000000000000000000200000602E72737263000000A00300000040000000040000000C0000000000000000000000000000400000402E72656C6F6300000C00000000600000000200000010000000000000000000000000000040000042000000+
+0x000000000000000000000000002428000000000000480000000200050058200000E005000009000000000000000000000000000000382600008000000000000000000000000000000000000000000000000000000000000000000000001E02280F00000A+
+0x2A42534A4201000100000000000C00000076322E302E35303732370000000005006C000000A8010000237E0000140200002C02000023537472696E67730000000040040000040000002355530044040000100000002347554944000000540400008C0100+
+0x0023426C6F620000000000000002000001471400000900000000FA013300160000010000001000000002000000010000000F0000000E0000000100000001000000000078010100000000000600ED00DE0106005A01DE0106002100AC010F00FE01000006+
+0x00490094010600D00094010600B100940106004101940106000D01940106002601940106007900940106003500BF0106001300BF0106009400940106006000940106000D028D010000000001000000000001000100000010002502140241000100010050+
+0x20000000008618A601060001000900A60101001100A60106001900A6010A002900A60110003100A60110003900A60110004100A60110004900A60110005100A60110005900A60110006100A60115006900A60110007100A60110007900A60110008100A6+
+0x0106002E000B00C5002E001300CE002E001B00ED002E002300F6002E002B000C012E0033000C012E003B000C012E00430012012E004B001D012E0053000C012E005B000C012E00630035012E006B005F012E0073006C0104800000010000000000000001+
+0x0000002300140200000200000000000000000000001A000A000000000000000000003C4D6F64756C653E006D73636F726C696200477569644174747269627574650044656275676761626C6541747472696275746500436F6D56697369626C6541747472+
+0x696275746500417373656D626C795469746C6541747472696275746500417373656D626C794B65794E616D6541747472696275746500417373656D626C7954726164656D61726B41747472696275746500417373656D626C7946696C6556657273696F6E+
+0x41747472696275746500417373656D626C79436F6E66696775726174696F6E41747472696275746500417373656D626C794465736372697074696F6E41747472696275746500436F6D70696C6174696F6E52656C61786174696F6E734174747269627574+
+0x6500417373656D626C7950726F6475637441747472696275746500417373656D626C79436F7079726967687441747472696275746500417373656D626C79436F6D70616E794174747269627574650052756E74696D65436F6D7061746962696C69747941+
+0x7474726962757465007453514C74417373656D626C794B65792E646C6C0053797374656D0053797374656D2E5265666C656374696F6E002E63746F720053797374656D2E446961676E6F73746963730053797374656D2E52756E74696D652E496E746572+
+0x6F7053657276696365730053797374656D2E52756E74696D652E436F6D70696C6572536572766963657300446562756767696E674D6F646573004F626A656374007453514C74417373656D626C794B657900656D70747900000000000098F06698E3084C+
+0x4BB7B62DDABC66C25000042001010803200001052001011111042001010E042001010208B77A5C561934E08980A00024000004800000940000000602000000240000525341310004000001000100B9AF416AD8DFEDEC08A5652FA257F1242BF4ED60EF5A+
+0x7B84A429604D62C919C5663A9C7710A7C5DF9953B69EC89FCE85D71E051140B273F4C9BF890A2BC19C48F22D7B1F1D739F90EEBC5729555F7F8B63ED088BBB083B336F7E38B92D44CFE1C842F09632B85114772FF2122BC638C78D497C4E88C2D656C166+
+0x050D6E1EF3940801000800000000001E01000100540216577261704E6F6E457863657074696F6E5468726F777301080100020000000000150100107453514C74417373656D626C794B657900000501000000000A0100057453514C74000017010012436F+
+0x7079726967687420C2A920203230313900002901002430333536303035622D373166642D346466332D383530322D32376336613630366539653800000C010007312E302E302E3000001D0100187453514C745F4F6666696369616C5369676E696E674B65+
+0x790000000085E1EC914D055DCA81D1275718A1746D031CBF462DD462F1CA24C7CB2A11EF3C631F2B593CD9D84310C89F8A458564EFAC3553223D60A515ED2E89B79A45B94B2A5ABE43075FF595DC62E6A59A2D6F51B910A4B582A0862B92796FF31F71EB+
+0x32A37CFDF0BA740F1F14EBB8A249FF7302DBAF9329B2E39C7A3C2CCFF38EC9156100000000A2465E6100000000020000001C010000D4260000D408000052534453307228729E144B4FBE124B43F8FC25BA01000000443A5C615C315C7453514C745C7453+
+0x514C74434C525C7453514C74417373656D626C794B65795C6F626A5C437275697365436F6E74726F6C5C7453514C74417373656D626C794B65792E7064620000000000000000000000000000000000000000000000000000000000000000000000000000+
+0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000+
+0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001828000000000000000000003228000000200000000000000000000000000000000000000000000024280000000000000000000000005F+
+0x436F72446C6C4D61696E006D73636F7265652E646C6C0000000000FF250020001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000+
+0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000+
+0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000+
+0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000+
+0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001001000000018000080000000+
+0x00000000000000000000000100010000003000008000000000000000000000000000000100000000004800000058400000440300000000000000000000440334000000560053005F00560045005200530049004F004E005F0049004E0046004F00000000+
+0x00BD04EFFE00000100000001000000000000000100000000003F000000000000000400000002000000000000000000000000000000440000000100560061007200460069006C00650049006E0066006F00000000002400040000005400720061006E0073+
+0x006C006100740069006F006E00000000000000B004A4020000010053007400720069006E006700460069006C00650049006E0066006F0000008002000001003000300030003000300034006200300000001A000100010043006F006D006D0065006E0074+
+0x00730000000000000022000100010043006F006D00700061006E0079004E0061006D00650000000000000000004A0011000100460069006C0065004400650073006300720069007000740069006F006E00000000007400530051004C0074004100730073+
+0x0065006D0062006C0079004B006500790000000000300008000100460069006C006500560065007200730069006F006E000000000031002E0030002E0030002E00300000004A001500010049006E007400650072006E0061006C004E0061006D00650000+
+0x007400530051004C00740041007300730065006D0062006C0079004B00650079002E0064006C006C00000000004800120001004C006500670061006C0043006F007000790072006900670068007400000043006F00700079007200690067006800740020+
+0x00A90020002000320030003100390000002A00010001004C006500670061006C00540072006100640065006D00610072006B00730000000000000000005200150001004F0072006900670069006E0061006C00460069006C0065006E0061006D00650000+
+0x007400530051004C00740041007300730065006D0062006C0079004B00650079002E0064006C006C00000000002C0006000100500072006F0064007500630074004E0061006D006500000000007400530051004C0074000000340008000100500072006F+
+0x006400750063007400560065007200730069006F006E00000031002E0030002E0030002E003000000038000800010041007300730065006D0062006C0079002000560065007200730069006F006E00000031002E0030002E0030002E0030000000000000+
+0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000+
+0x000C0000004438000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000+
+0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000+
+0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000+
+0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000+
+0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000+
+0x000000000000000000
+ ,@AssemblyKeyThumbPrint = 0xE8FFF6F136D7B53E ;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GetCursorForRunAll.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GetCursorForRunAll.sql
new file mode 100644
index 0000000..2c136a2
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GetCursorForRunAll.sql
@@ -0,0 +1,11 @@
+
+CREATE PROCEDURE tSQLt.Private_GetCursorForRunAll
+ @TestClassCursor CURSOR VARYING OUTPUT
+AS
+BEGIN
+ SET @TestClassCursor = CURSOR LOCAL FAST_FORWARD FOR
+ SELECT Name
+ FROM tSQLt.TestClasses;
+
+ OPEN @TestClassCursor;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GetCursorForRunNew.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GetCursorForRunNew.sql
new file mode 100644
index 0000000..fc63a46
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GetCursorForRunNew.sql
@@ -0,0 +1,13 @@
+
+CREATE PROCEDURE tSQLt.Private_GetCursorForRunNew
+ @TestClassCursor CURSOR VARYING OUTPUT
+AS
+BEGIN
+ SET @TestClassCursor = CURSOR LOCAL FAST_FORWARD FOR
+ SELECT TC.Name
+ FROM tSQLt.TestClasses AS TC
+ JOIN tSQLt.Private_NewTestClassList AS PNTCL
+ ON PNTCL.ClassName = TC.Name;
+
+ OPEN @TestClassCursor;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GetSQLProductMajorVersion.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GetSQLProductMajorVersion.sql
new file mode 100644
index 0000000..ca7b1d6
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GetSQLProductMajorVersion.sql
@@ -0,0 +1,3 @@
+CREATE PROCEDURE tSQLt.Private_GetSQLProductMajorVersion
+AS
+ RETURN CAST(PARSENAME(CAST(SERVERPROPERTY('ProductVersion') AS NVARCHAR(MAX)),4) AS INT);
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GetSetupProcedureName.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GetSetupProcedureName.sql
new file mode 100644
index 0000000..7d23592
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_GetSetupProcedureName.sql
@@ -0,0 +1,12 @@
+
+
+CREATE PROCEDURE tSQLt.Private_GetSetupProcedureName
+ @TestClassId INT = NULL,
+ @SetupProcName NVARCHAR(MAX) OUTPUT
+AS
+BEGIN
+ SELECT @SetupProcName = tSQLt.Private_GetQuotedFullName(object_id)
+ FROM sys.procedures
+ WHERE schema_id = @TestClassId
+ AND LOWER(name) = 'setup';
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_Init.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_Init.sql
new file mode 100644
index 0000000..29a5cad
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_Init.sql
@@ -0,0 +1,28 @@
+CREATE PROCEDURE tSQLt.Private_Init
+AS
+BEGIN
+ EXEC tSQLt.Private_CleanTestResult;
+
+ UPDATE tSQLt.Private_NullCellTable SET I=I WHERE 'Forcing trigger execution.' != '';
+
+ DECLARE @enable BIT; SET @enable = 1;
+ DECLARE @version_match BIT;SET @version_match = 0;
+ BEGIN TRY
+ EXEC sys.sp_executesql N'SELECT @r = CASE WHEN I.Version = I.ClrVersion THEN 1 ELSE 0 END FROM tSQLt.Info() AS I;',N'@r BIT OUTPUT',@version_match OUT;
+ END TRY
+ BEGIN CATCH
+ RAISERROR('Cannot access CLR. Assembly might be in an invalid state. Try running EXEC tSQLt.EnableExternalAccess @enable = 0; or reinstalling tSQLt.',16,10);
+ RETURN;
+ END CATCH;
+ SELECT @version_match = CASE WHEN I.SqlVersion = I.InstalledOnSqlVersion THEN 1 ELSE 0 END FROM tSQLt.Info() AS I WHERE @version_match = 1;
+ IF(@version_match = 0)
+ BEGIN
+ RAISERROR('tSQLt is in an invalid state. Please reinstall tSQLt.',16,10);
+ RETURN;
+ END;
+
+ IF(NOT EXISTS(SELECT 1 FROM tSQLt.Info() WHERE SqlEdition = 'SQL Azure'))
+ BEGIN
+ EXEC tSQLt.EnableExternalAccess @enable = @enable, @try = 1;
+ END;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_InputBuffer.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_InputBuffer.sql
new file mode 100644
index 0000000..c22c536
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_InputBuffer.sql
@@ -0,0 +1,9 @@
+CREATE PROCEDURE tSQLt.Private_InputBuffer
+ @InputBuffer NVARCHAR(MAX) OUTPUT
+AS
+BEGIN
+ CREATE TABLE #inputbuffer(EventType sysname, Parameters SMALLINT, EventInfo NVARCHAR(MAX));
+ INSERT INTO #inputbuffer
+ EXEC('DBCC INPUTBUFFER(@@SPID) WITH NO_INFOMSGS;');
+ SELECT @InputBuffer = I.EventInfo FROM #inputbuffer AS I;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_MarkFakeTable.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_MarkFakeTable.sql
new file mode 100644
index 0000000..c02371d
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_MarkFakeTable.sql
@@ -0,0 +1,18 @@
+
+CREATE PROCEDURE tSQLt.Private_MarkFakeTable
+ @SchemaName NVARCHAR(MAX),
+ @TableName NVARCHAR(MAX),
+ @NewNameOfOriginalTable NVARCHAR(4000)
+AS
+BEGIN
+ DECLARE @UnquotedSchemaName NVARCHAR(MAX);SET @UnquotedSchemaName = OBJECT_SCHEMA_NAME(OBJECT_ID(@SchemaName+'.'+@TableName));
+ DECLARE @UnquotedTableName NVARCHAR(MAX);SET @UnquotedTableName = OBJECT_NAME(OBJECT_ID(@SchemaName+'.'+@TableName));
+
+ EXEC sys.sp_addextendedproperty
+ @name = N'tSQLt.FakeTable_OrgTableName',
+ @value = @NewNameOfOriginalTable,
+ @level0type = N'SCHEMA', @level0name = @UnquotedSchemaName,
+ @level1type = N'TABLE', @level1name = @UnquotedTableName;
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_MarkObjectBeforeRename.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_MarkObjectBeforeRename.sql
new file mode 100644
index 0000000..18c1dd7
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_MarkObjectBeforeRename.sql
@@ -0,0 +1,11 @@
+
+CREATE PROCEDURE tSQLt.Private_MarkObjectBeforeRename
+ @SchemaName NVARCHAR(MAX),
+ @OriginalName NVARCHAR(MAX)
+AS
+BEGIN
+ INSERT INTO tSQLt.Private_RenamedObjectLog (ObjectId, OriginalName)
+ VALUES (OBJECT_ID(@SchemaName + '.' + @OriginalName), @OriginalName);
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_MarkSchemaAsTestClass.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_MarkSchemaAsTestClass.sql
new file mode 100644
index 0000000..cd10559
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_MarkSchemaAsTestClass.sql
@@ -0,0 +1,30 @@
+
+CREATE PROCEDURE tSQLt.Private_MarkSchemaAsTestClass
+ @QuotedClassName NVARCHAR(MAX)
+AS
+BEGIN
+ SET NOCOUNT ON;
+
+ DECLARE @UnquotedClassName NVARCHAR(MAX);
+
+ SELECT @UnquotedClassName = name
+ FROM sys.schemas
+ WHERE QUOTENAME(name) = @QuotedClassName;
+
+ EXEC sp_addextendedproperty @name = N'tSQLt.TestClass',
+ @value = 1,
+ @level0type = 'SCHEMA',
+ @level0name = @UnquotedClassName;
+
+ INSERT INTO tSQLt.Private_NewTestClassList(ClassName)
+ SELECT @UnquotedClassName
+ WHERE NOT EXISTS
+ (
+ SELECT *
+ FROM tSQLt.Private_NewTestClassList AS NTC
+ WITH(UPDLOCK,ROWLOCK,HOLDLOCK)
+ WHERE NTC.ClassName = @UnquotedClassName
+ );
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_OutputTestResults.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_OutputTestResults.sql
new file mode 100644
index 0000000..1b88a30
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_OutputTestResults.sql
@@ -0,0 +1,9 @@
+
+CREATE PROCEDURE tSQLt.Private_OutputTestResults
+ @TestResultFormatter NVARCHAR(MAX) = NULL
+AS
+BEGIN
+ DECLARE @Formatter NVARCHAR(MAX);
+ SELECT @Formatter = COALESCE(@TestResultFormatter, tSQLt.GetTestResultFormatter());
+ EXEC (@Formatter);
+END
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_PrepareFakeFunctionOutputTable.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_PrepareFakeFunctionOutputTable.sql
new file mode 100644
index 0000000..b6fe37a
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_PrepareFakeFunctionOutputTable.sql
@@ -0,0 +1,23 @@
+
+CREATE PROCEDURE tSQLt.Private_PrepareFakeFunctionOutputTable
+ @FakeDataSource NVARCHAR(MAX),
+ @OutputTable NVARCHAR(MAX) OUTPUT
+AS
+ BEGIN
+ SET @OutputTable = tSQLt.Private::CreateUniqueObjectName();
+
+ IF ( LOWER(LTRIM(@FakeDataSource)) LIKE 'select%'
+ AND OBJECT_ID(@FakeDataSource) IS NULL
+ )
+ BEGIN
+ SET @FakeDataSource = N'('+ @FakeDataSource + N') a';
+ END;
+
+ DECLARE @Cmd NVARCHAR(MAX) = N'SELECT * INTO ' + @OutputTable + N' FROM ' + @FakeDataSource;
+
+ EXEC sp_executesql @Cmd;
+
+ RETURN 0;
+ END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_Print.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_Print.sql
new file mode 100644
index 0000000..fbf7a6b
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_Print.sql
@@ -0,0 +1,29 @@
+CREATE PROCEDURE tSQLt.Private_Print
+ @Message NVARCHAR(MAX),
+ @Severity INT = 0
+AS
+BEGIN
+ DECLARE @SPos INT;SET @SPos = 1;
+ DECLARE @EPos INT;
+ DECLARE @Len INT; SET @Len = LEN(@Message);
+ DECLARE @SubMsg NVARCHAR(MAX);
+ DECLARE @Cmd NVARCHAR(MAX);
+
+ DECLARE @CleanedMessage NVARCHAR(MAX);
+ SET @CleanedMessage = REPLACE(@Message,'%','%%');
+
+ WHILE (@SPos <= @Len)
+ BEGIN
+ SET @EPos = CHARINDEX(CHAR(13)+CHAR(10),@CleanedMessage+CHAR(13)+CHAR(10),@SPos);
+ SET @SubMsg = SUBSTRING(@CleanedMessage, @SPos, @EPos - @SPos);
+ SET @Cmd = N'RAISERROR(@Msg,@Severity,10) WITH NOWAIT;';
+ EXEC sp_executesql @Cmd,
+ N'@Msg NVARCHAR(MAX),@Severity INT',
+ @SubMsg,
+ @Severity;
+ SELECT @SPos = @EPos + 2,
+ @Severity = 0; --Print only first line with high severity
+ END
+
+ RETURN 0;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_PrintXML.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_PrintXML.sql
new file mode 100644
index 0000000..40436d9
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_PrintXML.sql
@@ -0,0 +1,9 @@
+
+CREATE PROCEDURE tSQLt.Private_PrintXML
+ @Message XML
+AS
+BEGIN
+ SET NOCOUNT ON;
+ SELECT CAST(@Message AS XML);--Required together with ":XML ON" sqlcmd statement to allow more than 1mb to be returned
+ RETURN 0;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ProcessTestAnnotations.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ProcessTestAnnotations.sql
new file mode 100644
index 0000000..1dc5c21
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ProcessTestAnnotations.sql
@@ -0,0 +1,99 @@
+CREATE PROCEDURE tSQLt.Private_ProcessTestAnnotations
+ @TestObjectId INT
+AS
+BEGIN
+ DECLARE @Cmd NVARCHAR(MAX);
+ DECLARE @UnmatchedQuotesAnnotation NVARCHAR(MAX);
+ CREATE TABLE #AnnotationCommands(AnnotationOrderNo INT, AnnotationString NVARCHAR(MAX), AnnotationCmd NVARCHAR(MAX));
+
+ SELECT * INTO #AnnotationList FROM tSQLt.Private_ListTestAnnotations(@TestObjectId);
+ SET @UnmatchedQuotesAnnotation = NULL;
+ SELECT TOP(1) @UnmatchedQuotesAnnotation = AL.Annotation
+ FROM #AnnotationList AS AL
+ WHERE (LEN(AL.Annotation ) - LEN(REPLACE(AL.Annotation, '''', '')))%2=1
+ ORDER BY AL.AnnotationNo;
+
+ IF(@UnmatchedQuotesAnnotation IS NOT NULL)
+ BEGIN
+ RAISERROR('Annotation has unmatched quote: %s',16,10,@UnmatchedQuotesAnnotation);
+ END;
+
+ SELECT @Cmd =
+ 'DECLARE @EM NVARCHAR(MAX),@ES INT,@ET INT,@EP NVARCHAR(MAX);'+
+ (
+ SELECT
+ 'BEGIN TRY;INSERT INTO #AnnotationCommands '+
+ 'SELECT '+
+ CAST(AL.AnnotationNo AS NVARCHAR(MAX))+','+
+ ''''+AL.EscapedAnnotationString+''''+
+ ',A.AnnotationCmd FROM '+
+ AL.Annotation+' AS A;'+
+ ';END TRY BEGIN CATCH;'+
+ 'SELECT @EM=ERROR_MESSAGE(),'+--REPLACE(ERROR_MESSAGE(),'''''''',''''''''''''),'+
+ '@ES=ERROR_SEVERITY(),'+
+ '@ET=ERROR_STATE();'+
+ 'RAISERROR(''There is an internal error for annotation: %s'+CHAR(13)+CHAR(10)+
+ ' caused by {%i,%i} %s'',16,10,'''+
+ AL.EscapedAnnotationString+
+ ''',@ES,@ET,@EM);'+
+ 'END CATCH;'
+ FROM #AnnotationList AS AL
+ ORDER BY AL.AnnotationNo
+ FOR XML PATH,TYPE
+ ).value('.','NVARCHAR(MAX)');
+
+ IF(@Cmd IS NOT NULL)
+ BEGIN
+ --PRINT '--------------------------------';
+ --PRINT @Cmd
+ --PRINT '--------------------------------';
+ BEGIN TRY
+ EXEC(@Cmd);
+ END TRY
+ BEGIN CATCH
+ DECLARE @EM NVARCHAR(MAX),@ES INT,@ET INT,@EP NVARCHAR(MAX);
+ SELECT @EM=REPLACE(ERROR_MESSAGE(),'''',''''''),
+ @ES=ERROR_SEVERITY(),
+ @ET=ERROR_STATE();
+ DECLARE @NewErrorMessage NVARCHAR(MAX)=
+ 'There is a problem with the annotations:'+CHAR(13)+CHAR(10)+
+ 'Original Error: {%i,%i} %s'
+ RAISERROR(@NewErrorMessage,16,10,@ES,@ET,@EM);
+ END CATCH;
+ --PRINT '--------------------------------';
+
+
+ SELECT @Cmd =
+ 'DECLARE @EM NVARCHAR(MAX),@ES INT,@ET INT,@EP NVARCHAR(MAX);'+
+ (
+ SELECT
+ 'BEGIN TRY;'+
+ 'IF(NOT EXISTS(SELECT 1 FROM #SkipTest)) BEGIN '+
+ AnnotationCmd+
+ ';END'+
+ ';END TRY BEGIN CATCH;'+
+ 'SELECT @EM=ERROR_MESSAGE(),'+--REPLACE(ERROR_MESSAGE(),'''''''',''''''''''''),'+
+ '@ES=ERROR_SEVERITY(),'+
+ '@ET=ERROR_STATE(),'+
+ '@EP=ERROR_PROCEDURE();'+
+ 'RAISERROR(''There is a problem with this annotation: %s'+CHAR(13)+CHAR(10)+
+ 'Original Error: {%i,%i;%s} %s'',16,10,'''+
+ REPLACE(AnnotationString,'''','''''')+
+ ''',@ES,@ET,@EP,@EM);'+
+ 'END CATCH;'
+ FROM #AnnotationCommands
+ ORDER BY AnnotationOrderNo
+ FOR XML PATH,TYPE
+ ).value('.','NVARCHAR(MAX)');
+
+ IF(@Cmd IS NOT NULL)
+ BEGIN
+ --PRINT '--------------------------------';
+ --PRINT @Cmd
+ --PRINT '--------------------------------';
+ EXEC(@Cmd);
+ END;
+
+ END;
+
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RemoveSchemaBinding.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RemoveSchemaBinding.sql
new file mode 100644
index 0000000..9f54a64
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RemoveSchemaBinding.sql
@@ -0,0 +1,10 @@
+CREATE PROCEDURE tSQLt.Private_RemoveSchemaBinding
+ @object_id INT
+AS
+BEGIN
+ DECLARE @cmd NVARCHAR(MAX);
+ SELECT @cmd = tSQLt.[Private]::GetAlterStatementWithoutSchemaBinding(SM.definition)
+ FROM sys.sql_modules AS SM
+ WHERE SM.object_id = @object_id;
+ EXEC(@cmd);
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RemoveSchemaBoundReferences.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RemoveSchemaBoundReferences.sql
new file mode 100644
index 0000000..ec66b31
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RemoveSchemaBoundReferences.sql
@@ -0,0 +1,21 @@
+CREATE PROCEDURE tSQLt.Private_RemoveSchemaBoundReferences
+ @object_id INT
+AS
+BEGIN
+ DECLARE @cmd NVARCHAR(MAX);
+ SELECT @cmd =
+ (
+ SELECT
+ 'EXEC tSQLt.Private_RemoveSchemaBoundReferences @object_id = '+STR(SED.referencing_id)+';'+
+ 'EXEC tSQLt.Private_RemoveSchemaBinding @object_id = '+STR(SED.referencing_id)+';'
+ FROM
+ (
+ SELECT DISTINCT SEDI.referencing_id,SEDI.referenced_id
+ FROM sys.sql_expression_dependencies AS SEDI
+ WHERE SEDI.is_schema_bound_reference = 1
+ ) AS SED
+ WHERE SED.referenced_id = @object_id
+ FOR XML PATH(''),TYPE
+ ).value('.','NVARCHAR(MAX)');
+ EXEC(@cmd);
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RenameObjectToUniqueName.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RenameObjectToUniqueName.sql
new file mode 100644
index 0000000..b8b0dcc
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RenameObjectToUniqueName.sql
@@ -0,0 +1,22 @@
+
+CREATE PROCEDURE tSQLt.Private_RenameObjectToUniqueName
+ @SchemaName NVARCHAR(MAX),
+ @ObjectName NVARCHAR(MAX),
+ @NewName NVARCHAR(MAX) = NULL OUTPUT
+AS
+BEGIN
+ SET @NewName=tSQLt.Private::CreateUniqueObjectName();
+
+ DECLARE @RenameCmd NVARCHAR(MAX);
+ SET @RenameCmd = 'EXEC sp_rename ''' +
+ @SchemaName + '.' + @ObjectName + ''', ''' +
+ @NewName + ''',''OBJECT'';';
+
+ EXEC tSQLt.Private_MarkObjectBeforeRename @SchemaName, @ObjectName;
+
+
+ EXEC tSQLt.SuppressOutput @RenameCmd;
+
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RenameObjectToUniqueNameUsingObjectId.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RenameObjectToUniqueNameUsingObjectId.sql
new file mode 100644
index 0000000..066378e
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RenameObjectToUniqueNameUsingObjectId.sql
@@ -0,0 +1,15 @@
+
+CREATE PROCEDURE tSQLt.Private_RenameObjectToUniqueNameUsingObjectId
+ @ObjectId INT,
+ @NewName NVARCHAR(MAX) = NULL OUTPUT
+AS
+BEGIN
+ DECLARE @SchemaName NVARCHAR(MAX);
+ DECLARE @ObjectName NVARCHAR(MAX);
+
+ SELECT @SchemaName = QUOTENAME(OBJECT_SCHEMA_NAME(@ObjectId)), @ObjectName = QUOTENAME(OBJECT_NAME(@ObjectId));
+
+ EXEC tSQLt.Private_RenameObjectToUniqueName @SchemaName,@ObjectName, @NewName OUTPUT;
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ResetNewTestClassList.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ResetNewTestClassList.sql
new file mode 100644
index 0000000..4fc8e41
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ResetNewTestClassList.sql
@@ -0,0 +1,6 @@
+CREATE PROCEDURE tSQLt.Private_ResetNewTestClassList
+AS
+BEGIN
+ SET NOCOUNT ON;
+ DELETE FROM tSQLt.Private_NewTestClassList;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_Run.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_Run.sql
new file mode 100644
index 0000000..c872c69
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_Run.sql
@@ -0,0 +1,39 @@
+
+CREATE PROCEDURE tSQLt.Private_Run
+ @TestName NVARCHAR(MAX),
+ @TestResultFormatter NVARCHAR(MAX)
+AS
+BEGIN
+SET NOCOUNT ON;
+ DECLARE @FullName NVARCHAR(MAX);
+ DECLARE @TestClassId INT;
+ DECLARE @IsTestClass BIT;
+ DECLARE @IsTestCase BIT;
+ DECLARE @IsSchema BIT;
+ DECLARE @SetUp NVARCHAR(MAX);SET @SetUp = NULL;
+
+ SELECT @TestName = tSQLt.Private_GetLastTestNameIfNotProvided(@TestName);
+ EXEC tSQLt.Private_SaveTestNameForSession @TestName;
+
+ SELECT @TestClassId = schemaId,
+ @FullName = quotedFullName,
+ @IsTestClass = isTestClass,
+ @IsSchema = isSchema,
+ @IsTestCase = isTestCase
+ FROM tSQLt.Private_ResolveName(@TestName);
+
+ IF @IsSchema = 1
+ BEGIN
+ EXEC tSQLt.Private_RunTestClass @FullName;
+ END
+
+ IF @IsTestCase = 1
+ BEGIN
+ DECLARE @SetupProcName NVARCHAR(MAX);
+ EXEC tSQLt.Private_GetSetupProcedureName @TestClassId, @SetupProcName OUTPUT;
+
+ EXEC tSQLt.Private_RunTest @FullName, @SetupProcName;
+ END;
+
+ EXEC tSQLt.Private_OutputTestResults @TestResultFormatter;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunAll.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunAll.sql
new file mode 100644
index 0000000..404b066
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunAll.sql
@@ -0,0 +1,7 @@
+
+CREATE PROCEDURE tSQLt.Private_RunAll
+ @TestResultFormatter NVARCHAR(MAX)
+AS
+BEGIN
+ EXEC tSQLt.Private_RunCursor @TestResultFormatter = @TestResultFormatter, @GetCursorCallback = 'tSQLt.Private_GetCursorForRunAll';
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunCursor.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunCursor.sql
new file mode 100644
index 0000000..0fa1067
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunCursor.sql
@@ -0,0 +1,28 @@
+
+
+CREATE PROCEDURE tSQLt.Private_RunCursor
+ @TestResultFormatter NVARCHAR(MAX),
+ @GetCursorCallback NVARCHAR(MAX)
+AS
+BEGIN
+ SET NOCOUNT ON;
+ DECLARE @TestClassName NVARCHAR(MAX);
+ DECLARE @TestProcName NVARCHAR(MAX);
+
+ DECLARE @TestClassCursor CURSOR;
+ EXEC @GetCursorCallback @TestClassCursor = @TestClassCursor OUT;
+----
+ WHILE(1=1)
+ BEGIN
+ FETCH NEXT FROM @TestClassCursor INTO @TestClassName;
+ IF(@@FETCH_STATUS<>0)BREAK;
+
+ EXEC tSQLt.Private_RunTestClass @TestClassName;
+
+ END;
+
+ CLOSE @TestClassCursor;
+ DEALLOCATE @TestClassCursor;
+
+ EXEC tSQLt.Private_OutputTestResults @TestResultFormatter;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunMethodHandler.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunMethodHandler.sql
new file mode 100644
index 0000000..b667761
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunMethodHandler.sql
@@ -0,0 +1,22 @@
+
+CREATE PROCEDURE tSQLt.Private_RunMethodHandler
+ @RunMethod NVARCHAR(MAX),
+ @TestResultFormatter NVARCHAR(MAX) = NULL,
+ @TestName NVARCHAR(MAX) = NULL
+AS
+BEGIN
+ SELECT @TestResultFormatter = ISNULL(@TestResultFormatter,tSQLt.GetTestResultFormatter());
+
+ EXEC tSQLt.Private_Init;
+ IF(@@ERROR = 0)
+ BEGIN
+ IF(EXISTS(SELECT * FROM sys.parameters AS P WHERE P.object_id = OBJECT_ID(@RunMethod) AND name = '@TestName'))
+ BEGIN
+ EXEC @RunMethod @TestName = @TestName, @TestResultFormatter = @TestResultFormatter;
+ END;
+ ELSE
+ BEGIN
+ EXEC @RunMethod @TestResultFormatter = @TestResultFormatter;
+ END;
+ END;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunNew.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunNew.sql
new file mode 100644
index 0000000..d1ae35b
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunNew.sql
@@ -0,0 +1,7 @@
+
+CREATE PROCEDURE tSQLt.Private_RunNew
+ @TestResultFormatter NVARCHAR(MAX)
+AS
+BEGIN
+ EXEC tSQLt.Private_RunCursor @TestResultFormatter = @TestResultFormatter, @GetCursorCallback = 'tSQLt.Private_GetCursorForRunNew';
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunTest.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunTest.sql
new file mode 100644
index 0000000..9361124
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunTest.sql
@@ -0,0 +1,234 @@
+
+CREATE PROCEDURE tSQLt.Private_RunTest
+ @TestName NVARCHAR(MAX),
+ @SetUp NVARCHAR(MAX) = NULL
+AS
+BEGIN
+ DECLARE @Msg NVARCHAR(MAX); SET @Msg = '';
+ DECLARE @Msg2 NVARCHAR(MAX); SET @Msg2 = '';
+ DECLARE @Cmd NVARCHAR(MAX); SET @Cmd = '';
+ DECLARE @TestClassName NVARCHAR(MAX); SET @TestClassName = '';
+ DECLARE @TestProcName NVARCHAR(MAX); SET @TestProcName = '';
+ DECLARE @Result NVARCHAR(MAX);
+ DECLARE @TranName CHAR(32); EXEC tSQLt.GetNewTranName @TranName OUT;
+ DECLARE @TestResultId INT;
+ DECLARE @PreExecTrancount INT;
+ DECLARE @TestObjectId INT;
+
+ DECLARE @VerboseMsg NVARCHAR(MAX);
+ DECLARE @Verbose BIT;
+ SET @Verbose = ISNULL((SELECT CAST(Value AS BIT) FROM tSQLt.Private_GetConfiguration('Verbose')),0);
+
+ TRUNCATE TABLE tSQLt.CaptureOutputLog;
+ CREATE TABLE #ExpectException(ExpectException INT,ExpectedMessage NVARCHAR(MAX), ExpectedSeverity INT, ExpectedState INT, ExpectedMessagePattern NVARCHAR(MAX), ExpectedErrorNumber INT, FailMessage NVARCHAR(MAX));
+ CREATE TABLE #SkipTest(SkipTestMessage NVARCHAR(MAX) DEFAULT '');
+
+ IF EXISTS (SELECT 1 FROM sys.extended_properties WHERE name = N'SetFakeViewOnTrigger')
+ BEGIN
+ RAISERROR('Test system is in an invalid state. SetFakeViewOff must be called if SetFakeViewOn was called. Call SetFakeViewOff after creating all test case procedures.', 16, 10) WITH NOWAIT;
+ RETURN -1;
+ END;
+
+ SELECT @Cmd = 'EXEC ' + @TestName;
+
+ SELECT @TestClassName = OBJECT_SCHEMA_NAME(OBJECT_ID(@TestName)), --tSQLt.Private_GetCleanSchemaName('', @TestName),
+ @TestProcName = tSQLt.Private_GetCleanObjectName(@TestName),
+ @TestObjectId = OBJECT_ID(@TestName);
+
+ INSERT INTO tSQLt.TestResult(Class, TestCase, TranName, Result)
+ SELECT @TestClassName, @TestProcName, @TranName, 'A severe error happened during test execution. Test did not finish.'
+ OPTION(MAXDOP 1);
+ SELECT @TestResultId = SCOPE_IDENTITY();
+
+ IF(@Verbose = 1)
+ BEGIN
+ SET @VerboseMsg = 'tSQLt.Run '''+@TestName+'''; --Starting';
+ EXEC tSQLt.Private_Print @Message =@VerboseMsg, @Severity = 0;
+ END;
+
+
+ SET @Result = 'Success';
+ BEGIN TRAN;
+ SAVE TRAN @TranName;
+
+ SET @PreExecTrancount = @@TRANCOUNT;
+
+
+ TRUNCATE TABLE tSQLt.TestMessage;
+
+ BEGIN TRY
+ EXEC tSQLt.Private_ProcessTestAnnotations @TestObjectId=@TestObjectId;
+
+ DECLARE @TmpMsg NVARCHAR(MAX);
+ DECLARE @TestEndTime DATETIME2; SET @TestEndTime = NULL;
+ BEGIN TRY
+ IF(NOT EXISTS(SELECT 1 FROM #SkipTest))
+ BEGIN
+ IF (@SetUp IS NOT NULL) EXEC @SetUp;
+ EXEC (@Cmd);
+ IF(EXISTS(SELECT 1 FROM #ExpectException WHERE ExpectException = 1))
+ BEGIN
+ SET @TmpMsg = COALESCE((SELECT FailMessage FROM #ExpectException)+' ','')+'Expected an error to be raised.';
+ EXEC tSQLt.Fail @TmpMsg;
+ END
+ END;
+ ELSE
+ BEGIN
+ SELECT
+ @Result = 'Skipped',
+ @Msg = ST.SkipTestMessage
+ FROM #SkipTest AS ST;
+ SET @TmpMsg = '-->'+@TestName+' skipped: '+@Msg;
+ EXEC tSQLt.Private_Print @Message = @TmpMsg;
+ END;
+ SET @TestEndTime = SYSDATETIME();
+ END TRY
+ BEGIN CATCH
+ SET @TestEndTime = ISNULL(@TestEndTime,SYSDATETIME());
+ IF ERROR_MESSAGE() LIKE '%tSQLt.Failure%'
+ BEGIN
+ SELECT @Msg = Msg FROM tSQLt.TestMessage;
+ SET @Result = 'Failure';
+ END
+ ELSE
+ BEGIN
+ DECLARE @ErrorInfo NVARCHAR(MAX);
+ SELECT @ErrorInfo =
+ COALESCE(ERROR_MESSAGE(), '') +
+ '[' +COALESCE(LTRIM(STR(ERROR_SEVERITY())), '') + ','+COALESCE(LTRIM(STR(ERROR_STATE())), '') + ']' +
+ '{' + COALESCE(ERROR_PROCEDURE(), '') + ',' + COALESCE(CAST(ERROR_LINE() AS NVARCHAR), '') + '}';
+
+ IF(EXISTS(SELECT 1 FROM #ExpectException))
+ BEGIN
+ DECLARE @ExpectException INT;
+ DECLARE @ExpectedMessage NVARCHAR(MAX);
+ DECLARE @ExpectedMessagePattern NVARCHAR(MAX);
+ DECLARE @ExpectedSeverity INT;
+ DECLARE @ExpectedState INT;
+ DECLARE @ExpectedErrorNumber INT;
+ DECLARE @FailMessage NVARCHAR(MAX);
+ SELECT @ExpectException = ExpectException,
+ @ExpectedMessage = ExpectedMessage,
+ @ExpectedSeverity = ExpectedSeverity,
+ @ExpectedState = ExpectedState,
+ @ExpectedMessagePattern = ExpectedMessagePattern,
+ @ExpectedErrorNumber = ExpectedErrorNumber,
+ @FailMessage = FailMessage
+ FROM #ExpectException;
+
+ IF(@ExpectException = 1)
+ BEGIN
+ SET @Result = 'Success';
+ SET @TmpMsg = COALESCE(@FailMessage+' ','')+'Exception did not match expectation!';
+ IF(ERROR_MESSAGE() <> @ExpectedMessage)
+ BEGIN
+ SET @TmpMsg = @TmpMsg +CHAR(13)+CHAR(10)+
+ 'Expected Message: <'+@ExpectedMessage+'>'+CHAR(13)+CHAR(10)+
+ 'Actual Message : <'+ERROR_MESSAGE()+'>';
+ SET @Result = 'Failure';
+ END
+ IF(ERROR_MESSAGE() NOT LIKE @ExpectedMessagePattern)
+ BEGIN
+ SET @TmpMsg = @TmpMsg +CHAR(13)+CHAR(10)+
+ 'Expected Message to be like <'+@ExpectedMessagePattern+'>'+CHAR(13)+CHAR(10)+
+ 'Actual Message : <'+ERROR_MESSAGE()+'>';
+ SET @Result = 'Failure';
+ END
+ IF(ERROR_NUMBER() <> @ExpectedErrorNumber)
+ BEGIN
+ SET @TmpMsg = @TmpMsg +CHAR(13)+CHAR(10)+
+ 'Expected Error Number: '+CAST(@ExpectedErrorNumber AS NVARCHAR(MAX))+CHAR(13)+CHAR(10)+
+ 'Actual Error Number : '+CAST(ERROR_NUMBER() AS NVARCHAR(MAX));
+ SET @Result = 'Failure';
+ END
+ IF(ERROR_SEVERITY() <> @ExpectedSeverity)
+ BEGIN
+ SET @TmpMsg = @TmpMsg +CHAR(13)+CHAR(10)+
+ 'Expected Severity: '+CAST(@ExpectedSeverity AS NVARCHAR(MAX))+CHAR(13)+CHAR(10)+
+ 'Actual Severity : '+CAST(ERROR_SEVERITY() AS NVARCHAR(MAX));
+ SET @Result = 'Failure';
+ END
+ IF(ERROR_STATE() <> @ExpectedState)
+ BEGIN
+ SET @TmpMsg = @TmpMsg +CHAR(13)+CHAR(10)+
+ 'Expected State: '+CAST(@ExpectedState AS NVARCHAR(MAX))+CHAR(13)+CHAR(10)+
+ 'Actual State : '+CAST(ERROR_STATE() AS NVARCHAR(MAX));
+ SET @Result = 'Failure';
+ END
+ IF(@Result = 'Failure')
+ BEGIN
+ SET @Msg = @TmpMsg;
+ END
+ END
+ ELSE
+ BEGIN
+ SET @Result = 'Failure';
+ SET @Msg =
+ COALESCE(@FailMessage+' ','')+
+ 'Expected no error to be raised. Instead this error was encountered:'+
+ CHAR(13)+CHAR(10)+
+ @ErrorInfo;
+ END
+ END;
+ ELSE
+ BEGIN
+ SET @Result = 'Error';
+ SET @Msg = @ErrorInfo;
+ END;
+ END;
+ END CATCH;
+ END TRY
+ BEGIN CATCH
+ SET @Result = 'Error';
+ SET @Msg = ERROR_MESSAGE();
+ END CATCH
+
+ BEGIN TRY
+ ROLLBACK TRAN @TranName;
+ END TRY
+ BEGIN CATCH
+ DECLARE @PostExecTrancount INT;
+ SET @PostExecTrancount = @PreExecTrancount - @@TRANCOUNT;
+ IF (@@TRANCOUNT > 0) ROLLBACK;
+ BEGIN TRAN;
+ IF( @Result <> 'Success'
+ OR @PostExecTrancount <> 0
+ )
+ BEGIN
+ SELECT @Msg = COALESCE(@Msg, '') + ' (There was also a ROLLBACK ERROR --> ' + COALESCE(ERROR_MESSAGE(), '') + '{' + COALESCE(ERROR_PROCEDURE(), '') + ',' + COALESCE(CAST(ERROR_LINE() AS NVARCHAR), '') + '})';
+ SET @Result = 'Error';
+ END;
+ END CATCH;
+
+ If(@Result NOT IN ('Success','Skipped'))
+ BEGIN
+ SET @Msg2 = @TestName + ' failed: (' + @Result + ') ' + @Msg;
+ EXEC tSQLt.Private_Print @Message = @Msg2, @Severity = 0;
+ END;
+
+ IF EXISTS(SELECT 1 FROM tSQLt.TestResult WHERE Id = @TestResultId)
+ BEGIN
+ UPDATE tSQLt.TestResult SET
+ Result = @Result,
+ Msg = @Msg,
+ TestEndTime = @TestEndTime
+ WHERE Id = @TestResultId;
+ END;
+ ELSE
+ BEGIN
+ INSERT tSQLt.TestResult(Class, TestCase, TranName, Result, Msg)
+ SELECT @TestClassName,
+ @TestProcName,
+ '?',
+ 'Error',
+ 'TestResult entry is missing; Original outcome: ' + @Result + ', ' + @Msg;
+ END;
+ COMMIT;
+
+ IF(@Verbose = 1)
+ BEGIN
+ SET @VerboseMsg = 'tSQLt.Run '''+@TestName+'''; --Finished';
+ EXEC tSQLt.Private_Print @Message =@VerboseMsg, @Severity = 0;
+ END;
+
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunTestClass.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunTestClass.sql
new file mode 100644
index 0000000..0bab517
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_RunTestClass.sql
@@ -0,0 +1,31 @@
+
+CREATE PROCEDURE tSQLt.Private_RunTestClass
+ @TestClassName NVARCHAR(MAX)
+AS
+BEGIN
+ DECLARE @TestCaseName NVARCHAR(MAX);
+ DECLARE @TestClassId INT; SET @TestClassId = tSQLt.Private_GetSchemaId(@TestClassName);
+ DECLARE @SetupProcName NVARCHAR(MAX);
+ EXEC tSQLt.Private_GetSetupProcedureName @TestClassId, @SetupProcName OUTPUT;
+
+ DECLARE testCases CURSOR LOCAL FAST_FORWARD
+ FOR
+ SELECT tSQLt.Private_GetQuotedFullName(object_id)
+ FROM sys.procedures
+ WHERE schema_id = @TestClassId
+ AND LOWER(name) LIKE 'test%';
+
+ OPEN testCases;
+
+ FETCH NEXT FROM testCases INTO @TestCaseName;
+
+ WHILE @@FETCH_STATUS = 0
+ BEGIN
+ EXEC tSQLt.Private_RunTest @TestCaseName, @SetupProcName;
+
+ FETCH NEXT FROM testCases INTO @TestCaseName;
+ END;
+
+ CLOSE testCases;
+ DEALLOCATE testCases;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_SaveTestNameForSession.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_SaveTestNameForSession.sql
new file mode 100644
index 0000000..21a54e6
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_SaveTestNameForSession.sql
@@ -0,0 +1,15 @@
+
+CREATE PROCEDURE tSQLt.Private_SaveTestNameForSession
+ @TestName NVARCHAR(MAX)
+AS
+BEGIN
+ DELETE FROM tSQLt.Run_LastExecution
+ WHERE SessionId = @@SPID;
+
+ INSERT INTO tSQLt.Run_LastExecution(TestName, SessionId, LoginTime)
+ SELECT TestName = @TestName,
+ session_id,
+ login_time
+ FROM sys.dm_exec_sessions
+ WHERE session_id = @@SPID;
+END
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_SetConfiguration.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_SetConfiguration.sql
new file mode 100644
index 0000000..82a7c35
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_SetConfiguration.sql
@@ -0,0 +1,17 @@
+CREATE PROCEDURE tSQLt.Private_SetConfiguration
+ @Name NVARCHAR(100),
+ @Value SQL_VARIANT
+AS
+BEGIN
+ IF(EXISTS(SELECT 1 FROM tSQLt.Private_Configurations WITH(ROWLOCK,UPDLOCK) WHERE Name = @Name))
+ BEGIN
+ UPDATE tSQLt.Private_Configurations SET
+ Value = @Value
+ WHERE Name = @Name;
+ END;
+ ELSE
+ BEGIN
+ INSERT tSQLt.Private_Configurations(Name,Value)
+ VALUES(@Name,@Value);
+ END;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_SetFakeViewOff_SingleView.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_SetFakeViewOff_SingleView.sql
new file mode 100644
index 0000000..68d9961
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_SetFakeViewOff_SingleView.sql
@@ -0,0 +1,20 @@
+
+CREATE PROCEDURE [tSQLt].[Private_SetFakeViewOff_SingleView]
+ @ViewName NVARCHAR(MAX)
+AS
+BEGIN
+ DECLARE @Cmd NVARCHAR(MAX),
+ @SchemaName NVARCHAR(MAX),
+ @TriggerName NVARCHAR(MAX);
+
+ SELECT @SchemaName = QUOTENAME(OBJECT_SCHEMA_NAME(ObjId)),
+ @TriggerName = QUOTENAME(OBJECT_NAME(ObjId) + '_SetFakeViewOn')
+ FROM (SELECT OBJECT_ID(@ViewName) AS ObjId) X;
+
+ SET @Cmd = 'DROP TRIGGER %SCHEMA_NAME%.%TRIGGER_NAME%;';
+
+ SET @Cmd = REPLACE(@Cmd, '%SCHEMA_NAME%', @SchemaName);
+ SET @Cmd = REPLACE(@Cmd, '%TRIGGER_NAME%', @TriggerName);
+
+ EXEC(@Cmd);
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_SetFakeViewOn_SingleView.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_SetFakeViewOn_SingleView.sql
new file mode 100644
index 0000000..b8f2809
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_SetFakeViewOn_SingleView.sql
@@ -0,0 +1,39 @@
+
+CREATE PROCEDURE [tSQLt].[Private_SetFakeViewOn_SingleView]
+ @ViewName NVARCHAR(MAX)
+AS
+BEGIN
+ DECLARE @Cmd NVARCHAR(MAX),
+ @SchemaName NVARCHAR(MAX),
+ @TriggerName NVARCHAR(MAX);
+
+ SELECT @SchemaName = OBJECT_SCHEMA_NAME(ObjId),
+ @ViewName = OBJECT_NAME(ObjId),
+ @TriggerName = OBJECT_NAME(ObjId) + '_SetFakeViewOn'
+ FROM (SELECT OBJECT_ID(@ViewName) AS ObjId) X;
+
+ SET @Cmd =
+ 'CREATE TRIGGER $$SCHEMA_NAME$$.$$TRIGGER_NAME$$
+ ON $$SCHEMA_NAME$$.$$VIEW_NAME$$ INSTEAD OF INSERT AS
+ BEGIN
+ RAISERROR(''Test system is in an invalid state. SetFakeViewOff must be called if SetFakeViewOn was called. Call SetFakeViewOff after creating all test case procedures.'', 16, 10) WITH NOWAIT;
+ RETURN;
+ END;
+ ';
+
+ SET @Cmd = REPLACE(@Cmd, '$$SCHEMA_NAME$$', QUOTENAME(@SchemaName));
+ SET @Cmd = REPLACE(@Cmd, '$$VIEW_NAME$$', QUOTENAME(@ViewName));
+ SET @Cmd = REPLACE(@Cmd, '$$TRIGGER_NAME$$', QUOTENAME(@TriggerName));
+ EXEC(@Cmd);
+
+ EXEC sp_addextendedproperty @name = N'SetFakeViewOnTrigger',
+ @value = 1,
+ @level0type = 'SCHEMA',
+ @level0name = @SchemaName,
+ @level1type = 'VIEW',
+ @level1name = @ViewName,
+ @level2type = 'TRIGGER',
+ @level2name = @TriggerName;
+
+ RETURN 0;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_SkipTestAnnotationHelper.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_SkipTestAnnotationHelper.sql
new file mode 100644
index 0000000..52e666b
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_SkipTestAnnotationHelper.sql
@@ -0,0 +1,6 @@
+CREATE PROCEDURE tSQLt.Private_SkipTestAnnotationHelper
+ @SkipReason NVARCHAR(MAX)
+AS
+BEGIN
+ INSERT INTO #SkipTest VALUES(@SkipReason);
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ValidateFakeTableParameters.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ValidateFakeTableParameters.sql
new file mode 100644
index 0000000..4da9139
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ValidateFakeTableParameters.sql
@@ -0,0 +1,17 @@
+
+CREATE PROCEDURE tSQLt.Private_ValidateFakeTableParameters
+ @SchemaName NVARCHAR(MAX),
+ @OrigTableName NVARCHAR(MAX),
+ @OrigSchemaName NVARCHAR(MAX)
+AS
+BEGIN
+ IF @SchemaName IS NULL
+ BEGIN
+ DECLARE @FullName NVARCHAR(MAX); SET @FullName = @OrigTableName + COALESCE('.' + @OrigSchemaName, '');
+
+ RAISERROR ('FakeTable could not resolve the object name, ''%s''. (When calling tSQLt.FakeTable, avoid the use of the @SchemaName parameter, as it is deprecated.)',
+ 16, 10, @FullName);
+ END;
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ValidateObjectsCompatibleWithFakeFunction.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ValidateObjectsCompatibleWithFakeFunction.sql
new file mode 100644
index 0000000..ab3e24d
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ValidateObjectsCompatibleWithFakeFunction.sql
@@ -0,0 +1,71 @@
+CREATE PROCEDURE tSQLt.Private_ValidateObjectsCompatibleWithFakeFunction
+ @FunctionName NVARCHAR(MAX),
+ @FakeFunctionName NVARCHAR(MAX) = NULL,
+ @FakeDataSource NVARCHAR(MAX) = NULL,
+ @FunctionObjectId INT = NULL OUTPUT,
+ @FakeFunctionObjectId INT = NULL OUTPUT,
+ @IsScalarFunction BIT = NULL OUTPUT
+AS
+BEGIN
+ SET @FunctionObjectId = OBJECT_ID(@FunctionName);
+
+ IF(@FunctionObjectId IS NULL)
+ BEGIN
+ RAISERROR('%s does not exist!',16,10,@FunctionName);
+ END;
+
+ IF COALESCE(@FakeFunctionName, @FakeDataSource) IS NULL
+ BEGIN
+ RAISERROR ('Either @FakeFunctionName or @FakeDataSource must be provided', 16, 10);
+ END;
+
+ IF (@FakeFunctionName IS NOT NULL AND @FakeDataSource IS NOT NULL )
+ BEGIN
+ RAISERROR ('Both @FakeFunctionName and @FakeDataSource are valued. Please use only one.', 16, 10);
+ END;
+
+ IF (@FakeDataSource IS NOT NULL )
+ BEGIN
+ IF NOT EXISTS (
+ SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID(@FunctionName) and type in ('TF', 'IF', 'FT')
+ )
+ BEGIN
+ RAISERROR('You can use @FakeDataSource only with Inline, Multi-Statement or CLR Table-Valued functions.', 16, 10);
+ END
+
+ RETURN 0;
+ END
+
+ SET @FakeFunctionObjectId = OBJECT_ID(@FakeFunctionName);
+ IF(@FakeFunctionObjectId IS NULL)
+ BEGIN
+ RAISERROR('%s does not exist!',16,10,@FakeFunctionName);
+ END;
+
+ DECLARE @FunctionType CHAR(2);
+ DECLARE @FakeFunctionType CHAR(2);
+ SELECT @FunctionType = type FROM sys.objects WHERE object_id = @FunctionObjectId;
+ SELECT @FakeFunctionType = type FROM sys.objects WHERE object_id = @FakeFunctionObjectId;
+
+ IF((@FunctionType IN('FN','FS') AND @FakeFunctionType NOT IN('FN','FS'))
+ OR
+ (@FunctionType IN('TF','IF','FT') AND @FakeFunctionType NOT IN('TF','IF','FT'))
+ OR
+ (@FunctionType NOT IN('FN','FS','TF','IF','FT'))
+ )
+ BEGIN
+ RAISERROR('Both parameters must contain the name of either scalar or table valued functions!',16,10);
+ END;
+
+ SET @IsScalarFunction = CASE WHEN @FunctionType IN('FN','FS') THEN 1 ELSE 0 END;
+
+ IF(EXISTS(SELECT 1
+ FROM sys.parameters AS P
+ WHERE P.object_id IN(@FunctionObjectId,@FakeFunctionObjectId)
+ GROUP BY P.name, P.max_length, P.precision, P.scale, P.parameter_id
+ HAVING COUNT(1) <> 2
+ ))
+ BEGIN
+ RAISERROR('Parameters of both functions must match! (This includes the return type for scalar functions.)',16,10);
+ END;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ValidateProcedureCanBeUsedWithSpyProcedure.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ValidateProcedureCanBeUsedWithSpyProcedure.sql
new file mode 100644
index 0000000..217d91b
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ValidateProcedureCanBeUsedWithSpyProcedure.sql
@@ -0,0 +1,15 @@
+
+CREATE PROCEDURE tSQLt.Private_ValidateProcedureCanBeUsedWithSpyProcedure
+ @ProcedureName NVARCHAR(MAX)
+AS
+BEGIN
+ IF NOT EXISTS(SELECT 1 FROM sys.procedures WHERE object_id = OBJECT_ID(@ProcedureName))
+ BEGIN
+ RAISERROR('Cannot use SpyProcedure on %s because the procedure does not exist', 16, 10, @ProcedureName) WITH NOWAIT;
+ END;
+
+ IF (1020 < (SELECT COUNT(*) FROM sys.parameters WHERE object_id = OBJECT_ID(@ProcedureName)))
+ BEGIN
+ RAISERROR('Cannot use SpyProcedure on procedure %s because it contains more than 1020 parameters', 16, 10, @ProcedureName) WITH NOWAIT;
+ END;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ValidateThatAllDataTypesInTableAreSupported.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ValidateThatAllDataTypesInTableAreSupported.sql
new file mode 100644
index 0000000..8ffc3ed
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Private_ValidateThatAllDataTypesInTableAreSupported.sql
@@ -0,0 +1,12 @@
+CREATE PROCEDURE tSQLt.Private_ValidateThatAllDataTypesInTableAreSupported
+ @ResultTable NVARCHAR(MAX),
+ @ColumnList NVARCHAR(MAX)
+AS
+BEGIN
+ BEGIN TRY
+ EXEC('DECLARE @EatResult INT; SELECT @EatResult = COUNT(1) FROM ' + @ResultTable + ' GROUP BY ' + @ColumnList + ';');
+ END TRY
+ BEGIN CATCH
+ RAISERROR('The table contains a datatype that is not supported for tSQLt.AssertEqualsTable. Please refer to http://tsqlt.org/user-guide/assertions/assertequalstable/ for a list of unsupported datatypes.',16,10);
+ END CATCH
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/RemoveAssemblyKey.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/RemoveAssemblyKey.sql
new file mode 100644
index 0000000..af47dcb
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/RemoveAssemblyKey.sql
@@ -0,0 +1,32 @@
+CREATE PROCEDURE tSQLt.RemoveAssemblyKey
+AS
+BEGIN
+ IF(NOT EXISTS(SELECT * FROM sys.fn_my_permissions(NULL,'server') AS FMP WHERE FMP.permission_name = 'CONTROL SERVER'))
+ BEGIN
+ RAISERROR('Only principals with CONTROL SERVER permission can execute this procedure.',16,10);
+ RETURN -1;
+ END;
+
+ DECLARE @master_sys_sp_executesql NVARCHAR(MAX); SET @master_sys_sp_executesql = 'master.sys.sp_executesql';
+ DECLARE @ProductMajorVersion INT;
+ EXEC @ProductMajorVersion = tSQLt.Private_GetSQLProductMajorVersion;
+
+ IF SUSER_ID('tSQLtAssemblyKey') IS NOT NULL DROP LOGIN tSQLtAssemblyKey;
+ EXEC @master_sys_sp_executesql N'IF ASYMKEY_ID(''tSQLtAssemblyKey'') IS NOT NULL DROP ASYMMETRIC KEY tSQLtAssemblyKey;';
+ EXEC @master_sys_sp_executesql N'IF EXISTS(SELECT * FROM sys.assemblies WHERE name = ''tSQLtAssemblyKey'') DROP ASSEMBLY tSQLtAssemblyKey;';
+
+ DECLARE @cmd NVARCHAR(MAX);
+ IF(@ProductMajorVersion>=14)
+ BEGIN
+ DECLARE @TrustedHash NVARCHAR(MAX);
+ DECLARE @AssemblyKeyBytes VARBINARY(MAX);
+ EXEC tSQLt.Private_GetAssemblyKeyBytes @AssemblyKeyBytes = @AssemblyKeyBytes OUT;
+ SELECT @TrustedHash = CONVERT(NVARCHAR(MAX),HASHBYTES('SHA2_512',@AssemblyKeyBytes),1);
+ SELECT @cmd =
+ 'IF EXISTS(SELECT 1 FROM sys.trusted_assemblies WHERE hash = ' + @TrustedHash +' AND description = ''tSQLt Ephemeral'')'+
+ 'EXEC sys.sp_drop_trusted_assembly @hash = ' + @TrustedHash + ';';
+ EXEC master.sys.sp_executesql @cmd;
+ END;
+
+
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/RemoveExternalAccessKey.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/RemoveExternalAccessKey.sql
new file mode 100644
index 0000000..e5bc77c
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/RemoveExternalAccessKey.sql
@@ -0,0 +1,7 @@
+CREATE PROCEDURE tSQLt.RemoveExternalAccessKey
+AS
+BEGIN
+ EXEC tSQLt.Private_Print @Message='tSQLt.RemoveExternalAccessKey is deprecated. Please use tSQLt.RemoveAssemblyKey instead.';
+ EXEC tSQLt.RemoveAssemblyKey;
+RETURN;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/RemoveObject.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/RemoveObject.sql
new file mode 100644
index 0000000..2044fdb
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/RemoveObject.sql
@@ -0,0 +1,17 @@
+CREATE PROCEDURE tSQLt.RemoveObject
+ @ObjectName NVARCHAR(MAX),
+ @NewName NVARCHAR(MAX) = NULL OUTPUT,
+ @IfExists INT = 0
+AS
+BEGIN
+ DECLARE @ObjectId INT;
+ SELECT @ObjectId = OBJECT_ID(@ObjectName);
+
+ IF(@ObjectId IS NULL)
+ BEGIN
+ IF(@IfExists = 1) RETURN;
+ RAISERROR('%s does not exist!',16,10,@ObjectName);
+ END;
+
+ EXEC tSQLt.Private_RenameObjectToUniqueNameUsingObjectId @ObjectId, @NewName = @NewName OUTPUT;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/RemoveObjectIfExists.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/RemoveObjectIfExists.sql
new file mode 100644
index 0000000..1bb2d07
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/RemoveObjectIfExists.sql
@@ -0,0 +1,7 @@
+CREATE PROCEDURE tSQLt.RemoveObjectIfExists
+ @ObjectName NVARCHAR(MAX),
+ @NewName NVARCHAR(MAX) = NULL OUTPUT
+AS
+BEGIN
+ EXEC tSQLt.RemoveObject @ObjectName = @ObjectName, @NewName = @NewName OUT, @IfExists = 1;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/RenameClass.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/RenameClass.sql
new file mode 100644
index 0000000..9e342da
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/RenameClass.sql
@@ -0,0 +1,36 @@
+
+CREATE PROCEDURE tSQLt.RenameClass
+ @SchemaName NVARCHAR(MAX),
+ @NewSchemaName NVARCHAR(MAX)
+AS
+BEGIN
+ DECLARE @MigrateObjectsCommand NVARCHAR(MAX);
+
+ SELECT @NewSchemaName = PARSENAME(@NewSchemaName, 1),
+ @SchemaName = PARSENAME(@SchemaName, 1);
+
+ EXEC tSQLt.NewTestClass @NewSchemaName;
+
+ SELECT @MigrateObjectsCommand = (
+ SELECT Cmd AS [text()] FROM (
+ SELECT 'ALTER SCHEMA ' + QUOTENAME(@NewSchemaName) + ' TRANSFER ' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(name) + ';' AS Cmd
+ FROM sys.objects
+ WHERE schema_id = SCHEMA_ID(@SchemaName)
+ AND type NOT IN ('PK', 'F')
+ UNION ALL
+ SELECT 'ALTER SCHEMA ' + QUOTENAME(@NewSchemaName) + ' TRANSFER XML SCHEMA COLLECTION::' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(name) + ';' AS Cmd
+ FROM sys.xml_schema_collections
+ WHERE schema_id = SCHEMA_ID(@SchemaName)
+ UNION ALL
+ SELECT 'ALTER SCHEMA ' + QUOTENAME(@NewSchemaName) + ' TRANSFER TYPE::' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(name) + ';' AS Cmd
+ FROM sys.types
+ WHERE schema_id = SCHEMA_ID(@SchemaName)
+ ) AS Cmds
+ FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)');
+
+ EXEC (@MigrateObjectsCommand);
+
+ EXEC tSQLt.DropClass @SchemaName;
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Reset.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Reset.sql
new file mode 100644
index 0000000..6905745
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Reset.sql
@@ -0,0 +1,5 @@
+CREATE PROCEDURE tSQLt.Reset
+AS
+BEGIN
+ EXEC tSQLt.Private_ResetNewTestClassList;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/ResultSetFilter.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/ResultSetFilter.sql
new file mode 100644
index 0000000..dfc78a4
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/ResultSetFilter.sql
@@ -0,0 +1,4 @@
+CREATE PROCEDURE [tSQLt].[ResultSetFilter]
+@ResultsetNo INT NULL, @Command NVARCHAR (MAX) NULL
+AS EXTERNAL NAME [tSQLtCLR].[tSQLtCLR.StoredProcedures].[ResultSetFilter]
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Run.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Run.sql
new file mode 100644
index 0000000..92eb0ab
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Run.sql
@@ -0,0 +1,8 @@
+
+CREATE PROCEDURE tSQLt.Run
+ @TestName NVARCHAR(MAX) = NULL,
+ @TestResultFormatter NVARCHAR(MAX) = NULL
+AS
+BEGIN
+ EXEC tSQLt.Private_RunMethodHandler @RunMethod = 'tSQLt.Private_Run', @TestResultFormatter = @TestResultFormatter, @TestName = @TestName;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/RunAll.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/RunAll.sql
new file mode 100644
index 0000000..ab28804
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/RunAll.sql
@@ -0,0 +1,5 @@
+CREATE PROCEDURE tSQLt.RunAll
+AS
+BEGIN
+ EXEC tSQLt.Private_RunMethodHandler @RunMethod = 'tSQLt.Private_RunAll';
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/RunC.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/RunC.sql
new file mode 100644
index 0000000..16518c1
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/RunC.sql
@@ -0,0 +1,12 @@
+CREATE PROCEDURE tSQLt.RunC
+AS
+BEGIN
+ DECLARE @TestName NVARCHAR(MAX);SET @TestName = NULL;
+ DECLARE @InputBuffer NVARCHAR(MAX);
+ EXEC tSQLt.Private_InputBuffer @InputBuffer = @InputBuffer OUT;
+ IF(@InputBuffer LIKE 'EXEC tSQLt.RunC;--%')
+ BEGIN
+ SET @TestName = LTRIM(RTRIM(STUFF(@InputBuffer,1,18,'')));
+ END;
+ EXEC tSQLt.Run @TestName = @TestName;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/RunNew.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/RunNew.sql
new file mode 100644
index 0000000..95471cc
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/RunNew.sql
@@ -0,0 +1,6 @@
+
+CREATE PROCEDURE tSQLt.RunNew
+AS
+BEGIN
+ EXEC tSQLt.Private_RunMethodHandler @RunMethod = 'tSQLt.Private_RunNew';
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/RunTest.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/RunTest.sql
new file mode 100644
index 0000000..e2cd659
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/RunTest.sql
@@ -0,0 +1,7 @@
+
+CREATE PROCEDURE tSQLt.RunTest
+ @TestName NVARCHAR(MAX)
+AS
+BEGIN
+ RAISERROR('tSQLt.RunTest has been retired. Please use tSQLt.Run instead.', 16, 10);
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/RunTestClass.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/RunTestClass.sql
new file mode 100644
index 0000000..b148633
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/RunTestClass.sql
@@ -0,0 +1,7 @@
+
+CREATE PROCEDURE tSQLt.RunTestClass
+ @TestClassName NVARCHAR(MAX)
+AS
+BEGIN
+ EXEC tSQLt.Run @TestClassName;
+END
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/RunWithNullResults.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/RunWithNullResults.sql
new file mode 100644
index 0000000..21c214b
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/RunWithNullResults.sql
@@ -0,0 +1,7 @@
+
+CREATE PROCEDURE tSQLt.RunWithNullResults
+ @TestName NVARCHAR(MAX) = NULL
+AS
+BEGIN
+ EXEC tSQLt.Run @TestName = @TestName, @TestResultFormatter = 'tSQLt.NullTestResultFormatter';
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/RunWithXmlResults.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/RunWithXmlResults.sql
new file mode 100644
index 0000000..6bd793c
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/RunWithXmlResults.sql
@@ -0,0 +1,7 @@
+
+CREATE PROCEDURE tSQLt.RunWithXmlResults
+ @TestName NVARCHAR(MAX) = NULL
+AS
+BEGIN
+ EXEC tSQLt.Run @TestName = @TestName, @TestResultFormatter = 'tSQLt.XmlResultFormatter';
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/SetFakeViewOff.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/SetFakeViewOff.sql
new file mode 100644
index 0000000..1dd9e34
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/SetFakeViewOff.sql
@@ -0,0 +1,26 @@
+
+CREATE PROCEDURE [tSQLt].[SetFakeViewOff]
+ @SchemaName NVARCHAR(MAX)
+AS
+BEGIN
+ DECLARE @ViewName NVARCHAR(MAX);
+
+ DECLARE viewNames CURSOR LOCAL FAST_FORWARD FOR
+ SELECT QUOTENAME(OBJECT_SCHEMA_NAME(t.parent_id)) + '.' + QUOTENAME(OBJECT_NAME(t.parent_id)) AS viewName
+ FROM sys.extended_properties ep
+ JOIN sys.triggers t
+ on ep.major_id = t.object_id
+ WHERE ep.name = N'SetFakeViewOnTrigger'
+ OPEN viewNames;
+
+ FETCH NEXT FROM viewNames INTO @ViewName;
+ WHILE @@FETCH_STATUS = 0
+ BEGIN
+ EXEC tSQLt.Private_SetFakeViewOff_SingleView @ViewName;
+
+ FETCH NEXT FROM viewNames INTO @ViewName;
+ END;
+
+ CLOSE viewNames;
+ DEALLOCATE viewNames;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/SetFakeViewOn.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/SetFakeViewOn.sql
new file mode 100644
index 0000000..06964b4
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/SetFakeViewOn.sql
@@ -0,0 +1,25 @@
+
+CREATE PROCEDURE [tSQLt].[SetFakeViewOn]
+ @SchemaName NVARCHAR(MAX)
+AS
+BEGIN
+ DECLARE @ViewName NVARCHAR(MAX);
+
+ DECLARE viewNames CURSOR LOCAL FAST_FORWARD FOR
+ SELECT QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + '.' + QUOTENAME([name]) AS viewName
+ FROM sys.views
+ WHERE schema_id = SCHEMA_ID(@SchemaName);
+
+ OPEN viewNames;
+
+ FETCH NEXT FROM viewNames INTO @ViewName;
+ WHILE @@FETCH_STATUS = 0
+ BEGIN
+ EXEC tSQLt.Private_SetFakeViewOn_SingleView @ViewName;
+
+ FETCH NEXT FROM viewNames INTO @ViewName;
+ END;
+
+ CLOSE viewNames;
+ DEALLOCATE viewNames;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/SetSummaryError.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/SetSummaryError.sql
new file mode 100644
index 0000000..5702bf3
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/SetSummaryError.sql
@@ -0,0 +1,10 @@
+CREATE PROCEDURE tSQLt.SetSummaryError
+ @SummaryError INT
+AS
+BEGIN
+ IF(@SummaryError NOT IN (0,1))
+ BEGIN
+ RAISERROR('@SummaryError has to be 0 or 1, but it was: %i',16,10,@SummaryError);
+ END;
+ EXEC tSQLt.Private_SetConfiguration @Name = 'SummaryError', @Value = @SummaryError;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/SetTestResultFormatter.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/SetTestResultFormatter.sql
new file mode 100644
index 0000000..b808b92
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/SetTestResultFormatter.sql
@@ -0,0 +1,23 @@
+
+
+
+CREATE PROCEDURE tSQLt.SetTestResultFormatter
+ @Formatter NVARCHAR(4000)
+AS
+BEGIN
+ IF EXISTS (SELECT 1 FROM sys.extended_properties WHERE [name] = N'tSQLt.ResultsFormatter')
+ BEGIN
+ EXEC sp_dropextendedproperty @name = N'tSQLt.ResultsFormatter',
+ @level0type = 'SCHEMA',
+ @level0name = 'tSQLt',
+ @level1type = 'PROCEDURE',
+ @level1name = 'Private_OutputTestResults';
+ END;
+
+ EXEC sp_addextendedproperty @name = N'tSQLt.ResultsFormatter',
+ @value = @Formatter,
+ @level0type = 'SCHEMA',
+ @level0name = 'tSQLt',
+ @level1type = 'PROCEDURE',
+ @level1name = 'Private_OutputTestResults';
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/SetVerbose.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/SetVerbose.sql
new file mode 100644
index 0000000..fd937c5
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/SetVerbose.sql
@@ -0,0 +1,6 @@
+CREATE PROCEDURE tSQLt.SetVerbose
+ @Verbose BIT = 1
+AS
+BEGIN
+ EXEC tSQLt.Private_SetConfiguration @Name = 'Verbose', @Value = @Verbose;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/SpyProcedure.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/SpyProcedure.sql
new file mode 100644
index 0000000..7ae34c4
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/SpyProcedure.sql
@@ -0,0 +1,36 @@
+
+CREATE PROCEDURE tSQLt.SpyProcedure
+ @ProcedureName NVARCHAR(MAX),
+ @CommandToExecute NVARCHAR(MAX) = NULL
+AS
+BEGIN
+ DECLARE @ProcedureObjectId INT;
+ SELECT @ProcedureObjectId = OBJECT_ID(@ProcedureName);
+
+ EXEC tSQLt.Private_ValidateProcedureCanBeUsedWithSpyProcedure @ProcedureName;
+
+ DECLARE @LogTableName NVARCHAR(MAX);
+ SELECT @LogTableName = QUOTENAME(OBJECT_SCHEMA_NAME(@ProcedureObjectId)) + '.' + QUOTENAME(OBJECT_NAME(@ProcedureObjectId)+'_SpyProcedureLog');
+
+ DECLARE @CreateProcedureStatement NVARCHAR(MAX);
+ DECLARE @CreateLogTableStatement NVARCHAR(MAX);
+
+ EXEC tSQLt.Private_GenerateCreateProcedureSpyStatement
+ @ProcedureObjectId = @ProcedureObjectId,
+ @OriginalProcedureName = @ProcedureName,
+ @LogTableName = @LogTableName,
+ @CommandToExecute = @CommandToExecute,
+ @CreateProcedureStatement = @CreateProcedureStatement OUT,
+ @CreateLogTableStatement = @CreateLogTableStatement OUT;
+
+
+ EXEC tSQLt.Private_RenameObjectToUniqueNameUsingObjectId @ProcedureObjectId;
+
+ EXEC(@CreateLogTableStatement);
+
+ EXEC(@CreateProcedureStatement);
+
+ RETURN 0;
+END;
+
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/StubRecord.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/StubRecord.sql
new file mode 100644
index 0000000..36262ae
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/StubRecord.sql
@@ -0,0 +1,97 @@
+CREATE PROCEDURE tSQLt.StubRecord(@SnTableName AS NVARCHAR(MAX), @BintObjId AS BIGINT)
+AS
+BEGIN
+
+ RAISERROR('Warning, tSQLt.StubRecord is not currently supported. Use at your own risk!', 0, 1) WITH NOWAIT;
+
+ DECLARE @VcInsertStmt NVARCHAR(MAX),
+ @VcInsertValues NVARCHAR(MAX);
+ DECLARE @SnColumnName NVARCHAR(MAX);
+ DECLARE @SintDataType SMALLINT;
+ DECLARE @NvcFKCmd NVARCHAR(MAX);
+ DECLARE @VcFKVal NVARCHAR(MAX);
+
+ SET @VcInsertStmt = 'INSERT INTO ' + @SnTableName + ' ('
+
+ DECLARE curColumns CURSOR
+ LOCAL FAST_FORWARD
+ FOR
+ SELECT syscolumns.name,
+ syscolumns.xtype,
+ cmd.cmd
+ FROM syscolumns
+ LEFT OUTER JOIN dbo.sysconstraints ON syscolumns.id = sysconstraints.id
+ AND syscolumns.colid = sysconstraints.colid
+ AND sysconstraints.status = 1 -- Primary key constraints only
+ LEFT OUTER JOIN (select fkeyid id,fkey colid,N'select @V=cast(min('+syscolumns.name+') as NVARCHAR) from '+sysobjects.name cmd
+ from sysforeignkeys
+ join sysobjects on sysobjects.id=sysforeignkeys.rkeyid
+ join syscolumns on sysobjects.id=syscolumns.id and syscolumns.colid=rkey) cmd
+ on cmd.id=syscolumns.id and cmd.colid=syscolumns.colid
+ WHERE syscolumns.id = OBJECT_ID(@SnTableName)
+ AND (syscolumns.isnullable = 0 )
+ ORDER BY ISNULL(sysconstraints.status, 9999), -- Order Primary Key constraints first
+ syscolumns.colorder
+
+ OPEN curColumns
+
+ FETCH NEXT FROM curColumns
+ INTO @SnColumnName, @SintDataType, @NvcFKCmd
+
+ -- Treat the first column retrieved differently, no commas need to be added
+ -- and it is the ObjId column
+ IF @@FETCH_STATUS = 0
+ BEGIN
+ SET @VcInsertStmt = @VcInsertStmt + @SnColumnName
+ SELECT @VcInsertValues = ')VALUES(' + ISNULL(CAST(@BintObjId AS nvarchar), 'NULL')
+
+ FETCH NEXT FROM curColumns
+ INTO @SnColumnName, @SintDataType, @NvcFKCmd
+ END
+ ELSE
+ BEGIN
+ -- No columns retrieved, we need to insert into any first column
+ SELECT @VcInsertStmt = @VcInsertStmt + syscolumns.name
+ FROM syscolumns
+ WHERE syscolumns.id = OBJECT_ID(@SnTableName)
+ AND syscolumns.colorder = 1
+
+ SELECT @VcInsertValues = ')VALUES(' + ISNULL(CAST(@BintObjId AS nvarchar), 'NULL')
+
+ END
+
+ WHILE @@FETCH_STATUS = 0
+ BEGIN
+ SET @VcInsertStmt = @VcInsertStmt + ',' + @SnColumnName
+ SET @VcFKVal=',0'
+ if @NvcFKCmd is not null
+ BEGIN
+ set @VcFKVal=null
+ exec sp_executesql @NvcFKCmd,N'@V NVARCHAR(MAX) output',@VcFKVal output
+ set @VcFKVal=isnull(','''+@VcFKVal+'''',',NULL')
+ END
+ SET @VcInsertValues = @VcInsertValues + @VcFKVal
+
+ FETCH NEXT FROM curColumns
+ INTO @SnColumnName, @SintDataType, @NvcFKCmd
+ END
+
+ CLOSE curColumns
+ DEALLOCATE curColumns
+
+ SET @VcInsertStmt = @VcInsertStmt + @VcInsertValues + ')'
+
+ IF EXISTS (SELECT 1
+ FROM syscolumns
+ WHERE status = 128
+ AND id = OBJECT_ID(@SnTableName))
+ BEGIN
+ SET @VcInsertStmt = 'SET IDENTITY_INSERT ' + @SnTableName + ' ON ' + CHAR(10) +
+ @VcInsertStmt + CHAR(10) +
+ 'SET IDENTITY_INSERT ' + @SnTableName + ' OFF '
+ END
+
+ EXEC (@VcInsertStmt) -- Execute the actual INSERT statement
+
+END
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/SuppressOutput.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/SuppressOutput.sql
new file mode 100644
index 0000000..c8bf227
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/SuppressOutput.sql
@@ -0,0 +1,4 @@
+CREATE PROCEDURE [tSQLt].[SuppressOutput]
+@command NVARCHAR (MAX) NULL
+AS EXTERNAL NAME [tSQLtCLR].[tSQLtCLR.StoredProcedures].[SuppressOutput]
+
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/TableToText.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/TableToText.sql
new file mode 100644
index 0000000..9cbb198
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/TableToText.sql
@@ -0,0 +1,9 @@
+CREATE PROCEDURE tSQLt.TableToText
+ @txt NVARCHAR(MAX) OUTPUT,
+ @TableName NVARCHAR(MAX),
+ @OrderBy NVARCHAR(MAX) = NULL,
+ @PrintOnlyColumnNameAliasList NVARCHAR(MAX) = NULL
+AS
+BEGIN
+ SET @txt = tSQLt.Private::TableToString(@TableName, @OrderBy, @PrintOnlyColumnNameAliasList);
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/Uninstall.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/Uninstall.sql
new file mode 100644
index 0000000..a17803e
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/Uninstall.sql
@@ -0,0 +1,11 @@
+CREATE PROCEDURE tSQLt.Uninstall
+AS
+BEGIN
+
+ EXEC tSQLt.DropClass @ClassName = 'tSQLt';
+
+ DROP ASSEMBLY tSQLtCLR;
+
+ IF USER_ID('tSQLt.TestClass') IS NOT NULL DROP USER [tSQLt.TestClass];
+
+END;
diff --git a/DevopsTest.Tests/tSQLt/Stored Procedures/XmlResultFormatter.sql b/DevopsTest.Tests/tSQLt/Stored Procedures/XmlResultFormatter.sql
new file mode 100644
index 0000000..5cf4fae
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Stored Procedures/XmlResultFormatter.sql
@@ -0,0 +1,264 @@
+
+CREATE PROCEDURE tSQLt.XmlResultFormatter
+AS
+BEGIN
+ DECLARE @XmlOutput XML;
+
+ SELECT @XmlOutput = (
+ SELECT *--Tag, Parent, [testsuites!1!hide!hide], [testsuite!2!name], [testsuite!2!tests], [testsuite!2!errors], [testsuite!2!failures], [testsuite!2!timestamp], [testsuite!2!time], [testcase!3!classname], [testcase!3!name], [testcase!3!time], [failure!4!message]
+ FROM (
+ SELECT 1 AS Tag,
+ NULL AS Parent,
+ 'root' AS [testsuites!1!hide!hide],
+ NULL AS [testsuite!2!id],
+ NULL AS [testsuite!2!name],
+ NULL AS [testsuite!2!tests],
+ NULL AS [testsuite!2!errors],
+ NULL AS [testsuite!2!failures],
+ NULL AS [testsuite!2!skipped],
+ NULL AS [testsuite!2!timestamp],
+ NULL AS [testsuite!2!time],
+ NULL AS [testsuite!2!hostname],
+ NULL AS [testsuite!2!package],
+ NULL AS [properties!3!hide!hide],
+ NULL AS [testcase!4!classname],
+ NULL AS [testcase!4!name],
+ NULL AS [testcase!4!time],
+ NULL AS [failure!5!message],
+ NULL AS [failure!5!type],
+ NULL AS [error!6!message],
+ NULL AS [error!6!type],
+ NULL AS [skipped!7!message],
+ NULL AS [skipped!7!type],
+ NULL AS [system-out!8!hide],
+ NULL AS [system-err!9!hide]
+ UNION ALL
+ SELECT 2 AS Tag,
+ 1 AS Parent,
+ 'root',
+ ROW_NUMBER()OVER(ORDER BY Class),
+ Class,
+ COUNT(1),
+ SUM(CASE Result WHEN 'Error' THEN 1 ELSE 0 END),
+ SUM(CASE Result WHEN 'Failure' THEN 1 ELSE 0 END),
+ SUM(CASE Result WHEN 'Skipped' THEN 1 ELSE 0 END),
+ CONVERT(VARCHAR(19),MIN(TestResult.TestStartTime),126),
+ CAST(CAST(DATEDIFF(MILLISECOND,MIN(TestResult.TestStartTime),MAX(TestResult.TestEndTime))/1000.0 AS NUMERIC(20,3))AS VARCHAR(MAX)),
+ CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(MAX)),
+ 'tSQLt',
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ FROM tSQLt.TestResult
+ GROUP BY Class
+ UNION ALL
+ SELECT 3 AS Tag,
+ 2 AS Parent,
+ 'root',
+ NULL,
+ Class,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ Class,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ FROM tSQLt.TestResult
+ GROUP BY Class
+ UNION ALL
+ SELECT 4 AS Tag,
+ 2 AS Parent,
+ 'root',
+ NULL,
+ Class,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ Class,
+ TestCase,
+ CAST(CAST(DATEDIFF(MILLISECOND,TestResult.TestStartTime,TestResult.TestEndTime)/1000.0 AS NUMERIC(20,3))AS VARCHAR(MAX)),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ FROM tSQLt.TestResult
+ UNION ALL
+ SELECT 5 AS Tag,
+ 4 AS Parent,
+ 'root',
+ NULL,
+ Class,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ Class,
+ TestCase,
+ CAST(CAST(DATEDIFF(MILLISECOND,TestResult.TestStartTime,TestResult.TestEndTime)/1000.0 AS NUMERIC(20,3))AS VARCHAR(MAX)),
+ Msg,
+ 'tSQLt.Fail',
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ FROM tSQLt.TestResult
+ WHERE Result IN ('Failure')
+ UNION ALL
+ SELECT 6 AS Tag,
+ 4 AS Parent,
+ 'root',
+ NULL,
+ Class,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ Class,
+ TestCase,
+ CAST(CAST(DATEDIFF(MILLISECOND,TestResult.TestStartTime,TestResult.TestEndTime)/1000.0 AS NUMERIC(20,3))AS VARCHAR(MAX)),
+ NULL,
+ NULL,
+ Msg,
+ 'SQL Error',
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ FROM tSQLt.TestResult
+ WHERE Result IN ( 'Error')
+ UNION ALL
+ SELECT 7 AS Tag,
+ 4 AS Parent,
+ 'root',
+ NULL,
+ Class,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ Class,
+ TestCase,
+ CAST(CAST(DATEDIFF(MILLISECOND,TestResult.TestStartTime,TestResult.TestEndTime)/1000.0 AS NUMERIC(20,3))AS VARCHAR(MAX)),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ Msg,
+ NULL,
+ NULL,
+ NULL
+ FROM tSQLt.TestResult
+ WHERE Result IN ( 'Skipped')
+ UNION ALL
+ SELECT 8 AS Tag,
+ 2 AS Parent,
+ 'root',
+ NULL,
+ Class,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ Class,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ FROM tSQLt.TestResult
+ GROUP BY Class
+ UNION ALL
+ SELECT 9 AS Tag,
+ 2 AS Parent,
+ 'root',
+ NULL,
+ Class,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ Class,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ FROM tSQLt.TestResult
+ GROUP BY Class
+ ) AS X
+ ORDER BY [testsuite!2!name],CASE WHEN Tag IN (8,9) THEN 1 ELSE 0 END, [testcase!4!name], Tag
+ FOR XML EXPLICIT
+ );
+
+ EXEC tSQLt.Private_PrintXML @XmlOutput;
+END;
diff --git a/DevopsTest.Tests/tSQLt/Tables/CaptureOutputLog.sql b/DevopsTest.Tests/tSQLt/Tables/CaptureOutputLog.sql
new file mode 100644
index 0000000..9caeb14
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Tables/CaptureOutputLog.sql
@@ -0,0 +1,6 @@
+CREATE TABLE [tSQLt].[CaptureOutputLog] (
+ [Id] INT IDENTITY (1, 1) NOT NULL,
+ [OutputText] NVARCHAR (MAX) NULL,
+ PRIMARY KEY CLUSTERED ([Id] ASC)
+);
+
diff --git a/DevopsTest.Tests/tSQLt/Tables/Private_AssertEqualsTableSchema_Actual.sql b/DevopsTest.Tests/tSQLt/Tables/Private_AssertEqualsTableSchema_Actual.sql
new file mode 100644
index 0000000..2649906
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Tables/Private_AssertEqualsTableSchema_Actual.sql
@@ -0,0 +1,13 @@
+CREATE TABLE [tSQLt].[Private_AssertEqualsTableSchema_Actual] (
+ [name] NVARCHAR (256) NULL,
+ [RANK(column_id)] INT NULL,
+ [system_type_id] NVARCHAR (MAX) NULL,
+ [user_type_id] NVARCHAR (MAX) NULL,
+ [max_length] SMALLINT NULL,
+ [precision] TINYINT NULL,
+ [scale] TINYINT NULL,
+ [collation_name] NVARCHAR (256) NULL,
+ [is_nullable] BIT NULL,
+ [is_identity] BIT NULL
+);
+
diff --git a/DevopsTest.Tests/tSQLt/Tables/Private_AssertEqualsTableSchema_Expected.sql b/DevopsTest.Tests/tSQLt/Tables/Private_AssertEqualsTableSchema_Expected.sql
new file mode 100644
index 0000000..10bbc63
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Tables/Private_AssertEqualsTableSchema_Expected.sql
@@ -0,0 +1,13 @@
+CREATE TABLE [tSQLt].[Private_AssertEqualsTableSchema_Expected] (
+ [name] NVARCHAR (256) NULL,
+ [RANK(column_id)] INT NULL,
+ [system_type_id] NVARCHAR (MAX) NULL,
+ [user_type_id] NVARCHAR (MAX) NULL,
+ [max_length] SMALLINT NULL,
+ [precision] TINYINT NULL,
+ [scale] TINYINT NULL,
+ [collation_name] NVARCHAR (256) NULL,
+ [is_nullable] BIT NULL,
+ [is_identity] BIT NULL
+);
+
diff --git a/DevopsTest.Tests/tSQLt/Tables/Private_Configurations.sql b/DevopsTest.Tests/tSQLt/Tables/Private_Configurations.sql
new file mode 100644
index 0000000..e00fe10
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Tables/Private_Configurations.sql
@@ -0,0 +1,6 @@
+CREATE TABLE [tSQLt].[Private_Configurations] (
+ [Name] NVARCHAR (100) NOT NULL,
+ [Value] SQL_VARIANT NULL,
+ PRIMARY KEY CLUSTERED ([Name] ASC)
+);
+
diff --git a/DevopsTest.Tests/tSQLt/Tables/Private_ExpectException.sql b/DevopsTest.Tests/tSQLt/Tables/Private_ExpectException.sql
new file mode 100644
index 0000000..a40b5bb
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Tables/Private_ExpectException.sql
@@ -0,0 +1,4 @@
+CREATE TABLE [tSQLt].[Private_ExpectException] (
+ [i] INT NULL
+);
+
diff --git a/DevopsTest.Tests/tSQLt/Tables/Private_NewTestClassList.sql b/DevopsTest.Tests/tSQLt/Tables/Private_NewTestClassList.sql
new file mode 100644
index 0000000..953687b
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Tables/Private_NewTestClassList.sql
@@ -0,0 +1,5 @@
+CREATE TABLE [tSQLt].[Private_NewTestClassList] (
+ [ClassName] NVARCHAR (450) NOT NULL,
+ PRIMARY KEY CLUSTERED ([ClassName] ASC)
+);
+
diff --git a/DevopsTest.Tests/tSQLt/Tables/Private_NullCellTable.sql b/DevopsTest.Tests/tSQLt/Tables/Private_NullCellTable.sql
new file mode 100644
index 0000000..f1ebb02
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Tables/Private_NullCellTable.sql
@@ -0,0 +1,14 @@
+CREATE TABLE [tSQLt].[Private_NullCellTable] (
+ [I] INT NULL,
+ CONSTRAINT [U:tSQLt.Private_NullCellTable] UNIQUE CLUSTERED ([I] ASC)
+);
+
+
+GO
+
+CREATE TRIGGER tSQLt.Private_NullCellTable_StopModifications ON tSQLt.Private_NullCellTable INSTEAD OF DELETE, INSERT, UPDATE
+AS
+BEGIN
+ IF EXISTS (SELECT 1 FROM tSQLt.Private_NullCellTable) RETURN;
+ INSERT INTO tSQLt.Private_NullCellTable VALUES (NULL);
+END;
diff --git a/DevopsTest.Tests/tSQLt/Tables/Private_RenamedObjectLog.sql b/DevopsTest.Tests/tSQLt/Tables/Private_RenamedObjectLog.sql
new file mode 100644
index 0000000..0fc5cd4
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Tables/Private_RenamedObjectLog.sql
@@ -0,0 +1,7 @@
+CREATE TABLE [tSQLt].[Private_RenamedObjectLog] (
+ [Id] INT IDENTITY (1, 1) NOT NULL,
+ [ObjectId] INT NOT NULL,
+ [OriginalName] NVARCHAR (MAX) NOT NULL,
+ CONSTRAINT [PK__Private_RenamedObjectLog__Id] PRIMARY KEY CLUSTERED ([Id] ASC)
+);
+
diff --git a/DevopsTest.Tests/tSQLt/Tables/Run_LastExecution.sql b/DevopsTest.Tests/tSQLt/Tables/Run_LastExecution.sql
new file mode 100644
index 0000000..f958991
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Tables/Run_LastExecution.sql
@@ -0,0 +1,6 @@
+CREATE TABLE [tSQLt].[Run_LastExecution] (
+ [TestName] NVARCHAR (MAX) NULL,
+ [SessionId] INT NULL,
+ [LoginTime] DATETIME NULL
+);
+
diff --git a/DevopsTest.Tests/tSQLt/Tables/TestMessage.sql b/DevopsTest.Tests/tSQLt/Tables/TestMessage.sql
new file mode 100644
index 0000000..f4ee2dd
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Tables/TestMessage.sql
@@ -0,0 +1,4 @@
+CREATE TABLE [tSQLt].[TestMessage] (
+ [Msg] NVARCHAR (MAX) NULL
+);
+
diff --git a/DevopsTest.Tests/tSQLt/Tables/TestResult.sql b/DevopsTest.Tests/tSQLt/Tables/TestResult.sql
new file mode 100644
index 0000000..3793b1e
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Tables/TestResult.sql
@@ -0,0 +1,13 @@
+CREATE TABLE [tSQLt].[TestResult] (
+ [Id] INT IDENTITY (1, 1) NOT NULL,
+ [Class] NVARCHAR (MAX) NOT NULL,
+ [TestCase] NVARCHAR (MAX) NOT NULL,
+ [Name] AS ((quotename([Class])+'.')+quotename([TestCase])),
+ [TranName] NVARCHAR (MAX) NOT NULL,
+ [Result] NVARCHAR (MAX) NULL,
+ [Msg] NVARCHAR (MAX) NULL,
+ [TestStartTime] DATETIME2 (7) CONSTRAINT [DF:TestResult(TestStartTime)] DEFAULT (sysdatetime()) NOT NULL,
+ [TestEndTime] DATETIME2 (7) NULL,
+ PRIMARY KEY CLUSTERED ([Id] ASC)
+);
+
diff --git a/DevopsTest.Tests/tSQLt/User Defined Types/AssertStringTable.sql b/DevopsTest.Tests/tSQLt/User Defined Types/AssertStringTable.sql
new file mode 100644
index 0000000..e5960bb
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/User Defined Types/AssertStringTable.sql
@@ -0,0 +1,3 @@
+CREATE TYPE [tSQLt].[AssertStringTable] AS TABLE (
+ [value] NVARCHAR (MAX) NULL);
+
diff --git a/DevopsTest.Tests/tSQLt/User Defined Types/Private.sql b/DevopsTest.Tests/tSQLt/User Defined Types/Private.sql
new file mode 100644
index 0000000..33f4a84
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/User Defined Types/Private.sql
@@ -0,0 +1,3 @@
+CREATE TYPE [tSQLt].[Private]
+ EXTERNAL NAME [tSQLtCLR].[tSQLtCLR.tSQLtPrivate];
+
diff --git a/DevopsTest.Tests/tSQLt/Views/Private_HostPlatform.sql b/DevopsTest.Tests/tSQLt/Views/Private_HostPlatform.sql
new file mode 100644
index 0000000..e263800
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Views/Private_HostPlatform.sql
@@ -0,0 +1 @@
+CREATE VIEW tSQLt.Private_HostPlatform AS SELECT host_platform FROM sys.dm_os_host_info;
\ No newline at end of file
diff --git a/DevopsTest.Tests/tSQLt/Views/Private_SysIndexes.sql b/DevopsTest.Tests/tSQLt/Views/Private_SysIndexes.sql
new file mode 100644
index 0000000..824a893
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Views/Private_SysIndexes.sql
@@ -0,0 +1 @@
+CREATE VIEW tSQLt.Private_SysIndexes AS SELECT * FROM sys.indexes;
\ No newline at end of file
diff --git a/DevopsTest.Tests/tSQLt/Views/Private_SysTypes.sql b/DevopsTest.Tests/tSQLt/Views/Private_SysTypes.sql
new file mode 100644
index 0000000..17aeecc
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Views/Private_SysTypes.sql
@@ -0,0 +1 @@
+CREATE VIEW tSQLt.Private_SysTypes AS SELECT * FROM sys.types AS T;
diff --git a/DevopsTest.Tests/tSQLt/Views/TestClasses.sql b/DevopsTest.Tests/tSQLt/Views/TestClasses.sql
new file mode 100644
index 0000000..c64a1ca
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Views/TestClasses.sql
@@ -0,0 +1,8 @@
+CREATE VIEW tSQLt.TestClasses
+AS
+ SELECT s.name AS Name, s.schema_id AS SchemaId
+ FROM sys.schemas s
+ LEFT JOIN sys.extended_properties ep
+ ON ep.major_id = s.schema_id
+ WHERE ep.name = N'tSQLt.TestClass'
+ OR s.principal_id = USER_ID('tSQLt.TestClass');
diff --git a/DevopsTest.Tests/tSQLt/Views/Tests.sql b/DevopsTest.Tests/tSQLt/Views/Tests.sql
new file mode 100644
index 0000000..35b4bc0
--- /dev/null
+++ b/DevopsTest.Tests/tSQLt/Views/Tests.sql
@@ -0,0 +1,7 @@
+CREATE VIEW tSQLt.Tests
+AS
+ SELECT classes.SchemaId, classes.Name AS TestClassName,
+ procs.object_id AS ObjectId, procs.name AS Name
+ FROM tSQLt.TestClasses classes
+ JOIN sys.procedures procs ON classes.SchemaId = procs.schema_id
+ WHERE LOWER(procs.name) LIKE 'test%';
diff --git a/DevopsTest.sln b/DevopsTest.sln
new file mode 100644
index 0000000..d3d1bbd
--- /dev/null
+++ b/DevopsTest.sln
@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.1.31903.286
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "DevopsTest", "DevopsTest\DevopsTest.sqlproj", "{32C5D1B5-D115-46EF-90B7-8CD27FB6C5EE}"
+EndProject
+Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "DevopsTest.Tests", "DevopsTest.Tests\DevopsTest.Tests.sqlproj", "{36E394DF-C0D4-4DBC-AAB4-74AB0BBD2E54}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {32C5D1B5-D115-46EF-90B7-8CD27FB6C5EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {32C5D1B5-D115-46EF-90B7-8CD27FB6C5EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {32C5D1B5-D115-46EF-90B7-8CD27FB6C5EE}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {32C5D1B5-D115-46EF-90B7-8CD27FB6C5EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {32C5D1B5-D115-46EF-90B7-8CD27FB6C5EE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {32C5D1B5-D115-46EF-90B7-8CD27FB6C5EE}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ {36E394DF-C0D4-4DBC-AAB4-74AB0BBD2E54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {36E394DF-C0D4-4DBC-AAB4-74AB0BBD2E54}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {36E394DF-C0D4-4DBC-AAB4-74AB0BBD2E54}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {36E394DF-C0D4-4DBC-AAB4-74AB0BBD2E54}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {36E394DF-C0D4-4DBC-AAB4-74AB0BBD2E54}.Release|Any CPU.Build.0 = Release|Any CPU
+ {36E394DF-C0D4-4DBC-AAB4-74AB0BBD2E54}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {D2693012-3EFE-4566-A489-8AEEEB0AEF6B}
+ EndGlobalSection
+EndGlobal
diff --git a/DevopsTest/DevopsTest.sqlproj b/DevopsTest/DevopsTest.sqlproj
new file mode 100644
index 0000000..10fbaf4
--- /dev/null
+++ b/DevopsTest/DevopsTest.sqlproj
@@ -0,0 +1,65 @@
+
+
+
+ Debug
+ AnyCPU
+ DevopsTest
+ 2.0
+ 4.1
+ {32c5d1b5-d115-46ef-90b7-8cd27fb6c5ee}
+ Microsoft.Data.Tools.Schema.Sql.Sql150DatabaseSchemaProvider
+ Database
+
+
+ DevopsTest
+ DevopsTest
+ 1033, CI
+ BySchemaAndSchemaType
+ True
+ v4.7.2
+ CS
+ Properties
+ False
+ True
+ True
+
+
+ bin\Release\
+ $(MSBuildProjectName).sql
+ False
+ pdbonly
+ true
+ false
+ true
+ prompt
+ 4
+
+
+ bin\Debug\
+ $(MSBuildProjectName).sql
+ false
+ true
+ full
+ false
+ true
+ true
+ prompt
+ 4
+
+
+ 11.0
+
+ True
+ 11.0
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DevopsTest/dbo/Stored Procedures/DoSomething.sql b/DevopsTest/dbo/Stored Procedures/DoSomething.sql
new file mode 100644
index 0000000..9a66a0e
--- /dev/null
+++ b/DevopsTest/dbo/Stored Procedures/DoSomething.sql
@@ -0,0 +1,6 @@
+CREATE PROCEDURE [dbo].[DoSomething]
+ @param1 int = 0,
+ @param2 int
+AS
+ SELECT @param1, @param2
+RETURN 0