2121using System . Collections . Generic ;
2222using System . Globalization ;
2323using System . IO ;
24+ using System . Text . Json ;
25+
26+ #nullable enable
2427
2528namespace OpenQA . Selenium . Firefox
2629{
@@ -29,31 +32,27 @@ namespace OpenQA.Selenium.Firefox
2932 /// </summary>
3033 internal class Preferences
3134 {
32- private Dictionary < string , string > preferences = new Dictionary < string , string > ( ) ;
33- private Dictionary < string , string > immutablePreferences = new Dictionary < string , string > ( ) ;
35+ private readonly Dictionary < string , string > preferences = new Dictionary < string , string > ( ) ;
36+ private readonly HashSet < string > immutablePreferences = new HashSet < string > ( ) ;
3437
3538 /// <summary>
3639 /// Initializes a new instance of the <see cref="Preferences"/> class.
3740 /// </summary>
3841 /// <param name="defaultImmutablePreferences">A set of preferences that cannot be modified once set.</param>
3942 /// <param name="defaultPreferences">A set of default preferences.</param>
40- public Preferences ( Dictionary < string , object > defaultImmutablePreferences , Dictionary < string , object > defaultPreferences )
43+ public Preferences ( JsonElement defaultImmutablePreferences , JsonElement defaultPreferences )
4144 {
42- if ( defaultImmutablePreferences != null )
45+ foreach ( JsonProperty pref in defaultImmutablePreferences . EnumerateObject ( ) )
4346 {
44- foreach ( KeyValuePair < string , object > pref in defaultImmutablePreferences )
45- {
46- this . SetPreferenceValue ( pref . Key , pref . Value ) ;
47- this . immutablePreferences . Add ( pref . Key , pref . Value . ToString ( ) ) ;
48- }
47+ this . ThrowIfPreferenceIsImmutable ( pref . Name , pref . Value ) ;
48+ this . preferences [ pref . Name ] = pref . Value . GetRawText ( ) ;
49+ this . immutablePreferences . Add ( pref . Name ) ;
4950 }
5051
51- if ( defaultPreferences != null )
52+ foreach ( JsonProperty pref in defaultPreferences . EnumerateObject ( ) )
5253 {
53- foreach ( KeyValuePair < string , object > pref in defaultPreferences )
54- {
55- this . SetPreferenceValue ( pref . Key , pref . Value ) ;
56- }
54+ this . ThrowIfPreferenceIsImmutable ( pref . Name , pref . Value ) ;
55+ this . preferences [ pref . Name ] = pref . Value . GetRawText ( ) ;
5756 }
5857 }
5958
@@ -64,9 +63,31 @@ public Preferences(Dictionary<string, object> defaultImmutablePreferences, Dicti
6463 /// <param name="value">A <see cref="string"/> value give the preference.</param>
6564 /// <remarks>If the preference already exists in the currently-set list of preferences,
6665 /// the value will be updated.</remarks>
66+ /// <exception cref="ArgumentNullException">If <paramref name="key"/> or <paramref name="value"/> are <see langword="null"/>.</exception>
67+ /// <exception cref="ArgumentException">
68+ /// <para>If <paramref name="value"/> is wrapped with double-quotes.</para>
69+ /// <para>-or-</para>
70+ /// <para>If the specified preference is immutable.</para>
71+ /// </exception>
6772 internal void SetPreference ( string key , string value )
6873 {
69- this . SetPreferenceValue ( key , value ) ;
74+ if ( key is null )
75+ {
76+ throw new ArgumentNullException ( nameof ( key ) ) ;
77+ }
78+
79+ if ( value is null )
80+ {
81+ throw new ArgumentNullException ( nameof ( value ) ) ;
82+ }
83+
84+ if ( IsWrappedAsString ( value ) )
85+ {
86+ throw new ArgumentException ( string . Format ( CultureInfo . InvariantCulture , "Preference values must be plain strings: {0}: {1}" , key , value ) ) ;
87+ }
88+
89+ this . ThrowIfPreferenceIsImmutable ( key , value ) ;
90+ this . preferences [ key ] = string . Format ( CultureInfo . InvariantCulture , "\" {0}\" " , value ) ;
7091 }
7192
7293 /// <summary>
@@ -76,9 +97,17 @@ internal void SetPreference(string key, string value)
7697 /// <param name="value">A <see cref="int"/> value give the preference.</param>
7798 /// <remarks>If the preference already exists in the currently-set list of preferences,
7899 /// the value will be updated.</remarks>
100+ /// <exception cref="ArgumentNullException">If <paramref name="key"/> is <see langword="null"/>.</exception>
101+ /// <exception cref="ArgumentException">If the specified preference is immutable.</exception>
79102 internal void SetPreference ( string key , int value )
80103 {
81- this . SetPreferenceValue ( key , value ) ;
104+ if ( key is null )
105+ {
106+ throw new ArgumentNullException ( nameof ( key ) ) ;
107+ }
108+
109+ this . ThrowIfPreferenceIsImmutable ( key , value ) ;
110+ this . preferences [ key ] = value . ToString ( CultureInfo . InvariantCulture ) ;
82111 }
83112
84113 /// <summary>
@@ -88,16 +117,25 @@ internal void SetPreference(string key, int value)
88117 /// <param name="value">A <see cref="bool"/> value give the preference.</param>
89118 /// <remarks>If the preference already exists in the currently-set list of preferences,
90119 /// the value will be updated.</remarks>
120+ /// <exception cref="ArgumentNullException">If <paramref name="key"/> is <see langword="null"/>.</exception>
121+ /// <exception cref="ArgumentException">If the specified preference is immutable.</exception>
91122 internal void SetPreference ( string key , bool value )
92123 {
93- this . SetPreferenceValue ( key , value ) ;
124+ if ( key is null )
125+ {
126+ throw new ArgumentNullException ( nameof ( key ) ) ;
127+ }
128+
129+ this . ThrowIfPreferenceIsImmutable ( key , value ) ;
130+ this . preferences [ key ] = value ? "true" : "false" ;
94131 }
95132
96133 /// <summary>
97134 /// Gets a preference from the list of preferences.
98135 /// </summary>
99136 /// <param name="preferenceName">The name of the preference to retrieve.</param>
100137 /// <returns>The value of the preference, or an empty string if the preference is not set.</returns>
138+ /// <exception cref="ArgumentNullException">If <paramref name="preferenceName"/> is <see langword="null"/>.</exception>
101139 internal string GetPreference ( string preferenceName )
102140 {
103141 if ( this . preferences . ContainsKey ( preferenceName ) )
@@ -151,44 +189,18 @@ private static bool IsWrappedAsString(string value)
151189 return value . StartsWith ( "\" " , StringComparison . OrdinalIgnoreCase ) && value . EndsWith ( "\" " , StringComparison . OrdinalIgnoreCase ) ;
152190 }
153191
154- private bool IsSettablePreference ( string preferenceName )
192+ private void ThrowIfPreferenceIsImmutable < TValue > ( string preferenceName , TValue value )
155193 {
156- return ! this . immutablePreferences . ContainsKey ( preferenceName ) ;
157- }
158-
159- private void SetPreferenceValue ( string key , object value )
160- {
161- if ( ! this . IsSettablePreference ( key ) )
194+ if ( this . immutablePreferences . Contains ( preferenceName ) )
162195 {
163- string message = string . Format ( CultureInfo . InvariantCulture , "Preference {0} may not be overridden: frozen value={1}, requested value={2}" , key , this . immutablePreferences [ key ] , value . ToString ( ) ) ;
196+ string message = string . Format ( CultureInfo . InvariantCulture , "Preference {0} may not be overridden: frozen value={1}, requested value={2}" , preferenceName , this . preferences [ preferenceName ] , value ? . ToString ( ) ) ;
164197 throw new ArgumentException ( message ) ;
165198 }
199+ }
166200
167- string stringValue = value as string ;
168- if ( stringValue != null )
169- {
170- if ( IsWrappedAsString ( stringValue ) )
171- {
172- throw new ArgumentException ( string . Format ( CultureInfo . InvariantCulture , "Preference values must be plain strings: {0}: {1}" , key , value ) ) ;
173- }
174-
175- this . preferences [ key ] = string . Format ( CultureInfo . InvariantCulture , "\" {0}\" " , value ) ;
176- return ;
177- }
178-
179- if ( value is bool )
180- {
181- this . preferences [ key ] = Convert . ToBoolean ( value , CultureInfo . InvariantCulture ) . ToString ( ) . ToLowerInvariant ( ) ;
182- return ;
183- }
184-
185- if ( value is int || value is long )
186- {
187- this . preferences [ key ] = Convert . ToInt32 ( value , CultureInfo . InvariantCulture ) . ToString ( CultureInfo . InvariantCulture ) ;
188- return ;
189- }
190-
191- throw new WebDriverException ( "Value must be string, int or boolean" ) ;
201+ private bool IsSettablePreference ( string preferenceName )
202+ {
203+ return ! this . immutablePreferences . Contains ( preferenceName ) ;
192204 }
193205 }
194206}
0 commit comments