Skip to content

Commit ad32f1b

Browse files
Add Core configuration logger level binding
1 parent 42d283a commit ad32f1b

3 files changed

Lines changed: 129 additions & 0 deletions

File tree

source/Firebase/Core/ApiDefinition.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ interface Configuration
7878
// - (void)setLoggerLevel:(FIRLoggerLevel)loggerLevel;
7979
[Export ("setLoggerLevel:")]
8080
void SetLoggerLevel (LoggerLevel loggerLevel);
81+
82+
// - (FIRLoggerLevel)loggerLevel;
83+
[Export ("loggerLevel")]
84+
LoggerLevel LoggerLevel { get; }
8185
}
8286

8387
// @interface FIROptions : NSObject <NSCopying>

tests/E2E/Firebase.Foundation/FirebaseFoundationE2E/FirebaseRuntimeDriftCases.cs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
using System.Reflection;
22

3+
#if ENABLE_RUNTIME_DRIFT_CASE_CORE_CONFIGURATION_LOGGERLEVEL
4+
using Firebase.Core;
5+
using Foundation;
6+
using ObjCRuntime;
7+
#endif
8+
39
#if ENABLE_RUNTIME_DRIFT_CASE_ANALYTICS_SESSIONIDWITHCOMPLETION
410
using Firebase.Analytics;
511
using Foundation;
@@ -158,6 +164,119 @@ public static async Task<string> ExecuteConfiguredCaseAsync()
158164
?.Value;
159165
}
160166

167+
#if ENABLE_RUNTIME_DRIFT_CASE_CORE_CONFIGURATION_LOGGERLEVEL
168+
static Task<string> VerifyCoreConfigurationLoggerLevelAsync()
169+
{
170+
const string loggerLevelSelector = "loggerLevel";
171+
const string setLoggerLevelSelector = "setLoggerLevel:";
172+
const LoggerLevel requestedLevel = LoggerLevel.Warning;
173+
174+
var loggerLevelProperty = typeof(Configuration).GetProperty(
175+
nameof(Configuration.LoggerLevel),
176+
BindingFlags.Instance | BindingFlags.Public);
177+
if (loggerLevelProperty?.PropertyType != typeof(LoggerLevel))
178+
{
179+
throw new InvalidOperationException(
180+
$"Expected managed API '{typeof(Configuration).FullName}.{nameof(Configuration.LoggerLevel)}' " +
181+
$"to return '{typeof(LoggerLevel).FullName}' for selector '{loggerLevelSelector}', " +
182+
$"observed '{loggerLevelProperty?.PropertyType.FullName ?? "<missing>"}'.");
183+
}
184+
185+
var setter = typeof(Configuration).GetMethod(
186+
nameof(Configuration.SetLoggerLevel),
187+
BindingFlags.Instance | BindingFlags.Public,
188+
binder: null,
189+
types: new[] { typeof(LoggerLevel) },
190+
modifiers: null);
191+
if (setter?.ReturnType != typeof(void))
192+
{
193+
throw new InvalidOperationException(
194+
$"Expected managed API '{typeof(Configuration).FullName}.{nameof(Configuration.SetLoggerLevel)}({typeof(LoggerLevel).FullName})' " +
195+
$"to return void for selector '{setLoggerLevelSelector}', observed '{setter?.ReturnType.FullName ?? "<missing>"}'.");
196+
}
197+
198+
var configuration = Configuration.SharedInstance;
199+
if (configuration is null)
200+
{
201+
throw new InvalidOperationException("Firebase.Core.Configuration.SharedInstance returned null.");
202+
}
203+
204+
if (!configuration.RespondsToSelector(new Selector(loggerLevelSelector)))
205+
{
206+
throw new InvalidOperationException($"Native FIRConfiguration does not respond to expected selector '{loggerLevelSelector}'.");
207+
}
208+
209+
if (!configuration.RespondsToSelector(new Selector(setLoggerLevelSelector)))
210+
{
211+
throw new InvalidOperationException($"Native FIRConfiguration does not respond to expected selector '{setLoggerLevelSelector}'.");
212+
}
213+
214+
NSException? marshaledException = null;
215+
MarshalObjectiveCExceptionMode? marshaledExceptionMode = null;
216+
217+
void OnMarshalObjectiveCException(object? sender, MarshalObjectiveCExceptionEventArgs args)
218+
{
219+
marshaledException ??= args.Exception;
220+
marshaledExceptionMode ??= args.ExceptionMode;
221+
}
222+
223+
Runtime.MarshalObjectiveCException += OnMarshalObjectiveCException;
224+
try
225+
{
226+
LoggerLevel originalLevel = default;
227+
var originalLevelRead = false;
228+
LoggerLevel observedLevel;
229+
230+
try
231+
{
232+
originalLevel = configuration.LoggerLevel;
233+
originalLevelRead = true;
234+
configuration.SetLoggerLevel(requestedLevel);
235+
observedLevel = configuration.LoggerLevel;
236+
}
237+
catch (ObjCException ex)
238+
{
239+
throw new InvalidOperationException(
240+
$"Core configuration logger-level selectors should not throw after the missing getter binding is added, but observed {ex.GetType().FullName}. " +
241+
$"Selectors exercised: '{loggerLevelSelector}', '{setLoggerLevelSelector}'. " +
242+
$"NSException.Name: {FormatDetail(marshaledException?.Name?.ToString())}. " +
243+
$"NSException.Reason: {FormatDetail(marshaledException?.Reason)}. " +
244+
$"Marshal mode: {FormatDetail(marshaledExceptionMode?.ToString())}.",
245+
ex);
246+
}
247+
finally
248+
{
249+
if (originalLevelRead)
250+
{
251+
configuration.SetLoggerLevel(originalLevel);
252+
}
253+
}
254+
255+
if (observedLevel != requestedLevel)
256+
{
257+
throw new InvalidOperationException(
258+
$"Selector '{loggerLevelSelector}' returned '{observedLevel}' after setting '{requestedLevel}'.");
259+
}
260+
261+
if (marshaledException is not null)
262+
{
263+
throw new InvalidOperationException(
264+
$"Core configuration logger-level selectors completed, but Runtime.MarshalObjectiveCException captured unexpected NSException.Name '{marshaledException.Name}'. " +
265+
$"Reason: {FormatDetail(marshaledException.Reason)}. Marshal mode: {FormatDetail(marshaledExceptionMode?.ToString())}.");
266+
}
267+
268+
return Task.FromResult(
269+
$"Core configuration logger-level selectors crossed the native boundary. " +
270+
$"Selectors exercised: '{loggerLevelSelector}', '{setLoggerLevelSelector}'. " +
271+
$"Observed level after set: {observedLevel}.");
272+
}
273+
finally
274+
{
275+
Runtime.MarshalObjectiveCException -= OnMarshalObjectiveCException;
276+
}
277+
}
278+
#endif
279+
161280
#if ENABLE_RUNTIME_DRIFT_CASE_ANALYTICS_SESSIONIDWITHCOMPLETION
162281
static async Task<string> VerifyAnalyticsSessionIdWithCompletionAsync()
163282
{

tests/E2E/Firebase.Foundation/runtime-drift-cases.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
{
22
"cases": [
3+
{
4+
"id": "core-configuration-loggerlevel",
5+
"method": "VerifyCoreConfigurationLoggerLevelAsync",
6+
"bindingPackage": "AdamE.Firebase.iOS.Core",
7+
"packages": []
8+
},
39
{
410
"id": "analytics-sessionidwithcompletion",
511
"method": "VerifyAnalyticsSessionIdWithCompletionAsync",

0 commit comments

Comments
 (0)