11using System . IO ;
2+ using Microsoft . Extensions . Logging ;
23using Microsoft . Extensions . Logging . Abstractions ;
34using SharpFM . Plugin ;
45using SharpFM . Services ;
@@ -19,6 +20,12 @@ public void UpdateSelectedClipXml(string xml, string originPluginId) { }
1920
2021public class PluginServiceTests
2122{
23+ private static PluginService CreateService ( string pluginsDir )
24+ {
25+ var logger = LoggerFactory . Create ( _ => { } ) . CreateLogger < PluginService > ( ) ;
26+ return new PluginService ( logger , pluginsDir ) ;
27+ }
28+
2229 [ Fact ]
2330 public void LoadPlugins_NoPluginsDir_LoadsZero ( )
2431 {
@@ -35,19 +42,137 @@ public void LoadPlugins_NoPluginsDir_LoadsZero()
3542 public void LoadPlugins_EmptyDir_LoadsZero ( )
3643 {
3744 var dir = Path . Combine ( Path . GetTempPath ( ) , $ "sharpfm-test-{ Guid . NewGuid ( ) } ") ;
38- Directory . CreateDirectory ( Path . Combine ( dir , "plugins" ) ) ;
45+ Directory . CreateDirectory ( dir ) ;
46+
47+ try
48+ {
49+ var service = CreateService ( dir ) ;
50+ service . LoadPlugins ( new MockPluginHost ( ) ) ;
51+ Assert . Empty ( service . LoadedPlugins ) ;
52+ }
53+ finally
54+ {
55+ Directory . Delete ( dir , recursive : true ) ;
56+ }
57+ }
58+
59+ [ Fact ]
60+ public void LoadPlugins_InvalidDll_GracefullySkips ( )
61+ {
62+ var dir = Path . Combine ( Path . GetTempPath ( ) , $ "sharpfm-test-{ Guid . NewGuid ( ) } ") ;
63+ Directory . CreateDirectory ( dir ) ;
64+
65+ try
66+ {
67+ File . WriteAllText ( Path . Combine ( dir , "BadPlugin.dll" ) , "not a real assembly" ) ;
68+
69+ var service = CreateService ( dir ) ;
70+ service . LoadPlugins ( new MockPluginHost ( ) ) ;
71+
72+ Assert . Empty ( service . LoadedPlugins ) ;
73+ }
74+ finally
75+ {
76+ Directory . Delete ( dir , recursive : true ) ;
77+ }
78+ }
79+
80+ [ Fact ]
81+ public void LoadPlugins_DllWithNoPluginTypes_LoadsZero ( )
82+ {
83+ var dir = Path . Combine ( Path . GetTempPath ( ) , $ "sharpfm-test-{ Guid . NewGuid ( ) } ") ;
84+ Directory . CreateDirectory ( dir ) ;
3985
4086 try
4187 {
42- // PluginService scans AppContext.BaseDirectory/plugins, so this tests
43- // the scenario indirectly — the important behavior is graceful handling
44- var service = new PluginService ( NullLogger . Instance ) ;
88+ // Copy a real assembly that has no IPanelPlugin implementations
89+ var nlogAssembly = typeof ( NLog . LogManager ) . Assembly . Location ;
90+ File . Copy ( nlogAssembly , Path . Combine ( dir , "NLog.dll" ) ) ;
91+
92+ var service = CreateService ( dir ) ;
4593 service . LoadPlugins ( new MockPluginHost ( ) ) ;
94+
4695 Assert . Empty ( service . LoadedPlugins ) ;
4796 }
4897 finally
4998 {
5099 Directory . Delete ( dir , recursive : true ) ;
51100 }
52101 }
102+
103+ [ Fact ]
104+ public void InstallPlugin_InvalidDll_CopiesButReturnsEmpty ( )
105+ {
106+ var pluginsDir = Path . Combine ( Path . GetTempPath ( ) , $ "sharpfm-test-{ Guid . NewGuid ( ) } ") ;
107+ var sourceDir = Path . Combine ( Path . GetTempPath ( ) , $ "sharpfm-source-{ Guid . NewGuid ( ) } ") ;
108+ Directory . CreateDirectory ( sourceDir ) ;
109+
110+ try
111+ {
112+ var sourceDll = Path . Combine ( sourceDir , "Bad.dll" ) ;
113+ File . WriteAllText ( sourceDll , "not a real assembly" ) ;
114+
115+ var service = CreateService ( pluginsDir ) ;
116+ var result = service . InstallPlugin ( sourceDll , new MockPluginHost ( ) ) ;
117+
118+ Assert . Empty ( result ) ;
119+ Assert . True ( File . Exists ( Path . Combine ( pluginsDir , "Bad.dll" ) ) ) ;
120+ }
121+ finally
122+ {
123+ if ( Directory . Exists ( pluginsDir ) ) Directory . Delete ( pluginsDir , recursive : true ) ;
124+ Directory . Delete ( sourceDir , recursive : true ) ;
125+ }
126+ }
127+
128+ [ Fact ]
129+ public void InstallPlugin_OverwritesExisting ( )
130+ {
131+ var pluginsDir = Path . Combine ( Path . GetTempPath ( ) , $ "sharpfm-test-{ Guid . NewGuid ( ) } ") ;
132+ var sourceDir = Path . Combine ( Path . GetTempPath ( ) , $ "sharpfm-source-{ Guid . NewGuid ( ) } ") ;
133+ Directory . CreateDirectory ( pluginsDir ) ;
134+ Directory . CreateDirectory ( sourceDir ) ;
135+
136+ try
137+ {
138+ File . WriteAllText ( Path . Combine ( pluginsDir , "Plugin.dll" ) , "old content" ) ;
139+ var sourceDll = Path . Combine ( sourceDir , "Plugin.dll" ) ;
140+ File . WriteAllText ( sourceDll , "new content" ) ;
141+
142+ var service = CreateService ( pluginsDir ) ;
143+ service . InstallPlugin ( sourceDll , new MockPluginHost ( ) ) ;
144+
145+ Assert . Equal ( "new content" , File . ReadAllText ( Path . Combine ( pluginsDir , "Plugin.dll" ) ) ) ;
146+ }
147+ finally
148+ {
149+ Directory . Delete ( pluginsDir , recursive : true ) ;
150+ Directory . Delete ( sourceDir , recursive : true ) ;
151+ }
152+ }
153+
154+ [ Fact ]
155+ public void LoadPlugins_WithRealPlugin_LoadsIt ( )
156+ {
157+ var dir = Path . Combine ( Path . GetTempPath ( ) , $ "sharpfm-test-{ Guid . NewGuid ( ) } ") ;
158+ Directory . CreateDirectory ( dir ) ;
159+
160+ try
161+ {
162+ // Copy the sample plugin and its dependencies
163+ var sampleAssembly = typeof ( SharpFM . Plugin . Sample . ClipInspectorPlugin ) . Assembly . Location ;
164+ var sampleDir = Path . GetDirectoryName ( sampleAssembly ) ! ;
165+ File . Copy ( sampleAssembly , Path . Combine ( dir , Path . GetFileName ( sampleAssembly ) ) ) ;
166+
167+ var service = CreateService ( dir ) ;
168+ service . LoadPlugins ( new MockPluginHost ( ) ) ;
169+
170+ Assert . Single ( service . LoadedPlugins ) ;
171+ Assert . Equal ( "clip-inspector" , service . LoadedPlugins [ 0 ] . Id ) ;
172+ }
173+ finally
174+ {
175+ Directory . Delete ( dir , recursive : true ) ;
176+ }
177+ }
53178}
0 commit comments