|
| 1 | +using static Microsoft.VisualStudio.TestTools.UnitTesting.Assert; |
| 2 | + |
| 3 | +namespace SqlServerSimulator; |
| 4 | + |
| 5 | +/// <summary> |
| 6 | +/// Tests for the catalog surface SSMS Object Explorer's Views and |
| 7 | +/// Programmability nodes read via SMO: <c>sys.all_views</c> (create_date / |
| 8 | +/// principal_id / is_ms_shipped / ledger_view_type), the <c>principal_id</c> |
| 9 | +/// column SMO's function / procedure enumeration reads off |
| 10 | +/// <c>sys.all_objects</c>, <c>sys.sequences</c> (create_date / principal_id — |
| 11 | +/// the missing columns that left the Sequences node empty), |
| 12 | +/// <c>sys.types.max_length</c> / precision / scale (User-Defined Data Types |
| 13 | +/// node), <c>sys.assembly_types</c> (the three CLR system types), the empty |
| 14 | +/// <c>sys.plan_guides</c> view, and <c>sys.database_files</c> (current-database |
| 15 | +/// projection of <c>sys.master_files</c>, cross-database resolvable). Shapes / |
| 16 | +/// values probed against SQL Server 2025 (2026-07-15). |
| 17 | +/// </summary> |
| 18 | +[TestClass] |
| 19 | +public sealed class SsmsProgrammabilityNodeCatalogTests |
| 20 | +{ |
| 21 | + [TestMethod] |
| 22 | + public void AllViews_ExposesCreateDateNotNull() |
| 23 | + { |
| 24 | + var sim = new Simulation(); |
| 25 | + sim.ExecuteBatches("create view v as select 1 as c"); |
| 26 | + AreEqual(1, sim.ExecuteScalar<int>( |
| 27 | + "select count(*) from sys.all_views where name = 'v' and create_date is not null and modify_date is not null")); |
| 28 | + } |
| 29 | + |
| 30 | + [TestMethod] |
| 31 | + public void AllViews_PrincipalIdIsNull() |
| 32 | + { |
| 33 | + var sim = new Simulation(); |
| 34 | + sim.ExecuteBatches("create view v as select 1 as c"); |
| 35 | + AreEqual(1, sim.ExecuteScalar<int>("select count(*) from sys.all_views where name = 'v' and principal_id is null")); |
| 36 | + } |
| 37 | + |
| 38 | + [TestMethod] |
| 39 | + public void AllViews_IsMsShippedAndLedgerViewTypeAreZero() |
| 40 | + { |
| 41 | + var sim = new Simulation(); |
| 42 | + sim.ExecuteBatches("create view v as select 1 as c"); |
| 43 | + AreEqual(0, sim.ExecuteScalar<int>("select cast(is_ms_shipped as int) from sys.all_views where name = 'v'")); |
| 44 | + AreEqual(0, sim.ExecuteScalar<int>("select cast(ledger_view_type as int) from sys.all_views where name = 'v'")); |
| 45 | + } |
| 46 | + |
| 47 | + [TestMethod] |
| 48 | + public void AllObjects_ExposesPrincipalId_NullForUserFunction() |
| 49 | + { |
| 50 | + var sim = new Simulation(); |
| 51 | + sim.ExecuteBatches("create function dbo.f(@x int) returns int as begin return @x + 1 end"); |
| 52 | + AreEqual(1, sim.ExecuteScalar<int>( |
| 53 | + "select count(*) from sys.all_objects where name = 'f' and type = 'FN' and principal_id is null")); |
| 54 | + } |
| 55 | + |
| 56 | + [TestMethod] |
| 57 | + public void Objects_ExposesPrincipalId_NullForUserProcedure() |
| 58 | + { |
| 59 | + var sim = new Simulation(); |
| 60 | + sim.ExecuteBatches("create procedure dbo.p as select 1"); |
| 61 | + AreEqual(1, sim.ExecuteScalar<int>( |
| 62 | + "select count(*) from sys.objects where name = 'p' and type = 'P' and principal_id is null")); |
| 63 | + } |
| 64 | + |
| 65 | + [TestMethod] |
| 66 | + public void Sequences_ExposeCreateDateAndPrincipalId() |
| 67 | + { |
| 68 | + var sim = new Simulation(); |
| 69 | + _ = sim.ExecuteNonQuery("create sequence dbo.s as int start with 1 increment by 1"); |
| 70 | + AreEqual(1, sim.ExecuteScalar<int>( |
| 71 | + "select count(*) from sys.sequences where name = 's' and create_date is not null and principal_id is null")); |
| 72 | + } |
| 73 | + |
| 74 | + [TestMethod] |
| 75 | + public void Types_ScalarAliasReportsUnderlyingByteWidth() |
| 76 | + { |
| 77 | + var sim = new Simulation(); |
| 78 | + _ = sim.ExecuteNonQuery("create type dbo.MyStr from nvarchar(50)"); |
| 79 | + // nvarchar(50) byte width is 100; SMO halves it for the display Length. |
| 80 | + AreEqual(100, sim.ExecuteScalar<int>("select cast(max_length as int) from sys.types where name = 'MyStr'")); |
| 81 | + } |
| 82 | + |
| 83 | + [TestMethod] |
| 84 | + public void Types_ScalarAliasReportsPrecisionAndScale() |
| 85 | + { |
| 86 | + var sim = new Simulation(); |
| 87 | + _ = sim.ExecuteNonQuery("create type dbo.Amt from decimal(10, 2)"); |
| 88 | + AreEqual(9, sim.ExecuteScalar<int>("select cast(max_length as int) from sys.types where name = 'Amt'")); |
| 89 | + AreEqual(10, sim.ExecuteScalar<int>("select cast(precision as int) from sys.types where name = 'Amt'")); |
| 90 | + AreEqual(2, sim.ExecuteScalar<int>("select cast(scale as int) from sys.types where name = 'Amt'")); |
| 91 | + } |
| 92 | + |
| 93 | + [TestMethod] |
| 94 | + public void Types_SystemTypeMaxLengthMatchesSystypes() |
| 95 | + { |
| 96 | + var sim = new Simulation(); |
| 97 | + AreEqual(4, sim.ExecuteScalar<int>("select cast(max_length as int) from sys.types where name = 'int'")); |
| 98 | + AreEqual(8000, sim.ExecuteScalar<int>("select cast(max_length as int) from sys.types where name = 'nvarchar'")); |
| 99 | + AreEqual(8016, sim.ExecuteScalar<int>("select cast(max_length as int) from sys.types where name = 'sql_variant'")); |
| 100 | + } |
| 101 | + |
| 102 | + [TestMethod] |
| 103 | + public void AssemblyTypes_ProjectsThreeClrSystemTypes() |
| 104 | + => AreEqual(3, new Simulation().ExecuteScalar<int>("select count(*) from sys.assembly_types")); |
| 105 | + |
| 106 | + [TestMethod] |
| 107 | + public void AssemblyTypes_HierarchyidShape() |
| 108 | + { |
| 109 | + var sim = new Simulation(); |
| 110 | + AreEqual(892, sim.ExecuteScalar<int>("select cast(max_length as int) from sys.assembly_types where name = 'hierarchyid'")); |
| 111 | + AreEqual(240, sim.ExecuteScalar<int>("select cast(system_type_id as int) from sys.assembly_types where name = 'hierarchyid'")); |
| 112 | + AreEqual(128, sim.ExecuteScalar<int>("select user_type_id from sys.assembly_types where name = 'hierarchyid'")); |
| 113 | + AreEqual(4, sim.ExecuteScalar<int>("select schema_id from sys.assembly_types where name = 'hierarchyid'")); |
| 114 | + AreEqual(1, sim.ExecuteScalar<int>("select assembly_id from sys.assembly_types where name = 'hierarchyid'")); |
| 115 | + AreEqual(1, sim.ExecuteScalar<int>("select cast(is_assembly_type as int) from sys.assembly_types where name = 'hierarchyid'")); |
| 116 | + AreEqual(0, sim.ExecuteScalar<int>("select cast(is_user_defined as int) from sys.assembly_types where name = 'hierarchyid'")); |
| 117 | + } |
| 118 | + |
| 119 | + [TestMethod] |
| 120 | + public void AssemblyTypes_SpatialTypesReportMaxLengthMinusOne() |
| 121 | + { |
| 122 | + var sim = new Simulation(); |
| 123 | + AreEqual(-1, sim.ExecuteScalar<int>("select cast(max_length as int) from sys.assembly_types where name = 'geometry'")); |
| 124 | + AreEqual(-1, sim.ExecuteScalar<int>("select cast(max_length as int) from sys.assembly_types where name = 'geography'")); |
| 125 | + } |
| 126 | + |
| 127 | + /// <summary> |
| 128 | + /// SMO's User-Defined Types node filters is_user_defined = 1; the three |
| 129 | + /// system CLR types all report 0, so the node lists nothing (matching a |
| 130 | + /// WWI database with no user CLR types). |
| 131 | + /// </summary> |
| 132 | + [TestMethod] |
| 133 | + public void AssemblyTypes_UserDefinedFilterReturnsEmpty() |
| 134 | + => AreEqual(0, new Simulation().ExecuteScalar<int>("select count(*) from sys.assembly_types where is_user_defined = 1")); |
| 135 | + |
| 136 | + [TestMethod] |
| 137 | + public void PlanGuides_IsEmpty() |
| 138 | + => AreEqual(0, new Simulation().ExecuteScalar<int>("select count(*) from sys.plan_guides")); |
| 139 | + |
| 140 | + [TestMethod] |
| 141 | + public void PlanGuides_ExposesNameAndIsDisabled() |
| 142 | + { |
| 143 | + using var reader = new Simulation().ExecuteReader("select name, is_disabled from sys.plan_guides"); |
| 144 | + AreEqual(2, reader.FieldCount); |
| 145 | + AreEqual("name", reader.GetName(0)); |
| 146 | + AreEqual("is_disabled", reader.GetName(1)); |
| 147 | + IsFalse(reader.Read()); |
| 148 | + } |
| 149 | + |
| 150 | + [TestMethod] |
| 151 | + public void DatabaseFiles_ReturnsDataAndLogRow() |
| 152 | + { |
| 153 | + var sim = new Simulation(); |
| 154 | + AreEqual(2, sim.ExecuteScalar<int>("select count(*) from sys.database_files")); |
| 155 | + AreEqual(0, sim.ExecuteScalar<int>("select cast(type as int) from sys.database_files where file_id = 1")); |
| 156 | + AreEqual(1, sim.ExecuteScalar<int>("select cast(type as int) from sys.database_files where file_id = 2")); |
| 157 | + } |
| 158 | + |
| 159 | + [TestMethod] |
| 160 | + public void DatabaseFiles_AgreesWithMasterFilesOnName() |
| 161 | + { |
| 162 | + var sim = new Simulation(); |
| 163 | + var fromDatabaseFiles = (string?)sim.ExecuteScalar("select name from sys.database_files where file_id = 1"); |
| 164 | + var fromMasterFiles = (string?)sim.ExecuteScalar( |
| 165 | + "select name from sys.master_files where database_id = db_id() and file_id = 1"); |
| 166 | + AreEqual(fromMasterFiles, fromDatabaseFiles); |
| 167 | + IsTrue(fromDatabaseFiles!.EndsWith("_Data", StringComparison.Ordinal)); |
| 168 | + } |
| 169 | + |
| 170 | + [TestMethod] |
| 171 | + public void DatabaseFiles_ResolvesCrossDatabaseThroughMaster() |
| 172 | + { |
| 173 | + var sim = new Simulation(); |
| 174 | + AreEqual(2, sim.ExecuteScalar<int>("select count(*) from master.sys.database_files")); |
| 175 | + AreEqual("master_Data", (string?)sim.ExecuteScalar("select name from master.sys.database_files where file_id = 1")); |
| 176 | + AreEqual("master_Log", (string?)sim.ExecuteScalar("select name from master.sys.database_files where file_id = 2")); |
| 177 | + } |
| 178 | + |
| 179 | + [TestMethod] |
| 180 | + public void ViewsNode_TrimmedSmoQuery_ReturnsCreatedView() |
| 181 | + { |
| 182 | + var sim = new Simulation(); |
| 183 | + sim.ExecuteBatches("create view dbo.v as select 1 as c"); |
| 184 | + using var reader = sim.ExecuteReader(""" |
| 185 | + select v.name, schema_name(v.schema_id) as [Schema], v.create_date, |
| 186 | + cast(isnull(v.ledger_view_type, 0) as tinyint) as ledger |
| 187 | + from sys.all_views as v |
| 188 | + left outer join sys.database_principals as sv |
| 189 | + on sv.principal_id = isnull(v.principal_id, objectproperty(v.object_id, 'OwnerId')) |
| 190 | + where v.type = N'V' and cast(v.is_ms_shipped as bit) = 0 |
| 191 | + order by [Schema] asc, v.name asc |
| 192 | + """); |
| 193 | + IsTrue(reader.Read()); |
| 194 | + AreEqual("v", reader.GetString(0)); |
| 195 | + AreEqual("dbo", reader.GetString(1)); |
| 196 | + IsFalse(reader.Read()); |
| 197 | + } |
| 198 | +} |
0 commit comments