@@ -1765,10 +1765,100 @@ public async Task CanCustomizeBaseModelToSystemType()
17651765 // The BaseModelProvider should be null since the base is not a generated model
17661766 Assert . IsNull ( modelProvider . BaseModelProvider ) ;
17671767
1768- // System types from referenced assemblies are NOT found by FindForTypeInCustomization
1769- // (which only searches the customization assembly, not references), so they use SystemObjectTypeProvider
1770- Assert . IsInstanceOf < SystemObjectTypeProvider > ( modelProvider . BaseTypeProvider ,
1771- "System.Exception is from a referenced assembly and should use SystemObjectTypeProvider" ) ;
1768+ // System types from referenced assemblies are found in the customization compilation
1769+ // so inherited members can be represented by normal property providers.
1770+ Assert . IsInstanceOf < NamedTypeSymbolProvider > ( modelProvider . BaseTypeProvider ,
1771+ "System.Exception is from a referenced assembly and should use NamedTypeSymbolProvider" ) ;
1772+ }
1773+
1774+ [ Test ]
1775+ public async Task CanCustomizeSpecBaseModelToSystemType ( )
1776+ {
1777+ // This verifies that a custom partial base type wins even when the input model
1778+ // has a TypeSpec base model. Otherwise the generated partial would keep the
1779+ // TypeSpec base and conflict with the custom partial declaration.
1780+ var specBaseModel = InputFactory . Model (
1781+ "specBaseModel" ,
1782+ properties : [ InputFactory . Property ( "specBaseProp" , InputPrimitiveType . String ) ] ,
1783+ usage : InputModelTypeUsage . Json ) ;
1784+ var childModel = InputFactory . Model (
1785+ "mockInputModel" ,
1786+ properties : [
1787+ InputFactory . Property ( "message" , InputPrimitiveType . String ) ,
1788+ InputFactory . Property ( "childProp" , InputPrimitiveType . String ) ,
1789+ ] ,
1790+ baseModel : specBaseModel ,
1791+ usage : InputModelTypeUsage . Json ) ;
1792+
1793+ var mockGenerator = await MockHelpers . LoadMockGeneratorAsync (
1794+ inputModelTypes : [ childModel , specBaseModel ] ,
1795+ compilation : async ( ) => await Helpers . GetCompilationFromDirectoryAsync ( ) ) ;
1796+
1797+ var modelProvider = mockGenerator . Object . OutputLibrary . TypeProviders . Single ( t => t . Name == "MockInputModel" ) as ModelProvider ;
1798+
1799+ Assert . IsNotNull ( modelProvider ) ;
1800+ Assert . IsNotNull ( modelProvider ! . BaseType ) ;
1801+ Assert . AreEqual ( "Exception" , modelProvider . BaseType ! . Name ) ;
1802+ Assert . AreEqual ( "System" , modelProvider . BaseType ! . Namespace ) ;
1803+ Assert . IsNull ( modelProvider . BaseModelProvider , "The TypeSpec base model should not be used when custom code declares a system base type." ) ;
1804+ Assert . IsInstanceOf < NamedTypeSymbolProvider > ( modelProvider . BaseTypeProvider ) ;
1805+ Assert . That ( modelProvider . Properties . Select ( p => p . Name ) , Does . Not . Contain ( "Message" ) ) ;
1806+ Assert . That ( modelProvider . Properties . Select ( p => p . Name ) , Does . Contain ( "ChildProp" ) ) ;
1807+
1808+ var modelContent = new TypeProviderWriter ( modelProvider ) . Write ( ) . Content ;
1809+ Assert . That ( modelContent , Does . Contain ( "public partial class MockInputModel : global::System.Exception" ) ) ;
1810+ Assert . That ( modelContent , Does . Not . Contain ( "SpecBaseModel" ) ) ;
1811+ Assert . That ( modelContent , Does . Not . Contain ( "public string Message" ) ) ;
1812+ }
1813+
1814+ [ Test ]
1815+ public async Task CanCustomizeSpecBaseModelToSystemObjectModelProvider ( )
1816+ {
1817+ // This verifies the generator-specific system model path used by management-plane
1818+ // generators: a custom base type can resolve to a SystemObjectModelProvider in
1819+ // CSharpTypeMap, and generated members inherited from that mapped provider are filtered.
1820+ var specBaseModel = InputFactory . Model (
1821+ "specBaseModel" ,
1822+ properties : [ InputFactory . Property ( "specBaseProp" , InputPrimitiveType . String ) ] ,
1823+ usage : InputModelTypeUsage . Json ) ;
1824+ var childModel = InputFactory . Model (
1825+ "mockInputModel" ,
1826+ properties : [
1827+ InputFactory . Property ( "id" , InputPrimitiveType . String ) ,
1828+ InputFactory . Property ( "name" , InputPrimitiveType . String ) ,
1829+ InputFactory . Property ( "childProp" , InputPrimitiveType . String ) ,
1830+ ] ,
1831+ baseModel : specBaseModel ,
1832+ usage : InputModelTypeUsage . Json ) ;
1833+ var systemInputModel = InputFactory . Model (
1834+ "ResourceData" ,
1835+ properties : [
1836+ InputFactory . Property ( "id" , InputPrimitiveType . String ) ,
1837+ InputFactory . Property ( "name" , InputPrimitiveType . String ) ,
1838+ ] ,
1839+ usage : InputModelTypeUsage . Json ) ;
1840+
1841+ await MockHelpers . LoadMockGeneratorAsync (
1842+ inputModelTypes : [ childModel , specBaseModel , systemInputModel ] ,
1843+ compilation : async ( ) => await Helpers . GetCompilationFromDirectoryAsync ( ) ) ;
1844+
1845+ var customBaseType = CreateSystemCSharpType ( "ResourceData" , "TestFramework" ) ;
1846+ CodeModelGenerator . Instance . TypeFactory . CSharpTypeMap [ customBaseType ] = new SystemObjectModelProvider ( customBaseType , systemInputModel ) ;
1847+
1848+ var modelProvider = new ModelProvider ( childModel ) ;
1849+
1850+ Assert . IsNotNull ( modelProvider . BaseType ) ;
1851+ Assert . AreEqual ( "ResourceData" , modelProvider . BaseType ! . Name ) ;
1852+ Assert . AreEqual ( "TestFramework" , modelProvider . BaseType ! . Namespace ) ;
1853+ Assert . IsInstanceOf < SystemObjectModelProvider > ( modelProvider . BaseTypeProvider ) ;
1854+ Assert . That ( modelProvider . Properties . Select ( p => p . Name ) , Does . Not . Contain ( "Id" ) ) ;
1855+ Assert . That ( modelProvider . Properties . Select ( p => p . Name ) , Does . Not . Contain ( "Name" ) ) ;
1856+ Assert . That ( modelProvider . Properties . Select ( p => p . Name ) , Does . Contain ( "ChildProp" ) ) ;
1857+
1858+ var modelContent = new TypeProviderWriter ( modelProvider ) . Write ( ) . Content ;
1859+ Assert . That ( modelContent , Does . Contain ( "public partial class MockInputModel : global::TestFramework.ResourceData" ) ) ;
1860+ Assert . That ( modelContent , Does . Not . Contain ( "public string Id" ) ) ;
1861+ Assert . That ( modelContent , Does . Not . Contain ( "public string Name" ) ) ;
17721862 }
17731863
17741864 [ Test ]
@@ -1847,6 +1937,10 @@ await MockHelpers.LoadMockGeneratorAsync(
18471937
18481938 private const string AttributeNamespace = TestCustomCodeAttributeDefinition . AttributeNamespace ;
18491939
1940+ private static CSharpType CreateSystemCSharpType ( string name , string ns )
1941+ => new ( name , ns , isValueType : false , isNullable : false , declaringType : null ,
1942+ args : Array . Empty < CSharpType > ( ) , isPublic : true , isStruct : false ) ;
1943+
18501944 private class TestNameVisitor : NameVisitor
18511945 {
18521946 public TypeProvider ? InvokeVisit ( TypeProvider type )
0 commit comments